summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Blocks/BlockBed.cpp4
-rw-r--r--src/Blocks/BlockCauldron.h14
-rw-r--r--src/Blocks/BlockPortal.h2
-rw-r--r--src/Blocks/WorldInterface.h3
-rw-r--r--src/Chunk.cpp75
-rw-r--r--src/Chunk.h1
-rw-r--r--src/ClientHandle.cpp7
-rw-r--r--src/ClientHandle.h2
-rw-r--r--src/Entities/Entity.cpp123
-rw-r--r--src/Entities/Entity.h6
-rw-r--r--src/Entities/Player.cpp71
-rw-r--r--src/Entities/Player.h17
-rw-r--r--src/Generating/BioGen.cpp2
-rw-r--r--src/Generating/ComposableGenerator.cpp16
-rw-r--r--src/Generating/EndGen.cpp2
-rw-r--r--src/Generating/EndGen.h3
-rw-r--r--src/Mobs/Monster.cpp2
-rw-r--r--src/Protocol/Protocol.h2
-rw-r--r--src/Protocol/Protocol125.cpp4
-rw-r--r--src/Protocol/Protocol125.h2
-rw-r--r--src/Protocol/Protocol16x.cpp4
-rw-r--r--src/Protocol/Protocol16x.h2
-rw-r--r--src/Protocol/Protocol17x.cpp4
-rw-r--r--src/Protocol/Protocol17x.h2
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp4
-rw-r--r--src/Protocol/ProtocolRecognizer.h2
-rw-r--r--src/Root.cpp21
-rw-r--r--src/World.cpp31
-rw-r--r--src/World.h4
29 files changed, 318 insertions, 114 deletions
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index 6a3c6a55b..5525f0d0c 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -108,7 +108,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (Meta & 0x4)
{
- a_Player->SendMessageFailure("This bed is occupied.");
+ a_Player->SendMessageFailure("This bed is occupied");
}
else
{
@@ -133,6 +133,8 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
a_Player->SetIsInBed(true);
+ a_Player->SetBedPos(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
+ a_Player->SendMessageSuccess("Home position set successfully");
cTimeFastForwardTester Tester;
if (a_WorldInterface.ForEachPlayer(Tester))
diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h
index 41b79b6c3..8b5cd9ccb 100644
--- a/src/Blocks/BlockCauldron.h
+++ b/src/Blocks/BlockCauldron.h
@@ -58,6 +58,20 @@ public:
{
return true;
}
+
+ virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
+ {
+ if (!a_WorldInterface.IsWeatherWet())
+ {
+ return;
+ }
+
+ NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
+ if (Meta < 3)
+ {
+ a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta + 1);
+ }
+ }
} ;
diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h
index 3b8030028..e718d9a70 100644
--- a/src/Blocks/BlockPortal.h
+++ b/src/Blocks/BlockPortal.h
@@ -55,7 +55,7 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
- if ((a_RelY - 1 < 0) || (a_RelY + 1 > cChunkDef::Height))
+ if ((a_RelY == 0) || (a_RelY == cChunkDef::Height)) // Y can't be < 0 or > Height; (Fast)SetBlock won't allow it
{
return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1
}
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index bfbb053d9..08600d502 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -37,4 +37,7 @@ public:
virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0;
+ /** Returns true if the current weather has any precipitation - rain or storm */
+ virtual bool IsWeatherWet(void) const = 0;
+
};
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 1aaf076df..59f4a8507 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -579,30 +579,22 @@ void cChunk::Tick(float a_Dt)
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{
// Mobs are tickes inside MobTick (as we don't have to tick them if they are far away from players)
- if (!((*itr)->IsMob()))
+ // Don't tick things queued to be removed
+ if (!((*itr)->IsMob()) && (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()) == m_EntitiesToRemove.end()))
{
(*itr)->Tick(a_Dt, *this);
}
} // for itr - m_Entitites[]
- // Remove all entities that were scheduled for removal:
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();)
{
- if ((*itr)->IsDestroyed())
- {
- LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass());
- cEntity * ToDelete = *itr;
- itr = m_Entities.erase(itr);
- delete ToDelete;
- continue;
- }
- ++itr;
- } // for itr - m_Entitites[]
-
- // If any entity moved out of the chunk, move it to the neighbor:
- for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();)
- {
- if (
+ auto itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID());
+ if (itr2 != m_EntitiesToRemove.end())
+ {
+ itr = m_Entities.erase(itr);
+ m_EntitiesToRemove.erase(itr2);
+ }
+ else if ( // If any entity moved out of the chunk, move it to the neighbor:
((*itr)->GetChunkX() != m_PosX) ||
((*itr)->GetChunkZ() != m_PosZ)
)
@@ -612,9 +604,19 @@ void cChunk::Tick(float a_Dt)
}
else
{
- ++itr;
+ if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal:
+ {
+ LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass());
+ cEntity * ToDelete = *itr;
+ itr = m_Entities.erase(itr);
+ delete ToDelete;
+ }
+ else
+ {
+ ++itr;
+ }
}
- }
+ } // for itr - m_Entitites[]
ApplyWeatherToTop();
}
@@ -899,7 +901,6 @@ void cChunk::ApplyWeatherToTop()
}
break;
} // case (snowy biomes)
- // TODO: Rainy biomes should check for farmland and cauldrons
default:
{
break;
@@ -1759,7 +1760,7 @@ void cChunk::RemoveBlockEntity( cBlockEntity* a_BlockEntity )
-bool cChunk::AddClient(cClientHandle* a_Client)
+bool cChunk::AddClient(cClientHandle * a_Client)
{
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
{
@@ -1790,7 +1791,7 @@ bool cChunk::AddClient(cClientHandle* a_Client)
-void cChunk::RemoveClient( cClientHandle* a_Client )
+void cChunk::RemoveClient(cClientHandle * a_Client)
{
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
{
@@ -1798,12 +1799,12 @@ void cChunk::RemoveClient( cClientHandle* a_Client )
{
continue;
}
-
+
m_LoadedByClient.erase(itr);
if (!a_Client->IsDestroyed())
{
- for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr )
+ for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{
/*
// DEBUG:
@@ -1823,7 +1824,7 @@ void cChunk::RemoveClient( cClientHandle* a_Client )
-bool cChunk::HasClient( cClientHandle* a_Client )
+bool cChunk::HasClient(cClientHandle* a_Client)
{
for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
{
@@ -1854,9 +1855,9 @@ void cChunk::AddEntity(cEntity * a_Entity)
{
MarkDirty();
}
-
+
ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already
-
+
m_Entities.push_back(a_Entity);
}
@@ -1866,17 +1867,12 @@ void cChunk::AddEntity(cEntity * a_Entity)
void cChunk::RemoveEntity(cEntity * a_Entity)
{
- size_t SizeBefore = m_Entities.size();
- m_Entities.remove(a_Entity);
- size_t SizeAfter = m_Entities.size();
-
- if (SizeBefore != SizeAfter)
+ m_EntitiesToRemove.push_back(a_Entity->GetUniqueID());
+
+ // Mark as dirty if it was a server-generated entity:
+ if (!a_Entity->IsPlayer())
{
- // Mark as dirty if it was a server-generated entity:
- if (!a_Entity->IsPlayer())
- {
- MarkDirty();
- }
+ MarkDirty();
}
}
@@ -1886,6 +1882,11 @@ void cChunk::RemoveEntity(cEntity * a_Entity)
bool cChunk::HasEntity(int a_EntityID)
{
+ if (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), a_EntityID) != m_EntitiesToRemove.end())
+ {
+ return false; // If EntitiesToRemove contains our ID, this chunk doesn't have it, as it should be removed soon
+ }
+
for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr)
{
if ((*itr)->GetUniqueID() == a_EntityID)
diff --git a/src/Chunk.h b/src/Chunk.h
index e92a5bc29..92350243c 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -421,6 +421,7 @@ private:
// A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers
cClientHandleList m_LoadedByClient;
cEntityList m_Entities;
+ std::vector<int> m_EntitiesToRemove;
cBlockEntityList m_BlockEntities;
/** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index d47ceff0e..1e2c148b8 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -124,7 +124,6 @@ cClientHandle::~cClientHandle()
}
if (World != NULL)
{
- World->RemovePlayer(m_Player);
m_Player->Destroy();
}
delete m_Player;
@@ -1753,7 +1752,7 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
if (a_SendRespawnPacket)
{
- SendRespawn();
+ SendRespawn(a_World);
}
cWorld * World = m_Player->GetWorld();
@@ -2372,9 +2371,9 @@ void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effec
-void cClientHandle::SendRespawn(void)
+void cClientHandle::SendRespawn(const cWorld & a_World)
{
- m_Protocol->SendRespawn();
+ m_Protocol->SendRespawn(a_World);
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 659c67658..e86287735 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -149,7 +149,7 @@ public:
void SendPlayerSpawn (const cPlayer & a_Player);
void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp
void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID);
- void SendRespawn (void);
+ void SendRespawn (const cWorld & a_World);
void SendExperience (void);
void SendExperienceOrb (const cExpOrb & a_ExpOrb);
void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 1226a2319..de6c628e9 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -629,6 +629,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
// Handle drowning
HandleAir();
}
+ DetectPortal();
// None of the above functions change position, we remain in the chunk of NextChunk
HandlePhysics(a_Dt, *NextChunk);
@@ -1039,6 +1040,128 @@ void cEntity::DetectCacti(void)
+void cEntity::DetectPortal()
+{
+ int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT;
+ if ((Y > 0) && (Y < cChunkDef::Height))
+ {
+ switch (GetWorld()->GetBlock(X, Y, Z))
+ {
+ case E_BLOCK_NETHER_PORTAL:
+ {
+ switch (GetWorld()->GetDimension())
+ {
+ case dimNether:
+ {
+ AString OverworldName = GetWorld()->GetName().substr(0, GetWorld()->GetName().size() - 7);
+ cFile::CreateFolder(FILE_IO_PREFIX + OverworldName);
+ cIniFile File;
+ File.ReadFile(OverworldName + "/world.ini");
+ File.SetValue("General", "Dimension", "Overworld");
+ File.WriteFile(OverworldName + "/world.ini");
+
+ MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName));
+ break;
+ }
+ case dimOverworld:
+ {
+ AString NetherWorldName = GetWorld()->GetName() + "_nether";
+ cFile::CreateFolder(FILE_IO_PREFIX + NetherWorldName);
+ cIniFile File;
+ File.ReadFile(NetherWorldName + "/world.ini");
+ File.SetValue("General", "Dimension", "Nether");
+ File.WriteFile(NetherWorldName + "/world.ini");
+
+ MoveToWorld(NetherWorldName, cRoot::Get()->CreateAndInitializeWorld(NetherWorldName));
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ case E_BLOCK_END_PORTAL:
+ {
+ switch (GetWorld()->GetDimension())
+ {
+ case dimEnd:
+ {
+ AString OverworldName = GetWorld()->GetName().substr(0, GetWorld()->GetName().size() - 4);
+ cFile::CreateFolder(FILE_IO_PREFIX + OverworldName);
+ cIniFile File;
+ File.ReadFile(OverworldName + "/world.ini");
+ File.SetValue("General", "Dimension", "Overworld");
+ File.WriteFile(OverworldName + "/world.ini");
+
+ MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName));
+
+ if (IsPlayer())
+ {
+ cPlayer * Player = (cPlayer *)this;
+ Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z);
+ }
+ break;
+ }
+ case dimOverworld:
+ {
+ AString EndWorldName = GetWorld()->GetName() + "_end";
+ cFile::CreateFolder(FILE_IO_PREFIX + EndWorldName);
+ cIniFile File;
+ File.ReadFile(EndWorldName + "/world.ini");
+ File.SetValue("General", "Dimension", "End");
+ File.WriteFile(EndWorldName + "/world.ini");
+
+ MoveToWorld(EndWorldName, cRoot::Get()->CreateAndInitializeWorld(EndWorldName));
+ break;
+ }
+ default: break;
+ }
+ }
+ default: break;
+ }
+ }
+}
+
+
+
+
+
+bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World)
+{
+ cWorld * World;
+ if (a_World == NULL)
+ {
+ World = cRoot::Get()->GetWorld(a_WorldName);
+ if (World == NULL)
+ {
+ LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName);
+ return false;
+ }
+ }
+ else
+ {
+ World = a_World;
+ }
+
+ if (GetWorld() == World)
+ {
+ return false;
+ }
+
+ // Remove all links to the old world
+ GetWorld()->RemoveEntity(this);
+ GetWorld()->BroadcastDestroyEntity(*this);
+
+ // Add to all the necessary parts of the new world
+ SetWorld(World);
+ World->AddEntity(this);
+
+ return true;
+}
+
+
+
+
+
void cEntity::SetSwimState(cChunk & a_Chunk)
{
int RelY = (int)floor(GetPosY() + 0.1);
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 0c393c0f5..da8256606 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -323,6 +323,9 @@ public:
/** Detects the time for application of cacti damage */
virtual void DetectCacti(void);
+
+ /** Detects whether we are in a portal block and begins teleportation procedures if so */
+ virtual void DetectPortal(void);
/// Handles when the entity is in the void
virtual void TickInVoid(cChunk & a_Chunk);
@@ -365,6 +368,9 @@ public:
/// Teleports to the coordinates specified
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ);
+
+ /** Moves entity to specified world */
+ virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL);
// tolua_end
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 3a9324d09..02a55566c 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -82,13 +82,13 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_PlayerName = a_PlayerName;
- if (!LoadFromDisk())
+ cWorld * World;
+ if (!LoadFromDisk(World))
{
m_Inventory.Clear();
- cWorld * DefaultWorld = cRoot::Get()->GetDefaultWorld();
- SetPosX(DefaultWorld->GetSpawnX());
- SetPosY(DefaultWorld->GetSpawnY());
- SetPosZ(DefaultWorld->GetSpawnZ());
+ SetPosX(World->GetSpawnX());
+ SetPosY(World->GetSpawnY());
+ SetPosZ(World->GetSpawnZ());
LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
@@ -101,11 +101,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
if (m_GameMode == gmNotSet)
{
- cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName());
- if (World == NULL)
- {
- World = cRoot::Get()->GetDefaultWorld();
- }
if (World->IsGameModeCreative())
{
m_CanFly = true;
@@ -134,7 +129,7 @@ cPlayer::~cPlayer(void)
SaveToDisk();
- m_World->RemovePlayer( this );
+ m_World->RemovePlayer(this);
m_ClientHandle = NULL;
@@ -150,8 +145,6 @@ cPlayer::~cPlayer(void)
void cPlayer::Destroyed()
{
CloseWindow(false);
-
- m_ClientHandle = NULL;
}
@@ -952,12 +945,12 @@ void cPlayer::Respawn(void)
m_LifetimeTotalXp = 0;
// ToDo: send score to client? How?
- m_ClientHandle->SendRespawn();
+ m_ClientHandle->SendRespawn(*GetWorld());
// Extinguish the fire:
StopBurning();
- TeleportToCoords(GetWorld()->GetSpawnX(), GetWorld()->GetSpawnY(), GetWorld()->GetSpawnZ());
+ TeleportToCoords(GetLastBedPos().x, GetLastBedPos().y, GetLastBedPos().z);
SetVisible(true);
}
@@ -1574,12 +1567,25 @@ void cPlayer::TossItems(const cItems & a_Items)
-bool cPlayer::MoveToWorld(const char * a_WorldName)
+bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World)
{
- cWorld * World = cRoot::Get()->GetWorld(a_WorldName);
- if (World == NULL)
+ cWorld * World;
+ if (a_World == NULL)
+ {
+ World = cRoot::Get()->GetWorld(a_WorldName);
+ if (World == NULL)
+ {
+ LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName);
+ return false;
+ }
+ }
+ else
+ {
+ World = a_World;
+ }
+
+ if (GetWorld() == World)
{
- LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName);
return false;
}
@@ -1588,11 +1594,11 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
// Remove all links to the old world
m_World->RemovePlayer(this);
m_ClientHandle->RemoveFromAllChunks();
- m_World->RemoveEntity(this);
// If the dimension is different, we can send the respawn packet
// http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02
- m_ClientHandle->MoveToWorld(*World, (OldDimension != World->GetDimension()));
+ bool SendRespawn = OldDimension != World->GetDimension();
+ m_ClientHandle->MoveToWorld(*World, SendRespawn);
// Add player to all the necessary parts of the new world
SetWorld(World);
@@ -1600,6 +1606,13 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
World->AddEntity(this);
World->AddPlayer(this);
+ if (SendRespawn)
+ {
+ GetClientHandle()->SendPlayerMoveLook();
+ GetClientHandle()->SendHealth();
+ GetClientHandle()->SendWholeInventory((cWindow &)GetInventory());
+ }
+
return true;
}
@@ -1646,8 +1659,14 @@ void cPlayer::LoadPermissionsFromDisk()
-bool cPlayer::LoadFromDisk()
+bool cPlayer::LoadFromDisk(cWorld * a_World)
{
+ a_World = cRoot::Get()->GetWorld(GetLoadedWorldName());
+ if (a_World == NULL)
+ {
+ a_World = cRoot::Get()->GetDefaultWorld();
+ }
+
LoadPermissionsFromDisk();
AString SourceFile;
@@ -1701,6 +1720,9 @@ bool cPlayer::LoadFromDisk()
m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt();
m_CurrentXp = (short) root.get("xpCurrent", 0).asInt();
m_IsFlying = root.get("isflying", 0).asBool();
+ m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt();
+ m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt();
+ m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt();
m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt();
@@ -1719,7 +1741,7 @@ bool cPlayer::LoadFromDisk()
StatSerializer.Load();
LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
- GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
+ GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), GetLoadedWorldName().c_str()
);
return true;
@@ -1761,6 +1783,9 @@ bool cPlayer::SaveToDisk()
root["foodExhaustion"] = m_FoodExhaustionLevel;
root["world"] = GetWorld()->GetName();
root["isflying"] = IsFlying();
+ root["SpawnX"] = GetLastBedPos().x;
+ root["SpawnY"] = GetLastBedPos().y;
+ root["SpawnZ"] = GetLastBedPos().z;
if (m_GameMode == GetWorld()->GetGameMode())
{
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index b7cb27d6c..5c0b61064 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -328,10 +328,10 @@ public:
void SetVisible( bool a_bVisible ); // tolua_export
bool IsVisible(void) const { return m_bVisible; } // tolua_export
- bool MoveToWorld(const char * a_WorldName); // tolua_export
+ virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL) override; // tolua_export
bool SaveToDisk(void);
- bool LoadFromDisk(void);
+ bool LoadFromDisk(cWorld * a_World);
void LoadPermissionsFromDisk(void); // tolua_export
const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
@@ -391,11 +391,19 @@ public:
/** If true the player can fly even when he's not in creative. */
void SetCanFly(bool a_CanFly);
+ /** Gets the last position that the player slept in */
+ Vector3i GetLastBedPos(void) const { return m_LastBedPos; }
+
+ /** Sets the player's bed (home) position */
+ void SetBedPos(const Vector3i & a_Pos) { m_LastBedPos = a_Pos; }
+
/** Update movement-related statistics. */
void UpdateMovementStats(const Vector3d & a_DeltaPos);
/** Returns wheter the player can fly or not. */
virtual bool CanFly(void) const { return m_CanFly; }
+
+
// tolua_end
// cEntity overrides:
@@ -450,6 +458,9 @@ protected:
cWindow * m_CurrentWindow;
cWindow * m_InventoryWindow;
+ /** The player's last saved bed position */
+ Vector3i m_LastBedPos;
+
char m_Color;
eGameMode m_GameMode;
@@ -508,8 +519,6 @@ protected:
cStatManager m_Stats;
-
-
void ResolvePermissions(void);
void ResolveGroups(void);
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 47ba080c6..36a195a3d 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -95,7 +95,7 @@ void cBioGenConstant::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
void cBioGenConstant::InitializeBiomeGen(cIniFile & a_IniFile)
{
- AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", "Plains");
+ AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", "");
m_Biome = StringToBiome(Biome);
if (m_Biome == biInvalidBiome)
{
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index cf736ce64..37a6b829a 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -42,7 +42,6 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile &
{
LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\".");
CompoGenName = "Biomal";
- a_IniFile.SetValue("Generator", "CompositionGen", CompoGenName);
}
cTerrainCompositionGen * res = NULL;
@@ -96,7 +95,6 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile &
else
{
LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
- a_IniFile.DeleteValue("Generator", "CompositionGen");
a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed);
}
@@ -294,19 +292,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int Seed = m_ChunkGenerator.GetSeed();
eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
- // Older configuration used "Structures" in addition to "Finishers"; we don't distinguish between the two anymore (#398)
- // Therefore, we load Structures from the ini file for compatibility, but move its contents over to Finishers:
- AString Structures = a_IniFile.GetValue("Generator", "Structures", "");
- AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
- if (!Structures.empty())
- {
- LOGINFO("[Generator].Structures is deprecated, moving the contents to [Generator].Finishers.");
- // Structures used to generate before Finishers, so place them first:
- Structures.append(", ");
- Finishers = Structures + Finishers;
- a_IniFile.SetValue("Generator", "Finishers", Finishers);
- }
- a_IniFile.DeleteValue("Generator", "Structures");
+ AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "");
// Create all requested finishers:
AStringVector Str = StringSplitAndTrim(Finishers, ",");
diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp
index f466039b9..5be73bfbe 100644
--- a/src/Generating/EndGen.cpp
+++ b/src/Generating/EndGen.cpp
@@ -50,7 +50,7 @@ cEndGen::cEndGen(int a_Seed) :
-void cEndGen::Initialize(cIniFile & a_IniFile)
+void cEndGen::InitializeCompoGen(cIniFile & a_IniFile)
{
m_IslandSizeX = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeX", m_IslandSizeX);
m_IslandSizeY = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeY", m_IslandSizeY);
diff --git a/src/Generating/EndGen.h b/src/Generating/EndGen.h
index 4904a0e3d..322061810 100644
--- a/src/Generating/EndGen.h
+++ b/src/Generating/EndGen.h
@@ -23,8 +23,6 @@ class cEndGen :
public:
cEndGen(int a_Seed);
- void Initialize(cIniFile & a_IniFile);
-
protected:
/// Seed for the noise
@@ -66,4 +64,5 @@ protected:
// cTerrainCompositionGen overrides:
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
+ virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
} ;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 5843ca5a6..fa3969d5e 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -1034,7 +1034,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
(a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
!IsOnFire() && // Not already burning
- (GetWorld()->GetWeather() != eWeather_Rain) // Not raining
+ (GetWorld()->IsWeatherWet()) // Not raining
)
{
// Burn for 100 ticks, then decide again
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index a543c6361..c6e569919 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -100,7 +100,7 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0;
- virtual void SendRespawn (void) = 0;
+ virtual void SendRespawn (const cWorld & a_World) = 0;
virtual void SendExperience (void) = 0;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index f3bdae3ac..873295f62 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -831,12 +831,12 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
-void cProtocol125::SendRespawn(void)
+void cProtocol125::SendRespawn(const cWorld & a_World)
{
cCSLock Lock(m_CSPacket);
cPlayer * Player = m_Client->GetPlayer();
WriteByte (PACKET_RESPAWN);
- WriteInt ((int)(Player->GetWorld()->GetDimension()));
+ WriteInt ((int)(a_World.GetDimension()));
WriteByte (2); // TODO: Difficulty; 2 = Normal
WriteChar ((char)Player->GetGameMode());
WriteShort (256); // Current world height
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 18a626a2d..3f39c8965 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -72,7 +72,7 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
- virtual void SendRespawn (void) override;
+ virtual void SendRespawn (const cWorld & a_World) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp
index 714bf5e46..9e0f3f852 100644
--- a/src/Protocol/Protocol16x.cpp
+++ b/src/Protocol/Protocol16x.cpp
@@ -158,10 +158,10 @@ void cProtocol161::SendPlayerMaxSpeed(void)
-void cProtocol161::SendRespawn(void)
+void cProtocol161::SendRespawn(const cWorld & a_World)
{
// Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast
- super::SendRespawn();
+ super::SendRespawn(a_World);
SendPlayerMaxSpeed();
}
diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h
index 8eedce8d5..e91dc8a1c 100644
--- a/src/Protocol/Protocol16x.h
+++ b/src/Protocol/Protocol16x.h
@@ -42,7 +42,7 @@ protected:
virtual void SendGameMode (eGameMode a_GameMode) override;
virtual void SendHealth (void) override;
virtual void SendPlayerMaxSpeed(void) override;
- virtual void SendRespawn (void) override;
+ virtual void SendRespawn (const cWorld & a_World) override;
virtual void SendWindowOpen (const cWindow & a_Window) override;
virtual int ParseEntityAction (void) override;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index f7564fe6d..9c5f5eaba 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -984,11 +984,11 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
-void cProtocol172::SendRespawn(void)
+void cProtocol172::SendRespawn(const cWorld & a_World)
{
cPacketizer Pkt(*this, 0x07); // Respawn packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteInt(Player->GetWorld()->GetDimension());
+ Pkt.WriteInt((int)a_World.GetDimension());
Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
Pkt.WriteByte((Byte)Player->GetEffectiveGameMode());
Pkt.WriteString("default");
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 3c6a8c085..cafdb50e4 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -104,7 +104,7 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
- virtual void SendRespawn (void) override;
+ virtual void SendRespawn (const cWorld & a_World) override;
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index b0cbb6def..35a331f43 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -555,10 +555,10 @@ void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a
-void cProtocolRecognizer::SendRespawn(void)
+void cProtocolRecognizer::SendRespawn(const cWorld & a_World)
{
ASSERT(m_Protocol != NULL);
- m_Protocol->SendRespawn();
+ m_Protocol->SendRespawn(a_World);
}
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 3a291bf7a..5e178447c 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -107,7 +107,7 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
- virtual void SendRespawn (void) override;
+ virtual void SendRespawn (const cWorld & a_World) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
diff --git a/src/Root.cpp b/src/Root.cpp
index c82b05a66..2a80baeb3 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -320,7 +320,7 @@ cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName)
{
return NULL;
}
- cWorld* NewWorld = new cWorld(a_WorldName.c_str());
+ cWorld * NewWorld = new cWorld(a_WorldName.c_str());
m_WorldsByName[a_WorldName] = NewWorld;
NewWorld->Start();
NewWorld->InitializeSpawn();
@@ -372,7 +372,7 @@ void cRoot::UnloadWorlds(void)
-cWorld* cRoot::GetDefaultWorld()
+cWorld * cRoot::GetDefaultWorld()
{
return m_pDefaultWorld;
}
@@ -381,12 +381,14 @@ cWorld* cRoot::GetDefaultWorld()
-cWorld* cRoot::GetWorld( const AString & a_WorldName )
+cWorld * cRoot::GetWorld(const AString & a_WorldName)
{
- WorldMap::iterator itr = m_WorldsByName.find( a_WorldName );
- if( itr != m_WorldsByName.end() )
+ WorldMap::iterator itr = m_WorldsByName.find(a_WorldName);
+ if (itr != m_WorldsByName.end())
+ {
return itr->second;
- return 0;
+ }
+ return NULL;
}
@@ -398,9 +400,12 @@ bool cRoot::ForEachWorld(cWorldListCallback & a_Callback)
for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2)
{
++itr2;
- if (a_Callback.Item(itr->second))
+ if (itr->second != NULL)
{
- return false;
+ if (a_Callback.Item(itr->second))
+ {
+ return false;
+ }
}
}
return true;
diff --git a/src/World.cpp b/src/World.cpp
index 88e9c32e6..66aca83ef 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -571,6 +571,37 @@ void cWorld::Start(void)
m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure);
m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll);
+ switch (GetDimension())
+ {
+ case dimEnd:
+ {
+ IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
+ IniFile.GetValueSet("Generator", "ConstantBiome", "End");
+ IniFile.GetValueSet("Generator", "HeightGen", "Biomal");
+ IniFile.GetValueSet("Generator", "CompositionGen", "End");
+ break;
+ }
+ case dimOverworld:
+ {
+ IniFile.GetValueSet("Generator", "BiomeGen", "MultiStepMap");
+ IniFile.GetValueSet("Generator", "HeightGen", "DistortedHeightmap");
+ IniFile.GetValueSet("Generator", "CompositionGen", "DistortedHeightmap");
+ IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
+ break;
+ }
+ case dimNether:
+ {
+ IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
+ IniFile.GetValueSet("Generator", "ConstantBiome", "Nether");
+ IniFile.GetValueSet("Generator", "HeightGen", "Flat");
+ IniFile.GetValueSet("Generator", "FlatHeight", "128");
+ IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
+ IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
+ IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
+ break;
+ }
+ }
+
// Load allowed mobs:
const char * DefaultMonsters = "";
switch (m_Dimension)
diff --git a/src/World.h b/src/World.h
index 98b241a2b..e72675194 100644
--- a/src/World.h
+++ b/src/World.h
@@ -704,8 +704,8 @@ public:
bool IsWeatherStorm(void) const { return (m_Weather == wStorm); }
/** Returns true if the current weather has any precipitation - rain or storm */
- bool IsWeatherWet (void) const { return (m_Weather != wSunny); }
-
+ virtual bool IsWeatherWet(void) const override { return (m_Weather != wSunny); }
+
// tolua_end
cChunkGenerator & GetGenerator(void) { return m_Generator; }