diff options
Diffstat (limited to 'src')
44 files changed, 1004 insertions, 589 deletions
diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp index 59b02d8f7..154bcb200 100644 --- a/src/Bindings/LuaChunkStay.cpp +++ b/src/Bindings/LuaChunkStay.cpp @@ -107,7 +107,7 @@ void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index) } } // for itr - m_Chunks[] - m_Chunks.push_back(cChunkCoords(ChunkX, ZERO_CHUNK_Y, ChunkZ)); + m_Chunks.push_back(cChunkCoords(ChunkX, ChunkZ)); } diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 9fe93ccc2..ba2f3c5e0 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -859,6 +859,32 @@ void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) +{ + tolua_Error err; + if (tolua_isusertype(m_LuaState, a_StackPos, "cBoundingBox", false, &err)) + { + a_ReturnedVal = *((cBoundingBox **)lua_touserdata(m_LuaState, a_StackPos)); + } +} + + + + + +void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) +{ + tolua_Error err; + if (tolua_isusertype(m_LuaState, a_StackPos, "cWorld", false, &err)) + { + a_ReturnedVal = *((cWorld **)lua_touserdata(m_LuaState, a_StackPos)); + } +} + + + + + bool cLuaState::CallFunction(int a_NumResults) { ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index eeb93fd4d..44f187701 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -59,6 +59,10 @@ class cTNTEntity; class cCreeper; class cHopperEntity; class cBlockEntity; +class cBoundingBox; + +typedef cBoundingBox * pBoundingBox; +typedef cWorld * pWorld; @@ -230,6 +234,12 @@ public: /** Retrieve value at a_StackPos, if it is a valid number, converting and clamping it to eWeather. If not, a_Value is unchanged. */ void GetStackValue(int a_StackPos, eWeather & a_Value); + + /** Retrieve value at a_StackPos, if it is a valid cBoundingBox class. If not, a_Value is unchanged */ + void GetStackValue(int a_StackPos, pBoundingBox & a_Value); + + /** Retrieve value at a_StackPos, if it is a valid cWorld class. If not, a_Value is unchanged */ + void GetStackValue(int a_StackPos, pWorld & a_Value); // Include the cLuaState::Call() overload implementation that is generated by the gen_LuaState_Call.lua script: @@ -328,6 +338,14 @@ protected: */ bool PushFunction(int a_FnRef); + /** Pushes a function that has been saved as a reference. + Returns true if successful. Logs a warning on failure + */ + bool PushFunction(const cRef & a_FnRef) + { + return PushFunction((int)a_FnRef); + } + /** Pushes a function that is stored in a referenced table by name Returns true if successful. Logs a warning on failure */ diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index adf10a72f..b7ea65759 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -679,6 +679,75 @@ static int tolua_ForEachInChunk(lua_State * tolua_S) template < class Ty1, class Ty2, + bool (Ty1::*Func1)(const cBoundingBox &, cItemCallback<Ty2> &) +> +static int tolua_ForEachInBox(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamUserType(2, "cBoundingBox") || + !L.CheckParamFunction(3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + Ty1 * Self = NULL; + cBoundingBox * Box = NULL; + L.GetStackValues(1, Self, Box); + ASSERT(Self != NULL); // We have verified the type at the top, so we should get valid objects here + ASSERT(Box != NULL); + + // Create a reference for the function: + cLuaState::cRef FnRef(L, 3); + + // Callback wrapper for the Lua function: + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FuncRef) : + m_LuaState(a_LuaState), + m_FnRef(a_FuncRef) + {} + + private: + // cItemCallback<Ty2> overrides: + virtual bool Item(Ty2 * a_Item) override + { + bool res = false; + if (!m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res)) + { + LOGWARNING("Failed to call Lua callback"); + m_LuaState.LogStackTrace(); + return true; // Abort enumeration + } + + return res; + } + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); + + bool bRetVal = (Self->*Func1)(*Box, Callback); + + FnRef.UnRef(); + + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal); + return 1; +} + + + + + +template < + class Ty1, + class Ty2, bool (Ty1::*Func1)(cItemCallback<Ty2> &) > static int tolua_ForEach(lua_State * tolua_S) @@ -3327,6 +3396,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInBox", tolua_ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>); tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua index 2d8630d12..7f62573c7 100644 --- a/src/Bindings/gen_LuaState_Call.lua +++ b/src/Bindings/gen_LuaState_Call.lua @@ -109,7 +109,7 @@ local function WriteOverload(f, a_NumParams, a_NumReturns) -- Write the function signature: f:write("bool Call(") - f:write("FnT a_Function") + f:write("const FnT & a_Function") for i = 1, a_NumParams do f:write(", ParamT", i, " a_Param", i) end diff --git a/src/BlockID.h b/src/BlockID.h index 08c576886..d835f9518 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -362,6 +362,8 @@ enum ENUM_ITEM_ID E_ITEM_LEAD = 420, E_ITEM_NAME_TAG = 421, E_ITEM_MINECART_WITH_COMMAND_BLOCK = 422, + E_ITEM_RAW_MUTTON = 423, + E_ITEM_MUTTON = 424, // Keep these two as the last values of the consecutive list, without a number - they will get their correct number assigned automagically by C++ // IsValidItem() depends on this! diff --git a/src/BoundingBox.h b/src/BoundingBox.h index 793466302..928e62afa 100644 --- a/src/BoundingBox.h +++ b/src/BoundingBox.h @@ -80,6 +80,17 @@ public: /// Calculates the intersection of the two bounding boxes; returns true if nonempty bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection); + double GetMinX(void) const { return m_Min.x; } + double GetMinY(void) const { return m_Min.y; } + double GetMinZ(void) const { return m_Min.z; } + + double GetMaxX(void) const { return m_Max.x; } + 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; } + protected: Vector3d m_Min; Vector3d m_Max; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 40ffff834..caace5024 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -37,6 +37,7 @@ #include "MobSpawner.h" #include "BlockInServerPluginInterface.h" #include "SetChunkData.h" +#include "BoundingBox.h" #include "json/json.h" @@ -65,19 +66,18 @@ sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_Bloc // cChunk: cChunk::cChunk( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World, cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, cAllocationPool<cChunkData::sChunkSection> & a_Pool ) : - m_IsValid(false), + m_Presence(cpInvalid), m_IsLightValid(false), m_IsDirty(false), m_IsSaving(false), m_HasLoadFailed(false), m_StayCount(0), m_PosX(a_ChunkX), - m_PosY(a_ChunkY), m_PosZ(a_ChunkZ), m_World(a_World), m_ChunkMap(a_ChunkMap), @@ -165,11 +165,22 @@ cChunk::~cChunk() -void cChunk::SetValid(void) +void cChunk::SetPresence(cChunk::ePresence a_Presence) { - m_IsValid = true; - - m_World->GetChunkMap()->ChunkValidated(); + m_Presence = a_Presence; + if (a_Presence == cpPresent) + { + m_World->GetChunkMap()->ChunkValidated(); + } +} + + + + + +void cChunk::SetShouldGenerateIfLoadFailed(bool a_ShouldGenerateIfLoadFailed) +{ + m_ShouldGenerateIfLoadFailed = a_ShouldGenerateIfLoadFailed; } @@ -178,6 +189,9 @@ void cChunk::SetValid(void) void cChunk::MarkRegenerating(void) { + // Set as queued again: + SetPresence(cpQueued); + // Tell all clients attached to this chunk that they want this chunk: for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { @@ -191,7 +205,11 @@ void cChunk::MarkRegenerating(void) bool cChunk::CanUnload(void) { - return m_LoadedByClient.empty() && !m_IsDirty && (m_StayCount == 0); + return + m_LoadedByClient.empty() && // The chunk is not used by any client + !m_IsDirty && // The chunk has been saved properly or hasn't been touched since the load / gen + (m_StayCount == 0) && // The chunk is not in a ChunkStay + (m_Presence != cpQueued) ; // The chunk is not queued for loading / generating (otherwise multi-load / multi-gen could occur) } @@ -223,7 +241,7 @@ void cChunk::MarkSaved(void) void cChunk::MarkLoaded(void) { m_IsDirty = false; - SetValid(); + SetPresence(cpPresent); } @@ -232,12 +250,17 @@ void cChunk::MarkLoaded(void) void cChunk::MarkLoadFailed(void) { - if (m_IsValid) + ASSERT(m_Presence == cpQueued); + + // If the chunk is marked as needed, generate it: + if (m_ShouldGenerateIfLoadFailed) { - return; + m_World->GetGenerator().QueueGenerateChunk(m_PosX, m_PosZ, false); + } + else + { + m_Presence = cpInvalid; } - - m_HasLoadFailed = true; } @@ -246,6 +269,8 @@ void cChunk::MarkLoadFailed(void) void cChunk::GetAllData(cChunkDataCallback & a_Callback) { + ASSERT(m_Presence == cpPresent); + a_Callback.HeightMap(&m_HeightMap); a_Callback.BiomeData(&m_BiomeMap); @@ -272,6 +297,7 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData) { ASSERT(a_SetChunkData.IsHeightMapValid()); ASSERT(a_SetChunkData.AreBiomesValid()); + ASSERT(IsQueued()); memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap)); memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap)); @@ -317,7 +343,7 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData) CreateBlockEntities(); // Set the chunk data as valid. This may be needed for some simulators that perform actions upon block adding (Vaporize) - SetValid(); + SetPresence(cpPresent); // Wake up all simulators for their respective blocks: WakeUpSimulators(); @@ -653,7 +679,7 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); if (Neighbor == NULL) { - Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Neighbor == NULL) { // TODO: What to do with this? @@ -1960,6 +1986,30 @@ 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) + { + ++itr2; + cBoundingBox EntBox((*itr)->GetPosition(), (*itr)->GetWidth() / 2, (*itr)->GetHeight()); + if (!EntBox.DoesIntersect(a_Box)) + { + // The entity is not in the specified box + continue; + } + if (a_Callback.Item(*itr)) + { + return false; + } + } // for itr - m_Entitites[] + return true; +} + + + + + bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult) { // The entity list is locked by the parent chunkmap's CS @@ -2603,7 +2653,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ; int ChunkX, ChunkZ; BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); - return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + return m_ChunkMap->GetChunkNoLoad(ChunkX, ChunkZ); } // Walk the neighbors: diff --git a/src/Chunk.h b/src/Chunk.h index e5de22e3b..81862f2e7 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -66,8 +66,16 @@ 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 + { + cpInvalid, /**< The chunk is not present at all and is not queued in the loader / generator */ + cpQueued, /**< The chunk is not present, but is queued for loading / generation */ + cpPresent, /**< The chunk is present */ + }; + cChunk( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, // Chunk coords + int a_ChunkX, int a_ChunkZ, // Chunk coords cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks cAllocationPool<cChunkData::sChunkSection> & a_Pool @@ -75,11 +83,25 @@ public: cChunk(cChunk & other); ~cChunk(); - bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated) - void SetValid(void); // Also wakes up any calls to cChunkMap::GetHeight() - void MarkRegenerating(void); // Marks all clients attached to this chunk as wanting this chunk - bool IsDirty(void) const {return m_IsDirty; } // Returns true if the chunk has changed since it was last saved - bool HasLoadFailed(void) const {return m_HasLoadFailed; } // Returns true if the chunk failed to load and hasn't been generated since then + /** Returns true iff the chunk block data is valid (loaded / generated) */ + bool IsValid(void) const {return (m_Presence == cpPresent); } + + /** Returns true iff the chunk is in the queue for loading / generating */ + bool IsQueued(void) const {return (m_Presence == cpQueued); } + + /** Sets the chunk's presence. + Wakes up any calls to cChunkMap::GetHeight() when setting to cpPresent. */ + void SetPresence(ePresence a_Presence); + + /** Called to indicate whether the chunk should be queued in the generator if it fails to load. Set by cChunkMap::GetChunk(). */ + void SetShouldGenerateIfLoadFailed(bool a_ShouldGenerateIfLoadFailed); + + /** Marks all clients attached to this chunk as wanting this chunk. Also sets presence to cpQueued. */ + void MarkRegenerating(void); + + /** Returns true iff the chunk has changed since it was last saved. */ + bool IsDirty(void) const {return m_IsDirty; } + bool CanUnload(void); bool IsLightValid(void) const {return m_IsLightValid; } @@ -94,7 +116,10 @@ public: void MarkSaving(void); // Marks the chunk as being saved. void MarkSaved(void); // Marks the chunk as saved, if it didn't change from the last call to MarkSaving() void MarkLoaded(void); // Marks the chunk as freshly loaded. Fails if the chunk is already valid - void MarkLoadFailed(void); // Marks the chunk as failed to load. Ignored is the chunk is already valid + + /** Marks the chunk as failed to load. + If m_ShouldGenerateIfLoadFailed is set, queues the chunk for generating. */ + void MarkLoadFailed(void); /** Gets all chunk data, calls the a_Callback's methods for each data type */ void GetAllData(cChunkDataCallback & a_Callback); @@ -216,6 +241,10 @@ public: /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible + /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. + Returns true if all entities processed, false if the callback aborted by returning true. */ + bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible + /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */ bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible @@ -430,7 +459,12 @@ private: typedef std::vector<sSetBlockQueueItem> sSetBlockQueueVector; - bool m_IsValid; // True if the chunk is loaded / generated + /** Holds the presence status of the chunk - if it is present, or in the loader / generator queue, or unloaded */ + ePresence m_Presence; + + /** If the chunk fails to load, should it be queued in the generator or reset back to invalid? */ + bool m_ShouldGenerateIfLoadFailed; + bool m_IsLightValid; // True if the blocklight and skylight are calculated bool m_IsDirty; // True if the chunk has changed since it was last saved bool m_IsSaving; // True if the chunk is being saved diff --git a/src/ChunkDef.h b/src/ChunkDef.h index b8b4291c7..f4ed66c4b 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -16,11 +16,6 @@ -/** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord. -It will help us when the new chunk format comes out and we need to patch everything up for compatibility. -*/ -#define ZERO_CHUNK_Y 0 - // Used to smoothly convert to new axis ordering. One will be removed when deemed stable. #define AXIS_ORDER_YZX 1 // Original (1.1-) #define AXIS_ORDER_XZY 2 // New (1.2+) @@ -377,14 +372,13 @@ class cChunkCoords { public: int m_ChunkX; - int m_ChunkY; int m_ChunkZ; - cChunkCoords(int a_ChunkX, int a_ChunkY, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_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_ChunkY == a_Other.m_ChunkY) && (m_ChunkZ == a_Other.m_ChunkZ)); + return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); } } ; @@ -395,6 +389,27 @@ typedef std::vector<cChunkCoords> cChunkCoordsVector; +class cChunkCoordsWithBool +{ +public: + int m_ChunkX; + int m_ChunkZ; + bool m_ForceGenerate; + + cChunkCoordsWithBool(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_ForceGenerate(a_ForceGenerate){} + + bool operator == (const cChunkCoordsWithBool & a_Other) const + { + return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ) && (m_ForceGenerate == a_Other.m_ForceGenerate)); + } +}; + +typedef std::list<cChunkCoordsWithBool> cChunkCoordsWithBoolList; + + + + + /// Interface class used as a callback for operations that involve chunk coords class cChunkCoordCallback { diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index a3692ef11..9c105c5af 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -143,26 +143,27 @@ cChunkMap::cChunkLayer * cChunkMap::GetLayerForChunk(int a_ChunkX, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) { - // No need to lock m_CSLayers, since it's already locked by the operation that called us - ASSERT(m_CSLayers.IsLockedByCurrentThread()); + ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us - cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); + cChunkLayer * Layer = GetLayerForChunk(a_ChunkX, a_ChunkZ); if (Layer == NULL) { // An error must have occurred, since layers are automatically created if they don't exist return NULL; } - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return NULL; } - if (!(Chunk->IsValid())) + if (!Chunk->IsValid() && !Chunk->IsQueued()) { - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ, true); + Chunk->SetPresence(cChunk::cpQueued); + Chunk->SetShouldGenerateIfLoadFailed(true); + m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ); } return Chunk; } @@ -171,24 +172,26 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) { - // No need to lock m_CSLayers, since it's already locked by the operation that called us - cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); + ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us + + cChunkLayer * Layer = GetLayerForChunk(a_ChunkX, a_ChunkZ); if (Layer == NULL) { // An error must have occurred, since layers are automatically created if they don't exist return NULL; } - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return NULL; } - if (!(Chunk->IsValid())) + if (!Chunk->IsValid() && !Chunk->IsQueued()) { - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ, false); + Chunk->SetPresence(cChunk::cpQueued); + m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ); } return Chunk; @@ -198,9 +201,10 @@ cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkZ) { - // No need to lock m_CSLayers, since it's already locked by the operation that called us + ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us + cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); if (Layer == NULL) { @@ -208,7 +212,7 @@ cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkY, int a_ChunkZ) return NULL; } - return Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + return Layer->GetChunk(a_ChunkX, a_ChunkZ); } @@ -222,7 +226,7 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -244,7 +248,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -265,7 +269,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -284,7 +288,7 @@ bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY // We already have m_CSLayers locked since this can be called only from within the tick thread int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -303,7 +307,7 @@ bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLO // We already have m_CSLayers locked since this can be called only from within the tick thread int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -336,7 +340,7 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -356,7 +360,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c x = a_BlockX; z = a_BlockZ; cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -375,7 +379,7 @@ void cChunkMap::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_blockX, a_blockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -393,7 +397,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -408,7 +412,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, 0, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -424,7 +428,7 @@ void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSeriali void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -440,7 +444,7 @@ void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -456,7 +460,7 @@ void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHa void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -472,7 +476,7 @@ void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -488,7 +492,7 @@ void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotN void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -504,7 +508,7 @@ void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -520,7 +524,7 @@ void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandl void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -536,7 +540,7 @@ void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -552,7 +556,7 @@ void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, ch void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -568,7 +572,7 @@ void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -584,7 +588,7 @@ void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, c void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -600,7 +604,7 @@ void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -619,7 +623,7 @@ void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_ int ChunkX, ChunkZ; cChunkDef::BlockToChunk((int) a_SrcX, (int) a_SrcZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -636,7 +640,7 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -655,7 +659,7 @@ void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, do int ChunkX, ChunkZ; cChunkDef::BlockToChunk((int)std::floor(a_X), (int)std::floor(a_Z), ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -674,7 +678,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_SrcX, a_SrcZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -690,7 +694,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S void cChunkMap::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -708,7 +712,7 @@ void cChunkMap::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, c cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -727,7 +731,7 @@ void cChunkMap::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bl int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -745,7 +749,7 @@ void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClien cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -763,7 +767,7 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -778,7 +782,7 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return false; @@ -795,7 +799,7 @@ void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -824,7 +828,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M int MaxZ = std::min(a_MaxBlockZ, z * cChunkDef::Width + cChunkDef::Width - 1); for (int x = MinChunkX; x <= MaxChunkX; x++) { - cChunkPtr Chunk = GetChunkNoGen(x, 0, z); + cChunkPtr Chunk = GetChunkNoGen(x, z); if ((Chunk == NULL) || !Chunk->IsValid()) { continue; @@ -852,7 +856,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -867,7 +871,7 @@ void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -886,7 +890,7 @@ void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDi void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -901,7 +905,7 @@ void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -919,7 +923,7 @@ void cChunkMap::SetChunkData(cSetChunkData & a_SetChunkData) int ChunkZ = a_SetChunkData.GetChunkZ(); { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -964,7 +968,7 @@ void cChunkMap::ChunkLighted( ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -980,7 +984,7 @@ void cChunkMap::ChunkLighted( bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -996,7 +1000,7 @@ bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -1009,10 +1013,21 @@ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blo +bool cChunkMap::IsChunkQueued(int a_ChunkX, int a_ChunkZ) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); + return (Chunk != NULL) && Chunk->IsQueued(); +} + + + + + bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); return (Chunk != NULL) && Chunk->IsValid(); } @@ -1023,7 +1038,7 @@ bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); return (Chunk != NULL) && Chunk->HasAnyClients(); } @@ -1038,7 +1053,7 @@ int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if (Chunk == NULL) { return 0; @@ -1065,7 +1080,7 @@ bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -1088,7 +1103,7 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList) int ChunkX = a_BlockList.front().ChunkX; int ChunkZ = a_BlockList.front().ChunkZ; cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) @@ -1135,7 +1150,7 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player) int BlockX = (int)(a_Player->GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway int BlockY = (int)(a_Player->GetPosY()); int BlockZ = (int)(a_Player->GetPosZ()); - int ChunkX, ChunkZ, ChunkY = ZERO_CHUNK_Y; + int ChunkX = 0, ChunkZ = 0; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); int OtherChunkX = ChunkX + ((BlockX > 8) ? 1 : -1); int OtherChunkZ = ChunkZ + ((BlockZ > 8) ? 1 : -1); @@ -1144,13 +1159,13 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player) // The only time the chunks are not valid is when the player is downloading the initial world and they should not call this at that moment cCSLock Lock(m_CSLayers); - GetChunkNoLoad(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkZ)->CollectPickupsByPlayer(a_Player); // Check the neighboring chunks as well: - GetChunkNoLoad(OtherChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer (a_Player); - GetChunkNoLoad(OtherChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); - GetChunkNoLoad(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer (a_Player); - GetChunkNoLoad(ChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(OtherChunkX, ChunkZ)->CollectPickupsByPlayer (a_Player); + GetChunkNoLoad(OtherChunkX, OtherChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkZ)->CollectPickupsByPlayer (a_Player); + GetChunkNoLoad(ChunkX, OtherChunkZ)->CollectPickupsByPlayer(a_Player); } @@ -1177,7 +1192,7 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); @@ -1206,7 +1221,7 @@ NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); @@ -1224,7 +1239,7 @@ NIBBLETYPE cChunkMap::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetSkyLight(a_BlockX, a_BlockY, a_BlockZ); @@ -1242,7 +1257,7 @@ NIBBLETYPE cChunkMap::GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_Block cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetBlockLight(a_BlockX, a_BlockY, a_BlockZ); @@ -1261,7 +1276,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP // a_BlockXYZ now contains relative coords! cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); @@ -1284,7 +1299,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients); @@ -1303,7 +1318,7 @@ void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYP cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->QueueSetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType); @@ -1320,7 +1335,7 @@ bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->GetBlockTypeMeta(X, Y, Z, a_BlockType, a_BlockMeta); @@ -1339,7 +1354,7 @@ bool cChunkMap::GetBlockInfo(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->GetBlockInfo(X, Y, Z, a_BlockType, a_Meta, a_SkyLight, a_BlockLight); @@ -1357,7 +1372,7 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt cCSLock Lock(m_CSLayers); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ); + cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { continue; @@ -1378,7 +1393,7 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks) cCSLock Lock(m_CSLayers); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ); + cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { continue; @@ -1413,7 +1428,7 @@ EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ) cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetBiomeAt(X, Z); @@ -1434,7 +1449,7 @@ bool cChunkMap::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome) cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetBiomeAt(X, Z, a_Biome); @@ -1467,7 +1482,7 @@ bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMC { int MinRelZ = (z == MinChunkZ) ? MinZ : 0; int MaxRelZ = (z == MaxChunkZ) ? MaxZ : cChunkDef::Width - 1; - cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); + cChunkPtr Chunk = GetChunkNoLoad(x, z); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetAreaBiome(MinRelX, MaxRelX, MinRelZ, MaxRelZ, a_Biome); @@ -1491,7 +1506,7 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) cCSLock Lock(m_CSLayers); for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ); + cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { if (!a_ContinueOnFailure) @@ -1519,7 +1534,7 @@ bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z) { cCSLock Lock(m_CSLayers); - cChunkPtr DestChunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr DestChunk = GetChunk( ChunkX, ChunkZ); if ((DestChunk == NULL) || !DestChunk->IsValid()) { return false; @@ -1542,7 +1557,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) cChunkDef::AbsoluteToRelative(a_X, a_Y, a_Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && (Chunk->IsValid())) { Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle()); @@ -1556,12 +1571,12 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, ZERO_CHUNK_Y, a_ChunkZ1); + cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, a_ChunkZ1); if (Chunk1 == NULL) { return; } - cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, ZERO_CHUNK_Y, a_ChunkZ2); + cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, a_ChunkZ2); if (Chunk2 == NULL) { return; @@ -1623,7 +1638,7 @@ void cChunkMap::CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClien bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return false; @@ -1638,7 +1653,7 @@ bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Cli void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -1667,7 +1682,7 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) void cChunkMap::AddEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if ( (Chunk == NULL) || // Chunk not present at all (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) @@ -1688,7 +1703,7 @@ void cChunkMap::AddEntity(cEntity * a_Entity) void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if ( (Chunk == NULL) || // Chunk not present at all (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) @@ -1729,7 +1744,7 @@ bool cChunkMap::HasEntity(int a_UniqueID) void cChunkMap::RemoveEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) if (Chunk == NULL) @@ -1763,7 +1778,7 @@ bool cChunkMap::ForEachEntity(cEntityCallback & a_Callback) bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -1775,6 +1790,38 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback +bool cChunkMap::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) +{ + // Calculate the chunk range for the box: + int MinChunkX = (int)floor(a_Box.GetMinX() / cChunkDef::Width); + int MinChunkZ = (int)floor(a_Box.GetMinZ() / cChunkDef::Width); + int MaxChunkX = (int)floor((a_Box.GetMaxX() + cChunkDef::Width) / cChunkDef::Width); + int MaxChunkZ = (int)floor((a_Box.GetMaxZ() + cChunkDef::Width) / cChunkDef::Width); + + // Iterate over each chunk in the range: + cCSLock Lock(m_CSLayers); + for (int z = MinChunkZ; z <= MaxChunkZ; z++) + { + for (int x = MinChunkX; x <= MaxChunkX; x++) + { + cChunkPtr Chunk = GetChunkNoGen(x, z); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + continue; + } + if (!Chunk->ForEachEntityInBox(a_Box, a_Callback)) + { + return false; + } + } // for x + } // for z + return true; +} + + + + + void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlocksAffected) { // Don't explode if outside of Y range (prevents the following test running into unallocated memory): @@ -1989,7 +2036,7 @@ bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2004,7 +2051,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2019,7 +2066,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2034,7 +2081,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2049,7 +2096,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2064,7 +2111,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2082,7 +2129,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2100,7 +2147,7 @@ bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeacon int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2118,7 +2165,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2136,7 +2183,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2154,7 +2201,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2172,7 +2219,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2190,7 +2237,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2207,7 +2254,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2224,7 +2271,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2242,7 +2289,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2260,7 +2307,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2278,7 +2325,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2290,62 +2337,20 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & -void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); -} - - - - - -/// Loads the chunk synchronously, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) -bool cChunkMap::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -{ - { - cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); - if (Chunk == NULL) - { - // Internal error - return false; - } - if (Chunk->IsValid()) - { - // Already loaded - return true; - } - if (Chunk->HasLoadFailed()) - { - // Already tried loading and it failed - return false; - } - } - return m_World->GetStorage().LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ); -} - - - - - -/// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() -void cChunkMap::LoadChunks(const cChunkCoordsList & a_Chunks) -{ - for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr) - { - LoadChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); - } // for itr - a_Chunks[] + GetChunk(a_ChunkX, a_ChunkZ); } -void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -2362,7 +2367,7 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2377,7 +2382,7 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { // Not present @@ -2393,7 +2398,7 @@ void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) bool cChunkMap::IsChunkLighted(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { // Not present @@ -2414,7 +2419,7 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh { for (int x = a_MinChunkX; x <= a_MaxChunkX; x++) { - cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); + cChunkPtr Chunk = GetChunkNoLoad(x, z); if ((Chunk == NULL) || (!Chunk->IsValid())) { // Not present / not valid @@ -2456,7 +2461,7 @@ bool cChunkMap::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBl { for (int x = MinChunkX; x <= MaxChunkX; x++) { - cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); + cChunkPtr Chunk = GetChunkNoLoad(x, z); if ((Chunk == NULL) || (!Chunk->IsValid())) { // Not present / not valid @@ -2497,7 +2502,7 @@ void cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_Rand); @@ -2514,7 +2519,7 @@ void cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Nu cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow); @@ -2531,7 +2536,7 @@ void cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBl cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow); @@ -2548,7 +2553,7 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->SetNextBlockTick(a_BlockX, a_BlockY, a_BlockZ); @@ -2603,7 +2608,7 @@ void cChunkMap::TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -2672,7 +2677,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) // a_BlockXYZ now contains relative coords! cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->QueueTickBlock(a_BlockX, a_BlockY, a_BlockZ); @@ -2686,7 +2691,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk != NULL) { Chunk->SetAlwaysTicked(a_AlwaysTicked); @@ -2731,7 +2736,7 @@ cChunkMap::cChunkLayer::~cChunkLayer() -cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkZ) { // Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check @@ -2751,7 +2756,7 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_Ch cChunk * neixp = (LocalX < LAYER_SIZE - 1) ? m_Chunks[Index + 1] : m_Parent->FindChunk(a_ChunkX + 1, a_ChunkZ); cChunk * neizm = (LocalZ > 0) ? m_Chunks[Index - LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ - 1); cChunk * neizp = (LocalZ < LAYER_SIZE - 1) ? m_Chunks[Index + LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ + 1); - m_Chunks[Index] = new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); + m_Chunks[Index] = new cChunk(a_ChunkX, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); } return m_Chunks[Index]; } @@ -2951,7 +2956,7 @@ void cChunkMap::cChunkLayer::Save(void) { if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty()) { - World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosY(), m_Chunks[i]->GetPosZ()); + World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()); } } // for i - m_Chunks[] } @@ -3024,7 +3029,7 @@ void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay) const cChunkCoordsVector & WantedChunks = a_ChunkStay.GetChunks(); for (cChunkCoordsVector::const_iterator itr = WantedChunks.begin(); itr != WantedChunks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); if (Chunk == NULL) { continue; @@ -3073,7 +3078,7 @@ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay) const cChunkCoordsVector & Chunks = a_ChunkStay.GetChunks(); for (cChunkCoordsVector::const_iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr) { - cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkZ); if (Chunk == NULL) { continue; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 1e9a0f982..7354536d4 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -36,6 +36,7 @@ class cBlockArea; class cMobCensus; class cMobSpawner; class cSetChunkData; +class cBoundingBox; typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; @@ -132,6 +133,9 @@ public: /** Copies the chunk's blocktypes into a_Blocks; returns true if successful */ bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blocks); + /** Returns true iff the chunk is in the loader / generator queue. */ + bool IsChunkQueued(int a_ChunkX, int a_ChunkZ); + bool IsChunkValid (int a_ChunkX, int a_ChunkZ); bool HasChunkAnyClients (int a_ChunkX, int a_ChunkZ); int GetHeight (int a_BlockX, int a_BlockZ); // Waits for the chunk to get loaded / generated @@ -209,6 +213,11 @@ public: /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible + /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. + Returns true if all entities processed, false if the callback aborted by returning true. + If any chunk in the box is missing, ignores the entities in that chunk silently. */ + bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible + /** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected); @@ -270,16 +279,10 @@ public: bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible /** Touches the chunk, causing it to be loaded or generated */ - void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void TouchChunk(int a_ChunkX, int a_ChunkZ); - /** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */ - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */ - void LoadChunks(const cChunkCoordsList & a_Chunks); - /** Marks the chunk as failed-to-load */ - void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ); /** Sets the sign text. Returns true if sign text changed. */ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); @@ -363,7 +366,7 @@ private: ~cChunkLayer(); /** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */ - cChunkPtr GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ); + cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ); /** Returns the specified chunk, or NULL if not created yet */ cChunk * FindChunk(int a_ChunkX, int a_ChunkZ); @@ -456,9 +459,9 @@ private: std::auto_ptr<cAllocationPool<cChunkData::sChunkSection> > m_Pool; - cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid - cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate - cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate + cChunkPtr GetChunk (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid + cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate + cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); // Doesn't load, doesn't generate /** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp index ebcf0e272..95c4d03d2 100644 --- a/src/ChunkSender.cpp +++ b/src/ChunkSender.cpp @@ -81,7 +81,7 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkZ) // This is probably never gonna be called twice for the same chunk, and if it is, we don't mind, so we don't check { cCSLock Lock(m_CS); - m_ChunksReady.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } m_evtQueue.Set(); } @@ -95,12 +95,12 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * ASSERT(a_Client != NULL); { cCSLock Lock(m_CS); - if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)) != m_SendChunks.end()) + if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, a_ChunkZ, a_Client)) != m_SendChunks.end()) { // Already queued, bail out return; } - m_SendChunks.push_back(sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)); + m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkZ, a_Client)); } m_evtQueue.Set(); } @@ -160,7 +160,7 @@ void cChunkSender::Execute(void) m_ChunksReady.pop_front(); Lock.Unlock(); - SendChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, NULL); + SendChunk(Coords.m_ChunkX, Coords.m_ChunkZ, NULL); } else { @@ -169,7 +169,7 @@ void cChunkSender::Execute(void) m_SendChunks.pop_front(); Lock.Unlock(); - SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkY, Chunk.m_ChunkZ, Chunk.m_Client); + SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); } Lock.Lock(); int RemoveCount = m_RemoveCount; @@ -186,14 +186,14 @@ void cChunkSender::Execute(void) -void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { ASSERT(m_World != NULL); // Ask the client if it still wants the chunk: if (a_Client != NULL) { - if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ)) + if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ)) { return; } diff --git a/src/ChunkSender.h b/src/ChunkSender.h index 624a3a0bd..a0e9087a9 100644 --- a/src/ChunkSender.h +++ b/src/ChunkSender.h @@ -95,13 +95,11 @@ protected: struct sSendChunk { int m_ChunkX; - int m_ChunkY; int m_ChunkZ; cClientHandle * m_Client; - sSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) : + sSendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) : m_ChunkX(a_ChunkX), - m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Client(a_Client) { @@ -111,7 +109,6 @@ protected: { return ( (a_Other.m_ChunkX == m_ChunkX) && - (a_Other.m_ChunkY == m_ChunkY) && (a_Other.m_ChunkZ == m_ChunkZ) && (a_Other.m_Client == m_Client) ); @@ -162,7 +159,7 @@ protected: virtual void BlockEntity (cBlockEntity * a_Entity) override; /// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == NULL - void SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + void SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); } ; diff --git a/src/ChunkStay.cpp b/src/ChunkStay.cpp index b5002a63d..38aa89a37 100644 --- a/src/ChunkStay.cpp +++ b/src/ChunkStay.cpp @@ -51,7 +51,7 @@ void cChunkStay::Add(int a_ChunkX, int a_ChunkZ) return; } } // for itr - Chunks[] - m_Chunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_Chunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index f9c6a664c..6b31bfa64 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -472,13 +472,13 @@ void cClientHandle::StreamChunks(void) // For each distance touch chunks in a hollow square centered around current position: for (int i = -d; i <= d; ++i) { - World->TouchChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); - World->TouchChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); + World->TouchChunk(ChunkPosX + d, ChunkPosZ + i); + World->TouchChunk(ChunkPosX - d, ChunkPosZ + i); } // for i for (int i = -d + 1; i < d; ++i) { - World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); - World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); + World->TouchChunk(ChunkPosX + i, ChunkPosZ + d); + World->TouchChunk(ChunkPosX + i, ChunkPosZ - d); } // for i } // for d } @@ -501,8 +501,8 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) { { cCSLock Lock(m_CSChunkLists); - m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); - m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } World->SendChunkTo(a_ChunkX, a_ChunkZ, this); } @@ -2734,7 +2734,7 @@ bool cClientHandle::HasPluginChannel(const AString & a_PluginChannel) -bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkZ) { if (m_State >= csDestroying) { @@ -2742,7 +2742,7 @@ bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) } cCSLock Lock(m_CSChunkLists); - return (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)) != m_ChunksToSend.end()); + return (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkZ)) != m_ChunksToSend.end()); } @@ -2758,9 +2758,9 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ) LOGD("Adding chunk [%d, %d] to wanted chunks for client %p", a_ChunkX, a_ChunkZ, this); cCSLock Lock(m_CSChunkLists); - if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)) == m_ChunksToSend.end()) + if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkZ)) == m_ChunksToSend.end()) { - m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } } @@ -2858,11 +2858,27 @@ void cClientHandle::SocketClosed(void) -void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment) +void cClientHandle::HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment) { - cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow(); + if (a_Enchantment > 2) + { + LOGWARNING("%s attempt to crash the server with invalid enchanting selection!", GetUsername().c_str()); + Kick("Invalid enchanting!"); + return; + } + + if ( + (m_Player->GetWindow() == NULL) || + (m_Player->GetWindow()->GetWindowID() != a_WindowID) || + (m_Player->GetWindow()->GetWindowType() != cWindow::wtEnchantment) + ) + { + return; + } + + cEnchantingWindow * Window = (cEnchantingWindow*) m_Player->GetWindow(); cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player); - int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment); + int BaseEnchantmentLevel = Window->GetPropertyValue(a_Enchantment); if (Item.EnchantByXPLevels(BaseEnchantmentLevel)) { diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 7ae70a07f..593d0780d 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -209,7 +209,7 @@ public: // tolua_end /** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */ - bool WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool WantsSendChunk(int a_ChunkX, int a_ChunkZ); /** Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) */ void AddWantedChunk(int a_ChunkX, int a_ChunkZ); @@ -269,7 +269,7 @@ public: void RemoveFromWorld(void); /** Called when the player will enchant a Item */ - void HandleEnchantItem(Byte & WindowID, Byte & Enchantment); + void HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment); private: diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 89d1cffa1..9bcdcffeb 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -387,7 +387,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) case cMonster::mtGhast: case cMonster::mtZombiePigman: case cMonster::mtMagmaCube: - { + { break; }; default: StartBurning(BurnTicks * 20); @@ -417,7 +417,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) } if (!Player->IsOnGround()) - { + { if ((a_TDI.DamageType == dtAttack) || (a_TDI.DamageType == dtArrowAttack)) { a_TDI.FinalDamage += 2; diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp index 3e28392f4..f08755674 100644 --- a/src/Entities/EntityEffect.cpp +++ b/src/Entities/EntityEffect.cpp @@ -34,14 +34,14 @@ cEntityEffect::eType cEntityEffect::GetPotionEffectType(short a_ItemDamage) case 0x08: return cEntityEffect::effWeakness; case 0x09: return cEntityEffect::effStrength; case 0x0a: return cEntityEffect::effSlowness; + case 0x0b: return cEntityEffect::effJumpBoost; case 0x0c: return cEntityEffect::effInstantDamage; case 0x0d: return cEntityEffect::effWaterBreathing; case 0x0e: return cEntityEffect::effInvisibility; - + // No effect potions case 0x00: case 0x07: - case 0x0b: // Will be potion of leaping in 1.8 case 0x0f: { break; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 756410989..51a1f8699 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1670,7 +1670,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents); m_LoadedWorldName = root.get("world", "world").asString(); - a_World = cRoot::Get()->GetWorld(GetLoadedWorldName(), true); + a_World = cRoot::Get()->GetWorld(GetLoadedWorldName(), false); m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt(); m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt(); diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp index 8fad9f5c9..60ad4e3eb 100644 --- a/src/Generating/BioGen.cpp +++ b/src/Generating/BioGen.cpp @@ -151,7 +151,7 @@ void cBioGenCache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a LOGD("BioGenCache: %d hits, %d misses, saved %.2f %%", m_NumHits, m_NumMisses, 100.0 * m_NumHits / (m_NumHits + m_NumMisses)); LOGD("BioGenCache: Avg cache chain length: %.2f", (float)m_TotalChain / m_NumHits); } - + for (int i = 0; i < m_CacheSize; i++) { if ( @@ -208,6 +208,59 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile) +//////////////////////////////////////////////////////////////////////////////// +// cBioGenMulticache: + +cBioGenMulticache::cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength) : + m_CachesLength(a_CachesLength) +{ + m_Caches.reserve(a_CachesLength); + for (size_t i = 0; i < a_CachesLength; i++) + { + m_Caches.push_back(new cBioGenCache(a_BioGenToCache, a_CacheSize)); + } +} + + + + + +cBioGenMulticache::~cBioGenMulticache() +{ + for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++) + { + delete *it; + } +} + + + + + +void cBioGenMulticache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) +{ + const size_t coefficient = 3; + const size_t cacheIdx = ((size_t)a_ChunkX + coefficient * (size_t)a_ChunkZ) % m_CachesLength; + + m_Caches[cacheIdx]->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); +} + + + + + +void cBioGenMulticache::InitializeBiomeGen(cIniFile & a_IniFile) +{ + for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++) + { + cBiomeGen * tmp = *it; + tmp->InitializeBiomeGen(a_IniFile); + } +} + + + + //////////////////////////////////////////////////////////////////////////////// // cBiomeGenList: diff --git a/src/Generating/BioGen.h b/src/Generating/BioGen.h index 227ec97d7..20d199611 100644 --- a/src/Generating/BioGen.h +++ b/src/Generating/BioGen.h @@ -80,6 +80,36 @@ protected: +class cBioGenMulticache : + public cBiomeGen +{ + + typedef cBiomeGen super; + +public: + /* + a_CacheSize defines the size of each singular cache + a_CachesLength defines how many caches are used for the multicache + */ + cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength); // Doesn't take ownership of a_BioGenToCache + ~cBioGenMulticache(); + +protected: + typedef std::vector<cBiomeGen *> cBiomeGens; + + + size_t m_CachesLength; + cBiomeGens m_Caches; + + + virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; + virtual void InitializeBiomeGen(cIniFile & a_IniFile) override; +}; + + + + + /// Base class for generators that use a list of available biomes. This class takes care of the list. class cBiomeGenList : public cBiomeGen diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index a1188f984..d615456c1 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -52,10 +52,21 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a m_PluginInterface = &a_PluginInterface; m_ChunkSink = &a_ChunkSink; - MTRand rnd; - m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", (int)rnd.randInt()); + // Get the seed; create a new one and log it if not found in the INI file: + if (a_IniFile.HasValue("Seed", "Seed")) + { + m_Seed = a_IniFile.GetValueI("Seed", "Seed"); + } + else + { + MTRand rnd; + m_Seed = rnd.randInt(); + LOGINFO("Chosen a new random seed for world: %d", m_Seed); + a_IniFile.SetValueI("Seed", "Seed", m_Seed); + } + + // Get the generator engine based on the INI file settings: AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); - if (NoCaseCompare(GeneratorName, "Noise3D") == 0) { m_Generator = new cNoise3DGenerator(*this); @@ -99,15 +110,17 @@ void cChunkGenerator::Stop(void) -void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate) { + ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ)); + { cCSLock Lock(m_CS); // Check if it is already in the queue: - for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) + for (cChunkCoordsWithBoolList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) { - if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ)) + if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) { // Already in the queue, bail out return; @@ -119,7 +132,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk { LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size()); } - m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_Queue.push_back(cChunkCoordsWithBool(a_ChunkX, a_ChunkZ, a_ForceGenerate)); } m_Event.Set(); @@ -229,9 +242,9 @@ void cChunkGenerator::Execute(void) continue; } - cChunkCoords coords = m_Queue.front(); // Get next coord from queue - m_Queue.erase( m_Queue.begin()); // Remove coordinate from queue + cChunkCoordsWithBool coords = m_Queue.front(); // Get next coord from queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); + m_Queue.erase(m_Queue.begin()); // Remove coordinate from queue Lock.Unlock(); // Unlock ASAP m_evtRemoved.Set(); @@ -245,8 +258,7 @@ void cChunkGenerator::Execute(void) LastReportTick = clock(); } - // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) + if (!coords.m_ForceGenerate && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request @@ -259,8 +271,8 @@ void cChunkGenerator::Execute(void) continue; } - LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + LOGD("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); + DoGenerate(coords.m_ChunkX, coords.m_ChunkZ); NumChunksGenerated++; } // while (!bStop) @@ -269,11 +281,12 @@ void cChunkGenerator::Execute(void) -void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ) { ASSERT(m_PluginInterface != NULL); ASSERT(m_ChunkSink != NULL); - + ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ)); + cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ); m_PluginInterface->CallHookChunkGenerating(ChunkDesc); m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h index 88d71f3f9..190d9e616 100644 --- a/src/Generating/ChunkGenerator.h +++ b/src/Generating/ChunkGenerator.h @@ -106,6 +106,10 @@ public: If this callback returns false, the chunk is not generated. */ virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) = 0; + + /** Called to check whether the specified chunk is in the queued state. + Currently used only in Debug-mode asserts. */ + virtual bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) = 0; } ; @@ -116,7 +120,7 @@ public: void Stop(void); /// Queues the chunk for generation; removes duplicate requests - void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate); /// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap); @@ -137,10 +141,10 @@ private: int m_Seed; - cCriticalSection m_CS; - cChunkCoordsList m_Queue; - cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate - cEvent m_evtRemoved; ///< Set when an item is removed from the queue + cCriticalSection m_CS; + cChunkCoordsWithBoolList m_Queue; + cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate + cEvent m_evtRemoved; ///< Set when an item is removed from the queue cGenerator * m_Generator; ///< The actual generator engine used to generate chunks @@ -154,7 +158,7 @@ private: // cIsThread override: virtual void Execute(void) override; - void DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void DoGenerate(int a_ChunkX, int a_ChunkZ); }; diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 6f4007d24..69068d231 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -230,17 +230,29 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) // Add a cache, if requested: int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 64); - if (CacheSize > 0) + + if (CacheSize <= 0) + { + return; + } + + int MultiCacheLength = a_IniFile.GetValueSetI("Generator", "BiomeGenMultiCacheLength", 4); + if (CacheSize < 4) + { + LOGWARNING("Biomegen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d", + CacheSize, 4 + ); + CacheSize = 4; + } + LOGD("Using a cache for biomegen of size %d.", CacheSize); + m_UnderlyingBiomeGen = m_BiomeGen; + if (MultiCacheLength > 0) + { + LOGD("Enabling multicache for biomegen of length %d.", MultiCacheLength); + m_BiomeGen = new cBioGenMulticache(m_UnderlyingBiomeGen, CacheSize, MultiCacheLength); + } + else { - if (CacheSize < 4) - { - LOGWARNING("Biomegen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d", - CacheSize, 4 - ); - CacheSize = 4; - } - LOGD("Using a cache for biomegen of size %d.", CacheSize); - m_UnderlyingBiomeGen = m_BiomeGen; m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize); } } diff --git a/src/Item.cpp b/src/Item.cpp index 2c5deaddf..ebdf99ca5 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -190,31 +190,35 @@ void cItem::FromJson(const Json::Value & a_Value) -bool cItem::IsEnchantable(short item) +bool cItem::IsEnchantable(short a_ItemType, bool a_WithBook) { - if ((item >= 256) && (item <= 259)) + if ( + ItemCategory::IsAxe(a_ItemType) || + ItemCategory::IsSword(a_ItemType) || + ItemCategory::IsShovel(a_ItemType) || + ItemCategory::IsPickaxe(a_ItemType) || + (a_WithBook && ItemCategory::IsHoe(a_ItemType)) || + ItemCategory::IsArmor(a_ItemType) + ) { return true; } - if ((item >= 267) && (item <= 279)) - { - return true; - } - if ((item >= 283) && (item <= 286)) - { - return true; - } - if ((item >= 290) && (item <= 294)) - { - return true; - } - if ((item >= 298) && (item <= 317)) - { - return true; - } - if ((item == 346) || (item == 359) || (item == 261)) + + switch (a_ItemType) { - return true; + case E_ITEM_BOOK: + case E_ITEM_BOW: + case E_ITEM_FISHING_ROD: + { + return true; + } + + case E_ITEM_CARROT_ON_STICK: + case E_ITEM_SHEARS: + case E_ITEM_FLINT_AND_STEEL: + { + return a_WithBook; + } } return false; @@ -299,73 +303,77 @@ int cItem::GetEnchantability() bool cItem::EnchantByXPLevels(int a_NumXPLevels) { - if (!cItem::IsEnchantable(m_ItemType) && (m_ItemType != E_ITEM_BOOK)) + if (!cItem::IsEnchantable(m_ItemType)) { return false; } int Enchantability = GetEnchantability(); + if (Enchantability == 0) + { + return false; + } cFastRandom Random; int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1; float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F; int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F); - cWeightedEnchantments enchantments; - cEnchantments::AddItemEnchantmentWeights(enchantments, m_ItemType, FinalEnchantmentLevel); + cWeightedEnchantments Enchantments; + cEnchantments::AddItemEnchantmentWeights(Enchantments, m_ItemType, FinalEnchantmentLevel); if (m_ItemType == E_ITEM_BOOK) { m_ItemType = E_ITEM_ENCHANTED_BOOK; } - cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment1.ToString()); - cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment1); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment1); // Checking for conflicting enchantments - cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment1); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment1); float NewEnchantmentLevel = (float)a_NumXPLevels; // Next Enchantment (Second) NewEnchantmentLevel = NewEnchantmentLevel / 2; float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; - if (enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance)) + if (Enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance)) { return true; } - cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment2.ToString()); - cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment2); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment2); // Checking for conflicting enchantments - cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment2); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment2); // Next Enchantment (Third) NewEnchantmentLevel = NewEnchantmentLevel / 2; float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; - if (enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance)) + if (Enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance)) { return true; } - cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment3.ToString()); - cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment3); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment3); // Checking for conflicting enchantments - cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment3); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment3); // Next Enchantment (Fourth) NewEnchantmentLevel = NewEnchantmentLevel / 2; float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; - if (enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance)) + if (Enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance)) { return true; } - cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment4.ToString()); return true; diff --git a/src/Item.h b/src/Item.h index d8b9e78a0..056b5eb8a 100644 --- a/src/Item.h +++ b/src/Item.h @@ -183,8 +183,10 @@ public: /** Loads the item data from JSON representation */ void FromJson(const Json::Value & a_Value); - /** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */ - static bool IsEnchantable(short a_ItemType); // tolua_export + /** Returns true if the specified item type is enchantable. + If WithBook is true, the function is used in the anvil inventory with book enchantments. + So it checks the "only book enchantments" too. Example: You can only enchant a hoe with a book. */ + static bool IsEnchantable(short a_ItemType, bool a_WithBook = false); // tolua_export /** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */ int GetEnchantability(); // tolua_export diff --git a/src/Items/ItemFood.h b/src/Items/ItemFood.h index 98050cad8..9035344df 100644 --- a/src/Items/ItemFood.h +++ b/src/Items/ItemFood.h @@ -29,7 +29,7 @@ public: switch (m_ItemType) { // Please keep alpha-sorted. - case E_ITEM_BAKED_POTATO: return FoodInfo(6, 7.2); + case E_ITEM_BAKED_POTATO: return FoodInfo(5, 7.2); case E_ITEM_BREAD: return FoodInfo(5, 6); // Carrots handled in ItemSeeds case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2); @@ -43,14 +43,16 @@ public: case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2); // Potatoes handled in ItemSeeds case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8); + case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4); case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8); case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2); case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2); + case E_ITEM_RAW_MUTTON: return FoodInfo(2, 1.2); case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8); - case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4); case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8); case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2); case E_ITEM_STEAK: return FoodInfo(8, 12.8); + case E_ITEM_MUTTON: return FoodInfo(6, 9.6); } LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType); return FoodInfo(0, 0.f); diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index bceedaf69..67c945ce4 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -207,7 +207,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) } // Food (please keep alpha-sorted): - // (carrots and potatoes handled in SeedHandler as both seed and food + // (carrots and potatoes handled separately in SeedHandler as they're both seed and food) case E_ITEM_BAKED_POTATO: case E_ITEM_BREAD: case E_ITEM_COOKED_CHICKEN: @@ -217,13 +217,15 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_GOLDEN_CARROT: case E_ITEM_MELON_SLICE: case E_ITEM_MUSHROOM_SOUP: + case E_ITEM_MUTTON: case E_ITEM_POISONOUS_POTATO: case E_ITEM_PUMPKIN_PIE: + case E_ITEM_RED_APPLE: case E_ITEM_RAW_BEEF: case E_ITEM_RAW_CHICKEN: case E_ITEM_RAW_FISH: + case E_ITEM_RAW_MUTTON: case E_ITEM_RAW_PORKCHOP: - case E_ITEM_RED_APPLE: case E_ITEM_ROTTEN_FLESH: case E_ITEM_SPIDER_EYE: case E_ITEM_STEAK: diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h index 54a1183d7..e1db7c5f4 100644 --- a/src/Items/ItemSeeds.h +++ b/src/Items/ItemSeeds.h @@ -37,7 +37,7 @@ public: { switch (m_ItemType) { - case E_ITEM_CARROT: return FoodInfo(4, 4.8); + case E_ITEM_CARROT: return FoodInfo(3, 4.8); case E_ITEM_POTATO: return FoodInfo(1, 0.6); default: return FoodInfo(0, 0); } diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp index 9fb47201d..1a82115d2 100644 --- a/src/Mobs/Sheep.cpp +++ b/src/Mobs/Sheep.cpp @@ -39,6 +39,13 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer) { a_Drops.push_back(cItem(E_BLOCK_WOOL, 1, m_WoolColor)); } + + int LootingLevel = 0; + if (a_Killer != NULL) + { + LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); + } + AddRandomDropItem(a_Drops, 1, 3 + LootingLevel, IsOnFire() ? E_ITEM_MUTTON : E_ITEM_RAW_MUTTON); } diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index bfe59fbcb..707dfb9e8 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -44,7 +44,6 @@ cSetChunkData::cSetChunkData( // Check the params' validity: ASSERT(a_BlockTypes != NULL); ASSERT(a_BlockMetas != NULL); - ASSERT(a_Biomes != NULL); // Copy block types and metas: memcpy(m_BlockTypes, a_BlockTypes, sizeof(cChunkDef::BlockTypes)); diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index 71d64e71e..af9f1687f 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -180,3 +180,65 @@ extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & + +extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed) +{ + a_Uncompressed.reserve(a_Length); + + char Buffer[64 KiB]; + z_stream strm; + memset(&strm, 0, sizeof(strm)); + strm.next_in = (Bytef *)a_Data; + strm.avail_in = (uInt)a_Length; + strm.next_out = (Bytef *)Buffer; + strm.avail_out = sizeof(Buffer); + + int res = inflateInit(&strm); // Force GZIP decoding + if (res != Z_OK) + { + LOG("%s: inflation initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg); + return res; + } + + for (;;) + { + res = inflate(&strm, Z_NO_FLUSH); + switch (res) + { + case Z_OK: + { + // Some data has been uncompressed. Consume the buffer and continue uncompressing + a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out); + strm.next_out = (Bytef *)Buffer; + strm.avail_out = sizeof(Buffer); + if (strm.avail_in == 0) + { + // All data has been uncompressed + inflateEnd(&strm); + return Z_OK; + } + break; + } + + case Z_STREAM_END: + { + // Finished uncompressing. Consume the rest of the buffer and return + a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out); + inflateEnd(&strm); + return Z_OK; + } + + default: + { + // An error has occurred, log it and return the error value + LOG("%s: inflation failed: %d (\"%s\").", __FUNCTION__, res, strm.msg); + inflateEnd(&strm); + return res; + } + } // switch (res) + } // while (true) +} + + + + diff --git a/src/StringCompression.h b/src/StringCompression.h index 038240797..dde17ce30 100644 --- a/src/StringCompression.h +++ b/src/StringCompression.h @@ -21,5 +21,7 @@ extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_ /// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed); +/** Uncompresses a_Data into a_Uncompressed using Inflate; returns Z_OK for success or Z_XXX error constants same as zlib */ +extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed); diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 4199bbf56..b4facb2d3 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -207,7 +207,7 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ m_ParentWindow.DistributeStack(Slot, a_Player, this, true); if (Slot.IsEmpty()) { - // Empty the slot completely, the cilent doesn't like left-over ItemType with zero count + // Empty the slot completely, the client doesn't like left-over ItemType with zero count Slot.Empty(); } SetSlot(a_SlotNum, a_Player, Slot); @@ -1389,8 +1389,11 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) //////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnchanting: -cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) : - cSlotAreaTemporary(1, a_ParentWindow) +cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) : + cSlotAreaTemporary(1, a_ParentWindow), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) { a_ParentWindow.m_SlotArea = this; } @@ -1409,7 +1412,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); return; } - + switch (a_ClickAction) { case caShiftLeftClick: @@ -1428,6 +1431,25 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio MiddleClicked(a_Player, a_SlotNum); return; } + case caDropKey: + case caCtrlDropKey: + { + DropClicked(a_Player, a_SlotNum, false); + return; + } + case caNumber1: + case caNumber2: + case caNumber3: + case caNumber4: + case caNumber5: + case caNumber6: + case caNumber7: + case caNumber8: + case caNumber9: + { + NumberClicked(a_Player, a_SlotNum, a_ClickAction); + return; + } default: { break; @@ -1443,106 +1465,36 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio bAsync = true; } cItem & DraggingItem = a_Player.GetDraggingItem(); - switch (a_ClickAction) + + if (DraggingItem.IsEmpty()) { - case caRightClick: + // DraggingItem is empty -> Switch draggingitem and slot + if (!Slot.IsEmpty()) { - // Right-clicked - if (DraggingItem.IsEmpty()) - { - DraggingItem = Slot.CopyOne(); - Slot.Empty(); - break; - } - - if (Slot.IsEmpty()) - { - Slot = DraggingItem.CopyOne(); - DraggingItem.m_ItemCount -= 1; - if (DraggingItem.m_ItemCount <= 0) - { - DraggingItem.Empty(); - } - } - else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1)) - { - // Swap contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; - } - break; + std::swap(DraggingItem, Slot); } - - case caLeftClick: - { - // Left-clicked - if (DraggingItem.IsEmpty()) - { - DraggingItem = Slot.CopyOne(); - Slot.Empty(); - break; - } - - if (DraggingItem.IsEqual(Slot)) - { - // Do nothing - break; - } - - if (!Slot.IsEmpty()) - { - if (DraggingItem.m_ItemCount == 1) - { - // Swap contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; - } - } - else - { - Slot = DraggingItem.CopyOne(); - DraggingItem.m_ItemCount -= 1; - if (DraggingItem.m_ItemCount <= 0) - { - DraggingItem.Empty(); - } - } - break; - } - default: + } + else if (Slot.IsEmpty()) + { + // DraggingItem isn't empty and slot is empty -> Set one dragging item in the slot + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + + if (DraggingItem.m_ItemCount <= 0) { - LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); - m_ParentWindow.BroadcastWholeWindow(); - return; + DraggingItem.Empty(); } - } // switch (a_ClickAction - - SetSlot(a_SlotNum, a_Player, Slot); - if (bAsync) - { - m_ParentWindow.BroadcastWholeWindow(); } - UpdateResult(a_Player); -} - - - - - -void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum) -{ - cItem & Dragging = a_Player.GetDraggingItem(); - if ((!Dragging.IsEmpty()) || (a_SlotNum != 0)) + else if ((DraggingItem.m_ItemCount == 1) && !DraggingItem.IsEqual(Slot)) { - return; + // DraggingItem and slot aren't empty -> Switch items + std::swap(DraggingItem, Slot); } - - cItem Item = *GetSlot(0, a_Player); - if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false)) + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) { - m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true); + m_ParentWindow.BroadcastWholeWindow(); } } @@ -1567,7 +1519,15 @@ void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Playe { a_ItemStack.Empty(); } +} + + + + +void cSlotAreaEnchanting::OnPlayerAdded(cPlayer & a_Player) +{ + super::OnPlayerAdded(a_Player); UpdateResult(a_Player); } @@ -1587,29 +1547,33 @@ void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player) +void cSlotAreaEnchanting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) +{ + super::SetSlot(a_SlotNum, a_Player, a_Item); + UpdateResult(a_Player); +} + + + + + void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player) { cItem Item = *GetSlot(0, a_Player); - if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty()) - { - m_ParentWindow.SetProperty(0, 0, a_Player); - m_ParentWindow.SetProperty(1, 0, a_Player); - m_ParentWindow.SetProperty(2, 0, a_Player); - } - else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK) + if (cItem::IsEnchantable(Item.m_ItemType) && Item.m_Enchantments.IsEmpty()) { int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15); cFastRandom Random; - int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves)); - int topSlot = std::max(base / 3, 1); - int middleSlot = (base * 2) / 3 + 1; - int bottomSlot = std::max(base, Bookshelves * 2); + int Base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves)); + int TopSlot = std::max(Base / 3, 1); + int MiddleSlot = (Base * 2) / 3 + 1; + int BottomSlot = std::max(Base, Bookshelves * 2); - m_ParentWindow.SetProperty(0, topSlot, a_Player); - m_ParentWindow.SetProperty(1, middleSlot, a_Player); - m_ParentWindow.SetProperty(2, bottomSlot, a_Player); + m_ParentWindow.SetProperty(0, TopSlot, a_Player); + m_ParentWindow.SetProperty(1, MiddleSlot, a_Player); + m_ParentWindow.SetProperty(2, BottomSlot, a_Player); } else { @@ -1625,12 +1589,9 @@ void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player) int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World) { - int PosX, PosY, PosZ; - ((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); - int Bookshelves = 0; cBlockArea Area; - Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2); + Area.Read(a_World, m_BlockX - 2, m_BlockX + 2, m_BlockY, m_BlockY + 1, m_BlockZ - 2, m_BlockZ + 2); static const struct { @@ -1678,7 +1639,7 @@ int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World) if ( (Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot (Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place - ) + ) { Bookshelves++; } diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 9a96f2f3c..6bbc87b76 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -349,14 +349,15 @@ class cSlotAreaEnchanting : typedef cSlotAreaTemporary super; public: - cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow); + cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ); // cSlotArea overrides: virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override; virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; // cSlotAreaTemporary overrides: + virtual void OnPlayerAdded (cPlayer & a_Player) override; virtual void OnPlayerRemoved(cPlayer & a_Player) override; /* Get the count of bookshelves who stand in the near of the enchanting table */ @@ -365,6 +366,8 @@ public: protected: /** Handles a click in the item slot. */ void UpdateResult(cPlayer & a_Player); + + int m_BlockX, m_BlockY, m_BlockZ; }; diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 8f4913030..66900269f 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -881,7 +881,7 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : m_BlockY(a_BlockY), m_BlockZ(a_BlockZ) { - m_SlotAreas.push_back(new cSlotAreaEnchanting(*this)); + m_SlotAreas.push_back(new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } @@ -892,8 +892,13 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : void cEnchantingWindow::SetProperty(int a_Property, int a_Value) { - m_PropertyValue[a_Property] = a_Value; + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return; + } + m_PropertyValue[a_Property] = a_Value; super::SetProperty(a_Property, a_Value); } @@ -903,8 +908,13 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value) void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) { - m_PropertyValue[a_Property] = a_Value; + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return; + } + m_PropertyValue[a_Property] = a_Value; super::SetProperty(a_Property, a_Value, a_Player); } @@ -914,18 +924,13 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Pla int cEnchantingWindow::GetPropertyValue(int a_Property) { - return m_PropertyValue[a_Property]; -} - - - - + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return 0; + } -void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) -{ - a_PosX = m_BlockX; - a_PosY = m_BlockY; - a_PosZ = m_BlockZ; + return m_PropertyValue[a_Property]; } diff --git a/src/UI/Window.h b/src/UI/Window.h index 9fb0e3b38..3d860407f 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -291,9 +291,6 @@ public: /** Return the Value of a Property */ int GetPropertyValue(int a_Property); - /** Get the Position from the Enchantment Table */ - void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); - cSlotArea * m_SlotArea; protected: diff --git a/src/World.cpp b/src/World.cpp index 99e09c658..e669f6fa0 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -442,7 +442,7 @@ void cWorld::InitializeSpawn(void) { for (int z = 0; z < ViewDist; z++) { - m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader + m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader } } @@ -2374,6 +2374,8 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) void cWorld::QueueSetChunkData(const cSetChunkDataPtr & a_SetChunkData) { + ASSERT(IsChunkQueued(a_SetChunkData->GetChunkX(), a_SetChunkData->GetChunkZ())); + // Validate biomes, if needed: if (!a_SetChunkData->AreBiomesValid()) { @@ -2424,7 +2426,7 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) // Save the chunk right after generating, so that we don't have to generate it again on next run if (a_SetChunkData.ShouldMarkDirty()) { - m_Storage.QueueSaveChunk(ChunkX, 0, ChunkZ); + m_Storage.QueueSaveChunk(ChunkX, ChunkZ); } } @@ -2463,6 +2465,15 @@ bool cWorld::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockT +bool cWorld::IsChunkQueued(int a_ChunkX, int a_ChunkZ) const +{ + return m_ChunkMap->IsChunkQueued(a_ChunkX, a_ChunkZ); +} + + + + + bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkZ) const { return m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkZ); @@ -2696,6 +2707,15 @@ bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & +bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) +{ + return m_ChunkMap->ForEachEntityInBox(a_Box, a_Callback); +} + + + + + bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) { return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback); @@ -2769,36 +2789,18 @@ void cWorld::RemoveClientFromChunkSender(cClientHandle * a_Client) -void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -{ - m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkY, a_ChunkZ); -} - - - - - -bool cWorld::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -{ - return m_ChunkMap->LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ); -} - - - - - -void cWorld::LoadChunks(const cChunkCoordsList & a_Chunks) +void cWorld::TouchChunk(int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->LoadChunks(a_Chunks); + m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkZ); } -void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkZ); } @@ -2903,8 +2905,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) { m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ); - // Trick: use Y=1 to force the chunk generation even though the chunk data is already present - m_Generator.QueueGenerateChunk(a_ChunkX, 1, a_ChunkZ); + m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ, true); } @@ -2913,7 +2914,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) { - m_Generator.QueueGenerateChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ, false); } @@ -3512,6 +3513,15 @@ bool cWorld::cChunkGeneratorCallbacks::IsChunkValid(int a_ChunkX, int a_ChunkZ) +bool cWorld::cChunkGeneratorCallbacks::IsChunkQueued(int a_ChunkX, int a_ChunkZ) +{ + return m_World->IsChunkQueued(a_ChunkX, a_ChunkZ); +} + + + + + bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) { return m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ); diff --git a/src/World.h b/src/World.h index 578c9682b..6316c6811 100644 --- a/src/World.h +++ b/src/World.h @@ -279,7 +279,12 @@ public: /** Gets the chunk's blocks, only the block types */ bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); - bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; + /** Returns true iff the chunk is in the loader / generator queue. */ + bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) const; + + /** Returns true iff the chunk is present and valid. */ + bool IsChunkValid(int a_ChunkX, int a_ChunkZ) const; + bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const; /** Queues a task to unload unused chunks onto the tick thread. The prefferred way of unloading*/ @@ -324,6 +329,11 @@ public: /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. + Returns true if all entities processed, false if the callback aborted by returning true. + If any chunk in the box is missing, ignores the entities in that chunk silently. */ + bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */ bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp @@ -351,16 +361,10 @@ public: void RemoveClientFromChunkSender(cClientHandle * a_Client); /** Touches the chunk, causing it to be loaded or generated */ - void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */ - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */ - void LoadChunks(const cChunkCoordsList & a_Chunks); + void TouchChunk(int a_ChunkX, int a_ChunkZ); /** Marks the chunk as failed-to-load: */ - void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ); /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp @@ -380,7 +384,7 @@ public: /** Regenerate the given chunk: */ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - /** Generates the given chunk, if not already generated */ + /** Generates the given chunk */ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export /** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */ @@ -817,6 +821,7 @@ private: virtual void OnChunkGenerated (cChunkDesc & a_ChunkDesc) override; virtual bool IsChunkValid (int a_ChunkX, int a_ChunkZ) override; virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) override; + virtual bool IsChunkQueued (int a_ChunkX, int a_ChunkZ) override; // cPluginInterface overrides: virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) override; diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index e79cc291d..f78ee405b 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -66,8 +66,17 @@ Since only the header is actually in the memory, this number can be high, but st */ #define MAX_MCA_FILES 32 -/// The maximum size of an inflated chunk; raw chunk data is 192 KiB, allow 64 KiB more of entities -#define CHUNK_INFLATE_MAX 256 KiB +#define LOAD_FAILED(CHX, CHZ) \ + { \ + const int RegionX = FAST_FLOOR_DIV(CHX, 32); \ + const int RegionZ = FAST_FLOOR_DIV(CHZ, 32); \ + LOGERROR("%s (%d): Loading chunk [%d, %d] from file r.%d.%d.mca failed. " \ + "The server will now abort in order to avoid further data loss. " \ + "Please add the reported file and this message to the issue report.", \ + __FUNCTION__, __LINE__, CHX, CHZ, RegionX, RegionZ \ + ); \ + *((volatile int *)0) = 0; /* Crash intentionally */ \ + } @@ -248,29 +257,22 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk) bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data) { - // Decompress the data: - char Uncompressed[CHUNK_INFLATE_MAX]; - z_stream strm; - strm.zalloc = (alloc_func)NULL; - strm.zfree = (free_func)NULL; - strm.opaque = NULL; - inflateInit(&strm); - strm.next_out = (Bytef *)Uncompressed; - strm.avail_out = sizeof(Uncompressed); - strm.next_in = (Bytef *)a_Data.data(); - strm.avail_in = (uInt)a_Data.size(); - int res = inflate(&strm, Z_FINISH); - inflateEnd(&strm); - if (res != Z_STREAM_END) + // Uncompress the data: + AString Uncompressed; + int res = InflateString(a_Data.data(), a_Data.size(), Uncompressed); + if (res != Z_OK) { + LOGWARNING("Uncompressing chunk [%d, %d] failed: %d", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, res); + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } // Parse the NBT data: - cParsedNBT NBT(Uncompressed, strm.total_out); + cParsedNBT NBT(Uncompressed.data(), Uncompressed.size()); if (!NBT.IsValid()) { // NBT Parsing failed + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } @@ -317,11 +319,19 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT int Level = a_NBT.FindChildByName(0, "Level"); if (Level < 0) { + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } int Sections = a_NBT.FindChildByName(Level, "Sections"); - if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List) || (a_NBT.GetChildrenType(Sections) != TAG_Compound)) + if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List)) + { + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + return false; + } + eTagType SectionsType = a_NBT.GetChildrenType(Sections); + if ((SectionsType != TAG_Compound) && (SectionsType != TAG_End)) { + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child)) @@ -585,7 +595,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con // Get the BlockEntity's position int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, Child, x, y, z)) + if (!GetBlockEntityNBTPos(a_NBT, Child, x, y, z) || (y < 0) || (y >= cChunkDef::Height)) { LOGWARNING("Bad block entity, missing the coords. Will be ignored."); continue; @@ -2811,30 +2821,42 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a } unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]); unsigned ChunkOffset = ChunkLocation >> 8; + if (ChunkOffset <= 2) + { + return false; + } m_File.Seek((int)ChunkOffset * 4096); int ChunkSize = 0; if (m_File.Read(&ChunkSize, 4) != 4) { + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } ChunkSize = ntohl((u_long)ChunkSize); char CompressionType = 0; if (m_File.Read(&CompressionType, 1) != 1) { + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } if (CompressionType != 2) { // Chunk is in an unknown compression + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } ChunkSize--; // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly a_Data.assign(ChunkSize, '\0'); - return (m_File.Read((void *)a_Data.data(), ChunkSize) == ChunkSize); + if (m_File.Read((void *)a_Data.data(), ChunkSize) == ChunkSize) + { + return true; + } + LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); + return false; } @@ -2889,7 +2911,13 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri // Store the header: ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number - ASSERT(ChunkSize < 256); + if (ChunkSize > 255) + { + LOGWARNING("Cannot save chunk [%d, %d], the data is too large (%u KiB, maximum is 1024 KiB). Remove some entities and retry.", + a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, (unsigned)(ChunkSize * 4) + ); + return false; + } m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize); if (m_File.Seek(0) < 0) { diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index 58f9e3cab..6760186b2 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -980,7 +980,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer)) { // Chunk not valid - LOG("cWSSCompact: Trying to save chunk [%d, %d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); + LOG("cWSSCompact: Trying to save chunk [%d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } @@ -999,7 +999,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor); if (errorcode != Z_OK) { - LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); + LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } @@ -1010,7 +1010,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld sChunkHeader * Header = new sChunkHeader; if (Header == NULL) { - LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); + LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } Header->m_CompressedSize = (int)CompressedData.size(); diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 707e8f929..179cf9393 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -141,9 +141,11 @@ size_t cWorldStorage::GetSaveQueueLength(void) -void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) +void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ) { - m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); + ASSERT(m_World->IsChunkQueued(a_ChunkX, a_ChunkZ)); + + m_LoadQueue.EnqueueItem(cChunkCoords(a_ChunkX, a_ChunkZ)); m_Event.Set(); } @@ -151,9 +153,11 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, boo -void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ) { - m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + ASSERT(m_World->IsChunkValid(a_ChunkX, a_ChunkZ)); + + m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkZ)); m_Event.Set(); } @@ -161,9 +165,9 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ) { - m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, true)); + m_LoadQueue.Remove(cChunkCoords(a_ChunkX, a_ChunkZ)); } @@ -242,22 +246,14 @@ void cWorldStorage::Execute(void) bool cWorldStorage::LoadOneChunk(void) { - sChunkLoad ToLoad(0, 0, 0, false); + cChunkCoords ToLoad(0, 0); bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad); - if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ)) + + if (ShouldLoad) { - if (ToLoad.m_Generate) - { - // The chunk couldn't be loaded, generate it: - m_World->GetGenerator().QueueGenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); - } - else - { - // TODO: Notify the world that the load has failed: - // m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); - } + return LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ); } - return ShouldLoad; + return false; } @@ -266,7 +262,7 @@ bool cWorldStorage::LoadOneChunk(void) bool cWorldStorage::SaveOneChunk(void) { - cChunkCoords ToSave(0, 0, 0); + cChunkCoords ToSave(0, 0); bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave); if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ)) { @@ -283,15 +279,11 @@ bool cWorldStorage::SaveOneChunk(void) -bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkZ) { - if (m_World->IsChunkValid(a_ChunkX, a_ChunkZ)) - { - // Already loaded (can happen, since the queue is async) - return true; - } + ASSERT(m_World->IsChunkQueued(a_ChunkX, a_ChunkZ)); - cChunkCoords Coords(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkCoords Coords(a_ChunkX, a_ChunkZ); // First try the schema that is used for saving if (m_SaveSchema->LoadChunk(Coords)) @@ -309,7 +301,7 @@ bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) } // Notify the chunk owner that the chunk failed to load (sets cChunk::m_HasLoadFailed to true): - m_World->ChunkLoadFailed(a_ChunkX, a_ChunkY, a_ChunkZ); + m_World->ChunkLoadFailed(a_ChunkX, a_ChunkZ); return false; } diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index dd07ecb64..fc7e9f84c 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -64,13 +64,10 @@ public: cWorldStorage(void); ~cWorldStorage(); - void QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate); // Queues the chunk for loading; if not loaded, the chunk will be generated if a_Generate is true - void QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void QueueLoadChunk(int a_ChunkX, int a_ChunkZ); + void QueueSaveChunk(int a_ChunkX, int a_ChunkZ); - /// Loads the chunk specified; returns true on success, false on failure - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void UnqueueLoad(int a_ChunkX, int a_ChunkZ); void UnqueueSave(const cChunkCoords & a_Chunk); bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args @@ -84,40 +81,10 @@ public: protected: - struct sChunkLoad - { - int m_ChunkX; - int m_ChunkY; - int m_ChunkZ; - bool m_Generate; // If true, the chunk will be generated if it cannot be loaded - - sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {} - - bool operator ==(const sChunkLoad other) const - { - return ( - (this->m_ChunkX == other.m_ChunkX) && - (this->m_ChunkY == other.m_ChunkY) && - (this->m_ChunkZ == other.m_ChunkZ) - ); - } - } ; - - struct FuncTable - { - static void Delete(sChunkLoad) {} - static void Combine(sChunkLoad & a_orig, const sChunkLoad a_new) - { - a_orig.m_Generate |= a_new.m_Generate; - } - }; - - typedef cQueue<sChunkLoad, FuncTable> sChunkLoadQueue; - cWorld * m_World; AString m_StorageSchemaName; - sChunkLoadQueue m_LoadQueue; + cChunkCoordsQueue m_LoadQueue; cChunkCoordsQueue m_SaveQueue; /// All the storage schemas (all used for loading) @@ -125,7 +92,11 @@ protected: /// The one storage schema used for saving cWSSchema * m_SaveSchema; + + /// Loads the chunk specified; returns true on success, false on failure + bool LoadChunk(int a_ChunkX, int a_ChunkZ); + void InitSchemas(int a_StorageCompressionFactor); virtual void Execute(void) override; |