Portal improvements and suggestions
This commit is contained in:
parent
b925eb4ad4
commit
35b79e5d71
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
{
|
||||
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));
|
||||
break;
|
||||
}
|
||||
case dimNether: MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); 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");
|
||||
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));
|
||||
|
||||
MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName()));
|
||||
int MinChunkX, MaxChunkX;
|
||||
int MinChunkZ, MaxChunkZ;
|
||||
cChunkDef::BlockToChunk(X - 128, Z - 128, MinChunkX, MinChunkZ);
|
||||
cChunkDef::BlockToChunk(X + 128, Z + 128, MaxChunkX, MaxChunkZ);
|
||||
|
||||
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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 <<
|
||||
|
@ -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);
|
||||
|
13
src/World.h
13
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);
|
||||
|
Loading…
Reference in New Issue
Block a user