diff options
Diffstat (limited to '')
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; } |