summaryrefslogtreecommitdiffstats
path: root/src/World.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/World.cpp')
-rw-r--r--src/World.cpp302
1 files changed, 203 insertions, 99 deletions
diff --git a/src/World.cpp b/src/World.cpp
index c188fd522..6bcd1391a 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -316,12 +316,9 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather)
{
return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes
}
- default:
- {
- LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
- return -1;
- }
- } // switch (Weather)
+ }
+ LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
+ return -1;
}
@@ -397,10 +394,14 @@ void cWorld::InitializeSpawn(void)
// For the debugging builds, don't make the server build too much world upon start:
#if defined(_DEBUG) || defined(ANDROID_NDK)
- int ViewDist = 9;
+ const int DefaultViewDist = 9;
#else
- int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
+ const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
#endif // _DEBUG
+ cIniFile IniFile;
+ IniFile.ReadFile(m_IniFileName);
+ int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
+ IniFile.WriteFile(m_IniFileName);
LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str());
for (int x = 0; x < ViewDist; x++)
@@ -521,21 +522,6 @@ void cWorld::Start(void)
}
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)
// Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
int KeyNum = IniFile.FindKey("SpawnPosition");
@@ -574,7 +560,7 @@ void cWorld::Start(void)
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
- int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone);
+ int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slAll);
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
@@ -592,12 +578,6 @@ void cWorld::Start(void)
case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break;
case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break;
case dimEnd: DefaultMonsters = "enderman"; break;
- default:
- {
- ASSERT(!"Unhandled world dimension");
- DefaultMonsters = "wither";
- break;
- }
}
m_bAnimals = IniFile.GetValueSetB("Monsters", "AnimalsOn", true);
AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters);
@@ -687,6 +667,30 @@ void cWorld::GenerateRandomSpawn(void)
+eWeather cWorld::ChooseNewWeather()
+{
+ // Pick a new weather. Only reasonable transitions allowed:
+ switch (m_Weather)
+ {
+ case eWeather_Sunny:
+ case eWeather_ThunderStorm: return eWeather_Rain;
+
+ case eWeather_Rain:
+ {
+ // 1/8 chance of turning into a thunderstorm
+ return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
+ }
+ }
+
+ LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather);
+ ASSERT(!"Unknown weather");
+ return eWeather_Sunny;
+}
+
+
+
+
+
void cWorld::Stop(void)
{
// Delete the clients that have been in this world:
@@ -739,6 +743,20 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec)
m_LastTimeUpdate = m_WorldAge;
}
+ // Add entities waiting in the queue to be added:
+ {
+ cCSLock Lock(m_CSEntitiesToAdd);
+ for (cEntityList::iterator itr = m_EntitiesToAdd.begin(), end = m_EntitiesToAdd.end(); itr != end; ++itr)
+ {
+ (*itr)->SetWorld(this);
+ m_ChunkMap->AddEntity(*itr);
+ }
+ m_EntitiesToAdd.clear();
+ }
+
+ // Add players waiting in the queue to be added:
+ AddQueuedPlayers();
+
m_ChunkMap->Tick(a_Dt);
TickClients(a_Dt);
@@ -786,30 +804,8 @@ void cWorld::TickWeather(float a_Dt)
else
{
// Change weather:
-
- // Pick a new weather. Only reasonable transitions allowed:
- eWeather NewWeather = m_Weather;
- switch (m_Weather)
- {
- case eWeather_Sunny: NewWeather = eWeather_Rain; break;
- case eWeather_ThunderStorm: NewWeather = eWeather_Rain; break;
- case eWeather_Rain:
- {
- // 1/8 chance of turning into a thunderstorm
- NewWeather = ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
- break;
- }
-
- default:
- {
- LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather);
- ASSERT(!"Unknown weather");
- NewWeather = eWeather_Sunny;
- }
- }
-
- SetWeather(NewWeather);
- } // else (m_WeatherInterval > 0)
+ SetWeather(ChooseNewWeather());
+ }
if (m_Weather == eWeather_ThunderStorm)
{
@@ -860,7 +856,7 @@ void cWorld::TickMobs(float a_Dt)
{
m_ChunkMap->SpawnMobs(Spawner);
// do the spawn
- for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++)
+ for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2)
{
SpawnMobFinalize(*itr2);
}
@@ -870,14 +866,14 @@ void cWorld::TickMobs(float a_Dt)
// move close mobs
cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(-1, 64 * 16);// MG TODO : deal with this magic number (the 16 is the size of a block)
- for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++)
+ for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; ++itr)
{
itr->second.m_Monster.Tick(a_Dt, itr->second.m_Chunk);
}
// remove too far mobs
cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(128 * 16, -1);// MG TODO : deal with this magic number (the 16 is the size of a block)
- for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++)
+ for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; ++itr)
{
itr->second.m_Monster.Destroy(true);
}
@@ -1569,9 +1565,9 @@ bool cWorld::SetAreaBiome(const cCuboid & a_Area, EMCSBiome a_Biome)
-void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
- m_ChunkMap->SetBlock(*this, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
+ m_ChunkMap->SetBlock(*this, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_SendToClients);
}
@@ -1632,7 +1628,6 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated)
{
- MTRand r1;
a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
@@ -1642,15 +1637,15 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
continue;
}
- float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5));
- float SpeedY = (float)(a_FlyAwaySpeed * r1.randInt(50));
- float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5));
+ float SpeedX = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
+ float SpeedY = (float)(a_FlyAwaySpeed * GetTickRandomNumber(50));
+ float SpeedZ = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
cPickup * Pickup = new cPickup(
a_BlockX, a_BlockY, a_BlockZ,
*itr, IsPlayerCreated, SpeedX, SpeedY, SpeedZ
);
- Pickup->Initialize(this);
+ Pickup->Initialize(*this);
}
}
@@ -1671,7 +1666,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
a_BlockX, a_BlockY, a_BlockZ,
*itr, IsPlayerCreated, (float)a_SpeedX, (float)a_SpeedY, (float)a_SpeedZ
);
- Pickup->Initialize(this);
+ Pickup->Initialize(*this);
}
}
@@ -1682,7 +1677,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
int 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);
+ FallingBlock->Initialize(*this);
return FallingBlock->GetUniqueID();
}
@@ -1692,8 +1687,13 @@ int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NI
int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
{
+ if (a_Reward < 1)
+ {
+ return -1;
+ }
+
cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward);
- ExpOrb->Initialize(this);
+ ExpOrb->Initialize(*this);
return ExpOrb->GetUniqueID();
}
@@ -1716,7 +1716,7 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
return -1;
}
} // switch (a_MinecartType)
- Minecart->Initialize(this);
+ Minecart->Initialize(*this);
return Minecart->GetUniqueID();
}
@@ -1727,7 +1727,7 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
void 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);
+ TNT->Initialize(*this);
TNT->SetSpeed(
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */
a_InitialVelocityCoeff * 2,
@@ -2243,7 +2243,7 @@ void cWorld::SetChunkData(
// Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347):
for (cEntityList::iterator itr = a_Entities.begin(), end = a_Entities.end(); itr != end; ++itr)
{
- (*itr)->Initialize(this);
+ (*itr)->Initialize(*this);
}
// If a client is requesting this chunk, send it to them:
@@ -2336,23 +2336,8 @@ 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);
- }
-
- // Add the player's client to the list of clients to be ticked:
- if (a_Player->GetClientHandle() != NULL)
- {
- cCSLock Lock(m_CSClients);
- m_ClientsToAdd.push_back(a_Player->GetClientHandle());
- }
-
- // The player has already been added to the chunkmap as the entity, do NOT add again!
+ cCSLock Lock(m_CSPlayersToAdd);
+ m_PlayersToAdd.push_back(a_Player);
}
@@ -2361,17 +2346,26 @@ void cWorld::AddPlayer(cPlayer * a_Player)
void cWorld::RemovePlayer(cPlayer * a_Player)
{
+
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:
- if (a_Player->GetClientHandle() != NULL)
+ cClientHandle * Client = a_Player->GetClientHandle();
+ if (Client != NULL)
{
+ Client->RemoveFromWorld();
+ m_ChunkMap->RemoveClientFromChunks(Client);
cCSLock Lock(m_CSClients);
- m_ClientsToRemove.push_back(a_Player->GetClientHandle());
+ m_ClientsToRemove.push_back(Client);
}
}
@@ -2420,13 +2414,13 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_
bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback)
{
cPlayer * BestMatch = NULL;
- unsigned int BestRating = 0;
- unsigned int NameLength = a_PlayerNameHint.length();
+ 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)
{
- unsigned int Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName());
+ size_t Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName());
if (Rating >= BestRating)
{
BestMatch = *itr;
@@ -2440,7 +2434,6 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa
if (BestMatch != NULL)
{
- LOG("Compared %s and %s with rating %i", a_PlayerNameHint.c_str(), BestMatch->GetName().c_str(), BestRating);
return a_Callback.Item (BestMatch);
}
return false;
@@ -2823,9 +2816,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task)
+
void cWorld::AddEntity(cEntity * a_Entity)
{
- m_ChunkMap->AddEntity(a_Entity);
+ cCSLock Lock(m_CSEntitiesToAdd);
+ m_EntitiesToAdd.push_back(a_Entity);
}
@@ -2834,6 +2829,19 @@ void cWorld::AddEntity(cEntity * a_Entity)
bool cWorld::HasEntity(int 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:
return m_ChunkMap->HasEntity(a_UniqueID);
}
@@ -2890,7 +2898,7 @@ void cWorld::TickQueuedBlocks(void)
m_BlockTickQueueCopy.clear();
m_BlockTickQueue.swap(m_BlockTickQueueCopy);
- for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); itr++)
+ for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); ++itr)
{
BlockTickQueueItem * Block = (*itr);
Block->TicksToWait -= 1;
@@ -2966,7 +2974,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
delete a_Monster;
return -1;
}
- if (!a_Monster->Initialize(this))
+ if (!a_Monster->Initialize(*this))
{
delete a_Monster;
return -1;
@@ -2981,14 +2989,14 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
-int 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)
+int 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 == NULL)
{
return -1;
}
- if (!Projectile->Initialize(this))
+ if (!Projectile->Initialize(*this))
{
delete Projectile;
return -1;
@@ -3118,6 +3126,60 @@ 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 (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr)
+ {
+ ASSERT(std::find(m_Players.begin(), m_Players.end(), *itr) == m_Players.end()); // Is it already in the list? HOW?
+
+ m_Players.push_back(*itr);
+ (*itr)->SetWorld(this);
+
+ // Add to chunkmap, if not already there (Spawn vs MoveToWorld):
+ m_ChunkMap->AddEntityIfNotPresent(*itr);
+ } // 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)
+ {
+ cClientHandle * Client = (*itr)->GetClientHandle();
+ if (Client != NULL)
+ {
+ 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 != NULL)
+ {
+ Client->StreamChunks();
+ }
+ } // for itr - PlayersToAdd[]
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWorld::cTaskSaveAllChunks:
@@ -3143,6 +3205,49 @@ void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cWorld::cTaskSendBlockTo
+
+cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) :
+ m_SendQueue(a_SendQueue)
+{
+}
+
+void cWorld::cTaskSendBlockToAllPlayers::Run(cWorld & a_World)
+{
+ class cPlayerCallback :
+ public cPlayerListCallback
+ {
+ public:
+ cPlayerCallback(std::vector<Vector3i> & a_SendQueue, cWorld & a_World) :
+ m_SendQueue(a_SendQueue),
+ m_World(a_World)
+ {
+ }
+
+ virtual bool Item(cPlayer * a_Player)
+ {
+ for (std::vector<Vector3i>::const_iterator itr = m_SendQueue.begin(); itr != m_SendQueue.end(); ++itr)
+ {
+ m_World.SendBlockTo(itr->x, itr->y, itr->z, a_Player);
+ }
+ return false;
+ }
+
+ private:
+
+ std::vector<Vector3i> m_SendQueue;
+ cWorld & m_World;
+
+ } PlayerCallback(m_SendQueue, a_World);
+
+ a_World.ForEachPlayer(PlayerCallback);
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWorld::cChunkGeneratorCallbacks:
cWorld::cChunkGeneratorCallbacks::cChunkGeneratorCallbacks(cWorld & a_World) :
@@ -3215,4 +3320,3 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch
-