diff options
Diffstat (limited to 'src/World.cpp')
-rw-r--r-- | src/World.cpp | 837 |
1 files changed, 197 insertions, 640 deletions
diff --git a/src/World.cpp b/src/World.cpp index c687e9549..399776320 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -62,6 +62,8 @@ #include "SpawnPrepare.h" #include "FastRandom.h" +#include <memory> + const int TIME_SUNSET = 12000; @@ -75,18 +77,6 @@ const int TIME_SPAWN_DIVISOR = 148; //////////////////////////////////////////////////////////////////////////////// -// cWorld::cLock: - -cWorld::cLock::cLock(cWorld & a_World) : - super(&(a_World.m_ChunkMap->GetCS())) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// // cWorld::cTickThread: cWorld::cTickThread::cTickThread(cWorld & a_World) : @@ -101,6 +91,10 @@ cWorld::cTickThread::cTickThread(cWorld & a_World) : void cWorld::cTickThread::Execute(void) { + m_World.Initialise(); + m_World.InitialiseSpawn(); + cRoot::Get()->GetPluginManager()->CallHookWorldStarted(m_World); + auto LastTime = std::chrono::steady_clock::now(); auto TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(cTickTime(1)); @@ -108,9 +102,14 @@ void cWorld::cTickThread::Execute(void) { auto NowTime = std::chrono::steady_clock::now(); auto WaitTime = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime); - m_World.Tick(WaitTime, TickTime); - TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - NowTime); + if (m_World.m_ShouldTick) + { + m_World.Tick(WaitTime, TickTime); + } + m_World.TickQueuedTasks(); + + TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - NowTime); if (TickTime < cTickTime(1)) { // Stretch tick time until it's at least 1 tick @@ -119,6 +118,36 @@ void cWorld::cTickThread::Execute(void) LastTime = NowTime; } + + class DestructionCallback : public cEntityCallback + { + virtual bool Item(cEntity * a_Entity) override + { + a_Entity->Destroy(false); + return false; + } + } DestructionCallback; + m_World.ForEachEntity(DestructionCallback); + + // Write settings to file; these are all plugin changeable values - keep updated! + cIniFile IniFile; + IniFile.ReadFile(m_World.m_IniFileName); + if (m_World.GetDimension() == dimOverworld) + { + IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_World.m_LinkedNetherWorldName); + IniFile.SetValue("LinkedWorlds", "EndWorldName", m_World.m_LinkedEndWorldName); + } + else + { + IniFile.SetValue("LinkedWorlds", "OverworldName", m_World.m_LinkedOverworldName); + } + IniFile.SetValueI("Physics", "TNTShrapnelLevel", static_cast<int>(m_World.m_TNTShrapnelLevel)); + IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_World.m_bCommandBlocksEnabled); + IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_World.m_bUseChatPrefixes); + IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_World.m_IsDaylightCycleEnabled); + IniFile.SetValueI("General", "Weather", static_cast<int>(m_World.m_Weather)); + IniFile.SetValueI("General", "TimeInTicks", m_World.GetTimeOfDay()); + IniFile.WriteFile(m_World.m_IniFileName); } @@ -129,6 +158,7 @@ void cWorld::cTickThread::Execute(void) // cWorld: cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_LinkedOverworldName) : + m_ShouldTick(true), m_WorldName(a_WorldName), m_LinkedOverworldName(a_LinkedOverworldName), m_IniFileName(m_WorldName + "/world.ini"), @@ -218,8 +248,6 @@ cWorld::~cWorld() delete m_LavaSimulator; m_LavaSimulator = nullptr; delete m_RedstoneSimulator; m_RedstoneSimulator = nullptr; - m_Storage.WaitForFinish(); - // Unload the scoreboard cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard); Serializer.Save(); @@ -351,29 +379,41 @@ bool cWorld::SetSpawn(double a_X, double a_Y, double a_Z) -void cWorld::InitializeSpawn(void) +void cWorld::InitialiseSpawn(void) { // For the debugging builds, don't make the server build too much world upon start: #if defined(_DEBUG) || defined(ANDROID_NDK) - const int DefaultViewDist = 9; + static const int DefaultViewDist = 9; #else - const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is + static const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is #endif // _DEBUG - if (!m_IsSpawnExplicitlySet) + int ViewDist; { - // Spawn position wasn't already explicitly set, enumerate random solid-land coordinate and then write it to the world configuration: - GenerateRandomSpawn(DefaultViewDist); - } + cIniFile IniFile; + IniFile.ReadFile(m_IniFileName); + ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist); + IniFile.WriteFile(m_IniFileName); - cIniFile IniFile; - IniFile.ReadFile(m_IniFileName); - int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist); - IniFile.WriteFile(m_IniFileName); + } - int ChunkX = 0, ChunkZ = 0; - cChunkDef::BlockToChunk(FloorC(m_SpawnX), FloorC(m_SpawnZ), ChunkX, ChunkZ); - cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, ViewDist); + if (m_IsSpawnExplicitlySet) + { + cSpawnPrepare::PrepareChunks(*this, ViewDist); + } + else + { + // Spawn position wasn't already explicitly set, enumerate random solid-land coordinate and then write it to the world configuration: + cSpawnPrepare::PrepareChunks( + *this, + ViewDist, + [this] + { + auto Spawn = cSpawnPrepare::GenerateRandomSpawn(*this, DefaultViewDist); + SetSpawn(Spawn.x, Spawn.y, Spawn.z); + } + ); + } #ifdef TEST_LINEBLOCKTRACER // DEBUG: Test out the cLineBlockTracer class by tracing a few lines: @@ -433,7 +473,7 @@ void cWorld::InitializeSpawn(void) -void cWorld::Start(void) +void cWorld::Initialise() { m_SpawnX = 0; m_SpawnY = cChunkDef::Height; @@ -617,7 +657,6 @@ void cWorld::Start(void) m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor); m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile); m_ChunkSender.Start(); - m_TickThread.Start(); // Init of the spawn monster time (as they are supposed to have different spawn rate) m_LastSpawnMonster.insert(std::map<cMonster::eFamily, cTickTimeLong>::value_type(cMonster::mfHostile, cTickTimeLong(0))); @@ -638,203 +677,6 @@ void cWorld::Start(void) -void cWorld::GenerateRandomSpawn(int a_MaxSpawnRadius) -{ - LOGD("Generating random spawnpoint..."); - - // Number of checks to make sure we have a valid biome - // 100 checks will check across 400 chunks, we should have - // a valid biome by then. - static const int BiomeCheckCount = 100; - - // Make sure we are in a valid biome - Vector3i BiomeOffset = Vector3i(0, 0, 0); - for (int BiomeCheckIndex = 0; BiomeCheckIndex < BiomeCheckCount; ++BiomeCheckIndex) - { - EMCSBiome Biome = GetBiomeAt(BiomeOffset.x, BiomeOffset.z); - if ((Biome == EMCSBiome::biOcean) || (Biome == EMCSBiome::biFrozenOcean)) - { - BiomeOffset += Vector3d(cChunkDef::Width * 4, 0, 0); - continue; - } - - // Found a usable biome - // Spawn chunks so we can find a nice spawn. - int ChunkX = 0, ChunkZ = 0; - cChunkDef::BlockToChunk(BiomeOffset.x, BiomeOffset.z, ChunkX, ChunkZ); - cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, a_MaxSpawnRadius); - break; - } - - // Check 0, 0 first. - double SpawnY = 0.0; - if (CanSpawnAt(BiomeOffset.x, SpawnY, BiomeOffset.z)) - { - SetSpawn(BiomeOffset.x + 0.5, SpawnY, BiomeOffset.z + 0.5); - - LOGINFO("Generated spawnpoint position at {%.2f, %.2f, %.2f}", m_SpawnX, m_SpawnY, m_SpawnZ); - return; - } - - // A search grid (searches clockwise around the origin) - static const int HalfChunk = static_cast<int>(cChunkDef::Width / 2.0f); - static const Vector3i ChunkOffset[] = - { - Vector3i(0, 0, HalfChunk), - Vector3i(HalfChunk, 0, HalfChunk), - Vector3i(HalfChunk, 0, 0), - Vector3i(HalfChunk, 0, -HalfChunk), - Vector3i(0, 0, -HalfChunk), - Vector3i(-HalfChunk, 0, -HalfChunk), - Vector3i(-HalfChunk, 0, 0), - Vector3i(-HalfChunk, 0, HalfChunk), - }; - - static const int PerRadiSearchCount = ARRAYCOUNT(ChunkOffset); - - for (int RadiusOffset = 1; RadiusOffset < (a_MaxSpawnRadius * 2); ++RadiusOffset) - { - for (int SearchGridIndex = 0; SearchGridIndex < PerRadiSearchCount; ++SearchGridIndex) - { - const Vector3i PotentialSpawn = BiomeOffset + (ChunkOffset[SearchGridIndex] * RadiusOffset); - - if (CanSpawnAt(PotentialSpawn.x, SpawnY, PotentialSpawn.z)) - { - SetSpawn(PotentialSpawn.x + 0.5, SpawnY, PotentialSpawn.z + 0.5); - - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(static_cast<int>(m_SpawnX), static_cast<int>(m_SpawnZ), ChunkX, ChunkZ); - cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, a_MaxSpawnRadius); - - LOGINFO("Generated spawnpoint position at {%.2f, %.2f, %.2f}", m_SpawnX, m_SpawnY, m_SpawnZ); - return; - } - } - } - - m_SpawnY = GetHeight(static_cast<int>(m_SpawnX), static_cast<int>(m_SpawnZ)); - LOGWARNING("Did not find an acceptable spawnpoint. Generated a random spawnpoint position at {%.2f, %.2f, %.2f}", m_SpawnX, m_SpawnY, m_SpawnZ); -} - - - - - -bool cWorld::CanSpawnAt(double a_X, double & a_Y, double a_Z) -{ - // All this blocks can only be found above ground. - // Apart from netherrack (as the Nether is technically a massive cave) - static const BLOCKTYPE ValidSpawnBlocks[] = - { - E_BLOCK_GRASS, - E_BLOCK_SAND, - E_BLOCK_SNOW, - E_BLOCK_SNOW_BLOCK, - E_BLOCK_NETHERRACK - }; - - static const int ValidSpawnBlocksCount = ARRAYCOUNT(ValidSpawnBlocks); - - // Increase this by two, because we need two more blocks for body and head - static const int HighestSpawnPoint = GetHeight(static_cast<int>(a_X), static_cast<int>(a_Z)) + 2; - static const int LowestSpawnPoint = static_cast<int>(HighestSpawnPoint / 2.0f); - - for (int PotentialY = HighestSpawnPoint; PotentialY > LowestSpawnPoint; --PotentialY) - { - BLOCKTYPE HeadBlock = GetBlock(static_cast<int>(a_X), PotentialY, static_cast<int>(a_Z)); - - // Is this block safe for spawning - if (HeadBlock != E_BLOCK_AIR) - { - continue; - } - - BLOCKTYPE BodyBlock = GetBlock(static_cast<int>(a_X), PotentialY - 1, static_cast<int>(a_Z)); - - // Is this block safe for spawning - if (BodyBlock != E_BLOCK_AIR) - { - continue; - } - - BLOCKTYPE FloorBlock = GetBlock(static_cast<int>(a_X), PotentialY - 2, static_cast<int>(a_Z)); - - // Early out - Is the floor block air - if (FloorBlock == E_BLOCK_AIR) - { - continue; - } - - // Is the floor block ok - bool ValidSpawnBlock = false; - for (int BlockIndex = 0; BlockIndex < ValidSpawnBlocksCount; ++BlockIndex) - { - ValidSpawnBlock |= (ValidSpawnBlocks[BlockIndex] == FloorBlock); - } - - if (!ValidSpawnBlock) - { - continue; - } - - if (!CheckPlayerSpawnPoint(static_cast<int>(a_X), PotentialY - 1, static_cast<int>(a_Z))) - { - continue; - } - - a_Y = PotentialY - 1.0; - return true; - } - - return false; -} - - - - - -bool cWorld::CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ) -{ - // Check height bounds - if (!cChunkDef::IsValidHeight(a_PosY)) - { - return false; - } - - // Check that surrounding blocks are neither solid or liquid - static const Vector3i SurroundingCoords[] = - { - Vector3i(0, 0, 1), - Vector3i(1, 0, 1), - Vector3i(1, 0, 0), - Vector3i(1, 0, -1), - Vector3i(0, 0, -1), - Vector3i(-1, 0, -1), - Vector3i(-1, 0, 0), - Vector3i(-1, 0, 1), - }; - - static const int SurroundingCoordsCount = ARRAYCOUNT(SurroundingCoords); - - for (int CoordIndex = 0; CoordIndex < SurroundingCoordsCount; ++CoordIndex) - { - const int XPos = a_PosX + SurroundingCoords[CoordIndex].x; - const int ZPos = a_PosZ + SurroundingCoords[CoordIndex].z; - - const BLOCKTYPE BlockType = GetBlock(XPos, a_PosY, ZPos); - if (cBlockInfo::IsSolid(BlockType) || IsBlockLiquid(BlockType)) - { - return false; - } - } - - return true; -} - - - - - eWeather cWorld::ChooseNewWeather() { // Pick a new weather. Only reasonable transitions allowed: @@ -948,41 +790,18 @@ void cWorld::InitialiseAndLoadMobSpawningValues(cIniFile & a_IniFile) void cWorld::Stop(void) { - // Delete the clients that have been in this world: - { - cCSLock Lock(m_CSClients); - for (auto itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) - { - (*itr)->Destroy(); - } // for itr - m_Clients[] - m_Clients.clear(); - } - - // Write settings to file; these are all plugin changeable values - keep updated! - cIniFile IniFile; - IniFile.ReadFile(m_IniFileName); - if (GetDimension() == dimOverworld) - { - IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_LinkedNetherWorldName); - IniFile.SetValue("LinkedWorlds", "EndWorldName", m_LinkedEndWorldName); - } - else - { - IniFile.SetValue("LinkedWorlds", "OverworldName", m_LinkedOverworldName); - } - IniFile.SetValueI("Physics", "TNTShrapnelLevel", static_cast<int>(m_TNTShrapnelLevel)); - IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); - IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); - IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled); - IniFile.SetValueI("General", "Weather", static_cast<int>(m_Weather)); - IniFile.SetValueI("General", "TimeInTicks", GetTimeOfDay()); - IniFile.WriteFile(m_IniFileName); + // Stop calling cWorld::Tick; prevents occurences where a worker thread is stopped but + // SUDDENLY, A WILD CHUNK SAVE TASK APPEARS!!! + // NB: queued tasks which may be generated by worker threads are still processed + m_ShouldTick = false; - m_TickThread.Stop(); m_Lighting.Stop(); m_Generator.Stop(); m_ChunkSender.Stop(); m_Storage.Stop(); + + // Finally, stop the tick thread + m_TickThread.Stop(); } @@ -994,17 +813,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La // Call the plugins cPluginManager::Get()->CallHookWorldTick(*this, a_Dt, a_LastTickDurationMSec); - // Set any chunk data that has been queued for setting: - cSetChunkDataPtrs SetChunkDataQueue; - { - cCSLock Lock(m_CSSetChunkDataQueue); - std::swap(SetChunkDataQueue, m_SetChunkDataQueue); - } - for (cSetChunkDataPtrs::iterator itr = SetChunkDataQueue.begin(), end = SetChunkDataQueue.end(); itr != end; ++itr) - { - SetChunkData(**itr); - } // for itr - SetChunkDataQueue[] - m_WorldAge += a_Dt; if (m_IsDaylightCycleEnabled) @@ -1029,29 +837,11 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La } } - // Add entities waiting in the queue to be added: - { - cCSLock Lock(m_CSEntitiesToAdd); - for (auto & Entity : m_EntitiesToAdd) - { - Entity->SetWorld(this); - m_ChunkMap->AddEntity(Entity); - ASSERT(!Entity->IsTicking()); - Entity->SetIsTicking(true); - } - m_EntitiesToAdd.clear(); - } - - // Add players waiting in the queue to be added: - AddQueuedPlayers(); - m_ChunkMap->Tick(a_Dt); TickMobs(a_Dt); m_MapManager.TickMaps(); - TickClients(static_cast<float>(a_Dt.count())); TickQueuedBlocks(); - TickQueuedTasks(); GetSimulatorManager()->Simulate(static_cast<float>(a_Dt.count())); @@ -1066,7 +856,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La { UnloadUnusedChunks(); } - } @@ -1109,9 +898,6 @@ void cWorld::TickWeather(float a_Dt) void cWorld::TickMobs(std::chrono::milliseconds a_Dt) { - // _X 2013_10_22: This is a quick fix for #283 - the world needs to be locked while ticking mobs - cWorld::cLock Lock(*this); - // before every Mob action, we have to count them depending on the distance to players, on their family ... cMobCensus MobCensus; m_ChunkMap->CollectMobCensus(MobCensus); @@ -1213,7 +999,10 @@ void cWorld::TickQueuedTasks(void) } // 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) + auto MoveBeginIterator = std::partition( + m_Tasks.begin(), + m_Tasks.end(), + [this](const auto & a_Task) { if (a_Task.first < std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count()) { @@ -1233,60 +1022,10 @@ void cWorld::TickQueuedTasks(void) } // Execute each task: - for (const auto & Task : Tasks) + for (auto & Task : Tasks) { Task.second(*this); - } // for itr - m_Tasks[] -} - - - - -void cWorld::TickClients(float a_Dt) -{ - cClientHandlePtrs RemoveClients; - { - cCSLock Lock(m_CSClients); - - // Remove clients scheduled for removal: - for (auto itr = m_ClientsToRemove.begin(), end = m_ClientsToRemove.end(); itr != end; ++itr) - { - for (auto itrC = m_Clients.begin(), endC = m_Clients.end(); itrC != endC; ++itrC) - { - if (itrC->get() == *itr) - { - m_Clients.erase(itrC); - break; - } - } - } // for itr - m_ClientsToRemove[] - m_ClientsToRemove.clear(); - - // Add clients scheduled for adding: - for (auto itr = m_ClientsToAdd.begin(), end = m_ClientsToAdd.end(); itr != end; ++itr) - { - ASSERT(std::find(m_Clients.begin(), m_Clients.end(), *itr) == m_Clients.end()); - m_Clients.push_back(*itr); - } // for itr - m_ClientsToRemove[] - m_ClientsToAdd.clear(); - - // Tick the clients, take out those that have been destroyed into RemoveClients - for (auto itr = m_Clients.begin(); itr != m_Clients.end();) - { - if ((*itr)->IsDestroyed()) - { - // Remove the client later, when CS is not held, to avoid deadlock - RemoveClients.push_back(*itr); - itr = m_Clients.erase(itr); - continue; - } - (*itr)->Tick(a_Dt); - ++itr; - } // for itr - m_Clients[] } - - // Delete the clients queued for removal: - RemoveClients.clear(); } @@ -1412,29 +1151,26 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected); BroadcastSoundEffect("random.explode", static_cast<double>(a_BlockX), static_cast<double>(a_BlockY), static_cast<double>(a_BlockZ), 1.0f, 0.6f); + for (const auto & Player : m_Players) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + cClientHandle * ch = Player->GetClientHandle(); + if (ch == nullptr) { - cClientHandle * ch = (*itr)->GetClientHandle(); - if (ch == nullptr) - { - continue; - } + continue; + } - Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos; - if (distance_explosion.SqrLength() < 4096.0) + Vector3d distance_explosion = Player->GetPosition() - explosion_pos; + if (distance_explosion.SqrLength() < 4096.0) + { + double real_distance = std::max(0.004, distance_explosion.Length()); + double power = a_ExplosionSize / real_distance; + if (power <= 1) { - double real_distance = std::max(0.004, distance_explosion.Length()); - double power = a_ExplosionSize / real_distance; - if (power <= 1) - { - power = 0; - } - distance_explosion.Normalize(); - distance_explosion *= power; - ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, distance_explosion); + power = 0; } + distance_explosion.Normalize(); + distance_explosion *= power; + ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, distance_explosion); } } @@ -2390,10 +2126,9 @@ void cWorld::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude, eMessageType a_ChatPrefix) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2408,10 +2143,9 @@ void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Ex void cWorld::BroadcastChat(const cCompositeChat & a_Message, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2543,10 +2277,9 @@ void cWorld::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation void cWorld::BroadcastPlayerListAddPlayer(const cPlayer & a_Player, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2561,10 +2294,9 @@ void cWorld::BroadcastPlayerListAddPlayer(const cPlayer & a_Player, const cClien void cWorld::BroadcastPlayerListRemovePlayer(const cPlayer & a_Player, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn()) { continue; @@ -2579,10 +2311,9 @@ void cWorld::BroadcastPlayerListRemovePlayer(const cPlayer & a_Player, const cCl void cWorld::BroadcastPlayerListUpdateGameMode(const cPlayer & a_Player, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2597,10 +2328,9 @@ void cWorld::BroadcastPlayerListUpdateGameMode(const cPlayer & a_Player, const c void cWorld::BroadcastPlayerListUpdatePing(const cPlayer & a_Player, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2615,10 +2345,9 @@ void cWorld::BroadcastPlayerListUpdatePing(const cPlayer & a_Player, const cClie void cWorld::BroadcastPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2642,10 +2371,9 @@ void cWorld::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectI void cWorld::BroadcastScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2660,10 +2388,9 @@ void cWorld::BroadcastScoreboardObjective(const AString & a_Name, const AString void cWorld::BroadcastScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2678,10 +2405,9 @@ void cWorld::BroadcastScoreUpdate(const AString & a_Objective, const AString & a void cWorld::BroadcastDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2723,10 +2449,9 @@ void cWorld::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Ex void cWorld::BroadcastTeleportEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2750,10 +2475,9 @@ void cWorld::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2777,10 +2501,9 @@ void cWorld::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Block void cWorld::BroadcastWeather(eWeather a_Weather, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; @@ -2829,28 +2552,30 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) -void cWorld::QueueSetChunkData(const cSetChunkDataPtr & a_SetChunkData) +void cWorld::QueueSetChunkData(cSetChunkData & a_SetChunkData) { - ASSERT(IsChunkQueued(a_SetChunkData->GetChunkX(), a_SetChunkData->GetChunkZ())); - // Validate biomes, if needed: - if (!a_SetChunkData->AreBiomesValid()) + if (!a_SetChunkData.AreBiomesValid()) { // The biomes are not assigned, get them from the generator: - m_Generator.GenerateBiomes(a_SetChunkData->GetChunkX(), a_SetChunkData->GetChunkZ(), a_SetChunkData->GetBiomes()); - a_SetChunkData->MarkBiomesValid(); + m_Generator.GenerateBiomes(a_SetChunkData.GetChunkX(), a_SetChunkData.GetChunkZ(), a_SetChunkData.GetBiomes()); + a_SetChunkData.MarkBiomesValid(); } // Validate heightmap, if needed: - if (!a_SetChunkData->IsHeightMapValid()) + if (!a_SetChunkData.IsHeightMapValid()) { - a_SetChunkData->CalculateHeightMap(); + a_SetChunkData.CalculateHeightMap(); } - // Store a copy of the data in the queue: - // TODO: If the queue is too large, wait for it to get processed. Not likely, though. - cCSLock Lock(m_CSSetChunkDataQueue); - m_SetChunkDataQueue.push_back(a_SetChunkData); + cpp14::move_on_copy_wrapper<std::remove_reference<decltype(a_SetChunkData)>::type> SetChunkData(std::move(a_SetChunkData)); + QueueTask( + [SetChunkData](cWorld & a_World) + { + // TODO: make SetChunkData and all called functions const + a_World.SetChunkData(const_cast<cSetChunkData &>(SetChunkData.value)); + } + ); } @@ -2864,7 +2589,7 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) m_ChunkMap->SetChunkData(a_SetChunkData); - // Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347): + // Initialise the entities: cEntityList Entities; std::swap(a_SetChunkData.GetEntities(), Entities); for (cEntityList::iterator itr = Entities.begin(), end = Entities.end(); itr != end; ++itr) @@ -2872,31 +2597,10 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) (*itr)->Initialize(*this); } - // If a client is requesting this chunk, send it to them: - int ChunkX = a_SetChunkData.GetChunkX(); - int ChunkZ = a_SetChunkData.GetChunkZ(); - cChunkSender & ChunkSender = m_ChunkSender; - DoWithChunk( - ChunkX, ChunkZ, - [&ChunkSender] (cChunk & a_Chunk) -> bool - { - if (a_Chunk.HasAnyClients()) - { - ChunkSender.QueueSendChunkTo( - a_Chunk.GetPosX(), - a_Chunk.GetPosZ(), - cChunkSender::E_CHUNK_PRIORITY_MEDIUM, - a_Chunk.GetAllClients() - ); - } - return true; - } - ); - // 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, ChunkZ); + m_Storage.QueueSaveChunk(a_SetChunkData.GetChunkX(), a_SetChunkData.GetChunkZ()); } } @@ -2992,41 +2696,33 @@ void cWorld::CollectPickupsByPlayer(cPlayer & a_Player) void cWorld::AddPlayer(cPlayer * a_Player) { - cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.push_back(a_Player); + ASSERT(m_TickThread.IsCurrentThread()); + + m_Players.emplace_back(a_Player); + + // Stream chunks to all eligible clients: + auto Client = a_Player->GetClientHandle(); + if (Client != nullptr) + { + Client->SendHealth(); + Client->SendWholeInventory(*a_Player->GetWindow()); + + if (GetDimension() == dimOverworld) + { + Client->SendWeather(GetWeather()); + } + } + // Don't worry, the client handle may have been deleted right after a world move operation was queued } -void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) +void cWorld::RemovePlayer(cPlayer * a_Player) { - if (a_RemoveFromChunk) - { - // To prevent iterator invalidations when an entity goes through a portal and calls this function whilst being ticked by cChunk - // we should not change cChunk's entity list if asked not to - m_ChunkMap->RemoveEntity(a_Player); - } - { - cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.remove(a_Player); - } - { - cCSLock Lock(m_CSPlayers); - LOGD("Removing player %s from world \"%s\"", a_Player->GetName().c_str(), m_WorldName.c_str()); - m_Players.remove(a_Player); - } - - // Remove the player's client from the list of clients to be ticked: - cClientHandle * Client = a_Player->GetClientHandle(); - if (Client != nullptr) - { - Client->RemoveFromWorld(); - m_ChunkMap->RemoveClientFromChunks(Client); - cCSLock Lock(m_CSClients); - m_ClientsToRemove.push_back(Client); - } + LOGD("Removing player %s from world \"%s\"", a_Player->GetName().c_str(), m_WorldName.c_str()); + m_Players.erase(std::remove(m_Players.begin(), m_Players.end(), a_Player), m_Players.end()); } @@ -3036,8 +2732,7 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback) { // Calls the callback for each player in the list - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(), itr2 = itr; itr != m_Players.end(); itr = itr2) + for (auto itr = m_Players.begin(), itr2 = itr; itr != m_Players.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) @@ -3059,19 +2754,19 @@ bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback) bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback) { // Calls the callback for the specified player in the list - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - if (!(*itr)->IsTicking()) + if (!Player->IsTicking()) { continue; } - if (NoCaseCompare((*itr)->GetName(), a_PlayerName) == 0) + + if (NoCaseCompare(Player->GetName(), a_PlayerName) == 0) { - a_Callback.Item(*itr); + a_Callback.Item(Player); return true; } - } // for itr - m_Players[] + } return false; } @@ -3085,24 +2780,24 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa size_t BestRating = 0; size_t NameLength = a_PlayerNameHint.length(); - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - if (!(*itr)->IsTicking()) + if (!Player->IsTicking()) { continue; } - size_t Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName()); + + size_t Rating = RateCompareString (a_PlayerNameHint, Player->GetName()); if (Rating >= BestRating) { - BestMatch = *itr; + BestMatch = Player; BestRating = Rating; } if (Rating == NameLength) // Perfect match { break; } - } // for itr - m_Players[] + } if (BestMatch != nullptr) { @@ -3117,16 +2812,16 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback) { - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - if (!(*itr)->IsTicking()) + if (!Player->IsTicking()) { continue; } - if ((*itr)->GetUUID() == a_PlayerUUID) + + if (Player->GetUUID() == a_PlayerUUID) { - return a_Callback.Item(*itr); + return a_Callback.Item(Player); } } return false; @@ -3144,14 +2839,14 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, double ClosestDistance = a_SightLimit; cPlayer * ClosestPlayer = nullptr; - cCSLock Lock(m_CSPlayers); - for (cPlayerList::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - if (!(*itr)->IsTicking()) + if (!Player->IsTicking()) { continue; } - Vector3f Pos = (*itr)->GetPosition(); + + Vector3f Pos = Player->GetPosition(); double Distance = (Pos - a_Pos).Length(); if (Distance < ClosestDistance) @@ -3161,13 +2856,13 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, if (!LineOfSight.Trace(a_Pos, (Pos - a_Pos), static_cast<int>((Pos - a_Pos).Length()))) { ClosestDistance = Distance; - ClosestPlayer = *itr; + ClosestPlayer = Player; } } else { ClosestDistance = Distance; - ClosestPlayer = *itr; + ClosestPlayer = Player; } } } @@ -3181,13 +2876,12 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, void cWorld::SendPlayerList(cPlayer * a_DestPlayer) { // Sends the playerlist to a_DestPlayer - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for (const auto & Player : m_Players) { - cClientHandle * ch = (*itr)->GetClientHandle(); + cClientHandle * ch = Player->GetClientHandle(); if ((ch != nullptr) && !ch->IsDestroyed()) { - a_DestPlayer->GetClientHandle()->SendPlayerListAddPlayer(*(*itr)); + a_DestPlayer->GetClientHandle()->SendPlayerListAddPlayer(*Player); } } } @@ -3225,19 +2919,6 @@ bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback) { - // First check the entities-to-add: - { - cCSLock Lock(m_CSEntitiesToAdd); - for (auto & ent: m_EntitiesToAdd) - { - if (ent->GetUniqueID() == a_UniqueID) - { - a_Callback.Item(ent); - return true; - } - } // for ent - m_EntitiesToAdd[] - } - // Then check the chunkmap: return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback); } @@ -3255,7 +2936,7 @@ void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, in -bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) +bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkZ, const std::shared_ptr<cClientHandle> & a_Client) { return m_ChunkMap->AddChunkClient(a_ChunkX, a_ChunkZ, a_Client); } @@ -3264,7 +2945,7 @@ bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client -void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) +void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, const std::shared_ptr<cClientHandle> & a_Client) { m_ChunkMap->RemoveChunkClient(a_ChunkX, a_ChunkZ, a_Client); } @@ -3273,43 +2954,6 @@ void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Cli -void cWorld::RemoveClientFromChunks(cClientHandle * a_Client) -{ - m_ChunkMap->RemoveClientFromChunks(a_Client); -} - - - - - -void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority, cClientHandle * a_Client) -{ - m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, a_Client); -} - - - - - -void cWorld::ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority, cClientHandle * a_Client) -{ - a_Client->AddWantedChunk(a_ChunkX, a_ChunkZ); - m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, a_Client); -} - - - - - -void cWorld::RemoveClientFromChunkSender(cClientHandle * a_Client) -{ - m_ChunkSender.RemoveClient(a_Client); -} - - - - - void cWorld::TouchChunk(int a_ChunkX, int a_ChunkZ) { m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkZ); @@ -3500,16 +3144,6 @@ void cWorld::QueueSaveAllChunks(void) -void cWorld::QueueTask(std::function<void(cWorld &)> a_Task) -{ - cCSLock Lock(m_CSTasks); - m_Tasks.emplace_back(0, 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(); @@ -3517,7 +3151,7 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas // Insert the task into the list of scheduled tasks { cCSLock Lock(m_CSTasks); - m_Tasks.emplace_back(TargetTick, a_Task); + m_Tasks.emplace_back(TargetTick, decltype(m_Tasks)::value_type::second_type(a_Task)); } } @@ -3527,9 +3161,6 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas void cWorld::AddEntity(cEntity * a_Entity) { - a_Entity->SetWorld(this); - cCSLock Lock(m_CSEntitiesToAdd); - m_EntitiesToAdd.push_back(a_Entity); } @@ -3538,20 +3169,8 @@ void cWorld::AddEntity(cEntity * a_Entity) bool cWorld::HasEntity(UInt32 a_UniqueID) { - // Check if the entity is in the queue to be added to the world: - { - cCSLock Lock(m_CSEntitiesToAdd); - for (cEntityList::const_iterator itr = m_EntitiesToAdd.begin(), end = m_EntitiesToAdd.end(); itr != end; ++itr) - { - if ((*itr)->GetUniqueID() == a_UniqueID) - { - return true; - } - } // for itr - m_EntitiesToAdd[] - } - // Check if the entity is in the chunkmap: - if (m_ChunkMap.get() == nullptr) + if (m_ChunkMap == nullptr) { // Chunkmap has already been destroyed, there are no entities anymore. return false; @@ -3740,13 +3359,12 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul std::vector<pair_t> UsernamesByWeight; - cCSLock Lock(m_CSPlayers); - for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr) + for (const auto & Player : m_Players) { - AString PlayerName ((*itr)->GetName()); - if ((*itr)->HasCustomName()) + AString PlayerName = Player->GetName(); + if (Player->HasCustomName()) { - PlayerName = (*itr)->GetCustomName(); + PlayerName = Player->GetCustomName(); } AString::size_type Found = StrToLower(PlayerName).find(StrToLower(LastWord)); // Try to find last word in playername @@ -3757,7 +3375,6 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul UsernamesByWeight.push_back(std::make_pair(Found, PlayerName)); // Match! Store it with the position of the match as a weight } - Lock.Unlock(); std::sort(UsernamesByWeight.begin(), UsernamesByWeight.end()); // Sort lexicographically (by the first value, then second), so higher weights (usernames with match closer to start) come first (#1274) @@ -3889,66 +3506,6 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c - -void cWorld::AddQueuedPlayers(void) -{ - ASSERT(m_TickThread.IsCurrentThread()); - - // Grab the list of players to add, it has to be locked to access it: - cPlayerList PlayersToAdd; - { - cCSLock Lock(m_CSPlayersToAdd); - std::swap(PlayersToAdd, m_PlayersToAdd); - } - - // Add all the players in the grabbed list: - { - cCSLock Lock(m_CSPlayers); - for (auto Player : PlayersToAdd) - { - ASSERT(std::find(m_Players.begin(), m_Players.end(), Player) == m_Players.end()); // Is it already in the list? HOW? - LOGD("Adding player %s to world \"%s\".", Player->GetName().c_str(), m_WorldName.c_str()); - - m_Players.push_back(Player); - Player->SetWorld(this); - - // Add to chunkmap, if not already there (Spawn vs MoveToWorld): - m_ChunkMap->AddEntityIfNotPresent(Player); - ASSERT(!Player->IsTicking()); - Player->SetIsTicking(true); - } // for itr - PlayersToAdd[] - } // Lock(m_CSPlayers) - - // Add all the players' clienthandles: - { - cCSLock Lock(m_CSClients); - for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) - { - cClientHandlePtr Client = (*itr)->GetClientHandlePtr(); - if (Client != nullptr) - { - m_Clients.push_back(Client); - } - } // for itr - PlayersToAdd[] - } // Lock(m_CSClients) - - // Stream chunks to all eligible clients: - for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) - { - cClientHandle * Client = (*itr)->GetClientHandle(); - if (Client != nullptr) - { - Client->SendPlayerMoveLook(); - Client->SendHealth(); - Client->SendWholeInventory(*(*itr)->GetWindow()); - } - } // for itr - PlayersToAdd[] -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cWorld::cChunkGeneratorCallbacks: @@ -3966,7 +3523,7 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc cChunkDef::BlockNibbles BlockMetas; a_ChunkDesc.CompressBlockMetas(BlockMetas); - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData(cSetChunkData( a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_ChunkDesc.GetBlockTypes(), BlockMetas, nullptr, nullptr, // We don't have lighting, chunk will be lighted when needed @@ -3974,7 +3531,7 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc std::move(a_ChunkDesc.GetEntities()), std::move(a_ChunkDesc.GetBlockEntities()), true )); - SetChunkData->RemoveInvalidBlockEntities(); + SetChunkData.RemoveInvalidBlockEntities(); m_World->QueueSetChunkData(SetChunkData); } |