summaryrefslogtreecommitdiffstats
path: root/src/World.cpp
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@hotmail.co.uk>2016-08-20 14:34:29 +0200
committerTiger Wang <ziwei.tiger@hotmail.co.uk>2016-08-20 14:34:29 +0200
commit7175b9e435a54cff33914d21384625a445cc5cf0 (patch)
tree7feb44f1e8e4ed7ea4d5bf0ba1d173abd3417f34 /src/World.cpp
parentAdded cWorld:SetSpawn() API and Lua binding (#3316) (diff)
downloadcuberite-7175b9e435a54cff33914d21384625a445cc5cf0.tar
cuberite-7175b9e435a54cff33914d21384625a445cc5cf0.tar.gz
cuberite-7175b9e435a54cff33914d21384625a445cc5cf0.tar.bz2
cuberite-7175b9e435a54cff33914d21384625a445cc5cf0.tar.lz
cuberite-7175b9e435a54cff33914d21384625a445cc5cf0.tar.xz
cuberite-7175b9e435a54cff33914d21384625a445cc5cf0.tar.zst
cuberite-7175b9e435a54cff33914d21384625a445cc5cf0.zip
Diffstat (limited to '')
-rw-r--r--src/World.cpp949
1 files changed, 248 insertions, 701 deletions
diff --git a/src/World.cpp b/src/World.cpp
index c687e9549..242345f02 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,17 +248,11 @@ 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();
m_MapManager.SaveMapData();
-
- // Explicitly destroy the chunkmap, so that it's guaranteed to be destroyed before the other internals
- // This fixes crashes on stopping the server, because chunk destructor deletes entities and those access the world.
- m_ChunkMap.reset();
}
@@ -351,29 +375,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 +469,7 @@ void cWorld::InitializeSpawn(void)
-void cWorld::Start(void)
+void cWorld::Initialise()
{
m_SpawnX = 0;
m_SpawnY = cChunkDef::Height;
@@ -617,7 +653,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 +673,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 +786,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 +809,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 +833,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 +852,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
{
UnloadUnusedChunks();
}
-
}
@@ -1109,9 +894,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);
@@ -1144,7 +926,7 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt)
// do the spawn
for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2)
{
- SpawnMobFinalize(*itr2);
+ SpawnMobFinalize(std::move(const_cast<std::unique_ptr<cMonster> &>(*itr2)));
}
}
} // for i - AllFamilies[]
@@ -1213,7 +995,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 +1018,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 +1147,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);
}
}
@@ -1571,7 +1303,7 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback
-bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback)
+bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback)
{
struct cCallBackWrapper : cChunkCallback
{
@@ -2168,11 +1900,11 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
float SpeedY = static_cast<float>(a_FlyAwaySpeed * GetTickRandomNumber(50));
float SpeedZ = static_cast<float>(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
- cPickup * Pickup = new cPickup(
+ auto Pickup = cpp14::make_unique<cPickup>(
a_BlockX, a_BlockY, a_BlockZ,
*itr, IsPlayerCreated, SpeedX, SpeedY, SpeedZ
);
- Pickup->Initialize(*this);
+ Pickup->Initialize(std::move(Pickup), *this);
}
}
@@ -2189,11 +1921,11 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
continue;
}
- cPickup * Pickup = new cPickup(
+ auto Pickup = cpp14::make_unique<cPickup>(
a_BlockX, a_BlockY, a_BlockZ,
*itr, IsPlayerCreated, static_cast<float>(a_SpeedX), static_cast<float>(a_SpeedY), static_cast<float>(a_SpeedZ)
);
- Pickup->Initialize(*this);
+ Pickup->Initialize(std::move(Pickup), *this);
}
}
@@ -2203,9 +1935,10 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
UInt32 cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta)
{
- cFallingBlock * FallingBlock = new cFallingBlock(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta);
- FallingBlock->Initialize(*this);
- return FallingBlock->GetUniqueID();
+ auto FallingBlock = cpp14::make_unique<cFallingBlock>(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta);
+ auto ID = FallingBlock->GetUniqueID();
+ FallingBlock->Initialize(std::move(FallingBlock), *this);
+ return ID;
}
@@ -2220,9 +1953,10 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa
return cEntity::INVALID_ID;
}
- cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward);
- ExpOrb->Initialize(*this);
- return ExpOrb->GetUniqueID();
+ auto ExpOrb = cpp14::make_unique<cExpOrb>(a_X, a_Y, a_Z, a_Reward);
+ auto ID = ExpOrb->GetUniqueID();
+ ExpOrb->Initialize(std::move(ExpOrb), *this);
+ return ID;
}
@@ -2231,21 +1965,23 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa
UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
{
- cMinecart * Minecart;
+ std::unique_ptr<cMinecart> Minecart;
switch (a_MinecartType)
{
- case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break;
- case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break;
- case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break;
- case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break;
- case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART: Minecart = cpp14::make_unique<cRideableMinecart>(a_X, a_Y, a_Z, a_Content, a_BlockHeight); break;
+ case E_ITEM_CHEST_MINECART: Minecart = cpp14::make_unique<cMinecartWithChest>(a_X, a_Y, a_Z); break;
+ case E_ITEM_FURNACE_MINECART: Minecart = cpp14::make_unique<cMinecartWithFurnace>(a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART_WITH_TNT: Minecart = cpp14::make_unique<cMinecartWithTNT>(a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART_WITH_HOPPER: Minecart = cpp14::make_unique<cMinecartWithHopper>(a_X, a_Y, a_Z); break;
default:
{
return cEntity::INVALID_ID;
}
} // switch (a_MinecartType)
- Minecart->Initialize(*this);
- return Minecart->GetUniqueID();
+
+ auto ID = Minecart->GetUniqueID();
+ Minecart->Initialize(std::move(Minecart), *this);
+ return ID;
}
@@ -2254,17 +1990,13 @@ UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartT
UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z)
{
- cBoat * Boat = new cBoat(a_X, a_Y, a_Z);
- if (Boat == nullptr)
+ auto Boat = cpp14::make_unique<cBoat>(a_X, a_Y, a_Z);
+ auto ID = Boat->GetUniqueID();
+ if (!Boat->Initialize(std::move(Boat), *this))
{
return cEntity::INVALID_ID;
}
- if (!Boat->Initialize(*this))
- {
- delete Boat;
- return cEntity::INVALID_ID;
- }
- return Boat->GetUniqueID();
+ return ID;
}
@@ -2272,14 +2004,15 @@ UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z)
UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
{
- cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
- TNT->Initialize(*this);
+ auto TNT = cpp14::make_unique<cTNTEntity>(a_X, a_Y, a_Z, a_FuseTicks);
+ auto ID = TNT->GetUniqueID();
TNT->SetSpeed(
- a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */
+ a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /* -1, 0, 1 */
a_InitialVelocityCoeff * 2,
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1)
);
- return TNT->GetUniqueID();
+ TNT->Initialize(std::move(TNT), *this);
+ return ID;
}
@@ -2390,10 +2123,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 +2140,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 +2274,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 +2291,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 +2308,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 +2325,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 +2342,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 +2368,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 +2385,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 +2402,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 +2446,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 +2472,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 +2498,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 +2549,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,39 +2586,17 @@ 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)
+ for (auto & Entity : a_SetChunkData.GetEntities())
{
- (*itr)->Initialize(*this);
+ Entity->Initialize(std::move(Entity), *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 +2692,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 +2728,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 +2750,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 +2776,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 +2808,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 +2835,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 +2852,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 +2872,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 +2915,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 +2932,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 +2941,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 +2950,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 +3140,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 +3147,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));
}
}
@@ -3525,11 +3155,9 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas
-void cWorld::AddEntity(cEntity * a_Entity)
+void cWorld::AddEntity(std::unique_ptr<cEntity> a_Entity)
{
- a_Entity->SetWorld(this);
- cCSLock Lock(m_CSEntitiesToAdd);
- m_EntitiesToAdd.push_back(a_Entity);
+ m_ChunkMap->AddEntity(std::move(a_Entity));
}
@@ -3538,20 +3166,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;
@@ -3655,9 +3271,7 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ)
UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby)
{
- cMonster * Monster = nullptr;
-
- Monster = cMonster::NewMonsterFromType(a_MonsterType);
+ auto Monster = cMonster::NewMonsterFromType(a_MonsterType);
if (Monster == nullptr)
{
return cEntity::INVALID_ID;
@@ -3669,13 +3283,13 @@ UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterTyp
Monster->SetAge(-1);
}
- return SpawnMobFinalize(Monster);
+ return SpawnMobFinalize(std::move(Monster));
}
-UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster)
+UInt32 cWorld::SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster)
{
ASSERT(a_Monster != nullptr);
@@ -3685,22 +3299,20 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster)
// A plugin doesn't agree with the spawn. bail out.
if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster))
{
- delete a_Monster;
- a_Monster = nullptr;
return cEntity::INVALID_ID;
}
+ auto & Monster = *a_Monster;
+
// Initialize the monster into the current world.
- if (!a_Monster->Initialize(*this))
+ if (!a_Monster->Initialize(std::move(a_Monster), *this))
{
- delete a_Monster;
- a_Monster = nullptr;
return cEntity::INVALID_ID;
}
- cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster);
+ cPluginManager::Get()->CallHookSpawnedMonster(*this, Monster);
- return a_Monster->GetUniqueID();
+ return Monster.GetUniqueID();
}
@@ -3709,18 +3321,15 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster)
UInt32 cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed)
{
- cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
- if (Projectile == nullptr)
- {
- return cEntity::INVALID_ID;
- }
- if (!Projectile->Initialize(*this))
+ auto Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
+ auto ID = Projectile->GetUniqueID();
+
+ if ((Projectile == nullptr) || !Projectile->Initialize(std::move(Projectile), *this))
{
- delete Projectile;
- Projectile = nullptr;
return cEntity::INVALID_ID;
}
- return Projectile->GetUniqueID();
+
+ return ID;
}
@@ -3740,13 +3349,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 +3365,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 +3496,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 +3513,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 +3521,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);
}