summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/inifile/iniFile.cpp4
-rw-r--r--src/BlockID.cpp35
-rw-r--r--src/BlockID.h7
-rw-r--r--src/Chunk.cpp15
-rw-r--r--src/Entities/Entity.cpp130
-rw-r--r--src/Entities/Entity.h3
-rw-r--r--src/Root.cpp6
-rw-r--r--src/Root.h2
-rw-r--r--src/World.cpp18
-rw-r--r--src/World.h13
10 files changed, 179 insertions, 54 deletions
diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp
index 66410b901..30f93e5a3 100644
--- a/lib/inifile/iniFile.cpp
+++ b/lib/inifile/iniFile.cpp
@@ -586,7 +586,11 @@ Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename,
Printf(Data, "%lld", defValue);
AString resultstring = GetValueSet(keyname, valuename, Data);
Int64 result;
+#ifdef _WIN32
+ sscanf_s(resultstring.c_str(), "%lld", &result);
+#else
sscanf(resultstring.c_str(), "%lld", &result);
+#endif
return result;
}
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index bfe826f40..641a6a225 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -345,6 +345,41 @@ eDimension StringToDimension(const AString & a_DimensionString)
+AString DimensionToString(eDimension a_Dimension)
+{
+ // Decode using a built-in map:
+ static struct
+ {
+ eDimension m_Dimension;
+ const char * m_String;
+ } DimensionMap[] =
+ {
+ { dimOverworld, "Overworld" },
+ { dimOverworld, "Normal" },
+ { dimOverworld, "World" },
+ { dimNether, "Nether" },
+ { dimNether, "Hell" }, // Alternate name for Nether
+ { dimEnd, "End" },
+ { dimEnd, "Sky" }, // Old name for End
+ };
+
+ for (size_t i = 0; i < ARRAYCOUNT(DimensionMap); i++)
+ {
+ if (DimensionMap[i].m_Dimension == a_Dimension)
+ {
+ return DimensionMap[i].m_String;
+ }
+ } // for i - DimensionMap[]
+
+ // Not found
+ LOGWARNING("Unknown dimension: \"%i\". Setting to Overworld", (int)a_Dimension);
+ return "Overworld";
+}
+
+
+
+
+
/// Translates damage type constant to a string representation (built-in).
AString DamageTypeToString(eDamageType a_DamageType)
{
diff --git a/src/BlockID.h b/src/BlockID.h
index a227245aa..97c1aae86 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -916,9 +916,14 @@ extern AString ItemToFullString(const cItem & a_Item);
/// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT)
extern int StringToMobType(const AString & a_MobString);
-/// Translates a dimension string to dimension enum. Takes either a number or a dimension alias (built-in). Returns -1000 on failure
+/// Translates a dimension string to dimension enum. Takes either a number or a dimension alias (built-in). Returns dimOverworld on failure
extern eDimension StringToDimension(const AString & a_DimensionString);
+/** Translates a dimension enum to dimension string.
+Takes a string and returns "Overworld" on failure
+*/
+extern AString DimensionToString(eDimension a_Dimension);
+
/// Translates damage type constant to a string representation (built-in).
extern AString DamageTypeToString(eDamageType a_DamageType);
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 2850dd93b..02857ba5a 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -1859,7 +1859,20 @@ void cChunk::AddEntity(cEntity * a_Entity)
MarkDirty();
}
- ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already
+ if (std::find(m_Entities.begin(), m_Entities.end(), a_Entity) != m_Entities.end())
+ {
+ // Not there already
+ std::vector<int>::iterator itr = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), a_Entity->GetUniqueID());
+ if (itr != m_EntitiesToRemove.end())
+ {
+ m_EntitiesToRemove.erase(itr);
+ return;
+ }
+ else
+ {
+ ASSERT(!"Entity already present when AddEntity was called!");
+ }
+ }
m_Entities.push_back(a_Entity);
}
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 2d8f385cb..4b376a1fe 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -12,6 +12,7 @@
#include "../Bindings/PluginManager.h"
#include "../Tracer.h"
#include "Player.h"
+#include "BlockArea.h"
@@ -1047,6 +1048,28 @@ void cEntity::DetectPortal()
return;
}
+ class cPortalChunkLoader : public cChunkStay
+ {
+ public:
+ cPortalChunkLoader(cEntity * a_Entity, Vector3i & a_PortalPos) :
+ m_Entity(a_Entity),
+ m_PortalPos(a_PortalPos)
+ {}
+
+ private:
+ virtual bool OnAllChunksAvailable(void) override
+ {
+ m_Entity->CreateExitPortal(m_PortalPos.x, m_PortalPos.y, m_PortalPos.z);
+ return true;
+ }
+
+ virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override {};
+ virtual void OnDisabled(void) override {};
+
+ cEntity * m_Entity;
+ Vector3i m_PortalPos;
+ };
+
int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT;
if ((Y > 0) && (Y < cChunkDef::Height))
{
@@ -1061,31 +1084,31 @@ void cEntity::DetectPortal()
switch (GetWorld()->GetDimension())
{
- case dimNether:
+ case dimNether: MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); break;
+ case dimOverworld:
{
- cIniFile OwnIni;
- OwnIni.ReadFile(GetWorld()->GetIniFileName());
- AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName());
+ if (IsPlayer())
+ {
+ ((cPlayer *)this)->AwardAchievement(achEnterPortal);
+ }
+ MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()));
+
+ cChunkStay * Stay = new cPortalChunkLoader(this, Vector3i(X, Y, Z));
- cFile::CreateFolder(FILE_IO_PREFIX + OverworldName);
- cIniFile File;
- File.ReadFile(OverworldName + "/world.ini");
- File.SetValue("General", "Dimension", "Overworld");
- File.WriteFile(OverworldName + "/world.ini");
+ int MinChunkX, MaxChunkX;
+ int MinChunkZ, MaxChunkZ;
+ cChunkDef::BlockToChunk(X - 128, Z - 128, MinChunkX, MinChunkZ);
+ cChunkDef::BlockToChunk(X + 128, Z + 128, MaxChunkX, MaxChunkZ);
- MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName));
- break;
- }
- case dimOverworld:
- {
- cFile::CreateFolder(FILE_IO_PREFIX + GetWorld()->GetNetherWorldName());
- cIniFile File;
- File.ReadFile(GetWorld()->GetNetherWorldName() + "/world.ini");
- File.SetValue("General", "Dimension", "Nether");
- File.SetValue("General", "OverworldName", GetWorld()->GetName());
- File.WriteFile(GetWorld()->GetNetherWorldName() + "/world.ini");
-
- MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName()));
+ for (int OtherMinChunkX = MinChunkX; OtherMinChunkX <= MaxChunkX; ++OtherMinChunkX)
+ {
+ for (int OtherMinChunkZ = MinChunkZ; OtherMinChunkZ <= MaxChunkZ; ++OtherMinChunkZ)
+ {
+ Stay->Add(OtherMinChunkX, OtherMinChunkZ);
+ }
+ }
+
+ Stay->Enable(*GetWorld()->GetChunkMap());
break;
}
default: break;
@@ -1103,17 +1126,7 @@ void cEntity::DetectPortal()
{
case dimEnd:
{
- cIniFile OwnIni;
- OwnIni.ReadFile(GetWorld()->GetIniFileName());
- AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName());
-
- 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));
+ MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()));
if (IsPlayer())
{
@@ -1124,14 +1137,11 @@ void cEntity::DetectPortal()
}
case dimOverworld:
{
- cFile::CreateFolder(FILE_IO_PREFIX + GetWorld()->GetEndWorldName());
- cIniFile File;
- File.ReadFile(GetWorld()->GetEndWorldName() + "/world.ini");
- File.SetValue("General", "Dimension", "End");
- File.SetValue("General", "OverworldName", GetWorld()->GetName());
- File.WriteFile(GetWorld()->GetEndWorldName() + "/world.ini");
-
- MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName()));
+ if (IsPlayer())
+ {
+ ((cPlayer *)this)->AwardAchievement(achEnterTheEnd);
+ }
+ MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()));
break;
}
default: break;
@@ -1146,6 +1156,44 @@ void cEntity::DetectPortal()
+void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ cBlockArea Area;
+ Area.Read(GetWorld(), a_BlockX - 128, a_BlockX + 128, 0, 128, a_BlockZ - 128, a_BlockZ + 128);
+ for (int x = a_BlockX - 128; x <= a_BlockX + 128; ++x) for (int y = 0; y <= 128; ++y) for (int z = a_BlockZ - 128; z <= a_BlockZ + 128; ++z)
+ {
+ if (
+ (Area.GetBlockType(x, y, z) == E_BLOCK_NETHER_PORTAL) &&
+ (
+ (Area.GetBlockType(x, (int)floor(y + GetHeight()), z) == E_BLOCK_NETHER_PORTAL) ||
+ (Area.GetBlockType(x, (int)floor(y - GetHeight()), z) == E_BLOCK_NETHER_PORTAL)
+ )
+ )
+ {
+ TeleportToCoords(x, y, z);
+ return;
+ }
+ }
+
+ int MinX = std::max(a_BlockX - (int)ceil(GetWidth()), a_BlockX - 2), MaxX = std::max(a_BlockX + (int)ceil(GetWidth()), a_BlockX + 1);
+ int MinY = std::max(a_BlockY - (int)ceil(GetHeight()), a_BlockY - 2), MaxY = std::max(a_BlockY + (int)ceil(GetHeight()), a_BlockY + 1);
+
+ for (int y = MinY; y < MaxY + 1; y += MaxY - MinY) for (int x = MinX; x < MaxX + 1; ++x)
+ {
+ Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN);
+ }
+ for (int y = MinY; y < MaxY + 1; ++y) for (int x = MinX; x < MaxX + 1; x += MaxX - MinX)
+ {
+ Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN);
+ }
+
+ Area.Write(GetWorld(), MinX, MinY, a_BlockZ);
+}
+
+
+
+
+
bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World)
{
cWorld * World;
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index da8256606..b2317aaac 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -335,6 +335,9 @@ public:
/// Called when the entity finishes burning
virtual void OnFinishedBurning(void);
+
+ /** Creates exit portal at given coordinates */
+ void CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ);
// tolua_begin
diff --git a/src/Root.cpp b/src/Root.cpp
index 2a80baeb3..572cbf1fc 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -314,15 +314,15 @@ void cRoot::LoadWorlds(cIniFile & IniFile)
-cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName)
+cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName)
{
if (m_WorldsByName[a_WorldName] != NULL)
{
return NULL;
}
- cWorld * NewWorld = new cWorld(a_WorldName.c_str());
+ cWorld * NewWorld = new cWorld(a_WorldName.c_str(), a_Dimension, a_OverworldName);
m_WorldsByName[a_WorldName] = NewWorld;
- NewWorld->Start();
+ NewWorld->Start(!a_OverworldName.empty());
NewWorld->InitializeSpawn();
m_PluginManager->CallHookWorldStarted(*NewWorld);
return NewWorld;
diff --git a/src/Root.h b/src/Root.h
index d2a4d1eed..1b56b4528 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -44,7 +44,7 @@ public:
cServer * GetServer(void) { return m_Server; } // tolua_export
cWorld * GetDefaultWorld(void); // tolua_export
cWorld * GetWorld(const AString & a_WorldName); // tolua_export
- cWorld * CreateAndInitializeWorld(const AString & a_WorldName); // tolua_export
+ cWorld * CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = ""); // tolua_export
/// Calls the callback for each world; returns true if the callback didn't abort (return true)
bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings <<
diff --git a/src/World.cpp b/src/World.cpp
index 1b5582b81..1f4a88fa0 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -232,7 +232,7 @@ void cWorld::cTickThread::Execute(void)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWorld:
-cWorld::cWorld(const AString & a_WorldName) :
+cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) :
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
@@ -253,7 +253,9 @@ cWorld::cWorld(const AString & a_WorldName) :
m_Scoreboard(this),
m_MapManager(this),
m_GeneratorCallbacks(*this),
- m_TickThread(*this)
+ m_TickThread(*this),
+ m_Dimension(a_Dimension),
+ m_OverworldName(a_OverworldName)
{
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
@@ -511,7 +513,7 @@ void cWorld::InitializeSpawn(void)
-void cWorld::Start(void)
+void cWorld::Start(bool a_WasDimensionSet)
{
m_SpawnX = 0;
m_SpawnY = cChunkDef::Height;
@@ -523,8 +525,10 @@ void cWorld::Start(void)
{
LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str());
}
- AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld");
+
+ AString Dimension = IniFile.GetValueSet("General", "Dimension", a_WasDimensionSet ? DimensionToString(GetDimension()) : "Overworld");
m_Dimension = StringToDimension(Dimension);
+ m_OverworldName = IniFile.GetValue("General", "OverworldName", a_WasDimensionSet ? m_OverworldName : "");
// Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
int KeyNum = IniFile.FindKey("SpawnPosition");
@@ -570,7 +574,7 @@ void cWorld::Start(void)
m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode);
int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather);
- m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay);
+ m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay);
if ((GetDimension() != dimNether) && (GetDimension() != dimEnd))
{
@@ -759,6 +763,10 @@ void cWorld::Stop(void)
IniFile.SetValueB("General", "EndPortalsEnabled", m_bEndPortalsEnabled);
IniFile.SetValue("General", "EndWorldName", m_EndWorldName);
}
+ else
+ {
+ IniFile.SetValue("General", "OverworldName", m_OverworldName);
+ }
IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel);
IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled);
IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes);
diff --git a/src/World.h b/src/World.h
index 80f69f22f..676c5d69a 100644
--- a/src/World.h
+++ b/src/World.h
@@ -636,6 +636,9 @@ public:
AString GetEndWorldName(void) const { return m_EndWorldName; }
void SetEndWorldName(const AString & a_Name) { m_EndWorldName = a_Name; }
+
+ AString GetLinkedOverworldName(void) const { return m_OverworldName; }
+ void SetLinkedOverworldName(const AString & a_Name) { m_OverworldName = a_Name; }
// tolua_end
@@ -679,7 +682,7 @@ public:
void InitializeSpawn(void);
/** Starts threads that belong to this world */
- void Start(void);
+ void Start(bool a_WasDimensionSet = true);
/** Stops threads that belong to this world (part of deinit) */
void Stop(void);
@@ -816,6 +819,12 @@ private:
AString m_WorldName;
+
+ /** The name of the world that a portal in this world should link to
+ Only has effect if this world is a nether or end world, as it is used by entities to see which world to teleport to when in a portal
+ */
+ AString m_OverworldName;
+
AString m_IniFileName;
/** Name of the storage schema used to load and save chunks */
@@ -953,7 +962,7 @@ private:
cClientHandleList m_ClientsToAdd;
- cWorld(const AString & a_WorldName);
+ cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = "");
virtual ~cWorld();
void Tick(float a_Dt, int a_LastTickDurationMSec);