diff options
Diffstat (limited to 'src')
108 files changed, 2055 insertions, 786 deletions
diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp index bb59fca7c..3ae1fd990 100644 --- a/src/Bindings/DeprecatedBindings.cpp +++ b/src/Bindings/DeprecatedBindings.cpp @@ -291,6 +291,114 @@ tolua_lerror: +static int tolua_cBlockInfo_GetPlaceSound(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamStaticSelf("cBlockInfo") || + !L.CheckParamNumber(2) + ) + { + return 0; + } + + L.Push(""); + LOGWARNING("cBlockInfo:GetPlaceSound() is deprecated"); + L.LogStackTrace(0); + return 1; +} + + + + + +static int tolua_get_cBlockInfo_m_PlaceSound(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if (!L.CheckParamSelf("const cBlockInfo")) + { + return 0; + } + + L.Push(""); + LOGWARNING("cBlockInfo.m_PlaceSound is deprecated"); + L.LogStackTrace(0); + return 1; +} + + + + + +static int tolua_set_cBlockInfo_m_PlaceSound(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if (!L.CheckParamSelf("cBlockInfo")) + { + return 0; + } + + LOGWARNING("cBlockInfo.m_PlaceSound is deprecated"); + L.LogStackTrace(0); + return 0; +} + + + + + +static int tolua_get_cItem_m_Lore(lua_State * tolua_S) +{ + // Maintain legacy m_Lore variable as Lore table split by ` (grave-accent) + cLuaState L(tolua_S); + if (!L.CheckParamSelf("const cItem")) + { + return 0; + } + + const cItem * Self = nullptr; + L.GetStackValue(1, Self); + + AString LoreString = StringJoin(Self->m_LoreTable, "`"); + + L.Push(LoreString); + + LOGWARNING("cItem.m_Lore is deprecated, use cItem.m_LoreTable instead"); + L.LogStackTrace(0); + return 1; +} + + + + + +static int tolua_set_cItem_m_Lore(lua_State * tolua_S) +{ + // Maintain legacy m_Lore variable as Lore table split by ` (grave-accent) + cLuaState L(tolua_S); + if ( + !L.CheckParamSelf("cItem") || + !L.CheckParamString(2) + ) + { + return 0; + } + + cItem * Self = nullptr; + AString LoreString; + L.GetStackValues(1, Self, LoreString); + + Self->m_LoreTable = StringSplit(LoreString, "`"); + + LOGWARNING("cItem.m_Lore is deprecated, use cItem.m_LoreTable instead"); + L.LogStackTrace(0); + return 0; +} + + + + + /* method: Trace of class cTracer */ static int tolua_cTracer_Trace(lua_State * a_LuaState) { @@ -439,6 +547,15 @@ void DeprecatedBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "StringToMobType", tolua_AllToLua_StringToMobType00); + tolua_beginmodule(tolua_S, "cBlockInfo"); + tolua_function(tolua_S, "GetPlaceSound", tolua_cBlockInfo_GetPlaceSound); + tolua_variable(tolua_S, "m_PlaceSound", tolua_get_cBlockInfo_m_PlaceSound, tolua_set_cBlockInfo_m_PlaceSound); + tolua_endmodule(tolua_S); + + tolua_beginmodule(tolua_S, "cItem"); + tolua_variable(tolua_S, "m_Lore", tolua_get_cItem_m_Lore, tolua_set_cItem_m_Lore); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cTracer"); tolua_function(tolua_S, "Trace", tolua_cTracer_Trace); tolua_endmodule(tolua_S); diff --git a/src/Bindings/DiffAPIDesc.lua b/src/Bindings/DiffAPIDesc.lua index 8b8c340e2..54d379356 100644 --- a/src/Bindings/DiffAPIDesc.lua +++ b/src/Bindings/DiffAPIDesc.lua @@ -129,14 +129,17 @@ end -- a_FunctionDoc is a single documentation item for a function, as loaded from ToLua++'s parser local function functionDescMatchesDocs(a_FunctionDesc, a_FunctionDoc) -- Check the number of parameters: - local numParams + local numParams = 0 local numOptionalParams = 0 if (not(a_FunctionDesc.Params) or (a_FunctionDesc.Params == "")) then numParams = 0 else - _, numParams = string.gsub(a_FunctionDesc.Params, ",", "") - numParams = numParams + 1 - _, numOptionalParams = string.gsub(a_FunctionDesc.Params, "%b[]", "") + for _, Param in pairs(a_FunctionDesc.Params) do + numParams = numParams + 1 + if Param.IsOptional then + numOptionalParams = numOptionalParams + 1 + end + end end local numDocParams = #(a_FunctionDoc.Params) if ((numDocParams > numParams) or (numDocParams < numParams - numOptionalParams)) then diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index e30d0ed5f..185759acc 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -875,6 +875,17 @@ void cLuaState::Push(const char * a_Value) +void cLuaState::Push(const cItem & a_Item) +{ + ASSERT(IsValid()); + auto c = new cItem(a_Item); + tolua_pushusertype_and_takeownership(m_LuaState, c, "cItem"); +} + + + + + void cLuaState::Push(const cNil & a_Nil) { ASSERT(IsValid()); @@ -1140,6 +1151,37 @@ bool cLuaState::GetStackValue(int a_StackPos, AStringMap & a_Value) +bool cLuaState::GetStackValue(int a_StackPos, AStringVector & a_Value) +{ + // Retrieve all values in an array of string table: + if (!lua_istable(m_LuaState, a_StackPos)) + { + return false; + } + cStackTable tbl(*this, a_StackPos); + bool isValid = true; + tbl.ForEachArrayElement([&](cLuaState & a_LuaState, int a_Index) + { + AString tempStr; + if (a_LuaState.GetStackValue(-1, tempStr)) + { + a_Value.push_back(std::move(tempStr)); + } + else + { + isValid = false; + return true; + } + return false; + } + ); + return isValid; +} + + + + + bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) { a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 3d5b1e645..ffcddcfe8 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -614,6 +614,7 @@ public: void Push(const AStringMap & a_Dictionary); void Push(const AStringVector & a_Vector); void Push(const char * a_Value); + void Push(const cItem & a_Item); void Push(const cNil & a_Nil); void Push(const cRef & a_Ref); void Push(const Vector3d & a_Vector); @@ -639,6 +640,7 @@ public: // Enum values are checked for their allowed values and fail if the value is not assigned. bool GetStackValue(int a_StackPos, AString & a_Value); bool GetStackValue(int a_StackPos, AStringMap & a_Value); + bool GetStackValue(int a_StackPos, AStringVector & a_Value); bool GetStackValue(int a_StackPos, bool & a_Value); bool GetStackValue(int a_StackPos, cCallback & a_Callback); bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback); diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp index fd714390e..2802c69db 100644 --- a/src/Bindings/LuaWindow.cpp +++ b/src/Bindings/LuaWindow.cpp @@ -9,7 +9,7 @@ #include "PluginLua.h" #include "Root.h" #include "lua/src/lauxlib.h" // Needed for LUA_REFNIL - +#include "ClientHandle.h" @@ -86,6 +86,19 @@ cLuaWindow::~cLuaWindow() +void cLuaWindow::SetOnClicked(cLuaState::cCallbackPtr && a_OnClicked) +{ + // Only one Lua state can be a cLuaWindow object callback: + ASSERT(a_OnClicked->IsSameLuaState(*m_LuaState)); + + // Store the new reference, releasing the old one if appropriate: + m_OnClicked = std::move(a_OnClicked); +} + + + + + void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing) { // Only one Lua state can be a cLuaWindow object callback: @@ -206,3 +219,24 @@ void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) + +void cLuaWindow::Clicked(cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + if (m_OnClicked != nullptr) + { + // Plugin can stop a click + if (m_OnClicked->Call(this, &a_Player, a_SlotNum, a_ClickAction, a_ClickedItem)) + { + // Tell the client the actual state of the window + a_Player.GetClientHandle()->SendInventorySlot(-1, -1, a_Player.GetDraggingItem()); + BroadcastWholeWindow(); + return; + } + } + + cWindow::Clicked(a_Player, a_WindowID, a_SlotNum, a_ClickAction, a_ClickedItem); +} + + + + diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h index fb21c1c4e..8f3349d00 100644 --- a/src/Bindings/LuaWindow.h +++ b/src/Bindings/LuaWindow.h @@ -49,6 +49,10 @@ public: // tolua_end + /** Sets the Lua callback to call when the player clicks on the window. + The window can stop the click from propogating. */ + void SetOnClicked(cLuaState::cCallbackPtr && a_OnClicked); + /** Sets the Lua callback function to call when the window is about to close */ void SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing); @@ -63,6 +67,9 @@ protected: /** The canon Lua state that has opened the window and owns the m_LuaRef */ cLuaState * m_LuaState; + /** The Lua callback to call when the player clicked on a slot */ + cLuaState::cCallbackPtr m_OnClicked; + /** The Lua callback to call when the window is closing for any player */ cLuaState::cCallbackPtr m_OnClosing; @@ -80,6 +87,11 @@ protected: // cWindow overrides: virtual void OpenedByPlayer(cPlayer & a_Player) override; + virtual void Clicked( + cPlayer & a_Player, int a_WindowID, + short a_SlotNum, eClickAction a_ClickAction, + const cItem & a_ClickedItem + ) override; virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override; virtual void Destroy(void) override; virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index e4410dd14..6fe133e1e 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -11,11 +11,6 @@ #include "PluginLua.h" #include "PluginManager.h" #include "LuaWindow.h" -#include "../Root.h" -#include "../World.h" -#include "../Entities/Player.h" -#include "../WebAdmin.h" -#include "../ClientHandle.h" #include "../BlockArea.h" #include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/BrewingstandEntity.h" @@ -28,14 +23,20 @@ #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" +#include "../BoundingBox.h" +#include "../BuildInfo.h" +#include "../ClientHandle.h" +#include "../CommandOutput.h" +#include "../CompositeChat.h" +#include "../Entities/Player.h" #include "../Generating/ChunkDesc.h" +#include "../HTTP/UrlParser.h" +#include "../Item.h" #include "../LineBlockTracer.h" -#include "../CompositeChat.h" +#include "../Root.h" #include "../StringCompression.h" -#include "../CommandOutput.h" -#include "../BuildInfo.h" -#include "../HTTP/UrlParser.h" -#include "../BoundingBox.h" +#include "../WebAdmin.h" +#include "../World.h" @@ -2557,6 +2558,57 @@ static int tolua_cMojangAPI_MakeUUIDShort(lua_State * L) +static int tolua_get_cItem_m_LoreTable(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if (!L.CheckParamSelf("const cItem")) + { + return 0; + } + + // Get the params: + const cItem * Self = nullptr; + L.GetStackValue(1, Self); + + // Push the result: + L.Push(Self->m_LoreTable); + return 1; +} + + + + + +static int tolua_set_cItem_m_LoreTable(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamSelf("cItem") || + !L.CheckParamTable(2) + ) + { + return 0; + } + + // Get the params: + cItem * Self = nullptr; + L.GetStackValue(1, Self); + + // Set the value: + Self->m_LoreTable.clear(); + if (!L.GetStackValue(2, Self->m_LoreTable)) + { + return L.ApiParamError("cItem.m_LoreTable: Could not read value as an array of strings"); + } + return 0; +} + + + + + static int Lua_ItemGrid_GetSlotCoords(lua_State * L) { tolua_Error tolua_err; @@ -3798,6 +3850,10 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos); tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cItem"); + tolua_variable(tolua_S, "m_LoreTable", tolua_get_cItem_m_LoreTable, tolua_set_cItem_m_LoreTable); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cItemGrid"); tolua_function(tolua_S, "GetSlotCoords", Lua_ItemGrid_GetSlotCoords); tolua_endmodule(tolua_S); @@ -3816,6 +3872,7 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "new", tolua_cLuaWindow_new); tolua_function(tolua_S, "new_local", tolua_cLuaWindow_new_local); tolua_function(tolua_S, ".call", tolua_cLuaWindow_new_local); + tolua_function(tolua_S, "SetOnClicked", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClicked>); tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>); tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>); tolua_endmodule(tolua_S); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 3276fde67..22e8f15e2 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -80,6 +80,7 @@ public: virtual bool OnPlayerJoined (cPlayer & a_Player) = 0; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) = 0; virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; + virtual bool OnPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) = 0; virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 0; virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 0; virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index e3aa63aa1..5af336a95 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -659,6 +659,15 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi +bool cPluginLua::OnPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) +{ + return CallSimpleHooks(cPluginManager::HOOK_PLAYER_OPENING_WINDOW, &a_Player, &a_Window); +} + + + + + bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { return CallSimpleHooks(cPluginManager::HOOK_PLAYER_PLACED_BLOCK, @@ -1056,6 +1065,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_PLAYER_JOINED: return "OnPlayerJoined"; case cPluginManager::HOOK_PLAYER_LEFT_CLICK: return "OnPlayerLeftClick"; case cPluginManager::HOOK_PLAYER_MOVING: return "OnPlayerMoving"; + case cPluginManager::HOOK_PLAYER_OPENING_WINDOW: return "OnPlayerOpeningWindow"; case cPluginManager::HOOK_PLAYER_PLACED_BLOCK: return "OnPlayerPlacedBlock"; case cPluginManager::HOOK_PLAYER_PLACING_BLOCK: return "OnPlayerPlacingBlock"; case cPluginManager::HOOK_PLAYER_RIGHT_CLICK: return "OnPlayerRightClick"; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index ff5e8d726..4de5751e7 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -101,6 +101,7 @@ public: virtual bool OnPlayerJoined (cPlayer & a_Player) override; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) override; virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) override; + virtual bool OnPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) override; virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) override; virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) override; virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 066ccf9d7..1d977fcde 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -999,6 +999,25 @@ bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d & a +bool cPluginManager::CallHookPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) +{ + FIND_HOOK(HOOK_PLAYER_OPENING_WINDOW); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnPlayerOpeningWindow(a_Player, a_Window)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { FIND_HOOK(HOOK_PLAYER_PLACED_BLOCK); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index f38ac8fa1..f3fc3551a 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -24,6 +24,7 @@ class cPickup; class cPlayer; class cPlugin; class cProjectileEntity; +class cWindow; class cWorld; class cSettingsRepositoryInterface; class cDeadlockDetect; @@ -111,6 +112,7 @@ public: HOOK_PLAYER_JOINED, HOOK_PLAYER_LEFT_CLICK, HOOK_PLAYER_MOVING, + HOOK_PLAYER_OPENING_WINDOW, HOOK_PLAYER_PLACED_BLOCK, HOOK_PLAYER_PLACING_BLOCK, HOOK_PLAYER_RIGHT_CLICK, @@ -257,6 +259,7 @@ public: bool CallHookPlayerJoined (cPlayer & a_Player); bool CallHookPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); bool CallHookPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition); + bool CallHookPlayerOpeningWindow (cPlayer & a_Player, cWindow & a_Window); bool CallHookPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange); bool CallHookPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange); bool CallHookPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 74c4d867f..667a231a4 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -1954,8 +1954,8 @@ void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTY cCuboid cBlockArea::GetBounds(void) const { return cCuboid( - m_Origin.x, m_Origin.y, m_Origin.z, - m_Origin.x + m_Size.x - 1, m_Origin.y + m_Size.y - 1, m_Origin.z + m_Size.z - 1 + m_Origin, + m_Origin + m_Size - Vector3i(1, 1, 1) ); } diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 24de9e25c..a772290dd 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -19,7 +19,10 @@ cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int m_SecondaryEffect(cEntityEffect::effNoEffect) { ASSERT(a_BlockType == E_BLOCK_BEACON); - UpdateBeacon(); + if (m_World != nullptr) + { + UpdateBeacon(); + } } diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 54f6e0dfa..a8f5b7242 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -7,7 +7,6 @@ #include "../UI/ChestWindow.h" #include "../ClientHandle.h" #include "../Mobs/Ocelot.h" -#include "../BoundingBox.h" @@ -219,32 +218,13 @@ void cChestEntity::DestroyWindow() -class cFindSittingCat : - public cEntityCallback -{ - virtual bool Item(cEntity * a_Entity) override - { - return ( - (a_Entity->GetEntityType() == cEntity::etMonster) && - (static_cast<cMonster *>(a_Entity)->GetMobType() == eMonsterType::mtOcelot) && - (static_cast<cOcelot *>(a_Entity)->IsSitting()) - ); - } -}; - - - - - bool cChestEntity::IsBlocked() { - cFindSittingCat FindSittingCat; return ( - (GetPosY() >= cChunkDef::Height - 1) || - !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())) || + (GetPosY() < cChunkDef::Height - 1) && ( - (GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()) == E_BLOCK_AIR) && - !GetWorld()->ForEachEntityInBox(cBoundingBox(Vector3d(GetPosX(), GetPosY() + 1, GetPosZ()), 1, 1), FindSittingCat) + !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())) || + !cOcelot::IsCatSittingOnBlock(GetWorld(), Vector3d(GetPos())) ) ); } diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp index 9030a0172..e475d7022 100644 --- a/src/BlockEntities/EnderChestEntity.cpp +++ b/src/BlockEntities/EnderChestEntity.cpp @@ -7,6 +7,7 @@ #include "../Entities/Player.h" #include "../UI/EnderChestWindow.h" #include "../ClientHandle.h" +#include "../Mobs/Ocelot.h" @@ -48,8 +49,13 @@ void cEnderChestEntity::SendTo(cClientHandle & a_Client) bool cEnderChestEntity::UsedBy(cPlayer * a_Player) { - // TODO: cats are an obstruction - if ((GetPosY() < cChunkDef::Height - 1) && !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()))) + if ( + (GetPosY() < cChunkDef::Height - 1) && + ( + !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())) || + !cOcelot::IsCatSittingOnBlock(GetWorld(), Vector3d(GetPos())) + ) + ) { // Obstruction, don't open return false; diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index 9cc6f20c6..5246ae6ca 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -178,7 +178,7 @@ void cMobSpawnerEntity::SpawnEntity(void) double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX; double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ; - cMonster * Monster = cMonster::NewMonsterFromType(m_MobType); + auto Monster = cMonster::NewMonsterFromType(m_MobType); if (Monster == nullptr) { continue; @@ -186,7 +186,7 @@ void cMobSpawnerEntity::SpawnEntity(void) Monster->SetPosition(PosX, RelY, PosZ); Monster->SetYaw(Random.RandReal(360.0f)); - if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cEntity::INVALID_ID) + if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID) { EntitiesSpawned = true; Chunk->BroadcastSoundParticleEffect( diff --git a/src/BlockInServerPluginInterface.h b/src/BlockInServerPluginInterface.h index c6578fe72..b3a71577f 100644 --- a/src/BlockInServerPluginInterface.h +++ b/src/BlockInServerPluginInterface.h @@ -10,11 +10,10 @@ #pragma once #include "Blocks/BlockPluginInterface.h" -#include "World.h" #include "Bindings/PluginManager.h" - +class cWorld; class cBlockInServerPluginInterface : diff --git a/src/BlockInfo.h b/src/BlockInfo.h index 569b537c1..1ba818cb3 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -55,9 +55,6 @@ public: /** Block height */ float m_BlockHeight; - /** Sound when placing this block */ - AString m_PlaceSound; - /** Block's hardness. The greater the value the longer the player needs to break the block. */ float m_Hardness; @@ -85,7 +82,6 @@ public: inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; } inline static bool CanBeTerraformed (BLOCKTYPE a_Type) { return Get(a_Type).m_CanBeTerraformed; } inline static float GetBlockHeight (BLOCKTYPE a_Type) { return Get(a_Type).m_BlockHeight; } - inline static AString GetPlaceSound (BLOCKTYPE a_Type) { return Get(a_Type).m_PlaceSound; } inline static float GetHardness (BLOCKTYPE a_Type) { return Get(a_Type).m_Hardness; } // tolua_end @@ -105,7 +101,6 @@ public: , m_FullyOccupiesVoxel(false) , m_CanBeTerraformed(false) , m_BlockHeight(1.0) - , m_PlaceSound() , m_Hardness(0.0f) , m_Handler() {} diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 634c7dd3a..f2cbfde18 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -6,9 +6,9 @@ #include "BlockEntity.h" #include "MetaRotator.h" #include "ChunkInterface.h" -#include "../Entities/Entity.h" +class cEntity; class cPlayer; class cWorldInterface; diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 041a579f7..808c271b3 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -34,7 +34,7 @@ public: Meta |= 0x08; a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta, false); - a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_WorldInterface.WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", x, y, z, 0.5f, 0.6f); // Queue a button reset (unpress) @@ -45,7 +45,7 @@ public: { // Block hasn't change in the meantime; set its meta a_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07, false); - a_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_World.WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); a_World.BroadcastSoundEffect("block.stone_button.click_off", x, y, z, 0.5f, 0.5f); } } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 1eae70c42..4c2209383 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -650,7 +650,7 @@ void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterf // Wake up the simulators for this block: int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); } } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 56a1169e9..7d6a1bc8b 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -23,7 +23,7 @@ public: NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_WorldInterface.WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", static_cast<double>(a_BlockX), static_cast<double>(a_BlockY), static_cast<double>(a_BlockZ), 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); return true; } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 21dba0bed..eae9f7fd5 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -159,7 +159,7 @@ public: // Wake up the simulators for this block: int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); } } diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index d471df6f1..1300ffe8c 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -1,15 +1,17 @@ #pragma once -#include "BroadcastInterface.h" + #include "../Mobs/MonsterTypes.h" -class cItems; typedef cItemCallback<cBlockEntity> cBlockEntityCallback; +class cBroadcastInterface; +class cItems; +class cPlayer; + -class cPlayer; class cWorldInterface @@ -72,6 +74,6 @@ public: virtual int GetHeight(int a_BlockX, int a_BlockZ) = 0; /** Wakes up the simulators for the specified block */ - virtual void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) = 0; + virtual void WakeUpSimulators(Vector3i a_Block) = 0; }; diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp index 5a594a2a4..afb7e025b 100644 --- a/src/BoundingBox.cpp +++ b/src/BoundingBox.cpp @@ -19,7 +19,7 @@ cBoundingBox::cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a -cBoundingBox::cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max) : +cBoundingBox::cBoundingBox(Vector3d a_Min, Vector3d a_Max) : m_Min(a_Min), m_Max(a_Max) { @@ -29,7 +29,7 @@ cBoundingBox::cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max) : -cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height) : +cBoundingBox::cBoundingBox(Vector3d a_Pos, double a_Radius, double a_Height) : m_Min(a_Pos.x - a_Radius, a_Pos.y, a_Pos.z - a_Radius), m_Max(a_Pos.x + a_Radius, a_Pos.y + a_Height, a_Pos.z + a_Radius) { @@ -39,7 +39,7 @@ cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Hei -cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_CubeLength) : +cBoundingBox::cBoundingBox(Vector3d a_Pos, double a_CubeLength) : m_Min(a_Pos.x - a_CubeLength / 2, a_Pos.y - a_CubeLength / 2, a_Pos.z - a_CubeLength / 2), m_Max(a_Pos.x + a_CubeLength / 2, a_Pos.y + a_CubeLength / 2, a_Pos.z + a_CubeLength / 2) { @@ -84,7 +84,7 @@ void cBoundingBox::Move(double a_OffX, double a_OffY, double a_OffZ) -void cBoundingBox::Move(const Vector3d & a_Off) +void cBoundingBox::Move(Vector3d a_Off) { m_Min.x += a_Off.x; m_Min.y += a_Off.y; @@ -141,7 +141,7 @@ cBoundingBox cBoundingBox::Union(const cBoundingBox & a_Other) -bool cBoundingBox::IsInside(const Vector3d & a_Point) +bool cBoundingBox::IsInside(Vector3d a_Point) { return IsInside(m_Min, m_Max, a_Point); } @@ -169,7 +169,7 @@ bool cBoundingBox::IsInside(cBoundingBox & a_Other) -bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max) +bool cBoundingBox::IsInside(Vector3d a_Min, Vector3d a_Max) { // If both coords are inside this, then the entire a_Other is inside return (IsInside(a_Min) && IsInside(a_Max)); @@ -179,7 +179,7 @@ bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max) -bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point) +bool cBoundingBox::IsInside(Vector3d a_Min, Vector3d a_Max, Vector3d a_Point) { return ( ((a_Point.x >= a_Min.x) && (a_Point.x <= a_Max.x)) && @@ -192,7 +192,7 @@ bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, cons -bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z) +bool cBoundingBox::IsInside(Vector3d a_Min, Vector3d a_Max, double a_X, double a_Y, double a_Z) { return ( ((a_X >= a_Min.x) && (a_X <= a_Max.x)) && @@ -205,7 +205,7 @@ bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, doub -bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face) const +bool cBoundingBox::CalcLineIntersection(Vector3d a_Line1, Vector3d a_Line2, double & a_LineCoeff, eBlockFace & a_Face) const { return CalcLineIntersection(m_Min, m_Max, a_Line1, a_Line2, a_LineCoeff, a_Face); } @@ -214,7 +214,7 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Line1, const Vector3d -bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face) +bool cBoundingBox::CalcLineIntersection(Vector3d a_Min, Vector3d a_Max, Vector3d a_Line1, Vector3d a_Line2, double & a_LineCoeff, eBlockFace & a_Face) { if (IsInside(a_Min, a_Max, a_Line1)) { diff --git a/src/BoundingBox.h b/src/BoundingBox.h index 48b9a3d82..809b7fe7c 100644 --- a/src/BoundingBox.h +++ b/src/BoundingBox.h @@ -24,9 +24,9 @@ class cBoundingBox { public: cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ); - cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max); - cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height); - cBoundingBox(const Vector3d & a_Pos, double a_CubeLength); + cBoundingBox(Vector3d a_Min, Vector3d a_Max); + cBoundingBox(Vector3d a_Pos, double a_Radius, double a_Height); + cBoundingBox(Vector3d a_Pos, double a_CubeLength); cBoundingBox(const cBoundingBox & a_Orig); cBoundingBox & operator=(const cBoundingBox & a_Other); @@ -35,7 +35,7 @@ public: void Move(double a_OffX, double a_OffY, double a_OffZ); /** Moves the entire boundingbox by the specified offset */ - void Move(const Vector3d & a_Off); + void Move(Vector3d a_Off); /** Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each direction) */ void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ); @@ -47,7 +47,7 @@ public: cBoundingBox Union(const cBoundingBox & a_Other); /** Returns true if the point is inside the bounding box */ - bool IsInside(const Vector3d & a_Point); + bool IsInside(Vector3d a_Point); /** Returns true if the point is inside the bounding box */ bool IsInside(double a_X, double a_Y, double a_Z); @@ -56,13 +56,13 @@ public: bool IsInside(cBoundingBox & a_Other); /** Returns true if a boundingbox specified by a_Min and a_Max is inside this bounding box */ - bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max); + bool IsInside(Vector3d a_Min, Vector3d a_Max); /** Returns true if the specified point is inside the bounding box specified by its min / max corners */ - static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point); + static bool IsInside(Vector3d a_Min, Vector3d a_Max, Vector3d a_Point); /** Returns true if the specified point is inside the bounding box specified by its min / max corners */ - static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z); + static bool IsInside(Vector3d a_Min, Vector3d a_Max, double a_X, double a_Y, double a_Z); // tolua_end @@ -70,13 +70,13 @@ public: Also calculates the distance along the line in which the intersection occurs, and the face hit (BLOCK_FACE_ constants) Only forward collisions (a_LineCoeff >= 0) are returned. Exported to Lua manually, because ToLua++ would generate needless input params (a_LineCoeff, a_Face). */ - bool CalcLineIntersection(const Vector3d & a_LinePoint1, const Vector3d & a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face) const; + bool CalcLineIntersection(Vector3d a_LinePoint1, Vector3d a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face) const; /** Returns true if the specified bounding box is intersected by the line specified by its two points Also calculates the distance along the line in which the intersection occurs, and the face hit (BLOCK_FACE_ constants) Only forward collisions (a_LineCoeff >= 0) are returned. Exported to Lua manually, because ToLua++ would generate needless input params (a_LineCoeff, a_Face). */ - static bool CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_LinePoint1, const Vector3d & a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face); + static bool CalcLineIntersection(Vector3d a_Min, Vector3d a_Max, Vector3d a_LinePoint1, Vector3d a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face); /** Calculates the intersection of the two bounding boxes; returns true if nonempty. Exported manually, because ToLua++ would generate needless input params (a_Intersection). */ @@ -92,8 +92,8 @@ public: double GetMaxY(void) const { return m_Max.y; } double GetMaxZ(void) const { return m_Max.z; } - const Vector3d & GetMin(void) const { return m_Min; } - const Vector3d & GetMax(void) const { return m_Max; } + Vector3d GetMin(void) const { return m_Min; } + Vector3d GetMax(void) const { return m_Max; } // tolua_end diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 3b9739907..4c85c9c80 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -136,13 +136,12 @@ cChunk::~cChunk() // Remove and destroy all entities that are not players: cEntityList Entities; std::swap(Entities, m_Entities); // Need another list because cEntity destructors check if they've been removed from chunk - for (auto Entity : Entities) + for (auto & Entity : Entities) { if (!Entity->IsPlayer()) { // Scheduling a normal destruction is neither possible (Since this chunk will be gone till the schedule occurs) nor necessary. Entity->DestroyNoScheduling(false); // No point in broadcasting in an unloading chunk. Chunks unload when no one is nearby. - delete Entity; } } @@ -300,9 +299,9 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) a_Callback.ChunkData(m_ChunkData); - for (auto Entity : m_Entities) + for (const auto & Entity : m_Entities) { - a_Callback.Entity(Entity); + a_Callback.Entity(Entity.get()); } for (auto & KeyPair : m_BlockEntities) @@ -453,7 +452,10 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock } // for y // Erase all affected block entities: - cCuboid affectedArea(OffX, a_MinBlockY, OffZ, OffX + SizeX - 1, a_MinBlockY + SizeY - 1, OffZ + SizeZ - 1); + cCuboid affectedArea( + {OffX, a_MinBlockY, OffZ}, + {OffX + SizeX - 1, a_MinBlockY + SizeY - 1, OffZ + SizeZ - 1} + ); for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) { if (affectedArea.IsInside(itr->second->GetPos())) @@ -531,7 +533,7 @@ void cChunk::CollectMobCensus(cMobCensus & toFill) } Vector3d currentPosition; - for (auto entity : m_Entities) + for (auto & entity : m_Entities) { // LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); if (entity->IsMob()) @@ -634,7 +636,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner) continue; } - cEntity * newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); + auto newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); if (newMob == nullptr) { continue; @@ -658,7 +660,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) // If we are not valid, tick players and bailout if (!IsValid()) { - for (auto Entity : m_Entities) + for (const auto & Entity : m_Entities) { if (Entity->IsPlayer()) { @@ -683,7 +685,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) m_IsDirty = KeyPair.second->Tick(a_Dt, *this) | m_IsDirty; } - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + for (auto itr = m_Entities.begin(); itr != m_Entities.end();) { // Do not tick mobs that are detached from the world. They're either scheduled for teleportation or for removal. if (!(*itr)->IsTicking()) @@ -708,20 +710,22 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) continue; } - if ((((*itr)->GetChunkX() != m_PosX) || - ((*itr)->GetChunkZ() != m_PosZ)) + if ( + ((*itr)->GetChunkX() != m_PosX) || + ((*itr)->GetChunkZ() != m_PosZ) ) { - // This block is very similar to RemoveEntity, except it uses an iterator to avoid scanning the whole m_Entities - // The entity moved out of the chunk, move it to the neighbor - - (*itr)->SetParentChunk(nullptr); - MoveEntityToNewChunk(*itr); // Mark as dirty if it was a server-generated entity: if (!(*itr)->IsPlayer()) { MarkDirty(); } + + // This block is very similar to RemoveEntity, except it uses an iterator to avoid scanning the whole m_Entities + // The entity moved out of the chunk, move it to the neighbor + (*itr)->SetParentChunk(nullptr); + MoveEntityToNewChunk(std::move(*itr)); + itr = m_Entities.erase(itr); } else @@ -750,7 +754,7 @@ void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) -void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) +void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity) { cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); if (Neighbor == nullptr) @@ -764,28 +768,29 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) } ASSERT(Neighbor != this); // Moving into the same chunk? wtf? - Neighbor->AddEntity(a_Entity); + auto & Entity = *a_Entity; + Neighbor->AddEntity(std::move(a_Entity)); class cMover : public cClientDiffCallback { virtual void Removed(cClientHandle * a_Client) override { - a_Client->SendDestroyEntity(*m_Entity); + a_Client->SendDestroyEntity(m_Entity); } virtual void Added(cClientHandle * a_Client) override { - m_Entity->SpawnOn(*a_Client); + m_Entity.SpawnOn(*a_Client); } - cEntity * m_Entity; + cEntity & m_Entity; public: - cMover(cEntity * a_CallbackEntity) : + cMover(cEntity & a_CallbackEntity) : m_Entity(a_CallbackEntity) {} - } Mover(a_Entity); + } Mover(Entity); m_ChunkMap->CompareChunkClients(this, Neighbor, Mover); } @@ -1489,7 +1494,7 @@ void cChunk::WakeUpSimulators(void) // The redstone sim takes multiple blocks, use the inbuilt checker if (RedstoneSimulator->IsAllowedBlock(Block)) { - RedstoneSimulator->AddBlock(BlockX, y, BlockZ, this); + RedstoneSimulator->AddBlock({BlockX, y, BlockZ}, this); continue; } @@ -1497,12 +1502,12 @@ void cChunk::WakeUpSimulators(void) { case E_BLOCK_WATER: { - WaterSimulator->AddBlock(BlockX, y, BlockZ, this); + WaterSimulator->AddBlock({BlockX, y, BlockZ}, this); break; } case E_BLOCK_LAVA: { - LavaSimulator->AddBlock(BlockX, y, BlockZ, this); + LavaSimulator->AddBlock({BlockX, y, BlockZ}, this); break; } default: @@ -1770,16 +1775,20 @@ void cChunk::AddBlockEntityClean(cBlockEntity * a_BlockEntity) cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) { - // Check that the query coords are within chunk bounds: - ASSERT(a_BlockX >= m_PosX * cChunkDef::Width); - ASSERT(a_BlockX < m_PosX * cChunkDef::Width + cChunkDef::Width); - ASSERT(a_BlockZ >= m_PosZ * cChunkDef::Width); - ASSERT(a_BlockZ < m_PosZ * cChunkDef::Width + cChunkDef::Width); - int RelX = a_BlockX - m_PosX * cChunkDef::Width; int RelZ = a_BlockZ - m_PosZ * cChunkDef::Width; - auto itr = m_BlockEntities.find(MakeIndex(RelX, a_BlockY, RelZ)); + if ( + !IsValidWidth (RelX) || + !IsValidHeight(a_BlockY) || + !IsValidWidth (RelZ) + ) + { + // Coordinates are outside outside the world, no block entities here + return nullptr; + } + + auto itr = m_BlockEntities.find(MakeIndexNoCheck(RelX, a_BlockY, RelZ)); return (itr == m_BlockEntities.end()) ? nullptr : itr->second; } @@ -1866,15 +1875,15 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) double PosY = a_Player.GetPosY(); double PosZ = a_Player.GetPosZ(); - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + for (auto & Entity : m_Entities) { - if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile())) + if ((!Entity->IsPickup()) && (!Entity->IsProjectile())) { continue; // Only pickups and projectiles can be picked up } - float DiffX = static_cast<float>((*itr)->GetPosX() - PosX); - float DiffY = static_cast<float>((*itr)->GetPosY() - PosY); - float DiffZ = static_cast<float>((*itr)->GetPosZ() - PosZ); + float DiffX = static_cast<float>(Entity->GetPosX() - PosX); + float DiffY = static_cast<float>(Entity->GetPosY() - PosY); + float DiffZ = static_cast<float>(Entity->GetPosZ() - PosZ); float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ; if (SqrDist < 1.5f * 1.5f) // 1.5 block { @@ -1884,13 +1893,13 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) ); */ MarkDirty(); - if ((*itr)->IsPickup()) + if (Entity->IsPickup()) { - (reinterpret_cast<cPickup *>(*itr))->CollectedBy(a_Player); + reinterpret_cast<cPickup *>(Entity.get())->CollectedBy(a_Player); } else { - (reinterpret_cast<cProjectileEntity *>(*itr))->CollectedBy(a_Player); + reinterpret_cast<cProjectileEntity *>(Entity.get())->CollectedBy(a_Player); } } else if (SqrDist < 5 * 5) @@ -1986,7 +1995,7 @@ void cChunk::RemoveClient(cClientHandle * a_Client) if (!a_Client->IsDestroyed()) { - for (auto Entity : m_Entities) + for (auto & Entity : m_Entities) { /* // DEBUG: @@ -2024,34 +2033,59 @@ bool cChunk::HasAnyClients(void) const -void cChunk::AddEntity(cEntity * a_Entity) +void cChunk::AddEntity(OwnedEntity a_Entity) { if (!a_Entity->IsPlayer()) { MarkDirty(); } + auto EntityPtr = a_Entity.get(); + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already + m_Entities.emplace_back(std::move(a_Entity)); - m_Entities.push_back(a_Entity); - ASSERT(a_Entity->GetParentChunk() == nullptr); - a_Entity->SetParentChunk(this); + ASSERT(EntityPtr->GetParentChunk() == nullptr); + EntityPtr->SetParentChunk(this); } -void cChunk::RemoveEntity(cEntity * a_Entity) +OwnedEntity cChunk::RemoveEntity(cEntity & a_Entity) { - ASSERT(a_Entity->GetParentChunk() == this); - a_Entity->SetParentChunk(nullptr); - m_Entities.remove(a_Entity); + ASSERT(a_Entity.GetParentChunk() == this); + ASSERT(!a_Entity.IsTicking()); + a_Entity.SetParentChunk(nullptr); + // Mark as dirty if it was a server-generated entity: - if (!a_Entity->IsPlayer()) + if (!a_Entity.IsPlayer()) { MarkDirty(); } + + OwnedEntity Removed; + m_Entities.erase( + std::remove_if( + m_Entities.begin(), + m_Entities.end(), + [&a_Entity, &Removed](decltype(m_Entities)::value_type & a_Value) + { + if (a_Value.get() == &a_Entity) + { + ASSERT(!Removed); + Removed = std::move(a_Value); + return true; + } + + return false; + } + ), + m_Entities.end() + ); + + return Removed; } @@ -2060,13 +2094,13 @@ void cChunk::RemoveEntity(cEntity * a_Entity) bool cChunk::HasEntity(UInt32 a_EntityID) { - for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + for (const auto & Entity : m_Entities) { - if ((*itr)->GetUniqueID() == a_EntityID) + if (Entity->GetUniqueID() == a_EntityID) { return true; } - } // for itr - m_Entities[] + } return false; } @@ -2077,14 +2111,14 @@ bool cChunk::HasEntity(UInt32 a_EntityID) bool cChunk::ForEachEntity(cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) + for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) { continue; } - if (a_Callback.Item(*itr)) + if (a_Callback.Item(itr->get())) { return false; } @@ -2099,7 +2133,7 @@ bool cChunk::ForEachEntity(cEntityCallback & a_Callback) bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) + for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) @@ -2112,7 +2146,7 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ // The entity is not in the specified box continue; } - if (a_Callback.Item(*itr)) + if (a_Callback.Item(itr->get())) { return false; } @@ -2136,11 +2170,11 @@ bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, b bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + for (const auto & Entity : m_Entities) { - if (((*itr)->GetUniqueID() == a_EntityID) && ((*itr)->IsTicking())) + if ((Entity->GetUniqueID() == a_EntityID) && (Entity->IsTicking())) { - a_CallbackResult = a_Callback(*itr); + a_CallbackResult = a_Callback(Entity.get()); return true; } } // for itr - m_Entitites[] diff --git a/src/Chunk.h b/src/Chunk.h index 87f2cd568..7e399052d 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -61,6 +61,7 @@ class cChunk : public cChunkDef // The inheritance is "misused" here only to inherit the functions and constants defined in cChunkDef { public: + /** Represents the presence state of the chunk */ enum ePresence { @@ -75,7 +76,7 @@ public: cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks cAllocationPool<cChunkData::sChunkSection> & a_Pool ); - cChunk(cChunk & other); + cChunk(cChunk & other) = delete; ~cChunk(); /** Returns true iff the chunk block data is valid (loaded / generated) */ @@ -248,8 +249,12 @@ public: /** Returns true if theres any client in the chunk; false otherwise */ bool HasAnyClients(void) const; - void AddEntity(cEntity * a_Entity); - void RemoveEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); + + /** Releases ownership of the given entity if it was found in this chunk. + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); + bool HasEntity(UInt32 a_EntityID); /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ @@ -525,7 +530,7 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers std::vector<cClientHandle *> m_LoadedByClient; - cEntityList m_Entities; + std::vector<OwnedEntity> m_Entities; cBlockEntities m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ @@ -602,7 +607,7 @@ private: bool GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType); /** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */ - void MoveEntityToNewChunk(cEntity * a_Entity); + void MoveEntityToNewChunk(OwnedEntity a_Entity); }; typedef cChunk * cChunkPtr; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 11a03a26e..f4a0867b5 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -27,8 +27,10 @@ class cBlockEntity; class cEntity; class cClientHandle; class cBlockEntity; +class cChunkCoords; -typedef std::list<cEntity *> cEntityList; +typedef std::unique_ptr<cEntity> OwnedEntity; +typedef std::vector<OwnedEntity> cEntityList; typedef std::map<int, cBlockEntity *> cBlockEntities; @@ -50,6 +52,25 @@ typedef unsigned char HEIGHTTYPE; + +class cChunkCoords +{ +public: + int m_ChunkX; + int m_ChunkZ; + + cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} + + bool operator == (const cChunkCoords & a_Other) const + { + return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); + } +} ; + + + + + /** Constants used throughout the code, useful typedefs and utility functions */ class cChunkDef { @@ -107,9 +128,9 @@ public: } /** Converts relative block coordinates into absolute coordinates with a known chunk location */ - inline static Vector3i RelativeToAbsolute(const Vector3i & a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) + inline static Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) { - return Vector3i(a_RelBlockPosition.x + a_ChunkX * Width, a_RelBlockPosition.y, a_RelBlockPosition.z + a_ChunkZ * Width); + return {a_RelBlockPosition.x + a_ChunkX * Width, a_RelBlockPosition.y, a_RelBlockPosition.z + a_ChunkZ * Width}; } /** Validates a height-coordinate. Returns false if height-coordiante is out of height bounds */ @@ -127,16 +148,26 @@ public: /** Converts absolute block coords to chunk coords: */ inline static void BlockToChunk(int a_X, int a_Z, int & a_ChunkX, int & a_ChunkZ) { - a_ChunkX = a_X / Width; - if ((a_X < 0) && (a_X % Width != 0)) + // This version is deprecated in favor of the vector version + // If you're developing new code, use the other version. + auto ChunkCoords = BlockToChunk({a_X, 0, a_Z}); + a_ChunkX = ChunkCoords.m_ChunkX; + a_ChunkZ = ChunkCoords.m_ChunkZ; + } + + /** The Y coordinate of a_Pos is ignored */ + inline static cChunkCoords BlockToChunk(Vector3i a_Pos) + { + cChunkCoords Chunk(a_Pos.x / Width, a_Pos.z / Width); + if ((a_Pos.x < 0) && (a_Pos.x % Width != 0)) { - a_ChunkX--; + Chunk.m_ChunkX--; } - a_ChunkZ = a_Z / cChunkDef::Width; - if ((a_Z < 0) && (a_Z % Width != 0)) + if ((a_Pos.z < 0) && (a_Pos.z % Width != 0)) { - a_ChunkZ--; + Chunk.m_ChunkZ--; } + return Chunk; } @@ -407,24 +438,6 @@ struct sSetBlock typedef std::list<sSetBlock> sSetBlockList; typedef std::vector<sSetBlock> sSetBlockVector; - - - - -class cChunkCoords -{ -public: - int m_ChunkX; - int m_ChunkZ; - - cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} - - bool operator == (const cChunkCoords & a_Other) const - { - return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); - } -} ; - typedef std::list<cChunkCoords> cChunkCoordsList; typedef std::vector<cChunkCoords> cChunkCoordsVector; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index b1a7d6ec5..fcd990ad6 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -114,11 +114,11 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoGen(cChunkCoords a_Chunk) { ASSERT(m_CSChunks.IsLockedByCurrentThread()); // m_CSChunks should already be locked by the operation that called us - auto Chunk = ConstructChunk(a_ChunkX, a_ChunkZ); + auto Chunk = ConstructChunk(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); if (Chunk == nullptr) { return nullptr; @@ -126,7 +126,7 @@ cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) if (!Chunk->IsValid() && !Chunk->IsQueued()) { Chunk->SetPresence(cChunk::cpQueued); - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ); + m_World->GetStorage().QueueLoadChunk(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); } return Chunk; @@ -739,17 +739,15 @@ bool cChunkMap::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> -void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) +void cChunkMap::WakeUpSimulators(Vector3i a_Block) { cCSLock Lock(m_CSChunks); - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(cChunkDef::BlockToChunk(a_Block)); if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } - m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk); + m_World->GetSimulatorManager()->WakeUp(a_Block, Chunk); } @@ -1139,7 +1137,7 @@ void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_B if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients); - m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk); + m_World->GetSimulatorManager()->WakeUp({a_BlockX, a_BlockY, a_BlockZ}, Chunk); } BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } @@ -1360,7 +1358,7 @@ bool cChunkMap::DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ) } DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0); - m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, DestChunk); + m_World->GetSimulatorManager()->WakeUp({a_BlockX, a_BlockY, a_BlockZ}, DestChunk); } return true; @@ -1497,38 +1495,38 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) -void cChunkMap::AddEntity(cEntity * a_Entity) +void cChunkMap::AddEntity(OwnedEntity a_Entity) { cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", - static_cast<void *>(a_Entity), a_Entity->GetClass(), a_Entity->GetUniqueID() + static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() ); return; } - Chunk->AddEntity(a_Entity); + Chunk->AddEntity(std::move(a_Entity)); } -void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) +void cChunkMap::AddEntityIfNotPresent(OwnedEntity a_Entity) { cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", - static_cast<void *>(a_Entity), a_Entity->GetClass(), a_Entity->GetUniqueID() + static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() ); return; } if (!Chunk->HasEntity(a_Entity->GetUniqueID())) { - Chunk->AddEntity(a_Entity); + Chunk->AddEntity(std::move(a_Entity)); } } @@ -1553,17 +1551,18 @@ bool cChunkMap::HasEntity(UInt32 a_UniqueID) -void cChunkMap::RemoveEntity(cEntity * a_Entity) +OwnedEntity cChunkMap::RemoveEntity(cEntity & a_Entity) { cCSLock Lock(m_CSChunks); - cChunkPtr Chunk = a_Entity->GetParentChunk(); + cChunkPtr Chunk = a_Entity.GetParentChunk(); - // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) if (Chunk == nullptr) { - return; + return nullptr; } - Chunk->RemoveEntity(a_Entity); + + // Remove the entity no matter whether the chunk itself is valid or not (#1190) + return Chunk->RemoveEntity(a_Entity); } @@ -1821,8 +1820,8 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): m_World->GetSimulatorManager()->WakeUpArea(cCuboid( - bx - ExplosionSizeInt - 1, MinY, bz - ExplosionSizeInt - 1, - bx + ExplosionSizeInt + 1, MaxY, bz + ExplosionSizeInt + 1 + {bx - ExplosionSizeInt - 1, MinY, bz - ExplosionSizeInt - 1}, + {bx + ExplosionSizeInt + 1, MaxY, bz + ExplosionSizeInt + 1} )); } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 330c6532d..e902be60c 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -110,7 +110,14 @@ public: bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback); /** Wakes up simulators for the specified block */ - void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); + void WakeUpSimulators(Vector3i a_Block); + + // DEPRECATED, use the vector-parametered version instead. + void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) + { + LOGWARNING("cChunkMap::WakeUpSimulators(int, int, int) is deprecated, use cChunkMap::WakeUpSimulators(Vector3i) instead."); + WakeUpSimulators(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + } void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); void MarkChunkSaving (int a_ChunkX, int a_ChunkZ); @@ -207,17 +214,18 @@ public: void RemoveClientFromChunks(cClientHandle * a_Client); /** Adds the entity to its appropriate chunk, takes ownership of the entity pointer */ - void AddEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); /** Adds the entity to its appropriate chunk, if the entity is not already added. Takes ownership of the entity pointer */ - void AddEntityIfNotPresent(cEntity * a_Entity); + void AddEntityIfNotPresent(OwnedEntity a_Entity); /** Returns true if the entity with specified ID is present in the chunks */ bool HasEntity(UInt32 a_EntityID); - /** Removes the entity from its appropriate chunk */ - void RemoveEntity(cEntity * a_Entity); + /** Removes the entity from its appropriate chunk + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible @@ -484,7 +492,13 @@ private: cChunkPtr GetChunk(int a_ChunkX, int a_ChunkZ); /** Constructs a chunk and queues the chunk for loading if not valid, returning it; doesn't generate */ - cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ); + cChunkPtr GetChunkNoGen(cChunkCoords a_Chunk); + + // Deprecated in favor of the vector version + cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ) + { + return GetChunkNoGen(cChunkCoords(a_ChunkX, a_ChunkZ)); + } /** Constructs a chunk, returning it. Doesn't load, doesn't generate */ cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 54cfa5310..a8279a738 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -133,7 +133,7 @@ cClientHandle::~cClientHandle() } m_Player->DestroyNoScheduling(true); } - delete m_Player; + m_PlayerPtr.reset(); m_Player = nullptr; } @@ -157,8 +157,12 @@ void cClientHandle::Destroy(void) cCSLock Lock(m_CSOutgoingData); m_Link.reset(); } + + // Temporary (#3115-will-fix): variable to keep track of whether the client authenticated and had the opportunity to have ownership transferred to the world + bool WasAddedToWorld = false; { cCSLock Lock(m_CSState); + WasAddedToWorld = (m_State >= csAuthenticated); if (m_State >= csDestroying) { // Already called @@ -186,7 +190,23 @@ void cClientHandle::Destroy(void) { player->StopEveryoneFromTargetingMe(); player->SetIsTicking(false); - world->RemovePlayer(player, true); + + if (WasAddedToWorld) + { + // If ownership was transferred, our own smart pointer should be unset + ASSERT(!m_PlayerPtr); + + m_PlayerPtr = world->RemovePlayer(*player, true); + + // And RemovePlayer should have returned a valid smart pointer + ASSERT(m_PlayerPtr); + } + else + { + // If ownership was not transferred, our own smart pointer should be valid and RemovePlayer's should not + ASSERT(m_PlayerPtr); + ASSERT(!world->IsPlayerReferencedInWorldOrChunk(*player)); + } } player->RemoveClientHandle(); } @@ -359,7 +379,8 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, m_Protocol->SendLoginSuccess(); // Spawn player (only serversided, so data is loaded) - m_Player = new cPlayer(m_Self, GetUsername()); + m_PlayerPtr = cpp14::make_unique<cPlayer>(m_Self, GetUsername()); + m_Player = m_PlayerPtr.get(); /* LOGD("Created a new cPlayer object at %p for client %s @ %s (%p)", static_cast<void *>(m_Player), @@ -2203,7 +2224,7 @@ void cClientHandle::ServerTick(float a_Dt) // Add the player to the world (start ticking from there): m_State = csDownloadingWorld; - m_Player->Initialize(*(m_Player->GetWorld())); + m_Player->Initialize(std::move(m_PlayerPtr), *(m_Player->GetWorld())); return; } } // lock(m_CSState) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 9b7e3dd58..9e1d1a9b5 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -12,7 +12,6 @@ #include "OSSupport/Network.h" #include "Defines.h" #include "Scoreboard.h" -#include "Map.h" #include "UI/SlotArea.h" #include "json/json.h" #include "ChunkSender.h" @@ -34,6 +33,7 @@ class cWindow; class cFallingBlock; class cCompositeChat; class cStatManager; +class cMap; class cClientHandle; typedef std::shared_ptr<cClientHandle> cClientHandlePtr; @@ -416,6 +416,9 @@ private: cPlayer * m_Player; + // Temporary (#3115-will-fix): maintain temporary ownership of created cPlayer objects while they are in limbo + std::unique_ptr<cPlayer> m_PlayerPtr; + /** This is an optimization which saves you an iteration of m_SentChunks if you just want to know whether or not the player is standing at a sent chunk. If this is equal to the coordinates of the chunk the player is currrently standing at, then this must be a sent chunk diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp index 1aa1e92e1..d87a6ef5e 100644 --- a/src/Cuboid.cpp +++ b/src/Cuboid.cpp @@ -7,30 +7,9 @@ -/** Returns true if the two specified intervals have a non-empty union */ -static bool DoIntervalsIntersect(int a_Min1, int a_Max1, int a_Min2, int a_Max2) -{ - return ( - ((a_Min1 >= a_Min2) && (a_Min1 <= a_Max2)) || // Start of first interval is within the second interval - ((a_Max1 >= a_Min2) && (a_Max1 <= a_Max2)) || // End of first interval is within the second interval - ((a_Min2 >= a_Min1) && (a_Min2 <= a_Max1)) // Start of second interval is within the first interval - ); -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cCuboid: -cCuboid & cCuboid::operator =(cCuboid a_Other) -{ - std::swap(p1, a_Other.p1); - std::swap(p2, a_Other.p2); - return *this; -} - @@ -95,23 +74,6 @@ int cCuboid::GetVolume(void) const -bool cCuboid::DoesIntersect(const cCuboid & a_Other) const -{ - ASSERT(IsSorted()); - ASSERT(a_Other.IsSorted()); - - // In order for cuboids to intersect, each of their coord intervals need to intersect - return ( - DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) && - DoIntervalsIntersect(p1.y, p2.y, a_Other.p1.y, a_Other.p2.y) && - DoIntervalsIntersect(p1.z, p2.z, a_Other.p1.z, a_Other.p2.z) - ); -} - - - - - bool cCuboid::IsCompletelyInside(const cCuboid & a_Outer) const { ASSERT(IsSorted()); @@ -229,7 +191,7 @@ bool cCuboid::IsSorted(void) const -void cCuboid::Engulf(const Vector3i & a_Point) +void cCuboid::Engulf(Vector3i a_Point) { if (a_Point.x < p1.x) { diff --git a/src/Cuboid.h b/src/Cuboid.h index 3ade5bc20..b39d3ad4a 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -13,16 +13,14 @@ public: Vector3i p1, p2; cCuboid(void) {} - cCuboid(const cCuboid & a_Cuboid) : p1(a_Cuboid.p1), p2(a_Cuboid.p2) {} cCuboid(const Vector3i & a_p1, const Vector3i & a_p2) : p1(a_p1), p2(a_p2) {} cCuboid(int a_X1, int a_Y1, int a_Z1) : p1(a_X1, a_Y1, a_Z1), p2(a_X1, a_Y1, a_Z1) {} - cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) {} - // tolua_end - - cCuboid & operator =(cCuboid a_Other); - - // tolua_begin + // DEPRECATED, use cCuboid(Vector3i, Vector3i) instead + cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) + { + LOGWARNING("cCuboid(int, int, int, int, int, int) constructor is deprecated, use cCuboid(Vector3i, Vector3i) constructor instead."); + } void Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2); void Assign(const cCuboid & a_SrcCuboid); @@ -40,9 +38,20 @@ public: /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. Assumes both cuboids are sorted. */ - bool DoesIntersect(const cCuboid & a_Other) const; + inline bool DoesIntersect(const cCuboid & a_Other) const + { + ASSERT(IsSorted()); + ASSERT(a_Other.IsSorted()); + + // In order for cuboids to intersect, each of their coord intervals need to intersect + return ( + DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) && + DoIntervalsIntersect(p1.y, p2.y, a_Other.p1.y, a_Other.p2.y) && + DoIntervalsIntersect(p1.z, p2.z, a_Other.p1.z, a_Other.p2.z) + ); + } - bool IsInside(const Vector3i & v) const + bool IsInside(Vector3i v) const { return ( (v.x >= p1.x) && (v.x <= p2.x) && @@ -60,7 +69,7 @@ public: ); } - bool IsInside( const Vector3d & v) const + bool IsInside(Vector3d v) const { return ( (v.x >= p1.x) && (v.x <= p2.x) && @@ -94,7 +103,18 @@ public: bool IsSorted(void) const; /** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */ - void Engulf(const Vector3i & a_Point); + void Engulf(Vector3i a_Point); + +private: + + /** Returns true if the two specified intervals have a non-empty union */ + inline static bool DoIntervalsIntersect(int a_Min1, int a_Max1, int a_Min2, int a_Max2) + { + ASSERT(a_Min1 <= a_Max1); + ASSERT(a_Min2 <= a_Max2); + return ((a_Min1 <= a_Max2) && (a_Max1 >= a_Min2)); + } + } ; // tolua_end diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index e8430090b..6259098d8 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -119,23 +119,9 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) Damage += ExtraDamage; } - // int KnockbackAmount = 1; unsigned int PunchLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPunch); - if (PunchLevel > 0) - { - Vector3d LookVector = GetLookVector(); - Vector3f FinalSpeed = Vector3f(0, 0, 0); - switch (PunchLevel) - { - case 1: FinalSpeed = LookVector * Vector3d(5, 0.3, 5); break; - case 2: FinalSpeed = LookVector * Vector3d(8, 0.3, 8); break; - default: break; - } - a_EntityHit.SetSpeed(FinalSpeed); - } - - // a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); // TODO fix knockback. - a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, 0); // Until knockback is fixed. + double KnockbackAmount = 11 + 10 * PunchLevel; + a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, KnockbackAmount); if (IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming()) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index b596bc93d..a38a6552d 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -135,9 +135,9 @@ const char * cEntity::GetParentClass(void) const -bool cEntity::Initialize(cWorld & a_World) +bool cEntity::Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld) { - if (cPluginManager::Get()->CallHookSpawningEntity(a_World, *this)) + if (cPluginManager::Get()->CallHookSpawningEntity(a_EntityWorld, *this)) { return false; } @@ -151,13 +151,13 @@ bool cEntity::Initialize(cWorld & a_World) ASSERT(m_World == nullptr); ASSERT(GetParentChunk() == nullptr); - a_World.AddEntity(this); + a_EntityWorld.AddEntity(std::move(a_Self)); ASSERT(m_World != nullptr); - cPluginManager::Get()->CallHookSpawnedEntity(a_World, *this); + cPluginManager::Get()->CallHookSpawnedEntity(a_EntityWorld, *this); // Spawn the entity on the clients: - a_World.BroadcastSpawnEntity(*this); + a_EntityWorld.BroadcastSpawnEntity(*this); return true; } @@ -230,8 +230,10 @@ void cEntity::Destroy(bool a_ShouldBroadcast) this->GetUniqueID(), this->GetClass(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - delete this; + + // Make sure that RemoveEntity returned a valid smart pointer + // Also, not storing the returned pointer means automatic destruction + VERIFY(ParentChunk->RemoveEntity(*this)); }); Destroyed(); } @@ -343,7 +345,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R Vector3d Heading(0, 0, 0); if (a_Attacker != nullptr) { - Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11); + Heading = a_Attacker->GetLookVector(); } TDI.Knockback = Heading * a_KnockbackAmount; @@ -532,21 +534,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) // Add knockback: if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != nullptr)) { - int KnockbackLevel = static_cast<int>(a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback)); // More common enchantment - if (KnockbackLevel < 1) - { - // We support punch on swords and vice versa! :) - KnockbackLevel = static_cast<int>(a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch)); - } - - Vector3d AdditionalSpeed(0, 0, 0); - switch (KnockbackLevel) - { - case 1: AdditionalSpeed.Set(5, 0.3, 5); break; - case 2: AdditionalSpeed.Set(8, 0.3, 8); break; - default: break; - } - AddSpeed(a_TDI.Knockback + AdditionalSpeed); + AddSpeed(a_TDI.Knockback); } m_World->BroadcastEntityStatus(*this, esGenericHurt); @@ -761,9 +749,19 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama double cEntity::GetKnockbackAmountAgainst(const cEntity & a_Receiver) { // Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit + double Knockback = 11; - // TODO: Enchantments - return 1; + // If we're sprinting, bump up the knockback + if (IsSprinting()) + { + Knockback = 16; + } + + // Check for knockback enchantments (punch only applies to shot arrows) + unsigned int KnockbackLevel = GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); + Knockback += 10 * KnockbackLevel; + + return Knockback; } @@ -1585,8 +1583,7 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - a_World->AddEntity(this); + a_World->AddEntity(ParentChunk->RemoveEntity(*this)); cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld); }); return true; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8991b9fad..8f433b816 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -157,7 +157,7 @@ public: /** Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed). Adds the entity to the world. */ - virtual bool Initialize(cWorld & a_World); + virtual bool Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld); // tolua_begin @@ -670,8 +670,6 @@ private: int m_InvulnerableTicks; } ; // tolua_export -typedef std::list<cEntity *> cEntityList; - diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 3bbe334fb..a1b518cbc 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -149,12 +149,12 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : -bool cPlayer::Initialize(cWorld & a_World) +bool cPlayer::Initialize(OwnedEntity a_Self, cWorld & a_World) { UNUSED(a_World); ASSERT(GetWorld() != nullptr); ASSERT(GetParentChunk() == nullptr); - GetWorld()->AddPlayer(this); + GetWorld()->AddPlayer(std::unique_ptr<cPlayer>(static_cast<cPlayer *>(a_Self.release()))); cPluginManager::Get()->CallHookSpawnedEntity(*GetWorld(), *this); @@ -1321,10 +1321,16 @@ cTeam * cPlayer::UpdateTeam(void) void cPlayer::OpenWindow(cWindow & a_Window) { + if (cRoot::Get()->GetPluginManager()->CallHookPlayerOpeningWindow(*this, a_Window)) + { + return; + } + if (&a_Window != m_CurrentWindow) { CloseWindow(false); } + a_Window.OpenedByPlayer(*this); m_CurrentWindow = &a_Window; a_Window.SendWholeWindow(*GetClientHandle()); @@ -2003,7 +2009,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d GetWorld()->BroadcastDestroyEntity(*this); // Remove player from world - GetWorld()->RemovePlayer(this, false); + // Make sure that RemovePlayer didn't return a valid smart pointer, due to the second parameter being false + // We remain valid and not destructed after this call + VERIFY(!GetWorld()->RemovePlayer(*this, false)); // Set position to the new position SetPosition(a_NewPosition); @@ -2045,8 +2053,10 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - a_World->AddPlayer(this, &a_OldWorld); // New world will take over and announce client at its next tick + + // New world will take over and announce client at its next tick + auto PlayerPtr = static_cast<cPlayer *>(ParentChunk->RemoveEntity(*this).release()); + a_World->AddPlayer(std::unique_ptr<cPlayer>(PlayerPtr), &a_OldWorld); }); return true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c00dbc7f1..8c21c25d6 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -41,7 +41,7 @@ public: cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName); - virtual bool Initialize(cWorld & a_World) override; + virtual bool Initialize(OwnedEntity a_Self, cWorld & a_World) override; virtual ~cPlayer() override; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 64522acef..d1e101964 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -260,7 +260,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve -cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) +std::unique_ptr<cProjectileEntity> cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) { Vector3d Speed; if (a_Speed != nullptr) @@ -270,15 +270,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, switch (a_Kind) { - case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); - case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkSplashPotion: return new cSplashPotionEntity (a_Creator, a_X, a_Y, a_Z, Speed, *a_Item); - case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkArrow: return cpp14::make_unique<cArrowEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return cpp14::make_unique<cThrownEggEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return cpp14::make_unique<cThrownEnderPearlEntity>(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return cpp14::make_unique<cThrownSnowballEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkGhastFireball: return cpp14::make_unique<cGhastFireballEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFireCharge: return cpp14::make_unique<cFireChargeEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkExpBottle: return cpp14::make_unique<cExpBottleEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkSplashPotion: return cpp14::make_unique<cSplashPotionEntity> (a_Creator, a_X, a_Y, a_Z, Speed, *a_Item); + case pkWitherSkull: return cpp14::make_unique<cWitherSkullEntity> (a_Creator, a_X, a_Y, a_Z, Speed); case pkFirework: { ASSERT(a_Item != nullptr); @@ -287,7 +287,7 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, return nullptr; } - return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, *a_Item); + return cpp14::make_unique<cFireworkEntity>(a_Creator, a_X, a_Y, a_Z, *a_Item); } case pkFishingFloat: break; } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index b354c7cfc..da8c650f5 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -46,7 +46,7 @@ public: cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); - static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); + static std::unique_ptr<cProjectileEntity> Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); /** Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given */ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace); diff --git a/src/Entities/SplashPotionEntity.h b/src/Entities/SplashPotionEntity.h index 85aa5046f..baa5da725 100644 --- a/src/Entities/SplashPotionEntity.h +++ b/src/Entities/SplashPotionEntity.h @@ -12,10 +12,12 @@ #include "ProjectileEntity.h" #include "EntityEffect.h" #include "../World.h" -#include "Entity.h" +class cEntity; + + // tolua_begin diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index 22a0113e5..451451fd3 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -7,6 +7,7 @@ #include "ChunkDesc.h" #include "../Noise/Noise.h" #include "../BlockEntities/BlockEntity.h" +#include "../Entities/Entity.h" diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index 4c97430a2..709fccb70 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -231,7 +231,7 @@ private: cChunkDef::BiomeMap m_BiomeMap; cBlockArea m_BlockArea; cChunkDef::HeightMap m_HeightMap; - cEntityList m_Entities; // Individual entities are NOT owned by this object! + cEntityList m_Entities; cBlockEntities m_BlockEntities; // Individual block entities are NOT owned by this object! bool m_bUseDefaultBiomes; diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index d1201797c..fe5ce82be 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1489,11 +1489,11 @@ bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX double AnimalY = a_RelY; double AnimalZ = static_cast<double>(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ + 0.5); - cMonster * NewMob = cMonster::NewMonsterFromType(AnimalToSpawn); + auto NewMob = cMonster::NewMonsterFromType(AnimalToSpawn); NewMob->SetHealth(NewMob->GetMaxHealth()); NewMob->SetPosition(AnimalX, AnimalY, AnimalZ); - a_ChunkDesc.GetEntities().push_back(NewMob); LOGD("Spawning %s #%i at {%.02f, %.02f, %.02f}", NewMob->GetClass(), NewMob->GetUniqueID(), AnimalX, AnimalY, AnimalZ); + a_ChunkDesc.GetEntities().emplace_back(std::move(NewMob)); return true; } diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index de2f5f95d..818b8254c 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -18,8 +18,8 @@ uses a prefabricate in a cBlockArea for drawing itself. cPrefab::cPrefab(const cPrefab::sDef & a_Def) : m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ), m_HitBox( - a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ, - a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ + {a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ}, + {a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ} ), m_AllowedRotations(a_Def.m_AllowedRotations), m_MergeStrategy(a_Def.m_MergeStrategy), diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index bf1fee2e8..5473965d6 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -128,7 +128,10 @@ public: m_Noise(a_Seed), m_MaxSize(a_MaxSize), m_Density(a_Density), - m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize), + m_Borders( + {a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize}, + {a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize} + ), m_Prefabs(a_Prefabs), m_HeightGen(a_HeightGen) { diff --git a/src/Item.cpp b/src/Item.cpp index 3d9efb3b3..995ff59dc 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -158,7 +158,12 @@ void cItem::GetJson(Json::Value & a_OutValue) const } if (!IsLoreEmpty()) { - a_OutValue["Lore"] = m_Lore; + auto & LoreArray = (a_OutValue["Lore"] = Json::Value(Json::arrayValue)); + + for (const auto & Line : m_LoreTable) + { + LoreArray.append(Line); + } } if (m_ItemColor.IsValid()) @@ -196,7 +201,11 @@ void cItem::FromJson(const Json::Value & a_Value) m_Enchantments.Clear(); m_Enchantments.AddFromString(a_Value.get("ench", "").asString()); m_CustomName = a_Value.get("Name", "").asString(); - m_Lore = a_Value.get("Lore", "").asString(); + auto Lore = a_Value.get("Lore", Json::arrayValue); + for (auto & Line : Lore) + { + m_LoreTable.push_back(Line.asString()); + } int red = a_Value.get("Color_Red", -1).asInt(); int green = a_Value.get("Color_Green", -1).asInt(); diff --git a/src/Item.h b/src/Item.h index 18a1e69c0..493061d93 100644 --- a/src/Item.h +++ b/src/Item.h @@ -41,7 +41,6 @@ public: m_ItemCount(0), m_ItemDamage(0), m_CustomName(""), - m_Lore(""), m_RepairCost(0), m_FireworkItem(), m_ItemColor() @@ -56,14 +55,14 @@ public: short a_ItemDamage = 0, const AString & a_Enchantments = "", const AString & a_CustomName = "", - const AString & a_Lore = "" + const AStringVector & a_LoreTable = {} ) : m_ItemType (a_ItemType), m_ItemCount (a_ItemCount), m_ItemDamage (a_ItemDamage), m_Enchantments(a_Enchantments), m_CustomName (a_CustomName), - m_Lore (a_Lore), + m_LoreTable (a_LoreTable), m_RepairCost (0), m_FireworkItem(), m_ItemColor() @@ -106,7 +105,7 @@ public: m_ItemDamage = 0; m_Enchantments.Clear(); m_CustomName = ""; - m_Lore = ""; + m_LoreTable.clear(); m_RepairCost = 0; m_FireworkItem.EmptyData(); m_ItemColor.Clear(); @@ -137,7 +136,7 @@ public: (m_ItemDamage == a_Item.m_ItemDamage) && (m_Enchantments == a_Item.m_Enchantments) && (m_CustomName == a_Item.m_CustomName) && - (m_Lore == a_Item.m_Lore) && + (m_LoreTable == a_Item.m_LoreTable) && m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem) ); } @@ -151,12 +150,12 @@ public: bool IsBothNameAndLoreEmpty(void) const { - return (m_CustomName.empty() && m_Lore.empty()); + return (m_CustomName.empty() && m_LoreTable.empty()); } bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); } - bool IsLoreEmpty(void) const { return (m_Lore.empty()); } + bool IsLoreEmpty(void) const { return (m_LoreTable.empty()); } /** Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items */ cItem CopyOne(void) const; @@ -221,7 +220,12 @@ public: short m_ItemDamage; cEnchantments m_Enchantments; AString m_CustomName; - AString m_Lore; + + // tolua_end + + AStringVector m_LoreTable; // Exported in ManualBindings.cpp + + // tolua_begin int m_RepairCost; cFireworkItem m_FireworkItem; diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index bdfed8944..f39a35a88 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -95,11 +95,8 @@ public: } // Spawn block at water level - cBoat * Boat = new cBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())); - if (!Boat->Initialize(*a_World)) + if (a_World->SpawnBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())) == cEntity::INVALID_ID) { - delete Boat; - Boat = nullptr; return false; } diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index a2f646efc..7cbd1dc70 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -69,17 +69,12 @@ public: } // Create the arrow entity: - cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); - if (Arrow == nullptr) + auto Arrow = cpp14::make_unique<cArrowEntity>(*a_Player, Force * 2); + auto ArrowPtr = Arrow.get(); + if (!ArrowPtr->Initialize(std::move(Arrow), *a_Player->GetWorld())) { return; } - if (!Arrow->Initialize(*a_Player->GetWorld())) - { - delete Arrow; - Arrow = nullptr; - return; - } a_Player->GetWorld()->BroadcastSoundEffect( "entity.arrow.shoot", a_Player->GetPosX(), diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index a32368304..012f13a6c 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -251,14 +251,13 @@ public: } else { - cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); - if (!Floater->Initialize(*a_World)) + auto Floater = cpp14::make_unique<cFloater>(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); + auto FloaterPtr = Floater.get(); + if (!FloaterPtr->Initialize(std::move(Floater), *a_World)) { - delete Floater; - Floater = nullptr; return false; } - a_Player->SetIsFishing(true, Floater->GetUniqueID()); + a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID()); } return true; } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 48cf782d8..faee5d008 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -3,7 +3,6 @@ #include "../Defines.h" #include "../Item.h" -#include "../Blocks/BlockPluginInterface.h" @@ -12,6 +11,7 @@ // fwd: class cWorld; class cPlayer; +class cBlockPluginInterface; diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index 77a5bf47c..dd3e1f5a8 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -38,11 +38,10 @@ public: if (Block == E_BLOCK_AIR) { - cItemFrame * ItemFrame = new cItemFrame(a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); - if (!ItemFrame->Initialize(*a_World)) + auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); + auto ItemFramePtr = ItemFrame.get(); + if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World)) { - delete ItemFrame; - ItemFrame = nullptr; return false; } diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 623342d41..05f375f06 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -59,24 +59,9 @@ public: double x = static_cast<double>(a_BlockX) + 0.5; double y = static_cast<double>(a_BlockY) + 0.5; double z = static_cast<double>(a_BlockZ) + 0.5; - cMinecart * Minecart = nullptr; - switch (m_ItemType) - { - case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break; - case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break; - case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break; - case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break; - case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (x, y, z); break; - default: - { - ASSERT(!"Unhandled minecart item"); - return false; - } - } // switch (m_ItemType) - if (!Minecart->Initialize(*a_World)) + + if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID) { - delete Minecart; - Minecart = nullptr; return false; } diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index 3432583ca..8e5a1b5d2 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -70,11 +70,10 @@ public: { "BurningSkull" } }; - cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); - if (!Painting->Initialize(*a_World)) + auto Painting = cpp14::make_unique<cPainting>(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); + auto PaintingPtr = Painting.get(); + if (!PaintingPtr->Initialize(std::move(Painting), *a_World)) { - delete Painting; - Painting = nullptr; return false; } diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index e3f5298e4..1e0db5175 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -342,13 +342,12 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int & a_MaxPackSize) { - cMonster * toReturn = nullptr; if (m_NewPack) { m_MobType = ChooseMobType(a_Biome); if (m_MobType == mtInvalidType) { - return toReturn; + return nullptr; } if (m_MobType == mtWolf) { @@ -366,14 +365,16 @@ cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, if ((m_AllowedTypes.find(m_MobType) != m_AllowedTypes.end()) && CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome)) { - cMonster * newMob = cMonster::NewMonsterFromType(m_MobType); + auto newMob = cMonster::NewMonsterFromType(m_MobType); + auto NewMobPtr = newMob.get(); if (newMob) { - m_Spawned.insert(newMob); + m_Spawned.insert(std::move(newMob)); } - toReturn = newMob; + return NewMobPtr; } - return toReturn; + + return nullptr; } diff --git a/src/MobSpawner.h b/src/MobSpawner.h index 941a04a17..14c721ae3 100644 --- a/src/MobSpawner.h +++ b/src/MobSpawner.h @@ -7,12 +7,6 @@ -// fwd: -class cChunk; - - - - /** This class is used to determine which monster can be spawned in which place it is essentially static (eg. Squids spawn in water, Zombies spawn in dark places) @@ -43,7 +37,7 @@ public : // return true if there is at least one allowed type bool CanSpawnAnything(void); - typedef const std::set<cMonster *> tSpawnedContainer; + typedef const std::set<std::unique_ptr<cMonster>> tSpawnedContainer; tSpawnedContainer & getSpawned(void); /** Returns true if specified type of mob can spawn on specified block */ @@ -61,7 +55,7 @@ protected : std::set<eMonsterType> m_AllowedTypes; bool m_NewPack; eMonsterType m_MobType; - std::set<cMonster *> m_Spawned; + std::set<std::unique_ptr<cMonster>> m_Spawned; } ; diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index 8cdac12d1..a48bfa886 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -39,19 +39,17 @@ bool cBlaze::Attack(std::chrono::milliseconds a_Dt) // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; - cFireChargeEntity * FireCharge = new cFireChargeEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (FireCharge == nullptr) - { - return false; - } - if (!FireCharge->Initialize(*m_World)) + + auto FireCharge = cpp14::make_unique<cFireChargeEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto FireChargePtr = FireCharge.get(); + if (!FireChargePtr->Initialize(std::move(FireCharge), *m_World)) { - delete FireCharge; - FireCharge = nullptr; return false; } + ResetAttackCooldown(); // ToDo: Shoot 3 fireballs instead of 1. + return true; } return false; diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index 6f5a93d93..2488e63b1 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -39,17 +39,14 @@ bool cGhast::Attack(std::chrono::milliseconds a_Dt) // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; - cGhastFireballEntity * GhastBall = new cGhastFireballEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (GhastBall == nullptr) - { - return false; - } - if (!GhastBall->Initialize(*m_World)) + + auto GhastBall = cpp14::make_unique<cGhastFireballEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto GhastBallPtr = GhastBall.get(); + if (!GhastBallPtr->Initialize(std::move(GhastBall), *m_World)) { - delete GhastBall; - GhastBall = nullptr; return false; } + ResetAttackCooldown(); return true; } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index ecda6e724..8077e41d6 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -5,6 +5,7 @@ #include "../Root.h" #include "../Server.h" #include "../ClientHandle.h" +#include "../Items/ItemHandler.h" #include "../World.h" #include "../EffectID.h" #include "../Entities/Player.h" @@ -996,7 +997,7 @@ void cMonster::UnsafeUnsetTarget() -cPawn * cMonster::GetTarget () +cPawn * cMonster::GetTarget() { return m_Target; } @@ -1005,29 +1006,25 @@ cPawn * cMonster::GetTarget () -cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) +std::unique_ptr<cMonster> cMonster::NewMonsterFromType(eMonsterType a_MobType) { auto & Random = GetRandomProvider(); - cMonster * toReturn = nullptr; // Create the mob entity switch (a_MobType) { case mtMagmaCube: { - toReturn = new cMagmaCube(1 << Random.RandInt(2)); // Size 1, 2 or 4 - break; + return cpp14::make_unique<cMagmaCube>(1 << Random.RandInt(2)); // Size 1, 2 or 4 } case mtSlime: { - toReturn = new cSlime(1 << Random.RandInt(2)); // Size 1, 2 or 4 - break; + return cpp14::make_unique<cSlime>(1 << Random.RandInt(2)); // Size 1, 2 or 4 } case mtSkeleton: { // TODO: Actual detection of spawning in Nether - toReturn = new cSkeleton(false); - break; + return cpp14::make_unique<cSkeleton>(false); } case mtVillager: { @@ -1038,8 +1035,7 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) VillagerType = 0; } - toReturn = new cVillager(static_cast<cVillager::eVillagerType>(VillagerType)); - break; + return cpp14::make_unique<cVillager>(static_cast<cVillager::eVillagerType>(VillagerType)); } case mtHorse: { @@ -1055,42 +1051,41 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) HorseType = 0; } - toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes); - break; + return cpp14::make_unique<cHorse>(HorseType, HorseColor, HorseStyle, HorseTameTimes); } - case mtBat: toReturn = new cBat(); break; - case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCaveSpider(); break; - case mtChicken: toReturn = new cChicken(); break; - case mtCow: toReturn = new cCow(); break; - case mtCreeper: toReturn = new cCreeper(); break; - case mtEnderDragon: toReturn = new cEnderDragon(); break; - case mtEnderman: toReturn = new cEnderman(); break; - case mtGhast: toReturn = new cGhast(); break; - case mtGiant: toReturn = new cGiant(); break; - case mtGuardian: toReturn = new cGuardian(); break; - case mtIronGolem: toReturn = new cIronGolem(); break; - case mtMooshroom: toReturn = new cMooshroom(); break; - case mtOcelot: toReturn = new cOcelot(); break; - case mtPig: toReturn = new cPig(); break; - case mtRabbit: toReturn = new cRabbit(); break; - case mtSheep: toReturn = new cSheep(); break; - case mtSilverfish: toReturn = new cSilverfish(); break; - case mtSnowGolem: toReturn = new cSnowGolem(); break; - case mtSpider: toReturn = new cSpider(); break; - case mtSquid: toReturn = new cSquid(); break; - case mtWitch: toReturn = new cWitch(); break; - case mtWither: toReturn = new cWither(); break; - case mtWolf: toReturn = new cWolf(); break; - case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter - case mtZombiePigman: toReturn = new cZombiePigman(); break; + case mtBat: return cpp14::make_unique<cBat>(); + case mtBlaze: return cpp14::make_unique<cBlaze>(); + case mtCaveSpider: return cpp14::make_unique<cCaveSpider>(); + case mtChicken: return cpp14::make_unique<cChicken>(); + case mtCow: return cpp14::make_unique<cCow>(); + case mtCreeper: return cpp14::make_unique < cCreeper>(); + case mtEnderDragon: return cpp14::make_unique<cEnderDragon>(); + case mtEnderman: return cpp14::make_unique<cEnderman>(); + case mtGhast: return cpp14::make_unique<cGhast>(); + case mtGiant: return cpp14::make_unique<cGiant>(); + case mtGuardian: return cpp14::make_unique<cGuardian>(); + case mtIronGolem: return cpp14::make_unique<cIronGolem>(); + case mtMooshroom: return cpp14::make_unique<cMooshroom>(); + case mtOcelot: return cpp14::make_unique<cOcelot>(); + case mtPig: return cpp14::make_unique<cPig>(); + case mtRabbit: return cpp14::make_unique<cRabbit>(); + case mtSheep: return cpp14::make_unique<cSheep>(); + case mtSilverfish: return cpp14::make_unique<cSilverfish>(); + case mtSnowGolem: return cpp14::make_unique<cSnowGolem>(); + case mtSpider: return cpp14::make_unique<cSpider>(); + case mtSquid: return cpp14::make_unique<cSquid>(); + case mtWitch: return cpp14::make_unique<cWitch>(); + case mtWither: return cpp14::make_unique<cWither>(); + case mtWolf: return cpp14::make_unique<cWolf>(); + case mtZombie: return cpp14::make_unique<cZombie>(false); // TODO: Infected zombie parameter + case mtZombiePigman: return cpp14::make_unique<cZombiePigman>(); default: { ASSERT(!"Unhandled mob type whilst trying to spawn mob!"); + return nullptr; } } - return toReturn; } @@ -1099,7 +1094,13 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth) { - auto Count = GetRandomProvider().RandInt<char>(static_cast<char>(a_Min), static_cast<char>(a_Max)); + auto Count = GetRandomProvider().RandInt<unsigned int>(a_Min, a_Max); + auto MaxStackSize = static_cast<unsigned char>(ItemHandler(a_Item)->GetMaxStackSize()); + while (Count > MaxStackSize) + { + a_Drops.emplace_back(a_Item, MaxStackSize, a_ItemHealth); + Count -= MaxStackSize; + } if (Count > 0) { a_Drops.emplace_back(a_Item, Count, a_ItemHealth); diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index b79399a0f..268db6168 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -2,11 +2,11 @@ #pragma once #include "../Entities/Pawn.h" -#include "../Item.h" #include "MonsterTypes.h" #include "PathFinder.h" +class cItem; class cClientHandle; @@ -168,13 +168,13 @@ public: void UnsafeUnsetTarget(); /** Returns the current target. */ - cPawn * GetTarget (); + cPawn * GetTarget(); /** Creates a new object of the specified mob. a_MobType is the type of the mob to be created Asserts and returns null if mob type is not specified */ - static cMonster * NewMonsterFromType(eMonsterType a_MobType); + static std::unique_ptr<cMonster> NewMonsterFromType(eMonsterType a_MobType); /** Returns if this mob last target was a player to avoid destruction on player quit */ bool WasLastTargetAPlayer() const { return m_WasLastTargetAPlayer; } @@ -203,7 +203,11 @@ protected: bool ReachedFinalDestination(void) { return ((m_FinalDestination - GetPosition()).SqrLength() < WAYPOINT_RADIUS * WAYPOINT_RADIUS); } /** Returns whether or not the target is close enough for attack. */ - bool TargetIsInRange(void) { ASSERT(m_Target != nullptr); return ((m_Target->GetPosition() - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); } + bool TargetIsInRange(void) + { + ASSERT(GetTarget() != nullptr); + return ((GetTarget()->GetPosition() - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); + } /** Returns whether the monster needs to jump to reach a given height. */ inline bool DoesPosYRequireJump(double a_PosY) @@ -272,7 +276,9 @@ protected: void AddRandomWeaponDropItem(cItems & a_Drops, unsigned int a_LootingLevel); private: - /** A pointer to the entity this mobile is aiming to reach */ + /** A pointer to the entity this mobile is aiming to reach. + The validity of this pointer SHALL be guaranteed by the pointee; + it MUST be reset when the pointee changes worlds or is destroyed. */ cPawn * m_Target; } ; // tolua_export diff --git a/src/Mobs/Ocelot.cpp b/src/Mobs/Ocelot.cpp index 47776670c..e5004a1d1 100644 --- a/src/Mobs/Ocelot.cpp +++ b/src/Mobs/Ocelot.cpp @@ -6,6 +6,7 @@ #include "../Entities/Player.h" #include "../Items/ItemHandler.h" #include "Broadcaster.h" +#include "../BoundingBox.h" @@ -203,3 +204,30 @@ void cOcelot::SpawnOn(cClientHandle & a_ClientHandle) + +class cFindSittingCat : + public cEntityCallback +{ + virtual bool Item(cEntity * a_Entity) override + { + return ( + (a_Entity->GetEntityType() == cEntity::etMonster) && + (static_cast<cMonster *>(a_Entity)->GetMobType() == eMonsterType::mtOcelot) && + (static_cast<cOcelot *>(a_Entity)->IsSitting()) + ); + } +}; + + + + + +bool cOcelot::IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition) +{ + cFindSittingCat FindSittingCat; + return a_World->ForEachEntityInBox(cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1), FindSittingCat); +} + + + + diff --git a/src/Mobs/Ocelot.h b/src/Mobs/Ocelot.h index 5729851fe..59b4f25af 100644 --- a/src/Mobs/Ocelot.h +++ b/src/Mobs/Ocelot.h @@ -54,6 +54,9 @@ public: } void SetCatType (eCatType a_CatType) { m_CatType = a_CatType; } + /** Returns true if there's a cat sitting above the given position */ + static bool IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition); + protected: bool m_IsSitting; diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index 0d6d5e428..e48991a06 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -57,19 +57,15 @@ bool cSkeleton::Attack(std::chrono::milliseconds a_Dt) Vector3d Inaccuracy = Vector3d(Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25)); Vector3d Speed = (GetTarget()->GetPosition() + Inaccuracy - GetPosition()) * 5; Speed.y += Random.RandInt(-1, 1); - cArrowEntity * Arrow = new cArrowEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (Arrow == nullptr) - { - return false; - } - if (!Arrow->Initialize(*m_World)) + + auto Arrow = cpp14::make_unique<cArrowEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto ArrowPtr = Arrow.get(); + if (!ArrowPtr->Initialize(std::move(Arrow), *m_World)) { - delete Arrow; - Arrow = nullptr; return false; } - ResetAttackCooldown(); + ResetAttackCooldown(); return true; } return false; diff --git a/src/Mobs/Slime.cpp b/src/Mobs/Slime.cpp index 3f832ae87..291a3a57f 100644 --- a/src/Mobs/Slime.cpp +++ b/src/Mobs/Slime.cpp @@ -78,10 +78,10 @@ void cSlime::KilledBy(TakeDamageInfo & a_TDI) double AddX = (i % 2 - 0.5) * m_Size / 4.0; double AddZ = (i / 2 - 0.5) * m_Size / 4.0; - cSlime * NewSlime = new cSlime(m_Size / 2); + auto NewSlime = cpp14::make_unique<cSlime>(m_Size / 2); NewSlime->SetPosition(GetPosX() + AddX, GetPosY() + 0.5, GetPosZ() + AddZ); NewSlime->SetYaw(Random.RandReal(360.0f)); - m_World->SpawnMobFinalize(NewSlime); + m_World->SpawnMobFinalize(std::move(NewSlime)); } } super::KilledBy(a_TDI); diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp index fad51c05f..dd85d7d2b 100644 --- a/src/Mobs/Wither.cpp +++ b/src/Mobs/Wither.cpp @@ -15,6 +15,7 @@ cWither::cWither(void) : m_WitherInvulnerableTicks(220) { SetMaxHealth(300); + SetHealth(GetMaxHealth() / 3); } @@ -30,18 +31,6 @@ bool cWither::IsArmored(void) const -bool cWither::Initialize(cWorld & a_World) -{ - // Set health before BroadcastSpawnEntity() - SetHealth(GetMaxHealth() / 3); - - return super::Initialize(a_World); -} - - - - - bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI) { if (a_TDI.DamageType == dtDrowning) diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index b430588c9..5f6ec607c 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -25,7 +25,6 @@ public: bool IsArmored(void) const; // cEntity overrides - virtual bool Initialize(cWorld & a_World) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 70e761469..e05fedbf8 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -2,9 +2,9 @@ #pragma once #include "PassiveAggressiveMonster.h" -#include "../Entities/Entity.h" +class cEntity; diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h index efed9c7a9..26b3a7ec7 100644 --- a/src/Protocol/Packetizer.h +++ b/src/Protocol/Packetizer.h @@ -11,7 +11,10 @@ #pragma once #include "Protocol.h" -#include "../ByteBuffer.h" + + + +class cByteBuffer; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 93f25310b..18ede0640 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -12,7 +12,6 @@ #include "../Defines.h" #include "../Scoreboard.h" -#include "../Map.h" #include "../ByteBuffer.h" #include "../EffectID.h" @@ -20,6 +19,7 @@ +class cMap; class cExpOrb; class cPlayer; class cEntity; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 43facde72..a65fb931e 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -59,6 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) case PROTO_VERSION_1_11_0: return "1.11"; case PROTO_VERSION_1_11_1: return "1.11.1"; case PROTO_VERSION_1_12: return "1.12"; + case PROTO_VERSION_1_12_1: return "1.12.1"; } ASSERT(!"Unknown protocol version"); return Printf("Unknown protocol (%d)", a_ProtocolVersion); @@ -1107,6 +1108,11 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema m_Protocol = new cProtocol_1_12(m_Client, ServerAddress, ServerPort, NextState); return true; } + case PROTO_VERSION_1_12_1: + { + m_Protocol = new cProtocol_1_12_1(m_Client, ServerAddress, ServerPort, NextState); + return true; + } default: { LOGD("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))", diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 32dcca940..4c338a5b8 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -18,9 +18,9 @@ // Adjust these if a new protocol is added or an old one is removed: -#define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12" -#define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335" -#define MCS_LATEST_PROTOCOL_VERSION 335 +#define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x" +#define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335, 338" +#define MCS_LATEST_PROTOCOL_VERSION 338 @@ -43,6 +43,7 @@ public: PROTO_VERSION_1_11_0 = 315, PROTO_VERSION_1_11_1 = 316, PROTO_VERSION_1_12 = 335, + PROTO_VERSION_1_12_1 = 338, } ; cProtocolRecognizer(cClientHandle * a_Client); diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp index 278c063cc..b9eb1801d 100644 --- a/src/Protocol/Protocol_1_12.cpp +++ b/src/Protocol/Protocol_1_12.cpp @@ -1164,7 +1164,7 @@ void cProtocol_1_12::SendExperience(void) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x3f); // Experience Packet + cPacketizer Pkt(*this, 0x3f); // Set Experience Packet cPlayer * Player = m_Client->GetPlayer(); Pkt.WriteBEFloat(Player->GetXpPercentage()); Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel())); @@ -1211,7 +1211,7 @@ void cProtocol_1_12::SendScoreboardObjective(const AString & a_Name, const AStri void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x42); // Set passangers packet + cPacketizer Pkt(*this, 0x42); // Set Passengers packet Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); Pkt.WriteVarInt32(1); // 1 passenger Pkt.WriteVarInt32(a_Entity.GetUniqueID()); @@ -1224,7 +1224,7 @@ void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity & void cProtocol_1_12::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x42); // Set passangers packet + cPacketizer Pkt(*this, 0x42); // Set Passengers packet Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); Pkt.WriteVarInt32(0); // No passangers } @@ -1600,3 +1600,756 @@ bool cProtocol_1_12::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp m_Client->PacketUnknown(a_PacketType); return false; } + + + + + +cProtocol_1_12_1::cProtocol_1_12_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : + super(a_Client, a_ServerAddress, a_ServerPort, a_State) +{ +} + + + + + +void cProtocol_1_12_1::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) +{ + cServer * Server = cRoot::Get()->GetServer(); + AString ServerDescription = Server->GetDescription(); + auto NumPlayers = static_cast<signed>(Server->GetNumPlayers()); + auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers()); + AString Favicon = Server->GetFaviconData(); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); + + // Version: + Json::Value Version; + Version["name"] = "Cuberite 1.12.1"; + Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_1; + + // Players: + Json::Value Players; + Players["online"] = NumPlayers; + Players["max"] = MaxPlayers; + // TODO: Add "sample" + + // Description: + Json::Value Description; + Description["text"] = ServerDescription.c_str(); + + // Create the response: + Json::Value ResponseValue; + ResponseValue["version"] = Version; + ResponseValue["players"] = Players; + ResponseValue["description"] = Description; + if (!Favicon.empty()) + { + ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); + } + + // Serialize the response into a packet: + Json::FastWriter Writer; + cPacketizer Pkt(*this, 0x00); // Response packet + Pkt.WriteString(Writer.write(ResponseValue)); +} + + + + + +void cProtocol_1_12_1::SendRespawn(eDimension a_Dimension) +{ + cPacketizer Pkt(*this, 0x35); // Respawn packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEInt32(static_cast<Int32>(a_Dimension)); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8(static_cast<Byte>(Player->GetEffectiveGameMode())); + Pkt.WriteString("default"); +} + + + + + +void cProtocol_1_12_1::SendPlayerListAddPlayer(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(0); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + Pkt.WriteString(a_Player.GetPlayerListName()); + + const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); + Pkt.WriteVarInt32(Properties.size()); + for (auto & Node : Properties) + { + Pkt.WriteString(Node.get("name", "").asString()); + Pkt.WriteString(Node.get("value", "").asString()); + AString Signature = Node.get("signature", "").asString(); + if (Signature.empty()) + { + Pkt.WriteBool(false); + } + else + { + Pkt.WriteBool(true); + Pkt.WriteString(Signature); + } + } + + Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetGameMode())); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetClientHandle()->GetPing())); + Pkt.WriteBool(false); +} + + + + + +void cProtocol_1_12_1::SendPlayerListRemovePlayer(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(4); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); +} + + + + + +void cProtocol_1_12_1::SendPlayerListUpdateGameMode(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(1); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetGameMode())); +} + + + + + +void cProtocol_1_12_1::SendPlayerListUpdatePing(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + auto ClientHandle = a_Player.GetClientHandlePtr(); + if (ClientHandle != nullptr) + { + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(2); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + Pkt.WriteVarInt32(static_cast<UInt32>(ClientHandle->GetPing())); + } +} + + + + + +void cProtocol_1_12_1::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(3); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + + if (a_CustomName.empty()) + { + Pkt.WriteBool(false); + } + else + { + Pkt.WriteBool(true); + Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_CustomName.c_str())); + } +} + + + + + +void cProtocol_1_12_1::SendPlayerAbilities(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2c); // Player Abilities packet + Byte Flags = 0; + cPlayer * Player = m_Client->GetPlayer(); + if (Player->IsGameModeCreative()) + { + Flags |= 0x01; + Flags |= 0x08; // Godmode, used for creative + } + if (Player->IsFlying()) + { + Flags |= 0x02; + } + if (Player->CanFly()) + { + Flags |= 0x04; + } + Pkt.WriteBEUInt8(Flags); + Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed())); + Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed())); +} + + + + + +void cProtocol_1_12_1::SendPlayerMoveLook(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2f); // Player Position And Look packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEDouble(Player->GetPosX()); + Pkt.WriteBEDouble(Player->GetPosY()); + Pkt.WriteBEDouble(Player->GetPosZ()); + Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch())); + Pkt.WriteBEUInt8(0); + Pkt.WriteVarInt32(++m_OutstandingTeleportId); + + // This teleport ID hasn't been confirmed yet + m_IsTeleportIdConfirmed = false; +} + + + + + +void cProtocol_1_12_1::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x30); // Use bed + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); +} + + + + + +void cProtocol_1_12_1::SendDestroyEntity(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x32); // Destroy Entities packet + Pkt.WriteVarInt32(1); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); +} + + + + + +void cProtocol_1_12_1::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x33); // Remove entity effect packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID)); +} + + + + + +void cProtocol_1_12_1::SendEntityHeadLook(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x36); // Entity Head Look packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); +} + + + + + +void cProtocol_1_12_1::SendCameraSetTo(const cEntity & a_Entity) +{ + cPacketizer Pkt(*this, 0x39); // Camera packet (Attach the camera of a player at another entity in spectator mode) + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); +} + + + + + +void cProtocol_1_12_1::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3b); // Display Scoreboard packet + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Display)); + Pkt.WriteString(a_Objective); +} + + + + + +void cProtocol_1_12_1::SendEntityMetadata(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3c); // Entity Metadata packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityMetadata(Pkt, a_Entity); + Pkt.WriteBEUInt8(0xff); // The termination byte +} + + + + + +void cProtocol_1_12_1::SendEntityVelocity(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3e); // Entity Velocity packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + // 400 = 8000 / 20 ... Conversion from our speed in m / s to 8000 m / tick + Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400)); +} + + + + + +void cProtocol_1_12_1::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3f); // Entity Equipment packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + // Needs to be adjusted due to the insertion of offhand at slot 1 + if (a_SlotNum > 0) + { + a_SlotNum++; + } + Pkt.WriteVarInt32(static_cast<UInt32>(a_SlotNum)); + WriteItem(Pkt, a_Item); +} + + + + + +void cProtocol_1_12_1::SendExperience(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x40); // Set Experience packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEFloat(Player->GetXpPercentage()); + Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel())); + Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetCurrentXp())); +} + + + + + +void cProtocol_1_12_1::SendHealth(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x41); // Update Health packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth())); + Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetFoodLevel())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel())); +} + + + + + +void cProtocol_1_12_1::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x42); // Scoreboard Objective packet + Pkt.WriteString(a_Name); + Pkt.WriteBEUInt8(a_Mode); + if ((a_Mode == 0) || (a_Mode == 2)) + { + Pkt.WriteString(a_DisplayName); + Pkt.WriteString("integer"); + } +} + + + + + +void cProtocol_1_12_1::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) +{ + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x43); // Set Passengers packet + Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); + Pkt.WriteVarInt32(1); // 1 passenger + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); +} + + + + + +void cProtocol_1_12_1::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) +{ + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x43); // Set Passengers packet + Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); + Pkt.WriteVarInt32(0); // No passangers +} + + + + + +void cProtocol_1_12_1::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x45); // Update Score packet + Pkt.WriteString(a_Player); + Pkt.WriteBEUInt8(a_Mode); + Pkt.WriteString(a_Objective); + + if (a_Mode != 1) + { + Pkt.WriteVarInt32(static_cast<UInt32>(a_Score)); + } +} + + + + + +void cProtocol_1_12_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +{ + // Send the Join Game packet: + { + cServer * Server = cRoot::Get()->GetServer(); + cPacketizer Pkt(*this, 0x23); // Join Game packet + Pkt.WriteBEUInt32(a_Player.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 + Pkt.WriteBEInt32(static_cast<Int32>(a_World.GetDimension())); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8(static_cast<UInt8>(Clamp<size_t>(Server->GetMaxPlayers(), 0, 255))); + Pkt.WriteString("default"); // Level type - wtf? + Pkt.WriteBool(false); // Reduced Debug Info - wtf? + } + + // Send the spawn position: + { + cPacketizer Pkt(*this, 0x46); // Spawn Position packet + Pkt.WritePosition64(FloorC(a_World.GetSpawnX()), FloorC(a_World.GetSpawnY()), FloorC(a_World.GetSpawnZ())); + } + + // Send the server difficulty: + { + cPacketizer Pkt(*this, 0x0d); // Server difficulty packet + Pkt.WriteBEInt8(1); + } + + // Send player abilities: + SendPlayerAbilities(); +} + + + + + +void cProtocol_1_12_1::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) +{ + ASSERT(m_State == 3); // In game mode? + if (!a_DoDaylightCycle) + { + // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. + a_TimeOfDay = std::min(-a_TimeOfDay, -1LL); + } + + cPacketizer Pkt(*this, 0x47); // Time update packet + Pkt.WriteBEInt64(a_WorldAge); + Pkt.WriteBEInt64(a_TimeOfDay); +} + + + + + +void cProtocol_1_12_1::SendSetRawTitle(const AString & a_Title) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(0); // Set title + + Pkt.WriteString(a_Title); +} + + + + + +void cProtocol_1_12_1::SendSetRawSubTitle(const AString & a_SubTitle) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(1); // Set subtitle + + Pkt.WriteString(a_SubTitle); +} + + + + + +void cProtocol_1_12_1::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(3); // Set title display times + Pkt.WriteBEInt32(a_FadeInTicks); + Pkt.WriteBEInt32(a_DisplayTicks); + Pkt.WriteBEInt32(a_FadeOutTicks); +} + + + + + +void cProtocol_1_12_1::SendHideTitle(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(4); // Hide title +} + + + + + +void cProtocol_1_12_1::SendResetTitle(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(5); // Reset title +} + + + + + +void cProtocol_1_12_1::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4b); // Collect Item packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Count)); +} + + + + + +void cProtocol_1_12_1::SendTeleportEntity(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4c); // Entity teleport packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEDouble(a_Entity.GetPosX()); + Pkt.WriteBEDouble(a_Entity.GetPosY()); + Pkt.WriteBEDouble(a_Entity.GetPosZ()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteBool(a_Entity.IsOnGround()); +} + + + + + +void cProtocol_1_12_1::SendEntityProperties(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + + cPacketizer Pkt(*this, 0x4e); // Entity Properties packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityProperties(Pkt, a_Entity); +} + + + + + +void cProtocol_1_12_1::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4f); // Entity Effect packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID)); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier)); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Duration)); + Pkt.WriteBool(false); // Hide particles +} + + + + + +void cProtocol_1_12_1::SendPlayerMaxSpeed(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4e); // Entity Properties + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteVarInt32(Player->GetUniqueID()); + Pkt.WriteBEInt32(1); // Count + Pkt.WriteString("generic.movementSpeed"); + // The default game speed is 0.1, multiply that value by the relative speed: + Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed()); + if (Player->IsSprinting()) + { + Pkt.WriteVarInt32(1); // Modifier count + Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c); + Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier + Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); + Pkt.WriteBEUInt8(2); + } + else + { + Pkt.WriteVarInt32(0); // Modifier count + } +} + + + + + +bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) +{ + switch (m_State) + { + case 1: + { + // Status + switch (a_PacketType) + { + case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true; + case 0x01: HandlePacketStatusPing(a_ByteBuffer); return true; + } + break; + } + + case 2: + { + // Login + switch (a_PacketType) + { + case 0x00: HandlePacketLoginStart(a_ByteBuffer); return true; + case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true; + } + break; + } + + case 3: + { + // Game + switch (a_PacketType) + { + case 0x00: HandleConfirmTeleport(a_ByteBuffer); return true; + case 0x01: HandlePacketTabComplete(a_ByteBuffer); return true; + case 0x02: HandlePacketChatMessage(a_ByteBuffer); return true; + case 0x03: HandlePacketClientStatus(a_ByteBuffer); return true; + case 0x04: HandlePacketClientSettings(a_ByteBuffer); return true; + case 0x05: break; // Confirm transaction - not used in Cuberite + case 0x06: HandlePacketEnchantItem(a_ByteBuffer); return true; + case 0x07: HandlePacketWindowClick(a_ByteBuffer); return true; + case 0x08: HandlePacketWindowClose(a_ByteBuffer); return true; + case 0x09: HandlePacketPluginMessage(a_ByteBuffer); return true; + case 0x0a: HandlePacketUseEntity(a_ByteBuffer); return true; + case 0x0b: HandlePacketKeepAlive(a_ByteBuffer); return true; + case 0x0c: HandlePacketPlayer(a_ByteBuffer); return true; + case 0x0d: HandlePacketPlayerPos(a_ByteBuffer); return true; + case 0x0e: HandlePacketPlayerPosLook(a_ByteBuffer); return true; + case 0x0f: HandlePacketPlayerLook(a_ByteBuffer); return true; + case 0x10: HandlePacketVehicleMove(a_ByteBuffer); return true; + case 0x11: HandlePacketBoatSteer(a_ByteBuffer); return true; + case 0x12: break; // Craft Recipe Request - not yet implemented + case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true; + case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true; + case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true; + case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true; + case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true; + case 0x18: break; // Resource pack status - not yet implemented + case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true; + case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true; + case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; + case 0x1c: HandlePacketUpdateSign(a_ByteBuffer); return true; + case 0x1d: HandlePacketAnimation(a_ByteBuffer); return true; + case 0x1e: HandlePacketSpectate(a_ByteBuffer); return true; + case 0x1f: HandlePacketBlockPlace(a_ByteBuffer); return true; + case 0x20: HandlePacketUseItem(a_ByteBuffer); return true; + } + break; + } + default: + { + // Received a packet in an unknown state, report: + LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State); + + // Cannot kick the client - we don't know this state and thus the packet number for the kick packet + + // Switch to a state when all further packets are silently ignored: + m_State = 255; + return false; + } + case 255: + { + // This is the state used for "not processing packets anymore" when we receive a bad packet from a client. + // Do not output anything (the caller will do that for us), just return failure + return false; + } + } // switch (m_State) + + // Unknown packet type, report to the ClientHandle: + m_Client->PacketUnknown(a_PacketType); + return false; +} + + + + diff --git a/src/Protocol/Protocol_1_12.h b/src/Protocol/Protocol_1_12.h index 4d90e2183..53ff05aa6 100644 --- a/src/Protocol/Protocol_1_12.h +++ b/src/Protocol/Protocol_1_12.h @@ -5,6 +5,8 @@ Declares the 1.12 protocol classes: - cProtocol_1_12 - release 1.12 protocol (#335) + - cProtocol_1_12_1 + - release 1.12.1 protocol (#338) (others may be added later in the future for the 1.12 release series) */ @@ -69,3 +71,60 @@ protected: virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override; virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; }; + + + + + +class cProtocol_1_12_1 : + public cProtocol_1_12 +{ + typedef cProtocol_1_12 super; + +public: + cProtocol_1_12_1(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); + + virtual void SendRespawn(eDimension a_Dimension) override; + virtual void SendPlayerListAddPlayer(const cPlayer & a_Player) override; + virtual void SendPlayerListRemovePlayer(const cPlayer & a_Player) override; + virtual void SendPlayerListUpdateGameMode(const cPlayer & a_Player) override; + virtual void SendPlayerListUpdatePing(const cPlayer & a_Player) override; + virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override; + virtual void SendPlayerAbilities(void) override; + virtual void SendPlayerMoveLook(void) override; + virtual void SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void SendDestroyEntity(const cEntity & a_Entity) override; + virtual void SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) override; + virtual void SendEntityHeadLook(const cEntity & a_Entity) override; + virtual void SendCameraSetTo(const cEntity & a_Entity) override; + virtual void SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; + virtual void SendEntityMetadata(const cEntity & a_Entity) override; + virtual void SendEntityVelocity(const cEntity & a_Entity) override; + virtual void SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendExperience(void) override; + virtual void SendHealth(void) override; + virtual void SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; + virtual void SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) override; + virtual void SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override; + virtual void SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; + virtual void SendLogin(const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; + virtual void SendHideTitle(void) override; + virtual void SendResetTitle(void) override; + virtual void SendSetRawSubTitle(const AString & a_SubTitle) override; + virtual void SendSetRawTitle(const AString & a_Title) override; + virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override; + virtual void SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) override; + virtual void SendTeleportEntity(const cEntity & a_Entity) override; + virtual void SendEntityProperties(const cEntity & a_Entity) override; + virtual void SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) override; + virtual void SendPlayerMaxSpeed(void) override; + +protected: + virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override; + virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override; +}; + + + + diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index f578e0e65..873ed2902 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -2883,14 +2883,10 @@ void cProtocol_1_8_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metada } else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag { - AString Lore; - for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings { - AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a grave accent / backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;) + a_Item.m_LoreTable.push_back(NBT.GetString(loretag)); } - - a_Item.m_Lore = Lore; } else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color")) { @@ -3079,15 +3075,9 @@ void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { Writer.BeginList("Lore", TAG_String); - AStringVector Decls = StringSplit(a_Item.m_Lore, "`"); - for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) + for (const auto & Line : a_Item.m_LoreTable) { - if (itr->empty()) - { - // The decl is empty (two `s), ignore - continue; - } - Writer.AddString("", itr->c_str()); + Writer.AddString("", Line); } Writer.EndList(); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 3e0171b24..56f41ec51 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -2999,14 +2999,11 @@ void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metada } else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag { - AString Lore; - + a_Item.m_LoreTable.clear(); for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings { - AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a grave accent / backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;) + a_Item.m_LoreTable.push_back(NBT.GetString(loretag)); } - - a_Item.m_Lore = Lore; } else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color")) { @@ -3342,15 +3339,9 @@ void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { Writer.BeginList("Lore", TAG_String); - AStringVector Decls = StringSplit(a_Item.m_Lore, "`"); - for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) + for (const auto & Line : a_Item.m_LoreTable) { - if (itr->empty()) - { - // The decl is empty (two `s), ignore - continue; - } - Writer.AddString("", itr->c_str()); + Writer.AddString("", Line); } Writer.EndList(); diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index cb530b3b6..c218c361c 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "SetChunkData.h" #include "BlockEntities/BlockEntity.h" +#include "Entities/Entity.h" diff --git a/src/SetChunkData.h b/src/SetChunkData.h index b0c59e40b..c608a8f61 100644 --- a/src/SetChunkData.h +++ b/src/SetChunkData.h @@ -115,11 +115,3 @@ protected: bool m_AreBiomesValid; bool m_ShouldMarkDirty; }; - -typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; -typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; - - - - - diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index d21e8dc6d..c3e262dec 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -78,9 +78,9 @@ cDelayedFluidSimulator::cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Flu -void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cDelayedFluidSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + if ((a_Block.y < 0) || (a_Block.y >= cChunkDef::Height)) { // Not inside the world (may happen when rclk with a full bucket - the client sends Y = -1) return; @@ -91,9 +91,9 @@ void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); if (BlockType != m_FluidBlock) { return; @@ -104,7 +104,7 @@ void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cDelayedFluidSimulatorChunkData::cSlot & Slot = ChunkData->m_Slots[m_AddSlotNum]; // Add, if not already present: - if (!Slot.Add(RelX, a_BlockY, RelZ)) + if (!Slot.Add(RelX, a_Block.y, RelZ)) { return; } diff --git a/src/Simulator/DelayedFluidSimulator.h b/src/Simulator/DelayedFluidSimulator.h index 62efb717e..78619a608 100644 --- a/src/Simulator/DelayedFluidSimulator.h +++ b/src/Simulator/DelayedFluidSimulator.h @@ -54,7 +54,7 @@ public: cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay); // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; virtual void Simulate(float a_Dt) override; virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; virtual cFluidSimulatorData * CreateChunkData(void) override { return new cDelayedFluidSimulatorChunkData(m_TickDelay); } diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 55dd7008b..45969bd0a 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -218,16 +218,16 @@ bool cFireSimulator::DoesBurnForever(BLOCKTYPE a_BlockType) -void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cFireSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); if (!IsAllowedBlock(BlockType)) { return; @@ -237,15 +237,15 @@ void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * cFireSimulatorChunkData & ChunkData = a_Chunk->GetFireSimulatorData(); for (cCoordWithIntList::iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr) { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) + if ((itr->x == RelX) && (itr->y == a_Block.y) && (itr->z == RelZ)) { // Already present, skip adding return; } } // for itr - ChunkData[] - FLOG("FS: Adding block {%d, %d, %d}", a_BlockX, a_BlockY, a_BlockZ); - ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ, 100)); + FLOG("FS: Adding block {%d, %d, %d}", a_Block.x, a_Block.y, a_Block.z); + ChunkData.push_back(cCoordWithInt(RelX, a_Block.y, RelZ, 100)); } diff --git a/src/Simulator/FireSimulator.h b/src/Simulator/FireSimulator.h index 5c926e6ea..bbfeb045e 100644 --- a/src/Simulator/FireSimulator.h +++ b/src/Simulator/FireSimulator.h @@ -43,7 +43,7 @@ protected: int m_ReplaceFuelChance; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; /** Returns the time [msec] after which the specified fire block is stepped again; based on surrounding fuels */ int GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index 8d712824f..d24b6aa9b 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -325,7 +325,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i // Spread: FLOG(" Spreading to {%d, %d, %d} with meta %d", BlockX, a_RelY, BlockZ, a_NewMeta); a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); - m_World.GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, a_NearChunk); + m_World.GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, a_NearChunk); HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); } diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h index a869b3489..e00db39b5 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h @@ -31,9 +31,9 @@ public: return IsRedstone(a_BlockType); } - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override { - m_Data.WakeUp({ a_BlockX, a_BlockY, a_BlockZ }); + m_Data.WakeUp(a_Block); } /** Returns if a block is a mechanism (something that accepts power and does something) diff --git a/src/Simulator/NoopFluidSimulator.h b/src/Simulator/NoopFluidSimulator.h index a237e960b..11bbf061d 100644 --- a/src/Simulator/NoopFluidSimulator.h +++ b/src/Simulator/NoopFluidSimulator.h @@ -27,11 +27,9 @@ public: } // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override { - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); + UNUSED(a_Block); UNUSED(a_Chunk); } virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h index a5d9e9448..d9e8e00f5 100644 --- a/src/Simulator/NoopRedstoneSimulator.h +++ b/src/Simulator/NoopRedstoneSimulator.h @@ -27,11 +27,9 @@ public: UNUSED(a_Chunk); } virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType) override { return false; } - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override { - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); + UNUSED(a_Block); UNUSED(a_Chunk); } diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index cee43db60..2f6b32398 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -33,7 +33,7 @@ public: virtual void Simulate(float a_Dt) = 0; virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) = 0; virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) = 0; virtual cRedstoneSimulatorChunkData * CreateChunkData() = 0; diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index 6b1219edb..01e699b49 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -60,11 +60,11 @@ void cSandSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, Pos.x, Pos.y, Pos.z, ItemTypeToString(BlockType).c_str(), ItemTypeToString(BlockBelow).c_str() ); */ - cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z)); - if (!FallingBlock->Initialize(m_World)) + + auto FallingBlock = cpp14::make_unique<cFallingBlock>(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z)); + auto FallingBlockPtr = FallingBlock.get(); + if (!FallingBlockPtr->Initialize(std::move(FallingBlock), m_World)) { - delete FallingBlock; - FallingBlock = nullptr; continue; } a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); @@ -101,15 +101,15 @@ bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) -void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cSandSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ))) + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_Block.y, RelZ))) { return; } @@ -118,14 +118,14 @@ void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData(); for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) + if ((itr->x == RelX) && (itr->y == a_Block.y) && (itr->z == RelZ)) { return; } } m_TotalBlocks += 1; - ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ)); + ChunkData.push_back(cCoordWithInt(RelX, a_Block.y, RelZ)); } diff --git a/src/Simulator/SandSimulator.h b/src/Simulator/SandSimulator.h index cda26775e..cee0a85e6 100644 --- a/src/Simulator/SandSimulator.h +++ b/src/Simulator/SandSimulator.h @@ -59,7 +59,7 @@ protected: int m_TotalBlocks; // Total number of blocks currently in the queue for simulating - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; /** Performs the instant fall of the block - removes it from top, Finishes it at the bottom */ void DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp index 7d3ce7851..9dbdd6a07 100644 --- a/src/Simulator/Simulator.cpp +++ b/src/Simulator/Simulator.cpp @@ -18,20 +18,20 @@ -void cSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cSimulator::WakeUp(Vector3i a_Block, cChunk * a_Chunk) { - AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); - AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 1, a_BlockZ)); - AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 1, a_BlockZ)); - AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 1)); - AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 1)); - if (a_BlockY > 0) + AddBlock(a_Block, a_Chunk); + AddBlock(a_Block + Vector3i(-1, 0, 0), a_Chunk->GetNeighborChunk(a_Block.x - 1, a_Block.z)); + AddBlock(a_Block + Vector3i( 1, 0, 0), a_Chunk->GetNeighborChunk(a_Block.x + 1, a_Block.z)); + AddBlock(a_Block + Vector3i(0, 0, -1), a_Chunk->GetNeighborChunk(a_Block.x, a_Block.z - 1)); + AddBlock(a_Block + Vector3i(0, 0, 1), a_Chunk->GetNeighborChunk(a_Block.x, a_Block.z + 1)); + if (a_Block.y > 0) { - AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ, a_Chunk); + AddBlock(a_Block + Vector3i(0, -1, 0), a_Chunk); } - if (a_BlockY < cChunkDef::Height - 1) + if (a_Block.y < cChunkDef::Height - 1) { - AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ, a_Chunk); + AddBlock(a_Block + Vector3i(0, 1, 0), a_Chunk); } } @@ -47,12 +47,11 @@ void cSimulator::WakeUpArea(const cCuboid & a_Area) area.ClampY(0, cChunkDef::Height - 1); // Add all blocks, in a per-chunk manner: - int chunkStartX, chunkStartZ, chunkEndX, chunkEndZ; - cChunkDef::BlockToChunk(area.p1.x, area.p1.z, chunkStartX, chunkStartZ); - cChunkDef::BlockToChunk(area.p2.x, area.p2.z, chunkEndX, chunkEndZ); - for (int cz = chunkStartZ; cz <= chunkEndZ; ++cz) + cChunkCoords ChunkStart = cChunkDef::BlockToChunk(area.p1); + cChunkCoords ChunkEnd = cChunkDef::BlockToChunk(area.p2); + for (int cz = ChunkStart.m_ChunkZ; cz <= ChunkEnd.m_ChunkZ; ++cz) { - for (int cx = chunkStartX; cx <= chunkEndX; ++cx) + for (int cx = ChunkStart.m_ChunkX; cx <= ChunkEnd.m_ChunkX; ++cx) { m_World.DoWithChunk(cx, cz, [this, &area](cChunk & a_CBChunk) -> bool { @@ -73,7 +72,7 @@ void cSimulator::WakeUpArea(const cCuboid & a_Area) { for (int x = startX; x <= endX; ++x) { - AddBlock(x, y, z, &a_CBChunk); + AddBlock({x, y, z}, &a_CBChunk); } // for x } // for z } // for y diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index ef0a3bf68..669680693 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -39,7 +39,7 @@ public: } /** Called when a block changes */ - void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + void WakeUp(Vector3i a_Block, cChunk * a_Chunk); /** Does the same processing as WakeUp, but for all blocks within the specified area. Has better performance than calling WakeUp for each block individually, due to neighbor-checking. @@ -55,7 +55,7 @@ protected: friend class cChunk; // Calls AddBlock() in its WakeUpSimulators() function, to speed things up /** Called to simulate a new block */ - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) = 0; cWorld & m_World; } ; diff --git a/src/Simulator/SimulatorManager.cpp b/src/Simulator/SimulatorManager.cpp index 78c02fc07..a2740f707 100644 --- a/src/Simulator/SimulatorManager.cpp +++ b/src/Simulator/SimulatorManager.cpp @@ -58,11 +58,11 @@ void cSimulatorManager::SimulateChunk(std::chrono::milliseconds a_Dt, int a_Chun -void cSimulatorManager::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cSimulatorManager::WakeUp(Vector3i a_Block, cChunk * a_Chunk) { for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr) { - itr->first->WakeUp(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); + itr->first->WakeUp(a_Block, a_Chunk); } } diff --git a/src/Simulator/SimulatorManager.h b/src/Simulator/SimulatorManager.h index daa949157..98a60b4ee 100644 --- a/src/Simulator/SimulatorManager.h +++ b/src/Simulator/SimulatorManager.h @@ -36,7 +36,7 @@ public: void SimulateChunk(std::chrono::milliseconds a_DT, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk); /* Called when a single block changes, wakes all simulators up for the block and its face-neighbors. */ - void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + void WakeUp(Vector3i a_Block, cChunk * a_Chunk); /** Does the same processing as WakeUp, but for all blocks within the specified area. Has better performance than calling WakeUp for each block individually, due to neighbor-checking. diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 1d2db58fb..c023f88c9 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -20,26 +20,26 @@ cVaporizeFluidSimulator::cVaporizeFluidSimulator(cWorld & a_World, BLOCKTYPE a_F -void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cVaporizeFluidSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { if (a_Chunk == nullptr) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); if ( (BlockType == m_FluidBlock) || (BlockType == m_StationaryFluidBlock) ) { - a_Chunk->SetBlock(RelX, a_BlockY, RelZ, E_BLOCK_AIR, 0); + a_Chunk->SetBlock(RelX, a_Block.y, RelZ, E_BLOCK_AIR, 0); a_Chunk->BroadcastSoundEffect( "block.fire.extinguish", - static_cast<double>(a_BlockX), - static_cast<double>(a_BlockY), - static_cast<double>(a_BlockZ), + static_cast<double>(a_Block.x), + static_cast<double>(a_Block.y), + static_cast<double>(a_Block.z), 1.0f, 0.6f ); diff --git a/src/Simulator/VaporizeFluidSimulator.h b/src/Simulator/VaporizeFluidSimulator.h index 8076972a8..7a7006309 100644 --- a/src/Simulator/VaporizeFluidSimulator.h +++ b/src/Simulator/VaporizeFluidSimulator.h @@ -25,7 +25,7 @@ public: cVaporizeFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid); // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; virtual void Simulate(float a_Dt) override; } ; diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 42d736a8c..b7e446d53 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -228,6 +228,42 @@ AStringVector StringSplitWithQuotes(const AString & str, const AString & delim) + +AString StringJoin(const AStringVector & a_Strings, const AString & a_Delimeter) +{ + if (a_Strings.empty()) + { + return {}; + } + + // Do a dry run to gather the size + const auto DelimSize = a_Delimeter.size(); + size_t ResultSize = a_Strings[0].size(); + std::for_each(a_Strings.begin() + 1, a_Strings.end(), + [&](const AString & a_String) + { + ResultSize += DelimSize; + ResultSize += a_String.size(); + } + ); + + // Now do the actual join + AString Result; + Result.reserve(ResultSize); + Result.append(a_Strings[0]); + std::for_each(a_Strings.begin() + 1, a_Strings.end(), + [&](const AString & a_String) + { + Result += a_Delimeter; + Result += a_String; + } + ); + return Result; +} + + + + AStringVector StringSplitAndTrim(const AString & str, const AString & delim) { AStringVector results; diff --git a/src/StringUtils.h b/src/StringUtils.h index b59dde41a..12227014d 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -47,6 +47,9 @@ Resolves issue #490 Return the splitted strings as a stringvector. */ extern AStringVector StringSplitWithQuotes(const AString & str, const AString & delim); +/** Join a list of strings with the given delimiter between entries. */ +AString StringJoin(const AStringVector & a_Strings, const AString & a_Delimiter); + /** Split the string at any of the listed delimiters and trim each value. Returns the splitted strings as a stringvector. */ extern AStringVector StringSplitAndTrim(const AString & str, const AString & delim); diff --git a/src/UI/ChestWindow.cpp b/src/UI/ChestWindow.cpp index e889f9c44..7b3fe15af 100644 --- a/src/UI/ChestWindow.cpp +++ b/src/UI/ChestWindow.cpp @@ -76,12 +76,12 @@ cChestWindow::~cChestWindow() bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) { m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1); - m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ()); + m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPos()); if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1); - m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ()); + m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPos()); } cWindow::ClosedByPlayer(a_Player, a_CanRefuse); @@ -95,12 +95,12 @@ bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) void cChestWindow::OpenedByPlayer(cPlayer & a_Player) { m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1); - m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ()); + m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPos()); if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1); - m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ()); + m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPos()); } cWindow::OpenedByPlayer(a_Player); diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 5a94a26af..be21cdada 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -9,7 +9,8 @@ #pragma once #include "../Inventory.h" -#include "Window.h" + + diff --git a/src/UI/Window.h b/src/UI/Window.h index 5bb90a75e..d7a29dc47 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -113,7 +113,7 @@ public: void GetSlots(cPlayer & a_Player, cItems & a_Slots) const; /** Handles a click event from a player */ - void Clicked( + virtual void Clicked( cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem diff --git a/src/World.cpp b/src/World.cpp index f11aee878..738761aa6 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -999,9 +999,10 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La for (auto & Entity : m_EntitiesToAdd) { Entity->SetWorld(this); - m_ChunkMap->AddEntity(Entity); - ASSERT(!Entity->IsTicking()); - Entity->SetIsTicking(true); + auto EntityPtr = Entity.get(); + m_ChunkMap->AddEntity(std::move(Entity)); + ASSERT(!EntityPtr->IsTicking()); + EntityPtr->SetIsTicking(true); } m_EntitiesToAdd.clear(); } @@ -1114,7 +1115,7 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt) // do the spawn for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2) { - SpawnMobFinalize(*itr2); + SpawnMobFinalize(std::move(const_cast<std::unique_ptr<cMonster> &>(*itr2))); } } } // for i - AllFamilies[] @@ -1288,9 +1289,9 @@ void cWorld::UpdateSkyDarkness(void) -void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) +void cWorld::WakeUpSimulators(Vector3i a_Block) { - return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + return m_ChunkMap->WakeUpSimulators(a_Block); } @@ -1299,7 +1300,17 @@ void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) void cWorld::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ) { - m_SimulatorManager->WakeUpArea(cCuboid(a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ)); + LOGWARNING("cWorld::WakeUpSimulatorsInArea(int, int, int) is deprecated, use cWorld::WakeUpSimulatorsInArea(Vector3i) instead."); + WakeUpSimulatorsInArea(cCuboid({a_MinBlockX, a_MinBlockY, a_MinBlockZ}, {a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ})); +} + + + + + +void cWorld::WakeUpSimulatorsInArea(const cCuboid & a_Area) +{ + m_SimulatorManager->WakeUpArea(a_Area); } @@ -1550,7 +1561,7 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback -bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) +bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) { struct cCallBackWrapper : cChunkCallback { @@ -2176,15 +2187,12 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double float SpeedY = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(50)); float SpeedZ = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-5, 5)); - cPickup * Pickup = new cPickup( + auto Pickup = cpp14::make_unique<cPickup>( a_BlockX, a_BlockY, a_BlockZ, *itr, IsPlayerCreated, SpeedX, SpeedY, SpeedZ ); - if (!Pickup->Initialize(*this)) - { - delete Pickup; - Pickup = nullptr; - } + auto PickupPtr = Pickup.get(); + PickupPtr->Initialize(std::move(Pickup), *this); } } @@ -2201,15 +2209,12 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double continue; } - cPickup * Pickup = new cPickup( + auto Pickup = cpp14::make_unique<cPickup>( a_BlockX, a_BlockY, a_BlockZ, *itr, IsPlayerCreated, static_cast<float>(a_SpeedX), static_cast<float>(a_SpeedY), static_cast<float>(a_SpeedZ) ); - if (!Pickup->Initialize(*this)) - { - delete Pickup; - Pickup = nullptr; - } + auto PickupPtr = Pickup.get(); + PickupPtr->Initialize(std::move(Pickup), *this); } } @@ -2219,14 +2224,13 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double UInt32 cWorld::SpawnItemPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, float a_SpeedX, float a_SpeedY, float a_SpeedZ, int a_LifetimeTicks, bool a_CanCombine) { - cPickup * Pickup = new cPickup(a_PosX, a_PosY, a_PosZ, a_Item, false, a_SpeedX, a_SpeedY, a_SpeedZ, a_LifetimeTicks, a_CanCombine); - if (!Pickup->Initialize(*this)) + auto Pickup = cpp14::make_unique<cPickup>(a_PosX, a_PosY, a_PosZ, a_Item, false, a_SpeedX, a_SpeedY, a_SpeedZ, a_LifetimeTicks, a_CanCombine); + auto PickupPtr = Pickup.get(); + if (!PickupPtr->Initialize(std::move(Pickup), *this)) { - delete Pickup; - Pickup = nullptr; return cEntity::INVALID_ID; } - return Pickup->GetUniqueID(); + return PickupPtr->GetUniqueID(); } @@ -2235,14 +2239,14 @@ UInt32 cWorld::SpawnItemPickup(double a_PosX, double a_PosY, double a_PosZ, cons UInt32 cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta) { - cFallingBlock * FallingBlock = new cFallingBlock(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); - if (!FallingBlock->Initialize(*this)) + auto FallingBlock = cpp14::make_unique<cFallingBlock>(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); + auto FallingBlockPtr = FallingBlock.get(); + auto ID = FallingBlock->GetUniqueID(); + if (!FallingBlockPtr->Initialize(std::move(FallingBlock), *this)) { - delete FallingBlock; - FallingBlock = nullptr; return cEntity::INVALID_ID; } - return FallingBlock->GetUniqueID(); + return ID; } @@ -2257,14 +2261,13 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa return cEntity::INVALID_ID; } - cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward); - if (!ExpOrb->Initialize(*this)) + auto ExpOrb = cpp14::make_unique<cExpOrb>(a_X, a_Y, a_Z, a_Reward); + auto ExpOrbPtr = ExpOrb.get(); + if (!ExpOrbPtr->Initialize(std::move(ExpOrb), *this)) { - delete ExpOrb; - ExpOrb = nullptr; return cEntity::INVALID_ID; } - return ExpOrb->GetUniqueID(); + return ExpOrbPtr->GetUniqueID(); } @@ -2273,26 +2276,26 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight) { - cMinecart * Minecart; + std::unique_ptr<cMinecart> Minecart; switch (a_MinecartType) { - case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; - case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break; - case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break; - case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break; - case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break; + case E_ITEM_MINECART: Minecart = cpp14::make_unique<cRideableMinecart>(a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; + case E_ITEM_CHEST_MINECART: Minecart = cpp14::make_unique<cMinecartWithChest>(a_X, a_Y, a_Z); break; + case E_ITEM_FURNACE_MINECART: Minecart = cpp14::make_unique<cMinecartWithFurnace>(a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_TNT: Minecart = cpp14::make_unique<cMinecartWithTNT>(a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_HOPPER: Minecart = cpp14::make_unique<cMinecartWithHopper>(a_X, a_Y, a_Z); break; default: { return cEntity::INVALID_ID; } } // switch (a_MinecartType) - if (!Minecart->Initialize(*this)) + + auto MinecartPtr = Minecart.get(); + if (!MinecartPtr->Initialize(std::move(Minecart), *this)) { - delete Minecart; - Minecart = nullptr; return cEntity::INVALID_ID; } - return Minecart->GetUniqueID(); + return MinecartPtr->GetUniqueID(); } @@ -2301,18 +2304,13 @@ UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartT UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_Material) { - cBoat * Boat = new cBoat(a_X, a_Y, a_Z, a_Material); - if (Boat == nullptr) + auto Boat = cpp14::make_unique<cBoat>(a_X, a_Y, a_Z, a_Material); + auto BoatPtr = Boat.get(); + if (!BoatPtr->Initialize(std::move(Boat), *this)) { return cEntity::INVALID_ID; } - if (!Boat->Initialize(*this)) - { - delete Boat; - Boat = nullptr; - return cEntity::INVALID_ID; - } - return Boat->GetUniqueID(); + return BoatPtr->GetUniqueID(); } @@ -2320,20 +2318,20 @@ UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_ UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff) { - cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks); - if (!TNT->Initialize(*this)) + auto TNT = cpp14::make_unique<cTNTEntity>(a_X, a_Y, a_Z, a_FuseTicks); + auto TNTPtr = TNT.get(); + if (!TNTPtr->Initialize(std::move(TNT), *this)) { - delete TNT; - TNT = nullptr; return cEntity::INVALID_ID; } + auto & Random = GetRandomProvider(); - TNT->SetSpeed( + TNTPtr->SetSpeed( a_InitialVelocityCoeff * Random.RandInt(-1, 1), a_InitialVelocityCoeff * 2, a_InitialVelocityCoeff * Random.RandInt(-1, 1) ); - return TNT->GetUniqueID(); + return TNTPtr->GetUniqueID(); } @@ -2902,7 +2900,7 @@ void cWorld::QueueSetChunkData(cSetChunkDataPtr a_SetChunkData) // Store a copy of the data in the queue: // TODO: If the queue is too large, wait for it to get processed. Not likely, though. cCSLock Lock(m_CSSetChunkDataQueue); - m_SetChunkDataQueue.push_back(std::move(a_SetChunkData)); + m_SetChunkDataQueue.emplace_back(std::move(a_SetChunkData)); } @@ -2917,15 +2915,10 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) m_ChunkMap->SetChunkData(a_SetChunkData); // Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347): - cEntityList Entities; - std::swap(a_SetChunkData.GetEntities(), Entities); - for (cEntityList::iterator itr = Entities.begin(), end = Entities.end(); itr != end; ++itr) + for (auto & Entity : a_SetChunkData.GetEntities()) { - if (!(*itr)->Initialize(*this)) - { - delete *itr; - *itr = nullptr; - } + auto EntityPtr = Entity.get(); + EntityPtr->Initialize(std::move(Entity), *this); } // If a client is requesting this chunk, send it to them: @@ -3046,39 +3039,41 @@ void cWorld::CollectPickupsByPlayer(cPlayer & a_Player) -void cWorld::AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld) +void cWorld::AddPlayer(std::unique_ptr<cPlayer> a_Player, cWorld * a_OldWorld) { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.emplace_back(a_Player, a_OldWorld); + m_PlayersToAdd.emplace_back(std::move(a_Player), a_OldWorld); } -void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) +std::unique_ptr<cPlayer> cWorld::RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk) { + std::unique_ptr<cPlayer> PlayerPtr; + if (a_RemoveFromChunk) { // To prevent iterator invalidations when an entity goes through a portal and calls this function whilst being ticked by cChunk // we should not change cChunk's entity list if asked not to - m_ChunkMap->RemoveEntity(a_Player); + PlayerPtr = std::unique_ptr<cPlayer>(static_cast<cPlayer *>(m_ChunkMap->RemoveEntity(a_Player).release())); } { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.remove_if([&](const std::pair< cPlayer *, cWorld * > & value) -> bool + m_PlayersToAdd.remove_if([&](const decltype(m_PlayersToAdd)::value_type & value) -> bool { - return (value.first == a_Player); + return (value.first.get() == &a_Player); }); } { cCSLock Lock(m_CSPlayers); - LOGD("Removing player %s from world \"%s\"", a_Player->GetName().c_str(), m_WorldName.c_str()); - m_Players.remove(a_Player); + LOGD("Removing player %s from world \"%s\"", a_Player.GetName().c_str(), m_WorldName.c_str()); + m_Players.remove(&a_Player); } // Remove the player's client from the list of clients to be ticked: - cClientHandle * Client = a_Player->GetClientHandle(); + cClientHandle * Client = a_Player.GetClientHandle(); if (Client != nullptr) { Client->RemoveFromWorld(); @@ -3086,12 +3081,66 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) cCSLock Lock(m_CSClients); m_ClientsToRemove.push_back(Client); } + + return PlayerPtr; } +#ifdef _DEBUG +bool cWorld::IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player) +{ + if (m_ChunkMap->RemoveEntity(a_Player) != nullptr) + { + return true; + } + + { + cCSLock Lock(m_CSPlayersToAdd); + if (std::find_if( + m_PlayersToAdd.begin(), m_PlayersToAdd.end(), + [&a_Player](const cAwaitingPlayerList::value_type & Item) { return Item.first.get() == &a_Player; }) != m_PlayersToAdd.end() + ) + { + return true; + } + } + + { + cCSLock Lock(m_CSPlayers); + if (std::find(m_Players.begin(), m_Players.end(), &a_Player) != m_Players.end()) + { + return true; + } + } + + { + cCSLock Lock(m_CSEntitiesToAdd); + if (std::find(m_ClientsToAdd.begin(), m_ClientsToAdd.end(), a_Player.GetClientHandlePtr()) != m_ClientsToAdd.end()) + { + return true; + } + } + + { + cCSLock Lock(m_CSClients); + if (std::find(m_Clients.begin(), m_Clients.end(), a_Player.GetClientHandlePtr()) != m_Clients.end()) + { + return true; + } + } + + // Assume OK if in ClientsToRemove or PlayersToRemove + return false; +} +#endif + + + + + bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback) { // Calls the callback for each player in the list @@ -3204,7 +3253,7 @@ bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallb -cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight) +cPlayer * cWorld::FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight) { double ClosestDistance = a_SightLimit; cPlayer * ClosestPlayer = nullptr; @@ -3303,11 +3352,11 @@ bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callbac // First check the entities-to-add: { cCSLock Lock(m_CSEntitiesToAdd); - for (auto & ent: m_EntitiesToAdd) + for (const auto & ent: m_EntitiesToAdd) { if (ent->GetUniqueID() == a_UniqueID) { - a_Callback(ent); + a_Callback(ent.get()); return true; } } // for ent - m_EntitiesToAdd[] @@ -3600,11 +3649,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas -void cWorld::AddEntity(cEntity * a_Entity) +void cWorld::AddEntity(OwnedEntity a_Entity) { a_Entity->SetWorld(this); cCSLock Lock(m_CSEntitiesToAdd); - m_EntitiesToAdd.push_back(a_Entity); + m_EntitiesToAdd.emplace_back(std::move(a_Entity)); } @@ -3739,9 +3788,7 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby) { - cMonster * Monster = nullptr; - - Monster = cMonster::NewMonsterFromType(a_MonsterType); + auto Monster = cMonster::NewMonsterFromType(a_MonsterType); if (Monster == nullptr) { return cEntity::INVALID_ID; @@ -3753,13 +3800,13 @@ UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterTyp Monster->SetAge(-1); } - return SpawnMobFinalize(Monster); + return SpawnMobFinalize(std::move(Monster)); } -UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) +UInt32 cWorld::SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster) { ASSERT(a_Monster != nullptr); @@ -3769,22 +3816,20 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) // A plugin doesn't agree with the spawn. bail out. if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { - delete a_Monster; - a_Monster = nullptr; return cEntity::INVALID_ID; } + auto & Monster = *a_Monster; + // Initialize the monster into the current world. - if (!a_Monster->Initialize(*this)) + if (!Monster.Initialize(std::move(a_Monster), *this)) { - delete a_Monster; - a_Monster = nullptr; return cEntity::INVALID_ID; } - cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, Monster); - return a_Monster->GetUniqueID(); + return Monster.GetUniqueID(); } @@ -3793,18 +3838,19 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) UInt32 cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed) { - cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); + auto Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); if (Projectile == nullptr) { return cEntity::INVALID_ID; } - if (!Projectile->Initialize(*this)) + + auto ProjectilePtr = Projectile.get(); + if (!ProjectilePtr->Initialize(std::move(Projectile), *this)) { - delete Projectile; - Projectile = nullptr; return cEntity::INVALID_ID; } - return Projectile->GetUniqueID(); + + return ProjectilePtr->GetUniqueID(); } @@ -4000,29 +4046,35 @@ void cWorld::AddQueuedPlayers(void) std::swap(PlayersToAdd, m_PlayersToAdd); } + // Temporary (#3115-will-fix): store pointers to player objects after ownership transferral + std::vector<std::pair<cPlayer *, cWorld *>> AddedPlayerPtrs; + AddedPlayerPtrs.reserve(PlayersToAdd.size()); + // Add all the players in the grabbed list: { cCSLock Lock(m_CSPlayers); for (auto & AwaitingPlayer : PlayersToAdd) { auto & Player = AwaitingPlayer.first; - ASSERT(std::find(m_Players.begin(), m_Players.end(), Player) == m_Players.end()); // Is it already in the list? HOW? + ASSERT(std::find(m_Players.begin(), m_Players.end(), Player.get()) == m_Players.end()); // Is it already in the list? HOW? LOGD("Adding player %s to world \"%s\".", Player->GetName().c_str(), m_WorldName.c_str()); - m_Players.push_back(Player); + m_Players.push_back(Player.get()); Player->SetWorld(this); // Add to chunkmap, if not already there (Spawn vs MoveToWorld): - m_ChunkMap->AddEntityIfNotPresent(Player); - ASSERT(!Player->IsTicking()); - Player->SetIsTicking(true); + auto PlayerPtr = Player.get(); + m_ChunkMap->AddEntityIfNotPresent(std::move(Player)); + ASSERT(!PlayerPtr->IsTicking()); + PlayerPtr->SetIsTicking(true); + AddedPlayerPtrs.emplace_back(PlayerPtr, AwaitingPlayer.second); } // for itr - PlayersToAdd[] } // Lock(m_CSPlayers) // Add all the players' clienthandles: { cCSLock Lock(m_CSClients); - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { auto & Player = AwaitingPlayer.first; cClientHandlePtr Client = Player->GetClientHandlePtr(); @@ -4034,7 +4086,7 @@ void cWorld::AddQueuedPlayers(void) } // Lock(m_CSClients) // Stream chunks to all eligible clients: - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { auto & Player = AwaitingPlayer.first; cClientHandle * Client = Player->GetClientHandle(); @@ -4047,7 +4099,7 @@ void cWorld::AddQueuedPlayers(void) } // for itr - PlayersToAdd[] // Call EntityChangedWorld callback on all eligible clients - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { if (AwaitingPlayer.second != nullptr) { @@ -4077,14 +4129,14 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc cChunkDef::BlockNibbles BlockMetas; a_ChunkDesc.CompressBlockMetas(BlockMetas); - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData = cpp14::make_unique<cSetChunkData>( a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_ChunkDesc.GetBlockTypes(), BlockMetas, nullptr, nullptr, // We don't have lighting, chunk will be lighted when needed &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(), std::move(a_ChunkDesc.GetEntities()), std::move(a_ChunkDesc.GetBlockEntities()), true - )); + ); SetChunkData->RemoveInvalidBlockEntities(); m_World->QueueSetChunkData(std::move(SetChunkData)); } diff --git a/src/World.h b/src/World.h index a53d3471c..8ff64046d 100644 --- a/src/World.h +++ b/src/World.h @@ -40,19 +40,19 @@ class cChunkGenerator; // The thread responsible for generating chunks class cBeaconEntity; class cBrewingstandEntity; class cChestEntity; +class cCuboid; class cDispenserEntity; class cFlowerPotEntity; class cFurnaceEntity; class cNoteEntity; class cMobHeadEntity; class cCompositeChat; -class cCuboid; class cSetChunkData; class cBroadcaster; class cDeadlockDetect; typedef std::list< cPlayer * > cPlayerList; -typedef std::list< std::pair< cPlayer *, cWorld * > > cAwaitingPlayerList; +typedef std::list< std::pair< std::unique_ptr<cPlayer>, cWorld * > > cAwaitingPlayerList; typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; @@ -258,13 +258,18 @@ public: Uses a queue to store the player object until the Tick thread processes the addition event. Also adds the player as an entity in the chunkmap, and the player's ClientHandle, if any, for ticking. If a_OldWorld is provided, a corresponding ENTITY_CHANGED_WORLD event is triggerred after the addition. */ - void AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld = nullptr); + void AddPlayer(std::unique_ptr<cPlayer> a_Player, cWorld * a_OldWorld = nullptr); /** Removes the player from the world. Removes the player from the addition queue, too, if appropriate. If the player has a ClientHandle, the ClientHandle is removed from all chunks in the world and will not be ticked by this world anymore. - @param a_RemoveFromChunk determines if the entity should be removed from its chunk as well. Should be false when ticking from cChunk. */ - void RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk); + @param a_RemoveFromChunk determines if the entity should be removed from its chunk as well. Should be false when ticking from cChunk. + @return An owning reference to the given player. */ + std::unique_ptr<cPlayer> RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk); + +#ifdef _DEBUG + bool IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player); +#endif /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS << @@ -277,7 +282,7 @@ public: bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) - cPlayer * FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true); + cPlayer * FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true); /** Finds the player over his uuid and calls the callback */ bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << @@ -287,7 +292,7 @@ public: /** Adds the entity into its appropriate chunk; takes ownership of the entity ptr. The entity is added lazily - this function only puts it in a queue that is then processed by the Tick thread. */ - void AddEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); /** Returns true if an entity with the specified UniqueID exists in the world. Note: Only loaded chunks are considered. */ @@ -412,11 +417,11 @@ public: // tolua_begin // Vector3i variants: - void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta); } - BLOCKTYPE GetBlock (const Vector3i & a_Pos) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z); } - NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z); } - void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData); } - NIBBLETYPE GetBlockBlockLight(const Vector3i & a_Pos) { return GetBlockBlockLight( a_Pos.x, a_Pos.y, a_Pos.z); } + void FastSetBlock(Vector3i a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta); } + BLOCKTYPE GetBlock (Vector3i a_Pos) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z); } + NIBBLETYPE GetBlockMeta(Vector3i a_Pos) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z); } + void SetBlockMeta(Vector3i a_Pos, NIBBLETYPE a_MetaData) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData); } + NIBBLETYPE GetBlockBlockLight(Vector3i a_Pos) { return GetBlockBlockLight( a_Pos.x, a_Pos.y, a_Pos.z); } // tolua_end /** Writes the block area into the specified coords. @@ -484,9 +489,19 @@ public: double GetSpawnZ(void) const { return m_SpawnZ; } /** Wakes up the simulators for the specified block */ - virtual void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void WakeUpSimulators(Vector3i a_Block) override; /** Wakes up the simulators for the specified area of blocks */ + void WakeUpSimulatorsInArea(const cCuboid & a_Area); + + // DEPRECATED, use vector-parametered version instead + void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) + { + LOGWARNING("cWorld::WakeUpSimulators(int, int, int) is deprecated, use cWorld::WakeUpSimulators(Vector3i) instead."); + WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); + } + + // DEPRECATED, use vector-parametered version instead void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); // tolua_end @@ -791,7 +806,9 @@ public: /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, cEntity::INVALID_ID otherwise */ virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby = false) override; // tolua_export - UInt32 SpawnMobFinalize(cMonster * a_Monster); + /** Wraps cEntity::Initialize, doing Monster-specific things before spawning the monster. + Takes ownership of the given Monster reference. */ + UInt32 SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster); /** Creates a projectile of the specified type. Returns the projectile's UniqueID if successful, cEntity::INVALID_ID otherwise Item parameter is currently used for Fireworks to correctly set entity metadata based on item metadata. */ diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index d474f59e1..480558fa3 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -107,7 +107,7 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) || (a_Item.m_RepairCost > 0) || (a_Item.m_CustomName != "") || - (a_Item.m_Lore != "") + (!a_Item.m_LoreTable.empty()) ) { m_Writer.BeginCompound("tag"); @@ -116,16 +116,23 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin m_Writer.AddInt("RepairCost", a_Item.m_RepairCost); } - if ((a_Item.m_CustomName != "") || (a_Item.m_Lore != "")) + if ((a_Item.m_CustomName != "") || (!a_Item.m_LoreTable.empty())) { m_Writer.BeginCompound("display"); if (a_Item.m_CustomName != "") { m_Writer.AddString("Name", a_Item.m_CustomName); } - if (a_Item.m_Lore != "") + if (!a_Item.m_LoreTable.empty()) { - m_Writer.AddString("Lore", a_Item.m_Lore); + m_Writer.BeginList("Lore", TAG_String); + + for (const auto & Line : a_Item.m_LoreTable) + { + m_Writer.AddString("", Line); + } + + m_Writer.EndList(); } m_Writer.EndCompound(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 16688b712..77d1e46b8 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -458,7 +458,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT } // for y //*/ - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData = cpp14::make_unique<cSetChunkData>( a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, IsLightValid ? BlockLight : nullptr, @@ -466,7 +466,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT nullptr, Biomes, std::move(Entities), std::move(BlockEntities), false - )); + ); m_World->QueueSetChunkData(std::move(SetChunkData)); return true; } @@ -804,7 +804,17 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ int Lore = a_NBT.FindChildByName(DisplayTag, "Lore"); if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String)) { - a_Item.m_Lore = a_NBT.GetString(Lore); + // Legacy string lore + a_Item.m_LoreTable = StringSplit(a_NBT.GetString(Lore), "`"); + } + else if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_List)) + { + // Lore table + a_Item.m_LoreTable.clear(); + for (int loretag = a_NBT.GetFirstChild(Lore); loretag >= 0; loretag = a_NBT.GetNextSibling(loretag)) // Loop through array of strings + { + a_Item.m_LoreTable.push_back(a_NBT.GetString(loretag)); + } } } @@ -1655,7 +1665,7 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N { Boat->SetMaterial(cBoat::StringToMaterial(a_NBT.GetString(TypeIdx))); } - a_Entities.push_back(Boat.release()); + a_Entities.emplace_back(std::move(Boat)); } @@ -1669,7 +1679,7 @@ void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedN { return; } - a_Entities.push_back(EnderCrystal.release()); + a_Entities.emplace_back(std::move(EnderCrystal)); } @@ -1694,7 +1704,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN { return; } - a_Entities.push_back(FallingBlock.release()); + a_Entities.emplace_back(std::move(FallingBlock)); } @@ -1708,7 +1718,7 @@ void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT { return; } - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1740,7 +1750,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT Minecart->SetSlot(a_NBT.GetByte(Slot), Item); } } // for itr - ItemDefs[] - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1757,7 +1767,7 @@ void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Load the Push and Fuel tags - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1774,7 +1784,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Everything to do with TNT carts - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1791,7 +1801,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Everything to do with hopper carts - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1825,7 +1835,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a Pickup->SetAge(a_NBT.GetShort(Age)); } - a_Entities.push_back(Pickup.release()); + a_Entities.emplace_back(std::move(Pickup)); } @@ -1847,7 +1857,7 @@ void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB TNT->SetFuseTicks(static_cast<int>(a_NBT.GetByte(FuseTicks))); } - a_Entities.push_back(TNT.release()); + a_Entities.emplace_back(std::move(TNT)); } @@ -1876,7 +1886,7 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a ExpOrb->SetReward(a_NBT.GetShort(Reward)); } - a_Entities.push_back(ExpOrb.release()); + a_Entities.emplace_back(std::move(ExpOrb)); } @@ -1941,7 +1951,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT ItemFrame->SetItemRotation(static_cast<Byte>(a_NBT.GetByte(Rotation))); } - a_Entities.push_back(ItemFrame.release()); + a_Entities.emplace_back(std::move(ItemFrame)); } @@ -1964,7 +1974,7 @@ void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & } LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx); - a_Entities.push_back(Painting.release()); + a_Entities.emplace_back(std::move(Painting)); } @@ -2035,7 +2045,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ } // Store the new arrow in the entities list: - a_Entities.push_back(Arrow.release()); + a_Entities.emplace_back(std::move(Arrow)); } @@ -2058,7 +2068,7 @@ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedN SplashPotion->SetPotionColor(a_NBT.FindChildByName(a_TagIdx, "PotionName")); // Store the new splash potion in the entities list: - a_Entities.push_back(SplashPotion.release()); + a_Entities.emplace_back(std::move(SplashPotion)); } @@ -2074,7 +2084,7 @@ void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & } // Store the new snowball in the entities list: - a_Entities.push_back(Snowball.release()); + a_Entities.emplace_back(std::move(Snowball)); } @@ -2090,7 +2100,7 @@ void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB } // Store the new egg in the entities list: - a_Entities.push_back(Egg.release()); + a_Entities.emplace_back(std::move(Egg)); } @@ -2106,7 +2116,7 @@ void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & } // Store the new fireball in the entities list: - a_Entities.push_back(Fireball.release()); + a_Entities.emplace_back(std::move(Fireball)); } @@ -2122,7 +2132,7 @@ void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT } // Store the new FireCharge in the entities list: - a_Entities.push_back(FireCharge.release()); + a_Entities.emplace_back(std::move(FireCharge)); } @@ -2138,7 +2148,7 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar } // Store the new enderpearl in the entities list: - a_Entities.push_back(Enderpearl.release()); + a_Entities.emplace_back(std::move(Enderpearl)); } @@ -2158,7 +2168,7 @@ void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2178,7 +2188,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2198,7 +2208,7 @@ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2218,7 +2228,7 @@ void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2238,7 +2248,7 @@ void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2258,7 +2268,7 @@ void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2278,7 +2288,7 @@ void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2298,7 +2308,7 @@ void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2318,7 +2328,7 @@ void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2338,7 +2348,7 @@ void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2358,7 +2368,7 @@ void cWSSAnvil::LoadGuardianFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2404,7 +2414,7 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2424,7 +2434,7 @@ void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2453,7 +2463,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2473,7 +2483,7 @@ void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2527,7 +2537,7 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2560,7 +2570,7 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2604,7 +2614,7 @@ void cWSSAnvil::LoadRabbitFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2650,7 +2660,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2670,7 +2680,7 @@ void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2698,7 +2708,7 @@ void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2727,7 +2737,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2747,7 +2757,7 @@ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2767,7 +2777,7 @@ void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2787,7 +2797,7 @@ void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2829,7 +2839,7 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2849,7 +2859,7 @@ void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2875,7 +2885,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetWitherInvulnerableTicks(static_cast<unsigned int>(a_NBT.GetInt(CurrLine))); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2951,7 +2961,7 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2992,7 +3002,7 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -3025,7 +3035,7 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 37ccdda4c..454e6f73d 100755 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -10,7 +10,6 @@ #include "WorldStorage.h" #include "FastNBT.h" -#include "../Mobs/Monster.h" @@ -18,7 +17,7 @@ // fwd: ItemGrid.h class cItemGrid; - +class cMonster; class cProjectileEntity; class cHangingEntity; |