From eb9d45e9065a94c93dc2f1624c22f026b9be3d5f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 19:18:06 +0200 Subject: Moved MaxPlayers and Description from cWorld to cServer. Also started creating a new cWorld::cTickThread class, but not used yet. --- source/World.cpp | 73 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 23 deletions(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index 776bacff8..ebfee971b 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -128,6 +128,9 @@ protected: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorldLightingProgress: + /// A simple thread that displays the progress of world lighting in cWorld::InitializeSpawn() class cWorldLightingProgress : public cIsThread @@ -187,10 +190,46 @@ cWorld::cLock::cLock(cWorld & a_World) : +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorld::cTickThread: + +cWorld::cTickThread::cTickThread(cWorld & a_World) : + super(Printf("WorldTickThread: %s", a_World.GetName().c_str())), + m_World(a_World) +{ +} + + + + + +void cWorld::cTickThread::Execute(void) +{ + const int ClocksPerTick = CLOCKS_PER_SEC / 20; + clock_t LastTime = clock(); + while (!m_ShouldTerminate) + { + clock_t Start = clock(); + m_World.Tick((float)(LastTime - Start) / CLOCKS_PER_SEC); + clock_t Now = clock(); + if (Now - Start < ClocksPerTick) + { + cSleep::MilliSleep(1000 * (ClocksPerTick - (Now - Start)) / CLOCKS_PER_SEC); + } + LastTime = Start; + } +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWorld: cWorld::cWorld(const AString & a_WorldName) : + m_WorldName(a_WorldName), + m_IniFileName(m_WorldName + "/world.ini"), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), m_WorldAge(0), @@ -199,24 +238,26 @@ cWorld::cWorld(const AString & a_WorldName) : m_LastSpawnMonster(0), m_RSList(0), m_Weather(eWeather_Sunny), - m_WeatherInterval(24000) // Guaranteed 1 day of sunshine at server start :) + m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) + m_TickThread(*this) { LOGD("cWorld::cWorld(%s)", a_WorldName.c_str()); - m_WorldName = a_WorldName; - m_IniFileName = m_WorldName + "/world.ini"; cMakeDir::MakeDir(m_WorldName.c_str()); - MTRand r1; - m_SpawnX = (double)((r1.randInt() % 1000) - 500); + // TODO: Find a proper spawn location, based on the biomes (not in ocean) + m_SpawnX = (double)((m_TickRand.randInt() % 1000) - 500); m_SpawnY = cChunkDef::Height; - m_SpawnZ = (double)((r1.randInt() % 1000) - 500); + m_SpawnZ = (double)((m_TickRand.randInt() % 1000) - 500); m_GameMode = eGameMode_Creative; AString StorageSchema("Default"); cIniFile IniFile(m_IniFileName); - IniFile.ReadFile(); + if (!IniFile.ReadFile()) + { + LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str()); + } AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); m_Dimension = StringToDimension(Dimension); switch (m_Dimension) @@ -268,9 +309,6 @@ cWorld::cWorld(const AString & a_WorldName) : m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks - // TODO: Move this into cServer instead: - SetMaxPlayers(IniFile2.GetValueI("Server", "MaxPlayers", 100)); - m_Description = IniFile2.GetValue("Server", "Description", "MCServer! - In C++!").c_str(); } m_ChunkMap = new cChunkMap(this); @@ -1893,19 +1931,6 @@ void cWorld::CollectPickupsByPlayer(cPlayer * a_Player) -void cWorld::SetMaxPlayers(int iMax) -{ - m_MaxPlayers = MAX_PLAYERS; - if (iMax > 0 && iMax < MAX_PLAYERS) - { - m_MaxPlayers = iMax; - } -} - - - - - void cWorld::AddPlayer(cPlayer * a_Player) { cCSLock Lock(m_CSPlayers); @@ -2299,11 +2324,13 @@ void cWorld::RemoveEntity(cEntity * a_Entity) +/* unsigned int cWorld::GetNumPlayers(void) { cCSLock Lock(m_CSPlayers); return m_Players.size(); } +*/ -- cgit v1.2.3 From 4c5590636cf4a311f03e735878557b1e7b3362dd Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 20:16:41 +0200 Subject: Each world now ticks in a separate thread. --- source/World.cpp | 204 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 107 insertions(+), 97 deletions(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index ebfee971b..af66d1ead 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -230,6 +230,7 @@ void cWorld::cTickThread::Execute(void) cWorld::cWorld(const AString & a_WorldName) : m_WorldName(a_WorldName), m_IniFileName(m_WorldName + "/world.ini"), + m_StorageSchema("Default"), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), m_WorldAge(0), @@ -244,102 +245,6 @@ cWorld::cWorld(const AString & a_WorldName) : LOGD("cWorld::cWorld(%s)", a_WorldName.c_str()); cMakeDir::MakeDir(m_WorldName.c_str()); - - // TODO: Find a proper spawn location, based on the biomes (not in ocean) - m_SpawnX = (double)((m_TickRand.randInt() % 1000) - 500); - m_SpawnY = cChunkDef::Height; - m_SpawnZ = (double)((m_TickRand.randInt() % 1000) - 500); - m_GameMode = eGameMode_Creative; - - AString StorageSchema("Default"); - - cIniFile IniFile(m_IniFileName); - if (!IniFile.ReadFile()) - { - LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str()); - } - AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); - m_Dimension = StringToDimension(Dimension); - switch (m_Dimension) - { - case dimNether: - case dimOverworld: - case dimEnd: - { - break; - } - default: - { - LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", Dimension.c_str()); - m_Dimension = dimOverworld; - break; - } - } // switch (m_Dimension) - m_SpawnX = IniFile.GetValueSetF("SpawnPosition", "X", m_SpawnX); - m_SpawnY = IniFile.GetValueSetF("SpawnPosition", "Y", m_SpawnY); - m_SpawnZ = IniFile.GetValueSetF("SpawnPosition", "Z", m_SpawnZ); - StorageSchema = IniFile.GetValueSet ("Storage", "Schema", StorageSchema); - m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); - m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); - m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); - m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true); - m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true); - m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true); - m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true); - m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false); - m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true); - m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true); - m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false); - m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true); - m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); - m_bEnabledPVP = IniFile.GetValueSetB("PVP", "Enabled", true); - m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false); - - m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); - - m_Lighting.Start(this); - m_Storage.Start(this, StorageSchema); - m_Generator.Start(this, IniFile); - - m_bAnimals = true; - m_SpawnMonsterRate = 200; // 1 mob each 10 seconds - cIniFile IniFile2("settings.ini"); - if (IniFile2.ReadFile()) - { - m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); - m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks - - } - - m_ChunkMap = new cChunkMap(this); - - m_ChunkSender.Start(this); - - m_LastSave = 0; - m_LastUnload = 0; - - // preallocate some memory for ticking blocks so we don�t need to allocate that often - m_BlockTickQueue.reserve(1000); - m_BlockTickQueueCopy.reserve(1000); - - // Simulators: - m_SimulatorManager = new cSimulatorManager(*this); - m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); - m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); - m_SandSimulator = new cSandSimulator(*this, IniFile); - m_FireSimulator = new cFireSimulator(*this, IniFile); - m_RedstoneSimulator = new cRedstoneSimulator(*this); - - // Water and Lava simulators get registered in InitializeFluidSimulator() - m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1); - m_SimulatorManager->RegisterSimulator(m_FireSimulator, 1); - m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1); - - // Save any changes that the defaults may have done to the ini file: - if (!IniFile.WriteFile()) - { - LOGWARNING("Could not write world config to %s", m_IniFileName.c_str()); - } } @@ -542,10 +447,115 @@ void cWorld::InitializeSpawn(void) -void cWorld::StopThreads(void) +void cWorld::Start(void) +{ + // TODO: Find a proper spawn location, based on the biomes (not in ocean) + m_SpawnX = (double)((m_TickRand.randInt() % 1000) - 500); + m_SpawnY = cChunkDef::Height; + m_SpawnZ = (double)((m_TickRand.randInt() % 1000) - 500); + m_GameMode = eGameMode_Creative; + + cIniFile IniFile(m_IniFileName); + if (!IniFile.ReadFile()) + { + LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str()); + } + AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); + m_Dimension = StringToDimension(Dimension); + switch (m_Dimension) + { + case dimNether: + case dimOverworld: + case dimEnd: + { + break; + } + default: + { + LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", Dimension.c_str()); + m_Dimension = dimOverworld; + break; + } + } // switch (m_Dimension) + m_SpawnX = IniFile.GetValueSetF("SpawnPosition", "X", m_SpawnX); + m_SpawnY = IniFile.GetValueSetF("SpawnPosition", "Y", m_SpawnY); + m_SpawnZ = IniFile.GetValueSetF("SpawnPosition", "Z", m_SpawnZ); + m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema); + m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); + m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); + m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); + m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true); + m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true); + m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true); + m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true); + m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false); + m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true); + m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true); + m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false); + m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true); + m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); + m_bEnabledPVP = IniFile.GetValueSetB("PVP", "Enabled", true); + m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false); + + m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); + + m_bAnimals = true; + m_SpawnMonsterRate = 200; // 1 mob each 10 seconds + cIniFile IniFile2("settings.ini"); + if (IniFile2.ReadFile()) + { + m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); + m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks + + } + + m_ChunkMap = new cChunkMap(this); + + m_LastSave = 0; + m_LastUnload = 0; + + // preallocate some memory for ticking blocks so we don�t need to allocate that often + m_BlockTickQueue.reserve(1000); + m_BlockTickQueueCopy.reserve(1000); + + // Simulators: + m_SimulatorManager = new cSimulatorManager(*this); + m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); + m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); + m_SandSimulator = new cSandSimulator(*this, IniFile); + m_FireSimulator = new cFireSimulator(*this, IniFile); + m_RedstoneSimulator = new cRedstoneSimulator(*this); + + // Water and Lava simulators get registered in InitializeFluidSimulator() + m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1); + m_SimulatorManager->RegisterSimulator(m_FireSimulator, 1); + m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1); + + m_Lighting.Start(this); + m_Storage.Start(this, m_StorageSchema); + m_Generator.Start(this, IniFile); + m_ChunkSender.Start(this); + m_TickThread.Start(); + + // Save any changes that the defaults may have done to the ini file: + if (!IniFile.WriteFile()) + { + LOGWARNING("Could not write world config to %s", m_IniFileName.c_str()); + } + +} + + + + + +void cWorld::Stop(void) { + m_TickThread.Stop(); + m_Lighting.Stop(); m_Generator.Stop(); m_ChunkSender.Stop(); + m_Storage.Stop(); } -- cgit v1.2.3 From 829cc866cd63c50ebff4dac2f942a0df93d269fc Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 21:05:44 +0200 Subject: Added cWorld:QueueSaveAllChunks() function for saving chunks asynchronously. The cWorld:SaveAllChunks() is therefore deprecated in the API and will be removed soon, use QueueSaveAllChunks() instead. --- source/World.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index af66d1ead..9212202e9 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "BlockID.h" @@ -242,7 +243,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) m_TickThread(*this) { - LOGD("cWorld::cWorld(%s)", a_WorldName.c_str()); + LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); cMakeDir::MakeDir(m_WorldName.c_str()); } @@ -587,6 +588,7 @@ void cWorld::Tick(float a_Dt) m_ChunkMap->Tick(a_Dt); TickQueuedBlocks(a_Dt); + TickQueuedTasks(); GetSimulatorManager()->Simulate(a_Dt); @@ -781,6 +783,27 @@ void cWorld::TickSpawnMobs(float a_Dt) +void cWorld::TickQueuedTasks(void) +{ + // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks + cTasks Tasks; + { + cCSLock Lock(m_CSTasks); + std::swap(Tasks, m_Tasks); + } + + // Execute and delete each task: + for (cTasks::iterator itr = m_Tasks.begin(), end = m_Tasks.end(); itr != end; ++itr) + { + (*itr)->Run(*this); + delete *itr; + } // for itr - m_Tasks[] +} + + + + + void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) { return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); @@ -2307,6 +2330,25 @@ void cWorld::SaveAllChunks(void) +void cWorld::QueueSaveAllChunks(void) +{ + QueueTask(new cWorld::cTaskSaveAllChunks); +} + + + + + +void cWorld::QueueTask(cTask * a_Task) +{ + cCSLock Lock(m_CSTasks); + m_Tasks.push_back(a_Task); +} + + + + + void cWorld::AddEntity(cEntity * a_Entity) { m_ChunkMap->AddEntity(a_Entity); @@ -2552,3 +2594,15 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorld::cTaskSaveAllChunks: + +void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) +{ + a_World.SaveAllChunks(); +} + + + + -- cgit v1.2.3 From c628ab03e9aae0b8e56f260ad02cfc7d51285a71 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 12 Aug 2013 08:35:13 +0200 Subject: Removed cServer::BroadcastChat() and cServer::SendMessage(). These two functions make it difficult to move to the new ticking system, and they aren't used anyway. If so required, they can be emulated by ForEachWorld / ForEachPlayer calls. --- source/World.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index 341682a2a..b29bc751f 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -578,7 +578,7 @@ void cWorld::Tick(float a_Dt) m_WorldAge = (Int64)(m_WorldAgeSecs * 20.0); m_TimeOfDay = (Int64)(m_TimeOfDaySecs * 20.0); - // Broadcase time update every 40 ticks (2 seconds) + // Broadcast time update every 40 ticks (2 seconds) if (m_LastTimeUpdate < m_WorldAge - 40) { BroadcastTimeUpdate(); -- cgit v1.2.3 From 9020dc993241a4a90e8e98b3435d9b2576f313ea Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 13 Aug 2013 22:45:29 +0200 Subject: Clients are now ticked in cServer first, then in cWorld once they get assigned a world. --- source/World.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 8 deletions(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index b29bc751f..7a1ecb82e 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -587,6 +587,7 @@ void cWorld::Tick(float a_Dt) m_ChunkMap->Tick(a_Dt); + TickClients(a_Dt); TickQueuedBlocks(a_Dt); TickQueuedTasks(); @@ -811,6 +812,37 @@ void cWorld::TickQueuedTasks(void) +void cWorld::TickClients(float a_Dt) +{ + cClientHandleList RemoveClients; + { + cCSLock Lock(m_CSClients); + // Tick the clients, take out those that have been destroyed into RemoveClients + for (cClientHandleList::iterator 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 that have been destroyed + for (cClientHandleList::iterator itr = RemoveClients.begin(); itr != RemoveClients.end(); ++itr) + { + delete *itr; + } // for itr - RemoveClients[] +} + + + + + void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) { return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); @@ -1973,13 +2005,22 @@ void cWorld::CollectPickupsByPlayer(cPlayer * a_Player) void cWorld::AddPlayer(cPlayer * a_Player) { - cCSLock Lock(m_CSPlayers); - - ASSERT(std::find(m_Players.begin(), m_Players.end(), a_Player) == m_Players.end()); // Is it already in the list? HOW? - - m_Players.remove(a_Player); // Make sure the player is registered only once - m_Players.push_back(a_Player); + { + cCSLock Lock(m_CSPlayers); + + ASSERT(std::find(m_Players.begin(), m_Players.end(), a_Player) == m_Players.end()); // Is it already in the list? HOW? + + m_Players.remove(a_Player); // Make sure the player is registered only once + m_Players.push_back(a_Player); + } + // Add the player's client to the list of clients to be ticked: + if (a_Player->GetClientHandle() != NULL) + { + cCSLock Lock(m_CSClients); + m_Clients.push_back(a_Player->GetClientHandle()); + } + // The player has already been added to the chunkmap as the entity, do NOT add again! } @@ -1990,8 +2031,17 @@ void cWorld::AddPlayer(cPlayer * a_Player) void cWorld::RemovePlayer(cPlayer * a_Player) { m_ChunkMap->RemoveEntity(a_Player); - cCSLock Lock(m_CSPlayers); - m_Players.remove(a_Player); + { + cCSLock Lock(m_CSPlayers); + m_Players.remove(a_Player); + } + + // Remove the player's client from the list of clients to be ticked: + if (a_Player->GetClientHandle() != NULL) + { + cCSLock Lock(m_CSClients); + m_Clients.remove(a_Player->GetClientHandle()); + } } -- cgit v1.2.3 From f8757d3606a9cf14a353e5b7a61b8e660a4cce6d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 14 Aug 2013 13:43:55 +0200 Subject: Fixed crashes in world's clientlist manipulators --- source/World.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index 7a1ecb82e..59240c7da 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -817,6 +817,26 @@ void cWorld::TickClients(float a_Dt) cClientHandleList RemoveClients; { cCSLock Lock(m_CSClients); + + // Remove clients scheduled for removal: + for (cClientHandleList::iterator itr = m_ClientsToRemove.begin(), end = m_ClientsToRemove.end(); itr != end; ++itr) + { + m_Clients.remove(*itr); + } // for itr - m_ClientsToRemove[] + m_ClientsToRemove.clear(); + + // Add clients scheduled for adding: + for (cClientHandleList::iterator itr = m_ClientsToAdd.begin(), end = m_ClientsToAdd.end(); itr != end; ++itr) + { + if (std::find(m_Clients.begin(), m_Clients.end(), *itr) != m_Clients.end()) + { + ASSERT(!"Adding a client that is already in the clientlist"); + continue; + } + 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 (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end();) { @@ -2018,7 +2038,7 @@ void cWorld::AddPlayer(cPlayer * a_Player) if (a_Player->GetClientHandle() != NULL) { cCSLock Lock(m_CSClients); - m_Clients.push_back(a_Player->GetClientHandle()); + m_ClientsToAdd.push_back(a_Player->GetClientHandle()); } // The player has already been added to the chunkmap as the entity, do NOT add again! @@ -2040,7 +2060,7 @@ void cWorld::RemovePlayer(cPlayer * a_Player) if (a_Player->GetClientHandle() != NULL) { cCSLock Lock(m_CSClients); - m_Clients.remove(a_Player->GetClientHandle()); + m_ClientsToRemove.push_back(a_Player->GetClientHandle()); } } -- cgit v1.2.3 From e2ff4a2e5c654e1c4c33f5a9098bef35e0755897 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 14 Aug 2013 19:56:29 +0200 Subject: Clients are deleted when the world is stopped. This fixes #92. --- source/World.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index 59240c7da..5c3a24177 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -552,6 +552,17 @@ void cWorld::Start(void) void cWorld::Stop(void) { + // Delete the clients that have been in this world: + { + cCSLock Lock(m_CSClients); + for (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) + { + (*itr)->Destroy(); + delete *itr; + } // for itr - m_Clients[] + m_Clients.clear(); + } + m_TickThread.Stop(); m_Lighting.Stop(); m_Generator.Stop(); -- cgit v1.2.3 From f93d13c41993ba86cad8303fe0b07ec2098dac39 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 14 Aug 2013 22:36:34 +0200 Subject: Fixed world's a_Dt parameter getting time values in wrong units. --- source/World.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/World.cpp') diff --git a/source/World.cpp b/source/World.cpp index 5c3a24177..4cc130811 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -211,7 +211,7 @@ void cWorld::cTickThread::Execute(void) while (!m_ShouldTerminate) { clock_t Start = clock(); - m_World.Tick((float)(LastTime - Start) / CLOCKS_PER_SEC); + m_World.Tick((float)(1000 * (Start - LastTime)) / CLOCKS_PER_SEC); clock_t Now = clock(); if (Now - Start < ClocksPerTick) { -- cgit v1.2.3