summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--MCServer/.gitignore2
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua27
-rw-r--r--Tools/ProtoProxy/.gitignore4
-rw-r--r--Tools/ProtoProxy/Connection.cpp59
-rw-r--r--Tools/ProtoProxy/Connection.h10
-rw-r--r--VC2008/icon_128.pngbin0 -> 26758 bytes
-rw-r--r--VC2008/icon_256.pngbin0 -> 66137 bytes
-rw-r--r--source/ClientHandle.cpp25
-rw-r--r--source/ClientHandle.h8
-rw-r--r--source/Defines.h4
-rw-r--r--source/Items/ItemFood.h66
-rw-r--r--source/Items/ItemHandler.cpp15
-rw-r--r--source/Items/ItemHandler.h17
-rw-r--r--source/Player.cpp99
-rw-r--r--source/Player.h64
-rw-r--r--source/World.h11
17 files changed, 324 insertions, 90 deletions
diff --git a/.gitignore b/.gitignore
index bde685901..0f5712848 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,6 @@ SymSrv
cloc-ignored.txt
cloc.xml
cloc.xsl
+*.ncb
+*.user
+*.suo \ No newline at end of file
diff --git a/MCServer/.gitignore b/MCServer/.gitignore
index e455b8cdc..8452ec2d7 100644
--- a/MCServer/.gitignore
+++ b/MCServer/.gitignore
@@ -6,7 +6,7 @@ banned.ini
logs
players
whitelist.ini
-world
+world*
API.txt
*.dat
schematics
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index e2523e63e..1bc625c35 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -33,6 +33,8 @@ function Initialize(Plugin)
PluginManager:BindCommand("/dash", "debuggers", HandleDashCmd, "Switches between fast and normal sprinting speed");
PluginManager:BindCommand("/hunger", "debuggers", HandleHungerCmd, "Lists the current hunger-related variables");
PluginManager:BindCommand("/poison", "debuggers", HandlePoisonCmd, "Sets food-poisoning for 15 seconds");
+ PluginManager:BindCommand("/starve", "debuggers", HandleStarveCmd, "Sets the food level to zero");
+ PluginManager:BindCommand("/fl", "debuggers", HandleFoodLevelCmd, "Sets the food level to the given value");
-- Enable the following line for BlockArea / Generator interface testing:
-- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
@@ -715,3 +717,28 @@ end
+
+function HandleStarveCmd(a_Split, a_Player)
+ a_Player:SetFoodLevel(0);
+ a_Player:SendMessage("You are now starving");
+ return true;
+end
+
+
+
+
+
+function HandleFoodLevelCmd(a_Split, a_Player)
+ if (#a_Split ~= 2) then
+ a_Player:SendMessage("Missing an argument: the food level to set");
+ return true;
+ end
+
+ a_Player:SetFoodLevel(tonumber(a_Split[2]));
+ a_Player:SendMessage("Food level set to " .. a_Player:GetFoodLevel());
+ return true;
+end
+
+
+
+
diff --git a/Tools/ProtoProxy/.gitignore b/Tools/ProtoProxy/.gitignore
new file mode 100644
index 000000000..3097f7aab
--- /dev/null
+++ b/Tools/ProtoProxy/.gitignore
@@ -0,0 +1,4 @@
+Debug
+Release
+*.log
+*.nbt
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp
index a3d3191fc..32dfe321e 100644
--- a/Tools/ProtoProxy/Connection.cpp
+++ b/Tools/ProtoProxy/Connection.cpp
@@ -49,13 +49,25 @@
{ \
AString ToServer; \
m_ClientBuffer.ReadAgain(ToServer); \
- if (m_ServerState == csUnencrypted) \
+ switch (m_ServerState) \
{ \
- SERVERSEND(ToServer.data(), ToServer.size()); \
- } \
- else \
- { \
- SERVERENCRYPTSEND(ToServer.data(), ToServer.size()); \
+ case csUnencrypted: \
+ { \
+ SERVERSEND(ToServer.data(), ToServer.size()); \
+ break; \
+ } \
+ case csEncryptedUnderstood: \
+ case csEncryptedUnknown: \
+ { \
+ SERVERENCRYPTSEND(ToServer.data(), ToServer.size()); \
+ break; \
+ } \
+ case csWaitingForEncryption: \
+ { \
+ Log("Waiting for server encryption, queued %u bytes", ToServer.size()); \
+ m_ServerEncryptionBuffer.append(ToServer.data(), ToServer.size()); \
+ break; \
+ } \
} \
DebugSleep(50); \
}
@@ -64,13 +76,25 @@
{ \
AString ToClient; \
m_ServerBuffer.ReadAgain(ToClient); \
- if (m_ClientState == csUnencrypted) \
+ switch (m_ClientState) \
{ \
- CLIENTSEND(ToClient.data(), ToClient.size()); \
- } \
- else \
- { \
- CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \
+ case csUnencrypted: \
+ { \
+ CLIENTSEND(ToClient.data(), ToClient.size()); \
+ break; \
+ } \
+ case csEncryptedUnderstood: \
+ case csEncryptedUnknown: \
+ { \
+ CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \
+ break; \
+ } \
+ case csWaitingForEncryption: \
+ { \
+ Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \
+ m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \
+ break; \
+ } \
} \
DebugSleep(50); \
}
@@ -379,6 +403,7 @@ bool cConnection::RelayFromServer(void)
switch (m_ServerState)
{
case csUnencrypted:
+ case csWaitingForEncryption:
{
return DecodeServersPackets(Buffer, res);
}
@@ -419,6 +444,7 @@ bool cConnection::RelayFromClient(void)
switch (m_ClientState)
{
case csUnencrypted:
+ case csWaitingForEncryption:
{
return DecodeClientsPackets(Buffer, res);
}
@@ -1543,6 +1569,9 @@ bool cConnection::HandleServerEncryptionKeyResponse(void)
}
Log("Server communication is now encrypted");
m_ServerState = csEncryptedUnderstood;
+ DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size());
+ SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size());
+ m_ServerEncryptionBuffer.clear();
return true;
}
@@ -2459,6 +2488,7 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
ToServer.WriteBEShort(EncryptedLength);
ToServer.WriteBuf(EncryptedNonce, EncryptedLength);
SERVERSEND(ToServer);
+ m_ServerState = csWaitingForEncryption;
}
@@ -2507,6 +2537,11 @@ void cConnection::StartClientEncryption(const AString & a_EncKey, const AString
Log("Client connection is now encrypted");
m_ClientState = csEncryptedUnderstood;
+ // Send the queued data:
+ DataLog(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size(), "Sending the queued data to client (%u bytes):", m_ClientEncryptionBuffer.size());
+ CLIENTENCRYPTSEND(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size());
+ m_ClientEncryptionBuffer.clear();
+
// Handle all postponed server data
DecodeServersPackets(NULL, 0);
}
diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h
index 7f3a6f8bb..dafc1b36b 100644
--- a/Tools/ProtoProxy/Connection.h
+++ b/Tools/ProtoProxy/Connection.h
@@ -39,9 +39,10 @@ class cConnection
enum eConnectionState
{
- csUnencrypted, // The connection is not encrypted. Packets must be decoded in order to be able to start decryption.
- csEncryptedUnderstood, // The communication is encrypted and so far all packets have been understood, so they can be still decoded
- csEncryptedUnknown, // The communication is encrypted, but an unknown packet has been received, so packets cannot be decoded anymore
+ csUnencrypted, // The connection is not encrypted. Packets must be decoded in order to be able to start decryption.
+ csEncryptedUnderstood, // The communication is encrypted and so far all packets have been understood, so they can be still decoded
+ csEncryptedUnknown, // The communication is encrypted, but an unknown packet has been received, so packets cannot be decoded anymore
+ csWaitingForEncryption, // The communication is waiting for the other line to establish encryption
};
eConnectionState m_ClientState;
@@ -72,6 +73,9 @@ protected:
Decryptor m_ClientDecryptor;
Encryptor m_ClientEncryptor;
+ AString m_ClientEncryptionBuffer; // Buffer for the data to be sent to the client once encryption is established
+ AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
+
/// Set to true when PACKET_PING is received from the client; will cause special parsing for server kick
bool m_HasClientPinged;
diff --git a/VC2008/icon_128.png b/VC2008/icon_128.png
new file mode 100644
index 000000000..87d939a04
--- /dev/null
+++ b/VC2008/icon_128.png
Binary files differ
diff --git a/VC2008/icon_256.png b/VC2008/icon_256.png
new file mode 100644
index 000000000..9a77a490f
--- /dev/null
+++ b/VC2008/icon_256.png
Binary files differ
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index 155eac38a..d66e47d32 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -555,11 +555,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
if (ItemHandler->IsFood())
{
- if (PlgMgr->CallHookPlayerEating(*m_Player))
- {
- // A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
- return;
- }
+ m_Player->AbortEating();
+ return;
}
else
{
@@ -569,7 +566,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
return;
}
}
- LOGINFO("%s: Status SHOOT / EAT not implemented", __FUNCTION__);
+ LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
return;
}
@@ -804,15 +801,19 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
}
else if (ItemHandler->IsFood())
{
- cItem Item;
- Item.m_ItemType = Equipped.m_ItemType;
- Item.m_ItemCount = 1;
- if (ItemHandler->EatItem(m_Player, &Item))
+ if (m_Player->IsSatiated())
{
- ItemHandler->OnFoodEaten(World, m_Player, &Item);
- m_Player->GetInventory().RemoveOneEquippedItem();
+ // The player is satiated, they cannot eat
return;
}
+ m_Player->StartEating();
+ if (PlgMgr->CallHookPlayerEating(*m_Player))
+ {
+ // A plugin won't let us eat, abort (send the proper packets to the client, too):
+ m_Player->AbortEating();
+ return;
+ }
+ return;
}
else
{
diff --git a/source/ClientHandle.h b/source/ClientHandle.h
index a06aca39f..9cf1a3326 100644
--- a/source/ClientHandle.h
+++ b/source/ClientHandle.h
@@ -281,6 +281,9 @@ private:
/// Buffer for received messages to be processed in the Tick thread
AStringList m_PendingMessages;
+
+ static int s_ClientCount;
+ int m_UniqueID;
@@ -307,14 +310,11 @@ private:
/// Processes the messages in m_PendingMessages; called from the Tick thread
void ProcessPendingMessages(void);
-
+
// cSocketThreads::cCallback overrides:
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
virtual void SocketClosed (void) override; // The socket has been closed for any reason
-
- static int s_ClientCount;
- int m_UniqueID;
}; // tolua_export
diff --git a/source/Defines.h b/source/Defines.h
index f52050a9b..94e618eb0 100644
--- a/source/Defines.h
+++ b/source/Defines.h
@@ -116,6 +116,10 @@ enum eGameMode
gmSurvival = eGameMode_Survival,
gmCreative = eGameMode_Creative,
gmAdventure = eGameMode_Adventure,
+
+ // These two are used to check GameMode for validity when converting from integers.
+ gmMax, // Gets automatically assigned
+ gmMin = 0,
} ;
diff --git a/source/Items/ItemFood.h b/source/Items/ItemFood.h
index d4c0a012a..4ec2f7a36 100644
--- a/source/Items/ItemFood.h
+++ b/source/Items/ItemFood.h
@@ -4,53 +4,53 @@
#include "ItemHandler.h"
-class cItemFoodHandler : public cItemHandler
+
+
+
+class cItemFoodHandler :
+ public cItemHandler
{
+ typedef cItemHandler super;
+
public:
cItemFoodHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+ : super(a_ItemType)
{
}
- virtual bool IsFood() override
+
+ virtual bool IsFood(void) override
{
return true;
}
- virtual FoodInfo GetFoodInfo() override
+
+ virtual FoodInfo GetFoodInfo(void) override
{
switch(m_ItemType)
{
- case E_ITEM_BREAD:
- return FoodInfo(5, 6.f);
- case E_ITEM_COOKIE:
- return FoodInfo(2, 0.4f);
- case E_ITEM_MELON_SLICE:
- return FoodInfo(2, 1.2f);
- case E_ITEM_RAW_CHICKEN:
- return FoodInfo(2, 1.2f, 30);
- case E_ITEM_COOKED_CHICKEN:
- return FoodInfo(6, 7.2f);
- case E_ITEM_RAW_BEEF:
- case E_ITEM_RAW_PORKCHOP:
- return FoodInfo(3, 1.8f);
- case E_ITEM_STEAK:
- case E_ITEM_COOKED_PORKCHOP:
- return FoodInfo(8, 12.8f);
- case E_ITEM_RAW_FISH:
- return FoodInfo(2, 1.2f);
- case E_ITEM_COOKED_FISH:
- return FoodInfo(5, 6.f);
- case E_ITEM_RED_APPLE:
- return FoodInfo(4, 2.4f);
- case E_ITEM_GOLDEN_APPLE:
- return FoodInfo(4, 9.6f);
- case E_ITEM_ROTTEN_FLESH:
- return FoodInfo(4, 0.8f, 80);
- case E_ITEM_SPIDER_EYE:
- return FoodInfo(2, 3.2f, 100);
+ case E_ITEM_BREAD: return FoodInfo(5, 6);
+ case E_ITEM_COOKIE: return FoodInfo(2, 0.4);
+ case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
+ case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30);
+ case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
+ case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
+ case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
+ case E_ITEM_STEAK: return FoodInfo(8, 12.8);
+ case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
+ case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
+ case E_ITEM_COOKED_FISH: return FoodInfo(5, 6);
+ case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
+ case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6);
+ case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
+ case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
}
+ LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
return FoodInfo(0, 0.f);
}
-}; \ No newline at end of file
+};
+
+
+
+
diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp
index d99457029..acb6b6371 100644
--- a/source/Items/ItemHandler.cpp
+++ b/source/Items/ItemHandler.cpp
@@ -4,6 +4,7 @@
#include "../Item.h"
#include "../World.h"
#include "../Player.h"
+#include "../FastRandom.h"
// Handlers:
#include "ItemBed.h"
@@ -465,15 +466,17 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{
FoodInfo Info = GetFoodInfo();
- if(Info.FoodLevel > 0 || Info.Saturation > 0.f)
+ if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
{
bool Success = a_Player->Feed(Info.FoodLevel, Info.Saturation);
- if(Success && Info.PoisionChance > 0)
+
+ // If consumed and there's chance of foodpoisoning, do it:
+ if (Success && (Info.PoisonChance > 0))
{
- MTRand r1;
- if((r1.randInt(100) - Info.PoisionChance) <= 0)
- { //Unlucky guy :D
- //TODO: Make player ill
+ cFastRandom r1;
+ if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0)
+ {
+ a_Player->FoodPoison(300);
}
}
diff --git a/source/Items/ItemHandler.h b/source/Items/ItemHandler.h
index 0c141dea0..f7985327a 100644
--- a/source/Items/ItemHandler.h
+++ b/source/Items/ItemHandler.h
@@ -38,16 +38,17 @@ public:
struct FoodInfo
{
- FoodInfo(short a_FoodLevel, float a_Saturation, char a_PoisionChance = 0)
+ int FoodLevel;
+ double Saturation;
+ int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning
+
+ FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
+ FoodLevel(a_FoodLevel),
+ Saturation(a_Saturation),
+ PoisonChance(a_PoisonChance)
{
- FoodLevel = a_FoodLevel;
- Saturation = a_Saturation;
- PoisionChance = a_PoisionChance;
}
- short FoodLevel;
- float Saturation;
- char PoisionChance; //0 - 100
- };
+ } ;
/// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance)
virtual FoodInfo GetFoodInfo();
diff --git a/source/Player.cpp b/source/Player.cpp
index 83181dda6..c90f3c99c 100644
--- a/source/Player.cpp
+++ b/source/Player.cpp
@@ -20,6 +20,7 @@
#include "OSSupport/Timer.h"
#include "MersenneTwister.h"
#include "Chunk.h"
+#include "Items/ItemHandler.h"
#include "Vector3d.h"
#include "Vector3f.h"
@@ -58,6 +59,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_SprintingMaxSpeed(0.13)
, m_IsCrouched(false)
, m_IsSprinting(false)
+ , m_EatingFinishTick(-1)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@@ -189,6 +191,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
{
m_World->CollectPickupsByPlayer(this);
+ if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge()))
+ {
+ FinishEating();
+ }
+
HandleFood();
}
@@ -349,6 +356,57 @@ void cPlayer::FoodPoison(int a_NumTicks)
+void cPlayer::StartEating(void)
+{
+ // Set the timer:
+ m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS;
+
+ // Send the packets:
+ m_World->BroadcastPlayerAnimation(*this, 5);
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cPlayer::FinishEating(void)
+{
+ // Reset the timer:
+ m_EatingFinishTick = -1;
+
+ // Send the packets:
+ m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED);
+ m_World->BroadcastPlayerAnimation(*this, 0);
+ m_World->BroadcastEntityMetadata(*this);
+
+ // consume the item:
+ cItem Item(GetEquippedItem());
+ Item.m_ItemCount = 1;
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Item.m_ItemType);
+ if (!ItemHandler->EatItem(this, &Item))
+ {
+ return;
+ }
+ ItemHandler->OnFoodEaten(m_World, this, &Item);
+ GetInventory().RemoveOneEquippedItem();
+}
+
+
+
+
+
+void cPlayer::AbortEating(void)
+{
+ m_EatingFinishTick = -1;
+ m_World->BroadcastPlayerAnimation(*this, 0);
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
void cPlayer::SendHealth(void)
{
if (m_ClientHandle != NULL)
@@ -505,7 +563,10 @@ void cPlayer::KilledBy(cEntity * a_Killer)
void cPlayer::Respawn(void)
{
m_Health = GetMaxHealth();
+
+ // Reset food level:
m_FoodLevel = 20;
+ m_FoodSaturationLevel = 5;
m_ClientHandle->SendRespawn();
@@ -538,6 +599,36 @@ Vector3d cPlayer::GetEyePosition(void) const
+bool cPlayer::IsGameModeCreative(void) const
+{
+ return (m_GameMode == gmCreative) || // Either the player is explicitly in Creative
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Creative
+}
+
+
+
+
+
+bool cPlayer::IsGameModeSurvival(void) const
+{
+ return (m_GameMode == gmSurvival) || // Either the player is explicitly in Survival
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeSurvival()); // or they inherit from the world and the world is Survival
+}
+
+
+
+
+
+bool cPlayer::IsGameModeAdventure(void) const
+{
+ return (m_GameMode == gmCreative) || // Either the player is explicitly in Adventure
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Adventure
+}
+
+
+
+
+
void cPlayer::OpenWindow(cWindow * a_Window)
{
if (a_Window != m_CurrentWindow)
@@ -614,7 +705,7 @@ void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
void cPlayer::SetGameMode(eGameMode a_GameMode)
{
- if ((a_GameMode >= 3) || (a_GameMode < 0))
+ if ((a_GameMode >= gmMin) || (a_GameMode < gmMax))
{
LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode);
return;
@@ -1283,8 +1374,14 @@ void cPlayer::HandleFood(void)
void cPlayer::ApplyFoodExhaustionFromMovement(cChunk & a_Chunk)
{
+ if (IsGameModeCreative())
+ {
+ return;
+ }
+
// Calculate the distance travelled, update the last pos:
Vector3d Movement(GetPosition() - m_LastFoodPos);
+ Movement.y = 0; // Only take XZ movement into account
m_LastFoodPos = GetPosition();
// If riding anything, apply no food exhaustion
diff --git a/source/Player.h b/source/Player.h
index fed222157..eea8c1596 100644
--- a/source/Player.h
+++ b/source/Player.h
@@ -28,6 +28,7 @@ public:
{
MAX_HEALTH = 20,
MAX_FOOD_LEVEL = 20,
+ EATING_TICKS = 30, ///< Number of ticks it takes to eat an item
} ;
// tolua_end
@@ -65,7 +66,7 @@ public:
double GetEyeHeight(void) const; // tolua_export
Vector3d GetEyePosition(void) const; // tolua_export
inline bool IsOnGround(void) const {return m_bTouchGround; } // tolua_export
- inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
+ inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
inline const cInventory & GetInventory(void) const { return m_Inventory; }
@@ -73,18 +74,42 @@ public:
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
- eGameMode GetGameMode(void) const { return m_GameMode; } // tolua_export
- std::string GetIP() { return m_IP; } // tolua_export
- float GetLastBlockActionTime() { return m_LastBlockActionTime; } // tolua_export
- int GetLastBlockActionCnt() { return m_LastBlockActionCnt; } // tolua_export
- void SetLastBlockActionCnt( int ); // tolua_export
- void SetLastBlockActionTime(); // tolua_export
- void SetGameMode( eGameMode a_GameMode ); // tolua_export
- void LoginSetGameMode( eGameMode a_GameMode );
+ // tolua_begin
+
+ /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
+ eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /** Sets the gamemode for the player.
+ The gamemode may be gmNotSet, in that case the player inherits the world's gamemode.
+ Updates the gamemode on the client (sends the packet)
+ */
+ void SetGameMode(eGameMode a_GameMode);
+
+ /// Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world
+ bool IsGameModeCreative(void) const;
+
+ /// Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world
+ bool IsGameModeSurvival(void) const;
+
+ /// Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world
+ bool IsGameModeAdventure(void) const;
+
+ AString GetIP(void) const { return m_IP; } // tolua_export
+
+ // tolua_end
+
void SetIP(const AString & a_IP);
+ float GetLastBlockActionTime() { return m_LastBlockActionTime; }
+ int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
+ void SetLastBlockActionCnt( int );
+ void SetLastBlockActionTime();
+
+ // Sets the current gamemode, doesn't check validity, doesn't send update packets to client
+ void LoginSetGameMode(eGameMode a_GameMode);
+
/// Tries to move to a new position, with collision checks and stuff
- virtual void MoveTo( const Vector3d & a_NewPos ); // tolua_export
+ virtual void MoveTo( const Vector3d & a_NewPos ); // tolua_export
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
@@ -136,6 +161,9 @@ public:
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; }
+ /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore
+ bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
+
void SetFoodLevel (int a_FoodLevel);
void SetFoodSaturationLevel (double a_FoodSaturationLevel);
void SetFoodTickTimer (int a_FoodTickTimer);
@@ -151,8 +179,20 @@ public:
/// Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two
void FoodPoison(int a_NumTicks);
+ /// Returns true if the player is currently in the process of eating the currently equipped item
+ bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
+
// tolua_end
+ /// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet
+ void StartEating(void);
+
+ /// Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets
+ void FinishEating(void);
+
+ /// Aborts the current eating operation
+ void AbortEating(void);
+
virtual void KilledBy(cEntity * a_Killer) override;
void Respawn(void); // tolua_export
@@ -214,6 +254,7 @@ public:
// cEntity overrides:
virtual bool IsCrouched (void) const { return m_IsCrouched; }
virtual bool IsSprinting(void) const { return m_IsSprinting; }
+ virtual bool IsRclking (void) const { return IsEating(); }
protected:
typedef std::map< std::string, bool > PermissionMap;
@@ -285,6 +326,9 @@ protected:
bool m_IsCrouched;
bool m_IsSprinting;
+ /// The world tick in which eating will be finished. -1 if not eating
+ Int64 m_EatingFinishTick;
+
virtual void Destroyed(void);
diff --git a/source/World.h b/source/World.h
index 5da7218e2..e67b06789 100644
--- a/source/World.h
+++ b/source/World.h
@@ -106,7 +106,18 @@ public:
SetTimeOfDay(a_TimeOfDay);
}
+ /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /// Returns true if the world is in Creative mode
+ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); }
+
+ /// Returns true if the world is in Survival mode
+ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); }
+
+ /// Returns true if the world is in Adventure mode
+ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
+
bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }