From fca5a01145f78a4ae517da6c19ee61ab54574e82 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:41:50 +0100 Subject: [PATCH 1/7] Improved command block security --- src/BlockEntities/CommandBlockEntity.cpp | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 45f8a3e4d..fe2f5e60a 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -13,6 +13,7 @@ #include "../Root.h" #include "../Server.h" // ExecuteConsoleCommand() #include "../Chunk.h" +#include "../ChatColor.h" @@ -206,15 +207,27 @@ void cCommandBlockEntity::Execute() virtual void Out(const AString & a_Text) { // Overwrite field - m_CmdBlock->SetLastOutput(a_Text); + m_CmdBlock->SetLastOutput(cClientHandle::FormatChatPrefix(m_CmdBlock->GetWorld()->ShouldUseChatPrefixes(), "SUCCESS", cChatColor::Green, cChatColor::White) + a_Text); } } CmdBlockOutCb(this); - LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); - - cServer * Server = cRoot::Get()->GetServer(); - - Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + if ( // Administrator commands are not executable by command blocks + (m_Command != "stop") && + (m_Command != "restart") && + (m_Command != "kick") && + (m_Command != "ban") && + (m_Command != "ipban") + ) + { + cServer * Server = cRoot::Get()->GetServer(); + LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); + Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + } + else + { + SetLastOutput(cClientHandle::FormatChatPrefix(GetWorld()->ShouldUseChatPrefixes(), "FAILURE", cChatColor::Rose, cChatColor::White) + "Adminstration commands can not be executed"); + LOGD("cCommandBlockEntity: Prevented execution of administration command %s", m_Command.c_str()); + } // TODO 2014-01-18 xdot: Update the signal strength. m_Result = 0; From 114b14faad854661040a3a65c027d6b3fa818f56 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:44:01 +0100 Subject: [PATCH 2/7] Removed unused code --- src/Entities/ItemFrame.cpp | 1 - src/Items/ItemHandler.h | 2 +- src/WorldStorage/NBTChunkSerializer.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp index f0b0c8c65..0bc10ec60 100644 --- a/src/Entities/ItemFrame.cpp +++ b/src/Entities/ItemFrame.cpp @@ -55,7 +55,6 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI) { if (m_Item.IsEmpty()) { - SetHealth(0); super::KilledBy(a_TDI); Destroy(); return; diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 8b554ee34..67c250a97 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -75,7 +75,7 @@ public: int FoodLevel; double Saturation; - FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) : + FoodInfo(int a_FoodLevel, double a_Saturation) : FoodLevel(a_FoodLevel), Saturation(a_Saturation) { diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e435a1b1f..68e541eba 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -615,7 +615,6 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) { m_Writer.BeginCompound(""); AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName()); - Vector3d Pos = a_Projectile->GetPosition(); m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0); switch (a_Projectile->GetProjectileKind()) From 21ff1d81ab4e68f31874894a1f4b7feb53d210df Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:44:10 +0100 Subject: [PATCH 3/7] Improved explosion damage --- src/ChunkMap.cpp | 69 ++++++++++++++++-------------------------------- src/World.cpp | 9 ++++--- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index dd8be0631..8ca61e2cf 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1880,21 +1880,18 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around { - if (!cBlockInfo::FullyOccupiesVoxel(Block)) + if ( + ((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) || + ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL))) + ) { - break; + m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } - else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL))) - { - break; - } - m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); - break; - + break; } } // switch (BlockType) } // for z @@ -1916,51 +1913,31 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ virtual bool Item(cEntity * a_Entity) override { - if (a_Entity->IsPickup()) + if (a_Entity->IsPickup() && (a_Entity->GetTicksAlive() < 20)) { - if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + return false; + } + + Vector3d DistanceFromExplosion = a_Entity->GetPosition() - m_ExplosionPos; + + if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible + { + cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + if (!m_bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa! { return false; } - } - Vector3d EntityPos = a_Entity->GetPosition(); - cBoundingBox bbEntity(EntityPos, a_Entity->GetWidth() / 2, a_Entity->GetHeight()); - - if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround - { - return false; - } - - Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z)); - - // Work out how far we are from the edge of the TNT's explosive effect - AbsoluteEntityPos -= m_ExplosionPos; - - // All to positive - AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x); - AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y); - AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z); - - double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize; - - // Clip damage values - FinalDamage = Clamp(FinalDamage, 0.0, (double)a_Entity->GetMaxHealth()); - - if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible - { - a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0); + // Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit + a_Entity->TakeDamage(dtExplosion, NULL, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0); } // Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt() - Vector3d distance_explosion = a_Entity->GetPosition() - m_ExplosionPos; - if (distance_explosion.SqrLength() < 4096.0) - { - distance_explosion.Normalize(); - distance_explosion *= m_ExplosionSize * m_ExplosionSize; - - a_Entity->AddSpeed(distance_explosion); - } + DistanceFromExplosion.Normalize(); + DistanceFromExplosion *= m_ExplosionSize * m_ExplosionSize; + a_Entity->AddSpeed(DistanceFromExplosion); return false; } diff --git a/src/World.cpp b/src/World.cpp index d2213d1e5..c850c50d3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1188,24 +1188,26 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo return; } - // TODO: Add damage to entities and implement block hardiness + // TODO: Implement block hardiness Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ); cVector3iArray BlocksAffected; m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected); BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f); + { cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if (ch == NULL) { continue; } + Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos; if (distance_explosion.SqrLength() < 4096.0) { - double real_distance = std::max(0.004, sqrt(distance_explosion.SqrLength())); + double real_distance = std::max(0.004, distance_explosion.Length()); double power = a_ExplosionSize / real_distance; if (power <= 1) { @@ -1217,6 +1219,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo } } } + cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData); } From 618741f78e2e840552663590fd0d6eab03aa874e Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 14:43:49 +0100 Subject: [PATCH 4/7] Added new console command with cleanup --- src/Root.cpp | 14 +++--------- src/Server.cpp | 59 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/Root.cpp b/src/Root.cpp index c20cf0d21..f72f0bae3 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -462,16 +462,6 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCall void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd) { - // Some commands are built-in: - if (a_Cmd == "stop") - { - m_bStop = true; - } - else if (a_Cmd == "restart") - { - m_bRestart = true; - } - // Put the command into a queue (Alleviates FS #363): cCSLock Lock(m_CSPendingCommands); m_PendingCommands.push_back(cCommand(a_Cmd, new cLogCommandDeleteSelfOutputCallback)); @@ -483,14 +473,16 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd) void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output) { - // Some commands are built-in: + // cRoot handles stopping and restarting due to our access to controlling variables if (a_Cmd == "stop") { m_bStop = true; + return; } else if (a_Cmd == "restart") { m_bRestart = true; + return; } LOG("Executing console command: \"%s\"", a_Cmd.c_str()); diff --git a/src/Server.cpp b/src/Server.cpp index 42ad133f1..4524ece76 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -457,33 +457,34 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac return; } - // Special handling: "stop" and "restart" are built in - if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0)) - { - return; - } + // "stop" and "restart" are handled in cRoot::ExecuteConsoleCommand, our caller, due to its access to controlling variables // "help" and "reload" are to be handled by MCS, so that they work no matter what if (split[0] == "help") { PrintHelp(split, a_Output); + a_Output.Finished(); return; } if (split[0] == "reload") { cPluginManager::Get()->ReloadPlugins(); cRoot::Get()->ReloadGroups(); + a_Output.Out("Plugins and groups reloaded"); + a_Output.Finished(); return; } if (split[0] == "reloadplugins") { cPluginManager::Get()->ReloadPlugins(); + a_Output.Out("Plugins reloaded"); + a_Output.Finished(); return; } if (split[0] == "reloadgroups") { cRoot::Get()->ReloadGroups(); - a_Output.Out("Groups reloaded!"); + a_Output.Out("Groups reloaded"); a_Output.Finished(); return; } @@ -491,31 +492,54 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac { if (split.size() > 1) { - cPluginManager::Get()->LoadPlugin(split[1]); - - return; + a_Output.Out(cPluginManager::Get()->LoadPlugin(split[1]) ? "Plugin loaded" : "Error occurred loading plugin"); } else { - a_Output.Out("No plugin given! Command: load "); - a_Output.Finished(); - return; + a_Output.Out("Usage: load "); } + a_Output.Finished(); + return; } - if (split[0] == "unload") { if (split.size() > 1) { cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1])); - return; + a_Output.Out("Plugin unloaded"); } else { - a_Output.Out("No plugin given! Command: unload "); - a_Output.Finished(); - return; + a_Output.Out("Usage: unload "); } + a_Output.Finished(); + return; + } + if (split[0] == "destroyentities") + { + class WorldCallback : public cWorldListCallback + { + virtual bool Item(cWorld * a_World) override + { + class EntityCallback : public cEntityCallback + { + virtual bool Item(cEntity * a_Entity) override + { + if (!a_Entity->IsPlayer()) + { + a_Entity->Destroy(); + } + return false; + } + } EC; + a_World->ForEachEntity(EC); + return false; + } + } WC; + cRoot::Get()->ForEachWorld(WC); + a_Output.Out("Destroyed all entities"); + a_Output.Finished(); + return; } // There is currently no way a plugin can do these (and probably won't ever be): @@ -610,6 +634,7 @@ void cServer::BindBuiltInConsoleCommands(void) PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics"); PlgMgr->BindConsoleCommand("load ", NULL, " - Adds and enables the specified plugin"); PlgMgr->BindConsoleCommand("unload ", NULL, " - Disables the specified plugin"); + PlgMgr->BindConsoleCommand("destroyentities", NULL, " - Destroys all entities in all worlds"); #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml"); From 389614c9599dc6a24a0f22b0a16e8af02e4b4cca Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 15:12:45 +0100 Subject: [PATCH 5/7] A better hotfix for CraftingRecipies --- src/CraftingRecipes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 223184c64..ed3409207 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -367,7 +367,7 @@ void cCraftingRecipes::ClearRecipes(void) void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine) { AString RecipeLine(a_RecipeLine); - RecipeLine.erase(std::remove(RecipeLine.begin(), RecipeLine.end(), ' '), RecipeLine.end()); + RecipeLine.erase(std::remove_if(RecipeLine.begin(), RecipeLine.end(), isspace), RecipeLine.end()); AStringVector Sides = StringSplit(RecipeLine, "="); if (Sides.size() != 2) From 9c1fadd50cc935615bb776919ef1ff0587f2590b Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 15:13:47 +0100 Subject: [PATCH 6/7] Updated Core --- MCServer/Plugins/Core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core index 7cc99285a..bd23915df 160000 --- a/MCServer/Plugins/Core +++ b/MCServer/Plugins/Core @@ -1 +1 @@ -Subproject commit 7cc99285ae5117418f657c3b295ca71f2b75b4f4 +Subproject commit bd23915df763b182610c6163c5ff2d64a0756560 From db663c7ee1737f5e03c0bce6584933123b9d58e3 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 30 Aug 2014 22:24:04 +0200 Subject: [PATCH 7/7] Fixed style. --- src/BlockEntities/CommandBlockEntity.cpp | 5 +++-- src/ChunkMap.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index fe2f5e60a..dd0858378 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -211,13 +211,14 @@ void cCommandBlockEntity::Execute() } } CmdBlockOutCb(this); - if ( // Administrator commands are not executable by command blocks + // Administrator commands are not executable by command blocks: + if ( (m_Command != "stop") && (m_Command != "restart") && (m_Command != "kick") && (m_Command != "ban") && (m_Command != "ipban") - ) + ) { cServer * Server = cRoot::Get()->GetServer(); LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 8ca61e2cf..a3692ef11 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1880,10 +1880,11 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around { + // If the block is shrapnel-able, make a falling block entity out of it: if ( ((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) || ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL))) - ) + ) { m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } @@ -1891,7 +1892,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); - break; + break; } } // switch (BlockType) } // for z