summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities')
-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
4 files changed, 190 insertions, 27 deletions
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);