mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
add: restore the basic anti-cheat implementation and add spawn protection
Added the following anti-cheat measures and add spawn protection to `server.properties`. - instant break - speed - reach
This commit is contained in:
parent
797f73ba91
commit
48f0023d67
|
|
@ -569,6 +569,7 @@ MinecraftServer::MinecraftServer()
|
||||||
playerIdleTimeout = 0;
|
playerIdleTimeout = 0;
|
||||||
m_postUpdateThread = nullptr;
|
m_postUpdateThread = nullptr;
|
||||||
forceGameType = false;
|
forceGameType = false;
|
||||||
|
m_spawnProtectionRadius = 0;
|
||||||
|
|
||||||
commandDispatcher = new ServerCommandDispatcher();
|
commandDispatcher = new ServerCommandDispatcher();
|
||||||
InitializeCriticalSection(&m_consoleInputCS);
|
InitializeCriticalSection(&m_consoleInputCS);
|
||||||
|
|
@ -615,6 +616,10 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW
|
||||||
logger.info("Loading properties");
|
logger.info("Loading properties");
|
||||||
#endif
|
#endif
|
||||||
settings = new Settings(new File(L"server.properties"));
|
settings = new Settings(new File(L"server.properties"));
|
||||||
|
// Dedicated-only: spawn-protection radius in blocks; 0 disables protection.
|
||||||
|
m_spawnProtectionRadius = GetDedicatedServerInt(settings, L"spawn-protection", 0);
|
||||||
|
if (m_spawnProtectionRadius < 0) m_spawnProtectionRadius = 0;
|
||||||
|
if (m_spawnProtectionRadius > 256) m_spawnProtectionRadius = 256;
|
||||||
|
|
||||||
app.SetGameHostOption(eGameHostOption_Difficulty, GetDedicatedServerInt(settings, L"difficulty", app.GetGameHostOption(eGameHostOption_Difficulty)));
|
app.SetGameHostOption(eGameHostOption_Difficulty, GetDedicatedServerInt(settings, L"difficulty", app.GetGameHostOption(eGameHostOption_Difficulty)));
|
||||||
app.SetGameHostOption(eGameHostOption_GameType, GetDedicatedServerInt(settings, L"gamemode", app.GetGameHostOption(eGameHostOption_GameType)));
|
app.SetGameHostOption(eGameHostOption_GameType, GetDedicatedServerInt(settings, L"gamemode", app.GetGameHostOption(eGameHostOption_GameType)));
|
||||||
|
|
@ -631,6 +636,7 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW
|
||||||
app.DebugPrintf("ServerSettings: pvp is %s\n",(app.GetGameHostOption(eGameHostOption_PvP)>0)?"on":"off");
|
app.DebugPrintf("ServerSettings: pvp is %s\n",(app.GetGameHostOption(eGameHostOption_PvP)>0)?"on":"off");
|
||||||
app.DebugPrintf("ServerSettings: fire spreads is %s\n",(app.GetGameHostOption(eGameHostOption_FireSpreads)>0)?"on":"off");
|
app.DebugPrintf("ServerSettings: fire spreads is %s\n",(app.GetGameHostOption(eGameHostOption_FireSpreads)>0)?"on":"off");
|
||||||
app.DebugPrintf("ServerSettings: tnt explodes is %s\n",(app.GetGameHostOption(eGameHostOption_TNT)>0)?"on":"off");
|
app.DebugPrintf("ServerSettings: tnt explodes is %s\n",(app.GetGameHostOption(eGameHostOption_TNT)>0)?"on":"off");
|
||||||
|
app.DebugPrintf("ServerSettings: spawn protection radius is %d\n", m_spawnProtectionRadius);
|
||||||
app.DebugPrintf("\n");
|
app.DebugPrintf("\n");
|
||||||
|
|
||||||
// TODO 4J Stu - Init a load of settings based on data passed as params
|
// TODO 4J Stu - Init a load of settings based on data passed as params
|
||||||
|
|
@ -1661,7 +1667,9 @@ Level *MinecraftServer::getCommandSenderWorld()
|
||||||
|
|
||||||
int MinecraftServer::getSpawnProtectionRadius()
|
int MinecraftServer::getSpawnProtectionRadius()
|
||||||
{
|
{
|
||||||
return 16;
|
// Client-host mode must never apply dedicated-server spawn protection settings.
|
||||||
|
if (!ShouldUseDedicatedServerProperties()) return 0;
|
||||||
|
return m_spawnProtectionRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MinecraftServer::isUnderSpawnProtection(Level *level, int x, int y, int z, shared_ptr<Player> player)
|
bool MinecraftServer::isUnderSpawnProtection(Level *level, int x, int y, int z, shared_ptr<Player> player)
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ public:
|
||||||
int maxBuildHeight;
|
int maxBuildHeight;
|
||||||
int playerIdleTimeout;
|
int playerIdleTimeout;
|
||||||
bool forceGameType;
|
bool forceGameType;
|
||||||
|
int m_spawnProtectionRadius;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 4J Added
|
// 4J Added
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,19 @@
|
||||||
#include "..\Minecraft.Server\ServerLogManager.h"
|
#include "..\Minecraft.Server\ServerLogManager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Anti-cheat thresholds. Keep server-side checks authoritative even in host mode.
|
||||||
|
// Base max squared displacement allowed per move packet before speed flags trigger.
|
||||||
|
const double kMoveBaseAllowanceSq = 100.0;
|
||||||
|
// Extra squared displacement allowance derived from current server-side velocity.
|
||||||
|
const double kMoveVelocityAllowanceScale = 100.0;
|
||||||
|
// Max squared distance for interact/attack when the target is visible (normal reach).
|
||||||
|
const double kInteractReachSq = 6.0 * 6.0;
|
||||||
|
// Stricter max squared distance used when LOS is blocked to reduce wall-hit abuse.
|
||||||
|
const double kInteractBlockedReachSq = 3.0 * 3.0;
|
||||||
|
}
|
||||||
|
|
||||||
Random PlayerConnection::random;
|
Random PlayerConnection::random;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -300,16 +313,19 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
|
||||||
|
|
||||||
double dist = xDist * xDist + yDist * yDist + zDist * zDist;
|
double dist = xDist * xDist + yDist * yDist + zDist * zDist;
|
||||||
|
|
||||||
// 4J-PB - removing this one for now
|
// Anti-cheat: reject movement packets that exceed server-authoritative bounds.
|
||||||
/*if (dist > 100.0f)
|
double velocitySq = player->xd * player->xd + player->yd * player->yd + player->zd * player->zd;
|
||||||
|
double maxAllowedSq = kMoveBaseAllowanceSq + (velocitySq * kMoveVelocityAllowanceScale);
|
||||||
|
if (player->isAllowedToFly() || player->gameMode->isCreative())
|
||||||
{
|
{
|
||||||
// logger.warning(player->name + " moved too quickly!");
|
// Creative / flight-allowed players can move farther legitimately per tick.
|
||||||
disconnect(DisconnectPacket::eDisconnect_MovedTooQuickly);
|
maxAllowedSq *= 1.5;
|
||||||
// System.out.println("Moved too quickly at " + xt + ", " + yt + ", " + zt);
|
}
|
||||||
// teleport(player->x, player->y, player->z, player->yRot, player->xRot);
|
if (dist > maxAllowedSq)
|
||||||
return;
|
{
|
||||||
|
disconnect(DisconnectPacket::eDisconnect_MovedTooQuickly);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
float r = 1 / 16.0f;
|
float r = 1 / 16.0f;
|
||||||
bool oldOk = level->getCubes(player, player->bb->copy()->shrink(r, r, r))->empty();
|
bool oldOk = level->getCubes(player, player->bb->copy()->shrink(r, r, r))->empty();
|
||||||
|
|
@ -337,8 +353,8 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
|
||||||
xDist = xt - player->x;
|
xDist = xt - player->x;
|
||||||
yDist = yt - player->y;
|
yDist = yt - player->y;
|
||||||
|
|
||||||
// 4J-PB - line below will always be true!
|
// Clamp tiny Y drift noise to reduce false positives.
|
||||||
if (yDist > -0.5 || yDist < 0.5)
|
if (yDist > -0.5 && yDist < 0.5)
|
||||||
{
|
{
|
||||||
yDist = 0;
|
yDist = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -459,7 +475,8 @@ void PlayerConnection::handlePlayerAction(shared_ptr<PlayerActionPacket> packet)
|
||||||
|
|
||||||
if (packet->action == PlayerActionPacket::START_DESTROY_BLOCK)
|
if (packet->action == PlayerActionPacket::START_DESTROY_BLOCK)
|
||||||
{
|
{
|
||||||
if (true) player->gameMode->startDestroyBlock(x, y, z, packet->face); // 4J - condition was !server->isUnderSpawnProtection(level, x, y, z, player) (from Java 1.6.4) but putting back to old behaviour
|
// Anti-cheat: validate spawn protection on the server for mining start.
|
||||||
|
if (!server->isUnderSpawnProtection(level, x, y, z, player)) player->gameMode->startDestroyBlock(x, y, z, packet->face);
|
||||||
else player->connection->send(std::make_shared<TileUpdatePacket>(x, y, z, level));
|
else player->connection->send(std::make_shared<TileUpdatePacket>(x, y, z, level));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -487,8 +504,6 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet)
|
||||||
int face = packet->getFace();
|
int face = packet->getFace();
|
||||||
player->resetLastActionTime();
|
player->resetLastActionTime();
|
||||||
|
|
||||||
// 4J Stu - We don't have ops, so just use the levels setting
|
|
||||||
bool canEditSpawn = level->canEditSpawn; // = level->dimension->id != 0 || server->players->isOp(player->name);
|
|
||||||
if (packet->getFace() == 255)
|
if (packet->getFace() == 255)
|
||||||
{
|
{
|
||||||
if (item == nullptr) return;
|
if (item == nullptr) return;
|
||||||
|
|
@ -498,7 +513,8 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet)
|
||||||
{
|
{
|
||||||
if (synched && player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) < 8 * 8)
|
if (synched && player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) < 8 * 8)
|
||||||
{
|
{
|
||||||
if (true) // 4J - condition was !server->isUnderSpawnProtection(level, x, y, z, player) (from java 1.6.4) but putting back to old behaviour
|
// Anti-cheat: block placement/use must pass server-side spawn protection.
|
||||||
|
if (!server->isUnderSpawnProtection(level, x, y, z, player))
|
||||||
{
|
{
|
||||||
player->gameMode->useItemOn(player, level, item, x, y, z, face, packet->getClickX(), packet->getClickY(), packet->getClickZ());
|
player->gameMode->useItemOn(player, level, item, x, y, z, face, packet->getClickX(), packet->getClickY(), packet->getClickZ());
|
||||||
}
|
}
|
||||||
|
|
@ -782,17 +798,16 @@ void PlayerConnection::handleInteract(shared_ptr<InteractPacket> packet)
|
||||||
// 4J Stu - If the client says that we hit something, then agree with it. The canSee can fail here as it checks
|
// 4J Stu - If the client says that we hit something, then agree with it. The canSee can fail here as it checks
|
||||||
// a ray from head->head, but we may actually be looking at a different part of the entity that can be seen
|
// a ray from head->head, but we may actually be looking at a different part of the entity that can be seen
|
||||||
// even though the ray is blocked.
|
// even though the ray is blocked.
|
||||||
if (target != nullptr) // && player->canSee(target) && player->distanceToSqr(target) < 6 * 6)
|
if (target != nullptr)
|
||||||
{
|
{
|
||||||
//boole canSee = player->canSee(target);
|
// Anti-cheat: enforce reach and LOS on the server to reject forged hits.
|
||||||
//double maxDist = 6 * 6;
|
bool canSeeTarget = player->canSee(target);
|
||||||
//if (!canSee)
|
double maxDistSq = canSeeTarget ? kInteractReachSq : kInteractBlockedReachSq;
|
||||||
//{
|
if (player->distanceToSqr(target) > maxDistSq)
|
||||||
// maxDist = 3 * 3;
|
{
|
||||||
//}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//if (player->distanceToSqr(target) < maxDist)
|
|
||||||
//{
|
|
||||||
if (packet->action == InteractPacket::INTERACT)
|
if (packet->action == InteractPacket::INTERACT)
|
||||||
{
|
{
|
||||||
player->interact(target);
|
player->interact(target);
|
||||||
|
|
@ -807,7 +822,6 @@ void PlayerConnection::handleInteract(shared_ptr<InteractPacket> packet)
|
||||||
}
|
}
|
||||||
player->attack(target);
|
player->attack(target);
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,31 +176,29 @@ void ServerPlayerGameMode::stopDestroyBlock(int x, int y, int z)
|
||||||
{
|
{
|
||||||
if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock)
|
if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock)
|
||||||
{
|
{
|
||||||
// int ticksSpentDestroying = gameTicks - destroyProgressStart;
|
|
||||||
|
|
||||||
int t = level->getTile(x, y, z);
|
int t = level->getTile(x, y, z);
|
||||||
if (t != 0)
|
if (t != 0)
|
||||||
{
|
{
|
||||||
Tile *tile = Tile::tiles[t];
|
Tile *tile = Tile::tiles[t];
|
||||||
|
// Anti-cheat: re-check destroy progress on the server for STOP_DESTROY.
|
||||||
// MGH - removed checking for the destroy progress here, it has already been checked on the client before it sent the packet.
|
int ticksSpentDestroying = gameTicks - destroyProgressStart;
|
||||||
// fixes issues with this failing to destroy because of packets bunching up
|
float destroyProgress = tile->getDestroyProgress(player, player->level, x, y, z) * (ticksSpentDestroying + 1);
|
||||||
// float destroyProgress = tile->getDestroyProgress(player, player->level, x, y, z) * (ticksSpentDestroying + 1);
|
if (destroyProgress >= 1.0f)
|
||||||
// if (destroyProgress >= .7f || bIgnoreDestroyProgress)
|
|
||||||
{
|
{
|
||||||
isDestroyingBlock = false;
|
isDestroyingBlock = false;
|
||||||
level->destroyTileProgress(player->entityId, x, y, z, -1);
|
level->destroyTileProgress(player->entityId, x, y, z, -1);
|
||||||
destroyBlock(x, y, z);
|
destroyBlock(x, y, z);
|
||||||
}
|
}
|
||||||
// else if (!hasDelayedDestroy)
|
else if (!hasDelayedDestroy)
|
||||||
// {
|
{
|
||||||
// isDestroyingBlock = false;
|
// Keep server-authoritative mining while allowing legit latency to finish via delayed tick progression.
|
||||||
// hasDelayedDestroy = true;
|
isDestroyingBlock = false;
|
||||||
// delayedDestroyX = x;
|
hasDelayedDestroy = true;
|
||||||
// delayedDestroyY = y;
|
delayedDestroyX = x;
|
||||||
// delayedDestroyZ = z;
|
delayedDestroyY = y;
|
||||||
// delayedTickStart = destroyProgressStart;
|
delayedDestroyZ = z;
|
||||||
// }
|
delayedTickStart = destroyProgressStart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ static const ServerPropertyDefault kServerPropertyDefaults[] =
|
||||||
{ "level-seed", "" },
|
{ "level-seed", "" },
|
||||||
{ "level-type", "default" },
|
{ "level-type", "default" },
|
||||||
{ "world-size", "classic" },
|
{ "world-size", "classic" },
|
||||||
|
{ "spawn-protection", "0" },
|
||||||
{ "log-level", "info" },
|
{ "log-level", "info" },
|
||||||
{ "max-build-height", "256" },
|
{ "max-build-height", "256" },
|
||||||
{ "max-players", "16" },
|
{ "max-players", "16" },
|
||||||
|
|
@ -834,6 +835,7 @@ ServerPropertiesConfig LoadServerPropertiesConfig()
|
||||||
&config.worldHellScale,
|
&config.worldHellScale,
|
||||||
&shouldWrite);
|
&shouldWrite);
|
||||||
config.levelType = ReadNormalizedLevelTypeProperty(&merged, "level-type", &config.levelTypeFlat, &shouldWrite);
|
config.levelType = ReadNormalizedLevelTypeProperty(&merged, "level-type", &config.levelTypeFlat, &shouldWrite);
|
||||||
|
config.spawnProtectionRadius = ReadNormalizedIntProperty(&merged, "spawn-protection", 0, 0, 256, &shouldWrite);
|
||||||
config.generateStructures = ReadNormalizedBoolProperty(&merged, "generate-structures", true, &shouldWrite);
|
config.generateStructures = ReadNormalizedBoolProperty(&merged, "generate-structures", true, &shouldWrite);
|
||||||
config.bonusChest = ReadNormalizedBoolProperty(&merged, "bonus-chest", false, &shouldWrite);
|
config.bonusChest = ReadNormalizedBoolProperty(&merged, "bonus-chest", false, &shouldWrite);
|
||||||
config.pvp = ReadNormalizedBoolProperty(&merged, "pvp", true, &shouldWrite);
|
config.pvp = ReadNormalizedBoolProperty(&merged, "pvp", true, &shouldWrite);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ namespace ServerRuntime
|
||||||
/** Nether scale derived from `world-size` */
|
/** Nether scale derived from `world-size` */
|
||||||
int worldHellScale;
|
int worldHellScale;
|
||||||
bool levelTypeFlat;
|
bool levelTypeFlat;
|
||||||
|
/** `spawn-protection` radius in blocks (0 disables protection) */
|
||||||
|
int spawnProtectionRadius;
|
||||||
bool generateStructures;
|
bool generateStructures;
|
||||||
bool bonusChest;
|
bool bonusChest;
|
||||||
bool pvp;
|
bool pvp;
|
||||||
|
|
|
||||||
|
|
@ -409,6 +409,7 @@ int main(int argc, char **argv)
|
||||||
accessShutdownGuard.Activate();
|
accessShutdownGuard.Activate();
|
||||||
LogInfof("startup", "LAN advertise: %s", serverProperties.lanAdvertise ? "enabled" : "disabled");
|
LogInfof("startup", "LAN advertise: %s", serverProperties.lanAdvertise ? "enabled" : "disabled");
|
||||||
LogInfof("startup", "Whitelist: %s", serverProperties.whiteListEnabled ? "enabled" : "disabled");
|
LogInfof("startup", "Whitelist: %s", serverProperties.whiteListEnabled ? "enabled" : "disabled");
|
||||||
|
LogInfof("startup", "Spawn protection radius: %d", serverProperties.spawnProtectionRadius);
|
||||||
#ifdef _LARGE_WORLDS
|
#ifdef _LARGE_WORLDS
|
||||||
LogInfof(
|
LogInfof(
|
||||||
"startup",
|
"startup",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue