Each world now ticks in a separate thread.
This commit is contained in:
parent
c59d80a2af
commit
4c5590636c
@ -270,8 +270,9 @@ void cRoot::LoadWorlds(void)
|
|||||||
|
|
||||||
void cRoot::StartWorlds(void)
|
void cRoot::StartWorlds(void)
|
||||||
{
|
{
|
||||||
for( WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr )
|
for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
|
||||||
{
|
{
|
||||||
|
itr->second->Start();
|
||||||
itr->second->InitializeSpawn();
|
itr->second->InitializeSpawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,9 +283,9 @@ void cRoot::StartWorlds(void)
|
|||||||
|
|
||||||
void cRoot::StopWorlds(void)
|
void cRoot::StopWorlds(void)
|
||||||
{
|
{
|
||||||
for( WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr )
|
for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
|
||||||
{
|
{
|
||||||
itr->second->StopThreads();
|
itr->second->Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +345,7 @@ bool cRoot::ForEachWorld(cWorldListCallback & a_Callback)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRoot::TickWorlds(float a_Dt)
|
void cRoot::TickCommands(void)
|
||||||
{
|
{
|
||||||
// Execute any pending commands:
|
// Execute any pending commands:
|
||||||
cCommandQueue PendingCommands;
|
cCommandQueue PendingCommands;
|
||||||
@ -356,12 +357,6 @@ void cRoot::TickWorlds(float a_Dt)
|
|||||||
{
|
{
|
||||||
ExecuteConsoleCommand(itr->m_Command, *(itr->m_Output));
|
ExecuteConsoleCommand(itr->m_Command, *(itr->m_Output));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tick the worlds:
|
|
||||||
for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
|
|
||||||
{
|
|
||||||
itr->second->Tick(a_Dt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,7 +86,8 @@ public:
|
|||||||
/// Called by cAuthenticator to auth the specified user
|
/// Called by cAuthenticator to auth the specified user
|
||||||
void AuthenticateUser(int a_ClientID);
|
void AuthenticateUser(int a_ClientID);
|
||||||
|
|
||||||
void TickWorlds(float a_Dt);
|
/// Executes commands queued in the command queue
|
||||||
|
void TickCommands(void);
|
||||||
|
|
||||||
/// Returns the number of chunks loaded
|
/// Returns the number of chunks loaded
|
||||||
int GetTotalChunkCount(void); // tolua_export
|
int GetTotalChunkCount(void); // tolua_export
|
||||||
|
@ -317,7 +317,7 @@ void cServer::BroadcastChat(const AString & a_Message, const cClientHandle * a_E
|
|||||||
|
|
||||||
bool cServer::Tick(float a_Dt)
|
bool cServer::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
cRoot::Get()->TickWorlds(a_Dt);
|
cRoot::Get()->TickCommands();
|
||||||
|
|
||||||
cClientHandleList RemoveClients;
|
cClientHandleList RemoveClients;
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ public: // tolua_export
|
|||||||
/// Binds the built-in console commands with the plugin manager
|
/// Binds the built-in console commands with the plugin manager
|
||||||
static void BindBuiltInConsoleCommands(void);
|
static void BindBuiltInConsoleCommands(void);
|
||||||
|
|
||||||
void Shutdown();
|
void Shutdown(void);
|
||||||
|
|
||||||
void SendMessage(const AString & a_Message, cPlayer * a_Player = NULL, bool a_bExclude = false ); // tolua_export
|
void SendMessage(const AString & a_Message, cPlayer * a_Player = NULL, bool a_bExclude = false ); // tolua_export
|
||||||
|
|
||||||
|
204
source/World.cpp
204
source/World.cpp
@ -230,6 +230,7 @@ void cWorld::cTickThread::Execute(void)
|
|||||||
cWorld::cWorld(const AString & a_WorldName) :
|
cWorld::cWorld(const AString & a_WorldName) :
|
||||||
m_WorldName(a_WorldName),
|
m_WorldName(a_WorldName),
|
||||||
m_IniFileName(m_WorldName + "/world.ini"),
|
m_IniFileName(m_WorldName + "/world.ini"),
|
||||||
|
m_StorageSchema("Default"),
|
||||||
m_WorldAgeSecs(0),
|
m_WorldAgeSecs(0),
|
||||||
m_TimeOfDaySecs(0),
|
m_TimeOfDaySecs(0),
|
||||||
m_WorldAge(0),
|
m_WorldAge(0),
|
||||||
@ -244,102 +245,6 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||||||
LOGD("cWorld::cWorld(%s)", a_WorldName.c_str());
|
LOGD("cWorld::cWorld(%s)", a_WorldName.c_str());
|
||||||
|
|
||||||
cMakeDir::MakeDir(m_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<6F>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<6F>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_Generator.Stop();
|
||||||
m_ChunkSender.Stop();
|
m_ChunkSender.Stop();
|
||||||
|
m_Storage.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -477,8 +477,12 @@ public:
|
|||||||
|
|
||||||
void InitializeSpawn(void);
|
void InitializeSpawn(void);
|
||||||
|
|
||||||
|
/// Starts threads that belong to this world
|
||||||
|
void Start(void);
|
||||||
|
|
||||||
/// Stops threads that belong to this world (part of deinit)
|
/// Stops threads that belong to this world (part of deinit)
|
||||||
void StopThreads(void);
|
void Stop(void);
|
||||||
|
|
||||||
void TickQueuedBlocks(float a_Dt);
|
void TickQueuedBlocks(float a_Dt);
|
||||||
|
|
||||||
struct BlockTickQueueItem
|
struct BlockTickQueueItem
|
||||||
@ -548,6 +552,9 @@ private:
|
|||||||
AString m_WorldName;
|
AString m_WorldName;
|
||||||
AString m_IniFileName;
|
AString m_IniFileName;
|
||||||
|
|
||||||
|
/// Name of the storage schema used to load and save chunks
|
||||||
|
AString m_StorageSchema;
|
||||||
|
|
||||||
/// The dimension of the world, used by the client to provide correct lighting scheme
|
/// The dimension of the world, used by the client to provide correct lighting scheme
|
||||||
eDimension m_Dimension;
|
eDimension m_Dimension;
|
||||||
|
|
||||||
|
@ -84,6 +84,15 @@ bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorldStorage::Stop(void)
|
||||||
|
{
|
||||||
|
WaitForFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::WaitForFinish(void)
|
void cWorldStorage::WaitForFinish(void)
|
||||||
{
|
{
|
||||||
LOG("Waiting for the world storage to finish saving");
|
LOG("Waiting for the world storage to finish saving");
|
||||||
|
@ -75,6 +75,7 @@ public:
|
|||||||
void UnqueueSave(const cChunkCoords & a_Chunk);
|
void UnqueueSave(const cChunkCoords & a_Chunk);
|
||||||
|
|
||||||
bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
|
bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
|
||||||
|
void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event
|
||||||
void WaitForFinish(void);
|
void WaitForFinish(void);
|
||||||
void WaitForQueuesEmpty(void);
|
void WaitForQueuesEmpty(void);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user