diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Bindings/LuaState.cpp | 12 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 1 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 410 | ||||
-rw-r--r-- | src/Bindings/ManualBindings_World.cpp | 55 | ||||
-rw-r--r-- | src/Blocks/BlockPiston.cpp | 25 | ||||
-rw-r--r-- | src/Mobs/Guardian.cpp | 2 | ||||
-rw-r--r-- | src/Mobs/Monster.cpp | 45 | ||||
-rw-r--r-- | src/Mobs/Monster.h | 15 | ||||
-rw-r--r-- | src/Mobs/Squid.cpp | 2 | ||||
-rw-r--r-- | src/OSSupport/File.cpp | 206 | ||||
-rw-r--r-- | src/OSSupport/File.h | 75 | ||||
-rw-r--r-- | src/Protocol/Protocol18x.cpp | 14 | ||||
-rw-r--r-- | src/World.cpp | 216 | ||||
-rw-r--r-- | src/World.h | 110 |
14 files changed, 778 insertions, 410 deletions
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 4c0dfa676..c9e7815ca 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -676,6 +676,18 @@ void cLuaState::Push(int a_Value) +void cLuaState::Push(long a_Value) +{ + ASSERT(IsValid()); + + tolua_pushnumber(m_LuaState, static_cast<lua_Number>(a_Value)); + m_NumCurrentFunctionArgs += 1; +} + + + + + void cLuaState::Push(UInt32 a_Value) { ASSERT(IsValid()); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 759fdc54f..269a10369 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -248,6 +248,7 @@ public: void Push(cLuaUDPEndpoint * a_UDPEndpoint); void Push(double a_Value); void Push(int a_Value); + void Push(long a_Value); void Push(const UInt32 a_Value); void Push(void * a_Ptr); void Push(std::chrono::milliseconds a_time); diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 3fc5b477c..7e6839fdf 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -482,8 +482,258 @@ cPluginLua * cManualBindings::GetLuaPlugin(lua_State * L) +static int tolua_cFile_ChangeFileExt(lua_State * tolua_S) +{ + // API signature: + // ChangeFileExt(string, string) -> string + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2, 3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Execute: + AString FileName, NewExt; + ASSERT(L.GetStackValues(2, FileName, NewExt)); + L.Push(cFile::ChangeFileExt(FileName, NewExt)); + return 1; +} + + + + + +static int tolua_cFile_Copy(lua_State * tolua_S) +{ + // API signature: + // cFile:Copy(string, string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2, 3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Execute: + AString SrcFile, DstFile; + ASSERT(L.GetStackValues(2, SrcFile, DstFile)); + L.Push(cFile::Copy(SrcFile, DstFile)); + return 1; +} + + + + + +static int tolua_cFile_CreateFolder(lua_State * tolua_S) +{ + // API signature: + // cFile:CreateFolder(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString FolderPath; + ASSERT(L.GetStackValues(2, FolderPath)); + L.Push(cFile::CreateFolder(FolderPath)); + return 1; +} + + + + + +static int tolua_cFile_CreateFolderRecursive(lua_State * tolua_S) +{ + // API signature: + // cFile:CreateFolderRecursive(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString FolderPath; + ASSERT(L.GetStackValues(2, FolderPath)); + L.Push(cFile::CreateFolderRecursive(FolderPath)); + return 1; +} + + + + + +static int tolua_cFile_Delete(lua_State * tolua_S) +{ + // API signature: + // cFile:Delete(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::Delete(Path)); + return 1; +} + + + + + +static int tolua_cFile_DeleteFile(lua_State * tolua_S) +{ + // API signature: + // cFile:DeleteFile(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::DeleteFile(Path)); + return 1; +} + + + + + +static int tolua_cFile_DeleteFolder(lua_State * tolua_S) +{ + // API signature: + // cFile:DeleteFolder(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::DeleteFolder(Path)); + return 1; +} + + + + + +static int tolua_cFile_DeleteFolderContents(lua_State * tolua_S) +{ + // API signature: + // cFile:DeleteFolderContents(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::DeleteFolderContents(Path)); + return 1; +} + + + + + +static int tolua_cFile_Exists(lua_State * tolua_S) +{ + // API signature: + // cFile:Exists(string) -> bool + + // Obsolete, use IsFile() or IsFolder() instead + cLuaState L(tolua_S); + LOGWARNING("cFile:Exists() is obsolete, use cFile:IsFolder() or cFile:IsFile() instead!"); + L.LogStackTrace(); + + // Check params: + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::Exists(Path)); + return 1; +} + + + + + static int tolua_cFile_GetFolderContents(lua_State * tolua_S) { + // API signature: + // cFile:GetFolderContents(string) -> {string, string, ...} + // Check params: cLuaState LuaState(tolua_S); if ( @@ -497,7 +747,7 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) // Get params: AString Folder; - LuaState.GetStackValues(2, Folder); + ASSERT(LuaState.GetStackValues(2, Folder)); // Execute and push result: LuaState.Push(cFile::GetFolderContents(Folder)); @@ -508,8 +758,119 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) +static int tolua_cFile_GetLastModificationTime(lua_State * tolua_S) +{ + // API signature: + // cFile:GetLastModificationTime(string) -> number + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::GetLastModificationTime(Path)); + return 1; +} + + + + + +static int tolua_cFile_GetSize(lua_State * tolua_S) +{ + // API signature: + // cFile:GetSize(string) -> number + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::GetSize(Path)); + return 1; +} + + + + + +static int tolua_cFile_IsFile(lua_State * tolua_S) +{ + // API signature: + // cFile:IsFile(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::IsFile(Path)); + return 1; +} + + + + + +static int tolua_cFile_IsFolder(lua_State * tolua_S) +{ + // API signature: + // cFile:IsFolder(string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Execute: + AString Path; + ASSERT(L.GetStackValues(2, Path)); + L.Push(cFile::IsFolder(Path)); + return 1; +} + + + + + static int tolua_cFile_ReadWholeFile(lua_State * tolua_S) { + // API signature: + // cFile:ReadWholeFile(string) -> string + // Check params: cLuaState LuaState(tolua_S); if ( @@ -523,7 +884,7 @@ static int tolua_cFile_ReadWholeFile(lua_State * tolua_S) // Get params: AString FileName; - LuaState.GetStackValues(2, FileName); + ASSERT(LuaState.GetStackValues(2, FileName)); // Execute and push result: LuaState.Push(cFile::ReadWholeFile(FileName)); @@ -534,6 +895,33 @@ static int tolua_cFile_ReadWholeFile(lua_State * tolua_S) +static int tolua_cFile_Rename(lua_State * tolua_S) +{ + // API signature: + // cFile:Rename(string, string) -> bool + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cFile") || + !L.CheckParamString(2, 3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Execute: + AString SrcPath, DstPath; + ASSERT(L.GetStackValues(2, SrcPath, DstPath)); + L.Push(cFile::Rename(SrcPath, DstPath)); + return 1; +} + + + + + static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) { // API function no longer available: @@ -2846,8 +3234,22 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cFile"); - tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); - tolua_function(tolua_S, "ReadWholeFile", tolua_cFile_ReadWholeFile); + tolua_function(tolua_S, "ChangeFileExt", tolua_cFile_ChangeFileExt); + tolua_function(tolua_S, "Copy", tolua_cFile_Copy); + tolua_function(tolua_S, "CreateFolder", tolua_cFile_CreateFolder); + tolua_function(tolua_S, "CreateFolderRecursive", tolua_cFile_CreateFolderRecursive); + tolua_function(tolua_S, "Delete", tolua_cFile_Delete); + tolua_function(tolua_S, "DeleteFile", tolua_cFile_DeleteFile); + tolua_function(tolua_S, "DeleteFolder", tolua_cFile_DeleteFolder); + tolua_function(tolua_S, "DeleteFolderContents", tolua_cFile_DeleteFolderContents); + tolua_function(tolua_S, "Exists", tolua_cFile_Exists); + tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); + tolua_function(tolua_S, "GetLastModificationTime", tolua_cFile_GetLastModificationTime); + tolua_function(tolua_S, "GetSize", tolua_cFile_GetSize); + tolua_function(tolua_S, "IsFile", tolua_cFile_IsFile); + tolua_function(tolua_S, "IsFolder", tolua_cFile_IsFolder); + tolua_function(tolua_S, "ReadWholeFile", tolua_cFile_ReadWholeFile); + tolua_function(tolua_S, "Rename", tolua_cFile_Rename); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cHopperEntity"); diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp index 6f8499611..ba80d7130 100644 --- a/src/Bindings/ManualBindings_World.cpp +++ b/src/Bindings/ManualBindings_World.cpp @@ -374,7 +374,6 @@ static int tolua_cWorld_PrepareChunk(lua_State * tolua_S) class cLuaWorldTask : - public cWorld::cTask, public cPluginLua::cResettable { public: @@ -384,11 +383,7 @@ public: { } -protected: - int m_FnRef; - - // cWorld::cTask overrides: - virtual void Run(cWorld & a_World) override + void Run(cWorld & a_World) { cCSLock Lock(m_CSPlugin); if (m_Plugin != nullptr) @@ -396,7 +391,10 @@ protected: m_Plugin->Call(m_FnRef, &a_World); } } -} ; + +protected: + int m_FnRef; +}; @@ -433,9 +431,9 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - auto task = std::make_shared<cLuaWorldTask>(*Plugin, FnRef); - Plugin->AddResettable(task); - self->QueueTask(task); + auto ResettableTask = std::make_shared<cLuaWorldTask>(*Plugin, FnRef); + Plugin->AddResettable(ResettableTask); + self->QueueTask(std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1)); return 0; } @@ -483,35 +481,6 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S) -class cLuaScheduledWorldTask : - public cWorld::cTask, - public cPluginLua::cResettable -{ -public: - cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : - cPluginLua::cResettable(a_Plugin), - m_FnRef(a_FnRef) - { - } - -protected: - int m_FnRef; - - // cWorld::cTask overrides: - virtual void Run(cWorld & a_World) override - { - cCSLock Lock(m_CSPlugin); - if (m_Plugin != nullptr) - { - m_Plugin->Call(m_FnRef, &a_World); - } - } -}; - - - - - static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) { // Binding for cWorld::ScheduleTask @@ -548,11 +517,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - int DelayTicks = static_cast<int>(tolua_tonumber(tolua_S, 2, 0)); - - auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef); - Plugin->AddResettable(task); - World->ScheduleTask(DelayTicks, static_cast<cWorld::cTaskPtr>(task)); + auto ResettableTask = std::make_shared<cLuaWorldTask>(*Plugin, FnRef); + Plugin->AddResettable(ResettableTask); + World->ScheduleTask(static_cast<int>(tolua_tonumber(tolua_S, 2, 0)), std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1)); return 0; } diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 4e4814242..94782a7ed 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -27,7 +27,6 @@ } \ } -#define PISTON_TICK_DELAY 1 #define PISTON_MAX_PUSH_DISTANCE 12 @@ -156,15 +155,12 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, // Push blocks, from the furthest to the nearest: int oldx = a_BlockX, oldy = a_BlockY, oldz = a_BlockZ; NIBBLETYPE currBlockMeta; - std::vector<Vector3i> ScheduledBlocks; - ScheduledBlocks.reserve(PISTON_MAX_PUSH_DISTANCE); for (int i = dist + 1; i > 1; i--) { AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currBlockMeta); - a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta, false); - ScheduledBlocks.push_back(Vector3i(oldx, oldy, oldz)); + a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta); oldx = a_BlockX; oldy = a_BlockY; oldz = a_BlockZ; @@ -173,13 +169,11 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, int extx = a_BlockX; int exty = a_BlockY; int extz = a_BlockZ; - ScheduledBlocks.push_back(Vector3i(extx, exty, extz)); AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); // "a_Block" now at piston body, "ext" at future extension a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8); - a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false); - a_World->ScheduleTask(PISTON_TICK_DELAY, static_cast<cWorld::cTaskPtr>(std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks))); + a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0)); } @@ -223,23 +217,14 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ if (CanPull(tempBlock, tempMeta)) { // Pull the block - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta, false); - a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0, false); - - std::vector<Vector3i> ScheduledBlocks; - ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz)); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, static_cast<cWorld::cTaskPtr>(std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks))); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta); + a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0); return; } } // Retract without pulling - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0, false); - - std::vector<Vector3i> ScheduledBlocks; - ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, static_cast<cWorld::cTaskPtr>(std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks))); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); } diff --git a/src/Mobs/Guardian.cpp b/src/Mobs/Guardian.cpp index 1429e2b13..1bee8fdfb 100644 --- a/src/Mobs/Guardian.cpp +++ b/src/Mobs/Guardian.cpp @@ -37,7 +37,7 @@ void cGuardian::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cGuardian::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { - m_IsFollowingPath = false; // Disable Pathfinding until it's fixed. TODO + m_PathfinderActivated = false; // Disable Pathfinding until it's fixed. TODO // We must first process current location, and only then tick, otherwise we risk processing a location in a chunk // that is not where the entity currently resides (FS #411) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index b28e94ec1..4d9b9ca06 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -78,6 +78,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A , m_IsFollowingPath(false) , m_PathfinderActivated(false) , m_GiveUpCounter(0) + , m_TicksSinceLastPathReset(1000) , m_LastGroundHeight(POSY_TOINT) , m_JumpCoolDown(0) , m_IdleInterval(0) @@ -128,6 +129,11 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) { return false; } + if (m_TicksSinceLastPathReset < 1000) + { + // No need to count beyond 1000. 1000 is arbitary here. + ++m_TicksSinceLastPathReset; + } if (ReachedFinalDestination()) { @@ -135,6 +141,26 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) return false; } + if ((m_FinalDestination - m_PathFinderDestination).Length() > 0.25) // if the distance between where we're going and where we should go is too big. + { + /* If we reached the last path waypoint, + Or if we haven't re-calculated for too long. + Interval is proportional to distance squared, and its minimum is 10. + (Recalculate lots when close, calculate rarely when far) */ + if ( + ((GetPosition() - m_PathFinderDestination).Length() < 0.25) || + ((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.4 * (m_FinalDestination - GetPosition()).SqrLength()))) + ) + { + /* Re-calculating is expensive when there's no path to target, and it results in mobs freezing very often as a result of always recalculating. + This is a workaround till we get better path recalculation. */ + if (!m_NoPathToTarget) + { + ResetPathFinding(); + } + } + } + if (m_Path == nullptr) { if (!EnsureProperDestination(a_Chunk)) @@ -143,16 +169,21 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) return false; } m_GiveUpCounter = 40; - m_Path = new cPath(a_Chunk, GetPosition(), m_FinalDestination, 20, GetWidth(), GetHeight()); + m_NoPathToTarget = false; + m_NoMoreWayPoints = false; + m_PathFinderDestination = m_FinalDestination; + m_Path = new cPath(a_Chunk, GetPosition(), m_PathFinderDestination, 20, GetWidth(), GetHeight()); } switch (m_Path->Step(a_Chunk)) { case ePathFinderStatus::NEARBY_FOUND: { - m_FinalDestination = m_Path->AcceptNearbyPath(); + m_NoPathToTarget = true; + m_PathFinderDestination = m_Path->AcceptNearbyPath(); break; } + case ePathFinderStatus::PATH_NOT_FOUND: { StopMovingToPosition(); // Try to calculate a path again. @@ -166,10 +197,9 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) } case ePathFinderStatus::PATH_FOUND: { - if ((--m_GiveUpCounter) == 0) + if (m_NoMoreWayPoints || (--m_GiveUpCounter == 0)) { - // Failed to reach a waypoint - that's a failure condition whichever point we're at - if (m_EMState == CHASING) + if (m_EMState == ATTACKING) { ResetPathFinding(); // Try to calculate a path again. // This results in mobs hanging around an unreachable target (player). @@ -188,6 +218,10 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition. } } + else + { + m_NoMoreWayPoints = true; + } m_IsFollowingPath = true; return true; @@ -379,6 +413,7 @@ void cMonster::StopMovingToPosition() void cMonster::ResetPathFinding(void) { + m_TicksSinceLastPathReset = 0; m_IsFollowingPath = false; if (m_Path != nullptr) { diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index f9b271bf9..22280110c 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -120,8 +120,8 @@ public: char GetAge (void) const { return m_Age; } void SetAge(char a_Age) { m_Age = a_Age; } // tolua_end - - + + // tolua_begin /** Returns true if the monster has a custom name. */ @@ -178,6 +178,7 @@ protected: /* If 0, will give up reaching the next m_NextWayPointPosition and will re-compute path. */ int m_GiveUpCounter; + int m_TicksSinceLastPathReset; /** Coordinates of the next position that should be reached */ Vector3d m_NextWayPointPosition; @@ -185,6 +186,16 @@ protected: /** Coordinates for the ultimate, final destination. */ Vector3d m_FinalDestination; + /** Coordinates for the ultimate, final destination last given to the pathfinder. */ + Vector3d m_PathFinderDestination; + + /** True if there's no path to target and we're walking to an approximated location. */ + bool m_NoPathToTarget; + + /** Whether The mob has finished their path, note that this does not imply reaching the destination, + the destination may sometimes differ from the current path. */ + bool m_NoMoreWayPoints; + /** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does) If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1 If current Y is solid, goes up to find first nonsolid block, and returns that. diff --git a/src/Mobs/Squid.cpp b/src/Mobs/Squid.cpp index 30fbfa1ff..1b0163e30 100644 --- a/src/Mobs/Squid.cpp +++ b/src/Mobs/Squid.cpp @@ -35,7 +35,7 @@ void cSquid::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cSquid::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { - m_IsFollowingPath = false; // Disable Pathfinding until it's fixed. TODO + m_PathfinderActivated = false; // Disable Pathfinding until it's fixed. TODO // We must first process current location, and only then tick, otherwise we risk processing a location in a chunk // that is not where the entity currently resides (FS #411) diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 09f6147b2..dec873ccd 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -16,11 +16,7 @@ cFile::cFile(void) : - #ifdef USE_STDIO_FILE m_File(nullptr) - #else - m_File(INVALID_HANDLE_VALUE) - #endif // USE_STDIO_FILE { // Nothing needed yet } @@ -30,11 +26,7 @@ cFile::cFile(void) : cFile::cFile(const AString & iFileName, eMode iMode) : - #ifdef USE_STDIO_FILE m_File(nullptr) - #else - m_File(INVALID_HANDLE_VALUE) - #endif // USE_STDIO_FILE { Open(iFileName, iMode); } @@ -78,11 +70,11 @@ bool cFile::Open(const AString & iFileName, eMode iMode) return false; } -#ifdef _WIN32 - m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR); -#else - m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode); -#endif // _WIN32 + #ifdef _WIN32 + m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR); + #else + m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode); + #endif // _WIN32 if ((m_File == nullptr) && (iMode == fmReadWrite)) { @@ -91,11 +83,11 @@ bool cFile::Open(const AString & iFileName, eMode iMode) // So now we know either the file doesn't exist or we don't have rights, no need to worry about file contents. // Simply re-open for read-writing, erasing existing contents: -#ifdef _WIN32 - m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+", _SH_DENYWR); -#else - m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+"); -#endif // _WIN32 + #ifdef _WIN32 + m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+", _SH_DENYWR); + #else + m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+"); + #endif // _WIN32 } return (m_File != nullptr); @@ -310,7 +302,77 @@ bool cFile::Exists(const AString & a_FileName) -bool cFile::Delete(const AString & a_FileName) +bool cFile::Delete(const AString & a_Path) +{ + if (IsFolder(a_Path)) + { + return DeleteFolder(a_Path); + } + else + { + return DeleteFile(a_Path); + } +} + + + + + +bool cFile::DeleteFolder(const AString & a_FolderName) +{ + #ifdef _WIN32 + return (RemoveDirectoryA(a_FolderName.c_str()) != 0); + #else // _WIN32 + return (rmdir(a_FolderName.c_str()) == 0); + #endif // else _WIN32 +} + + + + + +bool cFile::DeleteFolderContents(const AString & a_FolderName) +{ + auto Contents = cFile::GetFolderContents(a_FolderName); + for (const auto item: Contents) + { + // Skip "." and ".." altogether: + if ((item == ".") || (item == "..")) + { + continue; + } + + // Remove the item: + auto WholePath = a_FolderName + GetPathSeparator() + item; + if (IsFolder(WholePath)) + { + if (!DeleteFolderContents(WholePath)) + { + return false; + } + if (!DeleteFolder(WholePath)) + { + return false; + } + } + else + { + if (!DeleteFile(WholePath)) + { + return false; + } + } + } // for item - Contents[] + + // All deletes succeeded + return true; +} + + + + + +bool cFile::DeleteFile(const AString & a_FileName) { return (remove(a_FileName.c_str()) == 0); } @@ -331,7 +393,7 @@ bool cFile::Rename(const AString & a_OrigFileName, const AString & a_NewFileName bool cFile::Copy(const AString & a_SrcFileName, const AString & a_DstFileName) { #ifdef _WIN32 - return (CopyFileA(a_SrcFileName.c_str(), a_DstFileName.c_str(), true) != 0); + return (CopyFileA(a_SrcFileName.c_str(), a_DstFileName.c_str(), FALSE) != 0); #else // Other OSs don't have a direct CopyFile equivalent, do it the harder way: std::ifstream src(a_SrcFileName.c_str(), std::ios::binary); @@ -409,57 +471,85 @@ bool cFile::CreateFolder(const AString & a_FolderPath) +bool cFile::CreateFolderRecursive(const AString & a_FolderPath) +{ + // Special case: Fail if the path is empty + if (a_FolderPath.empty()) + { + return false; + } + + // Go through each path element and create the folder: + auto len = a_FolderPath.length(); + auto PathSep = GetPathSeparator()[0]; + for (decltype(len) i = 0; i < len; i++) + { + if (a_FolderPath[i] == PathSep) + { + CreateFolder(a_FolderPath.substr(0, i)); + } + } + CreateFolder(a_FolderPath); + + // Check the result by querying whether the final path exists: + return IsFolder(a_FolderPath); +} + + + + + AStringVector cFile::GetFolderContents(const AString & a_Folder) { AStringVector AllFiles; #ifdef _WIN32 - // If the folder name doesn't contain the terminating slash / backslash, add it: - AString FileFilter = a_Folder; - if ( - !FileFilter.empty() && - (FileFilter[FileFilter.length() - 1] != '\\') && - (FileFilter[FileFilter.length() - 1] != '/') - ) - { - FileFilter.push_back('\\'); - } + // If the folder name doesn't contain the terminating slash / backslash, add it: + AString FileFilter = a_Folder; + if ( + !FileFilter.empty() && + (FileFilter[FileFilter.length() - 1] != '\\') && + (FileFilter[FileFilter.length() - 1] != '/') + ) + { + FileFilter.push_back('\\'); + } - // Find all files / folders: - FileFilter.append("*.*"); - HANDLE hFind; - WIN32_FIND_DATAA FindFileData; - if ((hFind = FindFirstFileA(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) - { - do + // Find all files / folders: + FileFilter.append("*.*"); + HANDLE hFind; + WIN32_FIND_DATAA FindFileData; + if ((hFind = FindFirstFileA(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) { - AllFiles.push_back(FindFileData.cFileName); - } while (FindNextFileA(hFind, &FindFileData)); - FindClose(hFind); - } + do + { + AllFiles.push_back(FindFileData.cFileName); + } while (FindNextFileA(hFind, &FindFileData)); + FindClose(hFind); + } #else // _WIN32 - DIR * dp; - struct dirent *dirp; - AString Folder = a_Folder; - if (Folder.empty()) - { - Folder = "."; - } - if ((dp = opendir(Folder.c_str())) == nullptr) - { - LOGERROR("Error (%i) opening directory \"%s\"\n", errno, Folder.c_str()); - } - else - { - while ((dirp = readdir(dp)) != nullptr) + DIR * dp; + struct dirent *dirp; + AString Folder = a_Folder; + if (Folder.empty()) { - AllFiles.push_back(dirp->d_name); + Folder = "."; + } + if ((dp = opendir(Folder.c_str())) == nullptr) + { + LOGERROR("Error (%i) opening directory \"%s\"\n", errno, Folder.c_str()); + } + else + { + while ((dirp = readdir(dp)) != nullptr) + { + AllFiles.push_back(dirp->d_name); + } + closedir(dp); } - closedir(dp); - } #endif // else _WIN32 diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index b8381ac0e..aab86811d 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -32,17 +32,6 @@ For reading entire files into memory, just use the static cFile::ReadWholeFile() -#ifndef _WIN32 - #define USE_STDIO_FILE -#endif // _WIN32 - -// DEBUG: -#define USE_STDIO_FILE - - - - - // tolua_begin class cFile @@ -101,48 +90,64 @@ public: /** Reads the file from current position till EOF into an AString; returns the number of bytes read or -1 for error */ int ReadRestOfFile(AString & a_Contents); - // tolua_begin - /** Returns true if the file specified exists */ - static bool Exists(const AString & a_FileName); + static bool Exists(const AString & a_FileName); // Exported in ManualBindings.cpp + + /** Deletes a file or a folder, returns true if successful. + Prefer to use DeleteFile or DeleteFolder, since those don't have the penalty of checking whether a_Path is a folder. */ + static bool Delete(const AString & a_Path); // Exported in ManualBindings.cpp + + /** Deletes a file, returns true if successful. + Returns false if a_FileName points to a folder. */ + static bool DeleteFile(const AString & a_FileName); // Exported in ManualBindings.cpp - /** Deletes a file, returns true if successful */ - static bool Delete(const AString & a_FileName); + /** Deletes a folder, returns true if successful. + Returns false if a_FolderName points to a file. */ + static bool DeleteFolder(const AString & a_FolderName); // Exported in ManualBindings.cpp + + /** Deletes all content from the specified folder. + The specified folder itself stays intact. + Returns true on success, false on failure. */ + static bool DeleteFolderContents(const AString & a_FolderName); // Exported in ManualBindings.cpp /** Renames a file or folder, returns true if successful. May fail if dest already exists (libc-dependant)! */ - static bool Rename(const AString & a_OrigPath, const AString & a_NewPath); + static bool Rename(const AString & a_OrigPath, const AString & a_NewPath); // Exported in ManualBindings.cpp - /** Copies a file, returns true if successful. */ - static bool Copy(const AString & a_SrcFileName, const AString & a_DstFileName); + /** Copies a file, returns true if successful. + Overwrites the dest file if it already exists. */ + static bool Copy(const AString & a_SrcFileName, const AString & a_DstFileName); // Exported in ManualBindings.cpp /** Returns true if the specified path is a folder */ - static bool IsFolder(const AString & a_Path); + static bool IsFolder(const AString & a_Path); // Exported in ManualBindings.cpp /** Returns true if the specified path is a regular file */ - static bool IsFile(const AString & a_Path); + static bool IsFile(const AString & a_Path); // Exported in ManualBindings.cpp /** Returns the size of the file, or a negative number on error */ - static long GetSize(const AString & a_FileName); + static long GetSize(const AString & a_FileName); // Exported in ManualBindings.cpp /** Creates a new folder with the specified name. Returns true if successful. Path may be relative or absolute */ - static bool CreateFolder(const AString & a_FolderPath); - - // tolua_end + static bool CreateFolder(const AString & a_FolderPath); // Exported in ManualBindings.cpp - /** Returns the entire contents of the specified file as a string. Returns empty string on error. - Exported manually in ManualBindings.cpp due to #1914 - ToLua code doesn't work well with binary files. */ - static AString ReadWholeFile(const AString & a_FileName); - - // tolua_begin + /** Creates a new folder with the specified name, creating its parents if needed. Path may be relative or absolute. + Returns true if the folder exists at the end of the operation (either created, or already existed). + Supports only paths that use the path separator used by the current platform (MSVC CRT supports slashes for file paths, too, but this function doesn't) */ + static bool CreateFolderRecursive(const AString & a_FolderPath); // Exported in ManualBindings.cpp + + /** Returns the entire contents of the specified file as a string. Returns empty string on error. */ + static AString ReadWholeFile(const AString & a_FileName); // Exported in ManualBindings.cpp /** Returns a_FileName with its extension changed to a_NewExt. a_FileName may contain path specification. */ - static AString ChangeFileExt(const AString & a_FileName, const AString & a_NewExt); + static AString ChangeFileExt(const AString & a_FileName, const AString & a_NewExt); // Exported in ManualBindings.cpp /** Returns the last modification time (in current timezone) of the specified file. The value returned is in the same units as the value returned by time() function. - If the file is not found / accessible, zero is returned. */ - static unsigned GetLastModificationTime(const AString & a_FileName); + If the file is not found / accessible, zero is returned. + Works for folders, too, when specified without the trailing path separator. */ + static unsigned GetLastModificationTime(const AString & a_FileName); // Exported in ManualBindings.cpp + + // tolua_begin /** Returns the path separator used by the current platform. Note that the platform / CRT may support additional path separators (such as slashes on Windows), these don't get reported. */ @@ -162,11 +167,7 @@ public: void Flush(void); private: - #ifdef USE_STDIO_FILE FILE * m_File; - #else - HANDLE m_File; - #endif } ; // tolua_export diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index d5ecb8023..ea71103f7 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -109,6 +109,20 @@ cProtocol180::cProtocol180(cClientHandle * a_Client, const AString & a_ServerAdd m_IsEncrypted(false), m_LastSentDimension(dimNotSet) { + + // BungeeCord handling: + // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field: + // hostname\00ip-address\00uuid\00profile-properties-as-json + AStringVector Params; + if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord() && SplitZeroTerminatedStrings(a_ServerAddress, Params) && (Params.size() == 4)) + { + LOGD("Player at %s connected via BungeeCord", Params[1].c_str()); + m_ServerAddress = Params[0]; + m_Client->SetIPString(Params[1]); + m_Client->SetUUID(cMojangAPI::MakeUUIDShort(Params[2])); + m_Client->SetProperties(Params[3]); + } + // Create the comm log file, if so requested: if (g_ShouldLogCommIn || g_ShouldLogCommOut) { diff --git a/src/World.cpp b/src/World.cpp index 5920b83fe..824ebf3fa 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -166,7 +166,13 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_ChunkMap(), m_bAnimals(true), m_Weather(eWeather_Sunny), - m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) + m_WeatherInterval(24000), // Guaranteed 1 game-day of sunshine at server start :) + m_MaxSunnyTicks(180000), // 150 real-world minutes -+ + m_MinSunnyTicks(12000), // 10 real-world minutes | + m_MaxRainTicks(24000), // 20 real-world minutes +- all values adapted from Vanilla 1.7.2 + m_MinRainTicks(12000), // 10 real-world minutes | + m_MaxThunderStormTicks(15600), // 13 real-world minutes | + m_MinThunderStormTicks(3600), // 3 real-world minutes -+ m_MaxCactusHeight(3), m_MaxSugarcaneHeight(4), m_IsCactusBonemealable(false), @@ -244,17 +250,25 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather) { case eWeather_Sunny: { - return 14400 + (m_TickRand.randInt() % 4800); // 12 - 16 minutes + auto dif = m_MaxSunnyTicks - m_MinSunnyTicks + 1; + return m_MinSunnyTicks + (m_TickRand.randInt() % dif); } case eWeather_Rain: { - return 9600 + (m_TickRand.randInt() % 7200); // 8 - 14 minutes + auto dif = m_MaxRainTicks - m_MinRainTicks + 1; + return m_MinRainTicks + (m_TickRand.randInt() % dif); } case eWeather_ThunderStorm: { - return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes + auto dif = m_MaxThunderStormTicks - m_MinThunderStormTicks + 1; + return m_MinThunderStormTicks + (m_TickRand.randInt() % dif); } } + + #ifndef __clang__ + ASSERT(!"Unknown weather"); + return -1; + #endif } @@ -472,6 +486,29 @@ void cWorld::Start(void) m_IsDaylightCycleEnabled = IniFile.GetValueSetB("General", "IsDaylightCycleEnabled", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", static_cast<int>(m_GameMode)); int Weather = IniFile.GetValueSetI("General", "Weather", static_cast<int>(m_Weather)); + + // Load the weather frequency data: + if (m_Dimension == dimOverworld) + { + m_MaxSunnyTicks = IniFile.GetValueSetI("Weather", "MaxSunnyTicks", m_MaxSunnyTicks); + m_MinSunnyTicks = IniFile.GetValueSetI("Weather", "MinSunnyTicks", m_MinSunnyTicks); + m_MaxRainTicks = IniFile.GetValueSetI("Weather", "MaxRainTicks", m_MaxRainTicks); + m_MinRainTicks = IniFile.GetValueSetI("Weather", "MinRainTicks", m_MinRainTicks); + m_MaxThunderStormTicks = IniFile.GetValueSetI("Weather", "MaxThunderStormTicks", m_MaxThunderStormTicks); + m_MinThunderStormTicks = IniFile.GetValueSetI("Weather", "MinThunderStormTicks", m_MinThunderStormTicks); + if (m_MaxSunnyTicks < m_MinSunnyTicks) + { + std::swap(m_MaxSunnyTicks, m_MinSunnyTicks); + } + if (m_MaxRainTicks < m_MinRainTicks) + { + std::swap(m_MaxRainTicks, m_MinRainTicks); + } + if (m_MaxThunderStormTicks < m_MinThunderStormTicks) + { + std::swap(m_MaxThunderStormTicks, m_MinThunderStormTicks); + } + } if (GetDimension() == dimOverworld) { @@ -644,6 +681,11 @@ eWeather cWorld::ChooseNewWeather() return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny; } } + + #ifndef __clang__ + ASSERT(!"Unknown weather"); + return eWeather_Sunny; + #endif } @@ -839,7 +881,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La TickClients(static_cast<float>(a_Dt.count())); TickQueuedBlocks(); TickQueuedTasks(); - TickScheduledTasks(); GetSimulatorManager()->Simulate(static_cast<float>(a_Dt.count())); @@ -962,55 +1003,39 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt) void cWorld::TickQueuedTasks(void) { - // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks - cTasks Tasks; - { - cCSLock Lock(m_CSTasks); - std::swap(Tasks, m_Tasks); - } - - // Execute and delete each task: - for (cTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) - { - (*itr)->Run(*this); - } // for itr - m_Tasks[] -} - - - - - -void cWorld::TickScheduledTasks(void) -{ // Move the tasks to be executed to a seperate vector to avoid deadlocks on accessing m_Tasks - cScheduledTasks Tasks; + decltype(m_Tasks) Tasks; { - cCSLock Lock(m_CSScheduledTasks); - auto WorldAge = m_WorldAge; - - // Move all the due tasks from m_ScheduledTasks into Tasks: - for (auto itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end();) // Cannot use range-based for, we're modifying the container + cCSLock Lock(m_CSTasks); + if (m_Tasks.empty()) { - if ((*itr)->m_TargetTick < std::chrono::duration_cast<cTickTimeLong>(WorldAge).count()) - { - auto next = itr; - ++next; - Tasks.push_back(std::move(*itr)); - m_ScheduledTasks.erase(itr); - itr = next; - } - else + return; + } + + // Partition everything to be executed by returning false to move to end of list if time reached + auto MoveBeginIterator = std::partition(m_Tasks.begin(), m_Tasks.end(), [this](const decltype(m_Tasks)::value_type & a_Task) { - // All the eligible tasks have been moved, bail out now - break; + if (a_Task.first < std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count()) + { + return false; + } + return true; } - } + ); + + // Cut all the due tasks from m_Tasks into Tasks: + Tasks.insert( + Tasks.end(), + std::make_move_iterator(MoveBeginIterator), + std::make_move_iterator(m_Tasks.end()) + ); + m_Tasks.erase(MoveBeginIterator, m_Tasks.end()); } - // Execute and delete each task: - for (cScheduledTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) + // Execute each task: + for (const auto & Task : Tasks) { - (*itr)->m_Task->Run(*this); + Task.second(*this); } // for itr - m_Tasks[] } @@ -2662,7 +2687,7 @@ void cWorld::UnloadUnusedChunks(void) void cWorld::QueueUnloadUnusedChunks(void) { - QueueTask(cpp14::make_unique<cWorld::cTaskUnloadUnusedChunks>()); + QueueTask([](cWorld & a_World) { a_World.UnloadUnusedChunks(); }); } @@ -3161,42 +3186,32 @@ void cWorld::SaveAllChunks(void) void cWorld::QueueSaveAllChunks(void) { - QueueTask(std::make_shared<cWorld::cTaskSaveAllChunks>()); + QueueTask([](cWorld & a_World) { a_World.SaveAllChunks(); }); } -void cWorld::QueueTask(cTaskPtr a_Task) +void cWorld::QueueTask(std::function<void(cWorld &)> a_Task) { cCSLock Lock(m_CSTasks); - m_Tasks.push_back(std::move(a_Task)); + m_Tasks.emplace_back(0, a_Task); } -void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld&)> a_Func) -{ - cTaskLambda task(a_Func); - ScheduleTask(a_DelayTicks, static_cast<cTaskPtr>(std::make_shared<cTaskLambda>(task))); -} -void cWorld::ScheduleTask(int a_DelayTicks, cTaskPtr a_Task) + +void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Task) { Int64 TargetTick = a_DelayTicks + std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count(); - - // Insert the task into the list of scheduled tasks, ordered by its target tick - cCSLock Lock(m_CSScheduledTasks); - for (cScheduledTasks::iterator itr = m_ScheduledTasks.begin(), end = m_ScheduledTasks.end(); itr != end; ++itr) + + // Insert the task into the list of scheduled tasks { - if ((*itr)->m_TargetTick >= TargetTick) - { - m_ScheduledTasks.insert(itr, cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task))); - return; - } + cCSLock Lock(m_CSTasks); + m_Tasks.emplace_back(TargetTick, a_Task); } - m_ScheduledTasks.push_back(cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task))); } @@ -3625,75 +3640,6 @@ void cWorld::AddQueuedPlayers(void) //////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskSaveAllChunks: - -void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) -{ - a_World.SaveAllChunks(); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskUnloadUnusedChunks - -void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World) -{ - a_World.UnloadUnusedChunks(); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskSendBlockToAllPlayers - -cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) : - m_SendQueue(a_SendQueue) -{ -} - -void cWorld::cTaskSendBlockToAllPlayers::Run(cWorld & a_World) -{ - class cPlayerCallback : - public cPlayerListCallback - { - public: - cPlayerCallback(std::vector<Vector3i> & a_SendQueue, cWorld & a_CallbackWorld) : - m_SendQueue(a_SendQueue), - m_World(a_CallbackWorld) - { - } - - virtual bool Item(cPlayer * a_Player) - { - for (std::vector<Vector3i>::const_iterator itr = m_SendQueue.begin(); itr != m_SendQueue.end(); ++itr) - { - m_World.SendBlockTo(itr->x, itr->y, itr->z, a_Player); - } - return false; - } - - private: - - std::vector<Vector3i> m_SendQueue; - cWorld & m_World; - - } PlayerCallback(m_SendQueue, a_World); - - a_World.ForEachPlayer(PlayerCallback); -} - -void cWorld::cTaskLambda::Run(cWorld & a_World) -{ - m_func(a_World); -} - - -//////////////////////////////////////////////////////////////////////////////// // cWorld::cChunkGeneratorCallbacks: cWorld::cChunkGeneratorCallbacks::cChunkGeneratorCallbacks(cWorld & a_World) : diff --git a/src/World.h b/src/World.h index 1902296be..8529ffb4d 100644 --- a/src/World.h +++ b/src/World.h @@ -96,72 +96,8 @@ public: typedef cCSLock super; public: cLock(cWorld & a_World); - } ; - - - /** A common ancestor for all tasks queued onto the tick thread */ - class cTask - { - public: - cTask(const cTask & other) = default; - virtual ~cTask() {} - virtual void Run(cWorld & a_World) = 0; - - protected: - cTask() {} - } ; - - typedef SharedPtr<cTask> cTaskPtr; - typedef std::vector<cTaskPtr> cTasks; - - - class cTaskSaveAllChunks : - public cTask - { - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - } ; - - - class cTaskUnloadUnusedChunks : - public cTask - { - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - }; - - - class cTaskSendBlockToAllPlayers : - public cTask - { - public: - cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue); - - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - - std::vector<Vector3i> m_SendQueue; - }; - - class cTaskLambda : - public cTask - { - - public: - cTaskLambda(std::function<void(cWorld&)> a_Func) : - m_func(a_Func) - { } - - protected: - virtual void Run(cWorld & a_World) override; - - std::function<void(cWorld&)> m_func; }; - static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates { return "cWorld"; @@ -739,13 +675,10 @@ public: void QueueSaveAllChunks(void); // tolua_export /** Queues a task onto the tick thread. The task object will be deleted once the task is finished */ - void QueueTask(cTaskPtr a_Task); // Exported in ManualBindings.cpp + void QueueTask(std::function<void(cWorld &)> a_Task); // Exported in ManualBindings.cpp /** Queues a lambda task onto the tick thread, with the specified delay. */ - void ScheduleTask(int a_DelayTicks, std::function<void(cWorld&)> a_Func); - - /** Queues a task onto the tick thread, with the specified delay. */ - void ScheduleTask(int a_DelayTicks, cTaskPtr a_Task); + void ScheduleTask(int a_DelayTicks, std::function<void(cWorld &)> a_Task); /** Returns the number of chunks loaded */ int GetNumChunks() const; // tolua_export @@ -912,27 +845,6 @@ private: public: cChunkGeneratorCallbacks(cWorld & a_World); } ; - - - /** A container for tasks that have been scheduled for a specific game tick */ - class cScheduledTask - { - public: - Int64 m_TargetTick; - cTaskPtr m_Task; - - /** Creates a new scheduled task; takes ownership of the task object passed to it. */ - cScheduledTask(Int64 a_TargetTick, cTaskPtr a_Task) : - m_TargetTick(a_TargetTick), - m_Task(a_Task) - { - } - - virtual ~cScheduledTask() {} - }; - - typedef std::unique_ptr<cScheduledTask> cScheduledTaskPtr; - typedef std::list<cScheduledTaskPtr> cScheduledTasks; AString m_WorldName; @@ -1009,6 +921,9 @@ private: eWeather m_Weather; int m_WeatherInterval; + int m_MaxSunnyTicks, m_MinSunnyTicks; + int m_MaxRainTicks, m_MinRainTicks; + int m_MaxThunderStormTicks, m_MinThunderStormTicks; int m_MaxCactusHeight; int m_MaxSugarcaneHeight; @@ -1062,16 +977,8 @@ private: /** Guards the m_Tasks */ cCriticalSection m_CSTasks; - /** Tasks that have been queued onto the tick thread; guarded by m_CSTasks */ - cTasks m_Tasks; - - /** Guards the m_ScheduledTasks */ - cCriticalSection m_CSScheduledTasks; - - /** Tasks that have been queued to be executed on the tick thread at target tick in the future. - Ordered by increasing m_TargetTick. - Guarded by m_CSScheduledTasks */ - cScheduledTasks m_ScheduledTasks; + /** Tasks that have been queued onto the tick thread, possibly to be executed at target tick in the future; guarded by m_CSTasks */ + std::vector<std::pair<Int64, std::function<void(cWorld &)>>> m_Tasks; /** Guards m_Clients */ cCriticalSection m_CSClients; @@ -1118,9 +1025,6 @@ private: /** Executes all tasks queued onto the tick thread */ void TickQueuedTasks(void); - /** Executes all tasks queued onto the tick thread */ - void TickScheduledTasks(void); - /** Ticks all clients that are in this world */ void TickClients(float a_Dt); |