From 01b24d73eab6b0e708063d82f01ea9bb9296550c Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 3 Mar 2013 19:05:11 +0000 Subject: [PATCH] Player can sit in minecarts (but not move them yet) git-svn-id: http://mc-server.googlecode.com/svn/trunk@1249 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Bindings.cpp | 36 +++++++- source/Bindings.h | 2 +- source/Chunk.cpp | 18 +++- source/Chunk.h | 1 + source/ChunkMap.cpp | 15 +++ source/ChunkMap.h | 2 + source/ClientHandle.cpp | 26 +++++- source/ClientHandle.h | 1 + source/Entity.cpp | 121 +++++++++++++++++++------ source/Entity.h | 22 ++++- source/Items/ItemMinecart.h | 12 ++- source/Minecart.cpp | 87 ++++++++++++++++++ source/Minecart.h | 58 +++++++++++- source/Player.cpp | 12 ++- source/Protocol/Protocol.h | 1 + source/Protocol/Protocol125.cpp | 14 +++ source/Protocol/Protocol125.h | 1 + source/Protocol/ProtocolRecognizer.cpp | 10 ++ source/Protocol/ProtocolRecognizer.h | 1 + source/World.cpp | 91 ++++++++++--------- source/World.h | 1 + 21 files changed, 448 insertions(+), 84 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 5db1c385b..ad8c397c6 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 03/03/13 14:57:13. +** Generated automatically by tolua++-1.0.92 on 03/03/13 20:02:17. */ #ifndef __cplusplus @@ -5046,6 +5046,39 @@ static int tolua_AllToLua_cEntity_SetRoll00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: AddSpeed of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_AddSpeed00 +static int tolua_AllToLua_cEntity_AddSpeed00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_AddSpeed = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddSpeed'", NULL); +#endif + { + self->AddSpeed(*a_AddSpeed); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'AddSpeed'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetUniqueID of class cEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetUniqueID00 static int tolua_AllToLua_cEntity_GetUniqueID00(lua_State* tolua_S) @@ -22073,6 +22106,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetRotation",tolua_AllToLua_cEntity_SetRotation00); tolua_function(tolua_S,"SetPitch",tolua_AllToLua_cEntity_SetPitch00); tolua_function(tolua_S,"SetRoll",tolua_AllToLua_cEntity_SetRoll00); + tolua_function(tolua_S,"AddSpeed",tolua_AllToLua_cEntity_AddSpeed00); tolua_function(tolua_S,"GetUniqueID",tolua_AllToLua_cEntity_GetUniqueID00); tolua_function(tolua_S,"IsDestroyed",tolua_AllToLua_cEntity_IsDestroyed00); tolua_function(tolua_S,"Destroy",tolua_AllToLua_cEntity_Destroy00); diff --git a/source/Bindings.h b/source/Bindings.h index 69cdcc5f7..6a9515913 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 03/03/13 14:57:13. +** Generated automatically by tolua++-1.0.92 on 03/03/13 20:02:18. */ /* Exported function */ diff --git a/source/Chunk.cpp b/source/Chunk.cpp index cfe6ad22d..f809892f4 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -1900,9 +1900,9 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) // For requests crossing both X and Z, the X-first way has been already tried } return NULL; - } - else if (a_RelZ >= cChunkDef::Width) - { + } + else if (a_RelZ >= cChunkDef::Width) + { if (m_NeighborZP != NULL) { return m_NeighborZP->GetRelNeighborChunk(a_RelX, a_RelZ - cChunkDef::Width); @@ -1918,6 +1918,18 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) +void cChunk::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) + { + (*itr)->SendAttachEntity(a_Entity, a_Vehicle); + } // for itr - LoadedByClient[] +} + + + + + void cChunk::BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude) { for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) diff --git a/source/Chunk.h b/source/Chunk.h index a85c99271..629e3a6b9 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -207,6 +207,7 @@ public: void CalculateLighting(); // Recalculate right now void CalculateHeightmap(); + void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); void BroadcastEntRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index 824c7cbfe..00f40f093 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -274,6 +274,21 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) +void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + if (Chunk == NULL) + { + return; + } + // It's perfectly legal to broadcast packets even to invalid chunks! + Chunk->BroadcastAttachEntity(a_Entity, a_Vehicle); +} + + + + void cChunkMap::BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); diff --git a/source/ChunkMap.h b/source/ChunkMap.h index 86cbf35a2..1ddd7d637 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -45,6 +45,8 @@ public: cChunkMap(cWorld* a_World ); ~cChunkMap(); + void BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle); + /// Broadcasts an a_Player's animation to all clients in the chunk where a_Player is void BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index e2a57d79e..fde80a083 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -1048,9 +1048,24 @@ void cClientHandle::HandleUpdateSign( void cClientHandle::HandleUseEntity(int a_TargetEntityID, bool a_IsLeftClick) { + // TODO: Let plugins interfere via a hook + if (!a_IsLeftClick) { - // TODO: we don't handle right-clicking yet + class cRclkEntity : public cEntityCallback + { + cPlayer & m_Player; + virtual bool Item(cEntity * a_Entity) override + { + a_Entity->OnRightClicked(m_Player); + return true; + } + public: + cRclkEntity(cPlayer & a_Player) : m_Player(a_Player) {} + } Callback (*m_Player); + + cWorld * World = m_Player->GetWorld(); + World->DoWithEntityByID(a_TargetEntityID, Callback); return; } @@ -1449,6 +1464,15 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity) +void cClientHandle::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + m_Protocol->SendAttachEntity(a_Entity, a_Vehicle); +} + + + + + void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) { m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType); diff --git a/source/ClientHandle.h b/source/ClientHandle.h index b6bcb20a2..2eb778c91 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -82,6 +82,7 @@ public: bool IsDestroyed (void) const { return (m_State == csDestroyed); } bool IsDestroying(void) const { return (m_State == csDestroying); } + void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType); void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes); diff --git a/source/Entity.cpp b/source/Entity.cpp index bbca17fce..b95648f59 100644 --- a/source/Entity.cpp +++ b/source/Entity.cpp @@ -23,19 +23,21 @@ cCriticalSection cEntity::m_CSCount; cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z) - : m_UniqueID( 0 ) - , m_Referencers( new cReferenceManager( cReferenceManager::RFMNGR_REFERENCERS ) ) - , m_References( new cReferenceManager( cReferenceManager::RFMNGR_REFERENCES ) ) - , m_ChunkX( 0 ) - , m_ChunkY( 0 ) - , m_ChunkZ( 0 ) - , m_Pos( a_X, a_Y, a_Z ) - , m_bDirtyPosition( true ) - , m_bDirtyOrientation( true ) - , m_bDestroyed( false ) + : m_UniqueID(0) + , m_AttachedTo(NULL) + , m_Attachee(NULL) + , m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS)) + , m_References(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCES)) + , m_ChunkX(0) + , m_ChunkY(0) + , m_ChunkZ(0) + , m_Pos(a_X, a_Y, a_Z) + , m_bDirtyPosition(true) + , m_bDirtyOrientation(true) + , m_bDestroyed(false) , m_EntityType(a_EntityType) , m_World(NULL) - , m_bRemovedFromChunk( false ) + , m_bRemovedFromChunk(false) , m_FireDamageInterval(0.f) , m_BurnPeriod(0.f) { @@ -57,6 +59,15 @@ cEntity::~cEntity() this ); + if (m_AttachedTo != NULL) + { + Detach(); + } + if (m_Attachee != NULL) + { + m_Attachee->Detach(); + } + if (!m_bDestroyed || !m_bRemovedFromChunk) { LOGERROR("ERROR: Entity deallocated without being destroyed %i or unlinked %i", m_bDestroyed, m_bRemovedFromChunk); @@ -100,7 +111,7 @@ const char * cEntity::GetParentClass(void) const void cEntity::Initialize(cWorld * a_World) { m_World = a_World; - m_World->AddEntity( this ); + m_World->AddEntity(this); MoveToCorrectChunk(true); } @@ -124,10 +135,10 @@ void cEntity::WrapRotation() void cEntity::MoveToCorrectChunk(bool a_bIgnoreOldChunk) { ASSERT(m_World != NULL); // Entity needs a world to move to a chunk - if( !m_World ) return; + if (!m_World) return; int ChunkX = 0, ChunkY = 0, ChunkZ = 0; - cWorld::BlockToChunk( (int)m_Pos.x, (int)m_Pos.y, (int)m_Pos.z, ChunkX, ChunkY, ChunkZ ); + cWorld::BlockToChunk((int)m_Pos.x, (int)m_Pos.y, (int)m_Pos.z, ChunkX, ChunkY, ChunkZ); if (!a_bIgnoreOldChunk && (m_ChunkX == ChunkX) && (m_ChunkY == ChunkY) && (m_ChunkZ == ChunkZ)) { return; @@ -213,7 +224,54 @@ void cEntity::Tick(float a_Dt, MTRand & a_TickRandom) { UNUSED(a_TickRandom); - HandlePhysics(a_Dt); + if (m_AttachedTo != NULL) + { + if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5) + { + SetPosition(m_AttachedTo->GetPosition()); + } + } + else + { + HandlePhysics(a_Dt); + } +} + + + + + +void cEntity::AttachTo(cEntity * a_AttachTo) +{ + if (m_AttachedTo == a_AttachTo) + { + // Already attached to that entity, nothing to do here + return; + } + + // Detach from any previous entity: + Detach(); + + // Attach to the new entity: + m_AttachedTo = a_AttachTo; + a_AttachTo->m_Attachee = this; + m_World->BroadcastAttachEntity(*this, a_AttachTo); +} + + + + + +void cEntity::Detach(void) +{ + if (m_AttachedTo == NULL) + { + // Attached to no entity, our work is done + return; + } + m_AttachedTo->m_Attachee = NULL; + m_AttachedTo = NULL; + m_World->BroadcastAttachEntity(*this, NULL); } @@ -231,7 +289,7 @@ bool cEntity::IsA(const char * a_ClassName) const ////////////////////////////////////////////////////////////////////////// // Set orientations -void cEntity::SetRot( const Vector3f & a_Rot ) +void cEntity::SetRot(const Vector3f & a_Rot) { m_Rot = a_Rot; m_bDirtyOrientation = true; @@ -241,7 +299,7 @@ void cEntity::SetRot( const Vector3f & a_Rot ) -void cEntity::SetRotation( float a_Rotation ) +void cEntity::SetRotation(float a_Rotation) { m_Rot.x = a_Rotation; m_bDirtyOrientation = true; @@ -251,7 +309,7 @@ void cEntity::SetRotation( float a_Rotation ) -void cEntity::SetPitch( float a_Pitch ) +void cEntity::SetPitch(float a_Pitch) { m_Rot.y = a_Pitch; m_bDirtyOrientation = true; @@ -261,7 +319,7 @@ void cEntity::SetPitch( float a_Pitch ) -void cEntity::SetRoll( float a_Roll ) +void cEntity::SetRoll(float a_Roll) { m_Rot.z = a_Roll; m_bDirtyOrientation = true; @@ -271,13 +329,22 @@ void cEntity::SetRoll( float a_Roll ) +void cEntity::AddSpeed(const Vector3d & a_AddSpeed) +{ + m_Speed += a_AddSpeed; +} + + + + + ////////////////////////////////////////////////////////////////////////// // Get look vector (this is NOT a rotation!) Vector3f cEntity::GetLookVector(void) const { Matrix4f m; - m.Init( Vector3f(), 0, m_Rot.x, -m_Rot.y ); - Vector3f Look = m.Transform( Vector3f(0, 0, 1) ); + m.Init(Vector3f(), 0, m_Rot.x, -m_Rot.y); + Vector3f Look = m.Transform(Vector3f(0, 0, 1)); return Look; } @@ -287,7 +354,7 @@ Vector3f cEntity::GetLookVector(void) const ////////////////////////////////////////////////////////////////////////// // Set position -void cEntity::SetPosition( const Vector3d & a_Pos ) +void cEntity::SetPosition(const Vector3d & a_Pos) { m_Pos = a_Pos; MoveToCorrectChunk(); @@ -346,8 +413,8 @@ void cEntity::SetPosZ(double a_PosZ) // Reference stuffs void cEntity::AddReference(cEntity * & a_EntityPtr) { - m_References->AddReference( a_EntityPtr ); - a_EntityPtr->ReferencedBy( a_EntityPtr ); + m_References->AddReference(a_EntityPtr); + a_EntityPtr->ReferencedBy(a_EntityPtr); } @@ -356,16 +423,16 @@ void cEntity::AddReference(cEntity * & a_EntityPtr) void cEntity::ReferencedBy(cEntity * & a_EntityPtr) { - m_Referencers->AddReference( a_EntityPtr ); + m_Referencers->AddReference(a_EntityPtr); } -void cEntity::Dereference(cEntity*& a_EntityPtr) +void cEntity::Dereference(cEntity * & a_EntityPtr) { - m_Referencers->Dereference( a_EntityPtr ); + m_Referencers->Dereference(a_EntityPtr); } diff --git a/source/Entity.h b/source/Entity.h index 82e1c3c7a..e0c0bb191 100644 --- a/source/Entity.h +++ b/source/Entity.h @@ -37,6 +37,7 @@ class cWorld; class cReferenceManager; class cClientHandle; +class cPlayer; class MTRand; @@ -130,6 +131,8 @@ public: void SetRotation(float a_Rotation); void SetPitch (float a_Pitch); void SetRoll (float a_Roll); + + void AddSpeed(const Vector3d & a_AddSpeed); // tolua_end inline int GetUniqueID(void) const { return m_UniqueID; } // tolua_export @@ -147,6 +150,12 @@ public: */ virtual void SpawnOn(cClientHandle & a_Client) {ASSERT(!"SpawnOn() unimplemented!"); } + /// Attaches to the specified entity; detaches from any previous one first + void AttachTo(cEntity * a_AttachTo); + + /// Detaches from the currently attached entity, if any + void Detach(void); + void WrapRotation(); // tolua_begin @@ -159,11 +168,14 @@ public: virtual bool IsRclking (void) const {return false; } // tolua_end + + /// Called when the specified player right-clicks this entity + virtual void OnRightClicked(cPlayer & a_Player) {}; protected: - virtual void Destroyed() {} // Called after the entity has been destroyed + virtual void Destroyed(void) {} // Called after the entity has been destroyed - void SetWorld( cWorld* a_World ) { m_World = a_World; } + void SetWorld(cWorld * a_World) { m_World = a_World; } void MoveToCorrectChunk(bool a_bIgnoreOldChunk = false); friend class cReferenceManager; @@ -175,6 +187,12 @@ protected: static int m_EntityCount; int m_UniqueID; + + /// The entity to which this entity is attached (vehicle), NULL if none + cEntity * m_AttachedTo; + + /// The entity which is attached to this entity (rider), NULL if none + cEntity * m_Attachee; cReferenceManager* m_Referencers; cReferenceManager* m_References; diff --git a/source/Items/ItemMinecart.h b/source/Items/ItemMinecart.h index 5a2d78774..52dda942c 100644 --- a/source/Items/ItemMinecart.h +++ b/source/Items/ItemMinecart.h @@ -54,19 +54,21 @@ public: } } - cMinecart::ePayload Payload = cMinecart::mpNone; + double x = (double)a_BlockX + 0.5; + double y = (double)a_BlockY + 0.5; + double z = (double)a_BlockZ + 0.5; + cMinecart * Minecart = NULL; switch (m_ItemType) { - case E_ITEM_MINECART: Payload = cMinecart::mpNone; break; - case E_ITEM_CHEST_MINECART: Payload = cMinecart::mpChest; break; - case E_ITEM_FURNACE_MINECART: Payload = cMinecart::mpFurnace; break; + case E_ITEM_MINECART: Minecart = new cEmptyMinecart (x, y, z); break; + case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break; + case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace(x, y, z); break; default: { ASSERT(!"Unhandled minecart item"); return false; } } // switch (m_ItemType) - cMinecart * Minecart = new cMinecart(Payload, (double)a_BlockX + 0.5, a_BlockY, (double)a_BlockZ + 0.5); a_World->AddEntity(Minecart); Minecart->Initialize(a_World); return true; diff --git a/source/Minecart.cpp b/source/Minecart.cpp index 10c9fe580..84ca57bcd 100644 --- a/source/Minecart.cpp +++ b/source/Minecart.cpp @@ -7,6 +7,7 @@ #include "Minecart.h" #include "World.h" #include "ClientHandle.h" +#include "Player.h" @@ -60,3 +61,89 @@ void cMinecart::Tick(float a_Dt, MTRand & a_TickRandom) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cEmptyMinecart: + +cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) : + super(mpNone, a_X, a_Y, a_Z) +{ +} + + + + + +void cEmptyMinecart::OnRightClicked(cPlayer & a_Player) +{ + if (m_Attachee != NULL) + { + if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) + { + // This player is already sitting in, they want out. + a_Player.Detach(); + return; + } + + if (m_Attachee->IsPlayer()) + { + // Another player is already sitting in here, cannot attach + return; + } + + // Detach whatever is sitting in this minecart now: + m_Attachee->Detach(); + } + + // Attach the player to this minecart + a_Player.AttachTo(this); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cMinecartWithChest: + +cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) : + super(mpChest, a_X, a_Y, a_Z) +{ +} + + + + + +void cMinecartWithChest::OnRightClicked(cPlayer & a_Player) +{ + // Show the chest UI window to the player + // TODO +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cMinecartWithFurnace: + +cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) : + super(mpFurnace, a_X, a_Y, a_Z) +{ +} + + + + + +void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player) +{ + // Try to power the furnace with whatever the player is holding + // TODO +} + + + + + diff --git a/source/Minecart.h b/source/Minecart.h index d46b80b3f..a074e2f97 100644 --- a/source/Minecart.h +++ b/source/Minecart.h @@ -31,8 +31,6 @@ public: // TODO: Other 1.5 features: hopper, tnt, dispenser, spawner } ; - cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z); - // cEntity overrides: virtual void Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; @@ -42,6 +40,62 @@ public: protected: ePayload m_Payload; + + cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z); +} ; + + + + + +class cEmptyMinecart : + public cMinecart +{ + typedef cMinecart super; + +public: + CLASS_PROTODEF(cEmptyMinecart); + + cEmptyMinecart(double a_X, double a_Y, double a_Z); + + // cEntity overrides: + virtual void OnRightClicked(cPlayer & a_Player) override; +} ; + + + + + +class cMinecartWithChest : + public cMinecart +{ + typedef cMinecart super; + +public: + CLASS_PROTODEF(cMinecartWithChest); + + cMinecartWithChest(double a_X, double a_Y, double a_Z); + + // cEntity overrides: + virtual void OnRightClicked(cPlayer & a_Player) override; +} ; + + + + + +class cMinecartWithFurnace : + public cMinecart +{ + typedef cMinecart super; + +public: + CLASS_PROTODEF(cMinecartWithFurnace); + + cMinecartWithFurnace(double a_X, double a_Y, double a_Z); + + // cEntity overrides: + virtual void OnRightClicked(cPlayer & a_Player) override; } ; diff --git a/source/Player.cpp b/source/Player.cpp index f00b0768c..e84eee899 100644 --- a/source/Player.cpp +++ b/source/Player.cpp @@ -165,7 +165,7 @@ void cPlayer::Tick(float a_Dt, MTRand & a_TickRandom) } super::Tick(a_Dt, a_TickRandom); - + if (m_bDirtyOrientation && !m_bDirtyPosition) { m_World->BroadcastEntLook(*this, m_ClientHandle); @@ -558,6 +558,16 @@ void cPlayer::TeleportTo(double a_PosX, double a_PosY, double a_PosZ) void cPlayer::MoveTo( const Vector3d & a_NewPos ) { + if (m_AttachedTo != NULL) + { + // When attached to an entity, the client sends position packets with weird coords: + // Y = -999 and X, Z = attempting to create speed, usually up to 0.03 + Vector3d AddSpeed(a_NewPos); + AddSpeed.y = 0; + m_AttachedTo->AddSpeed(AddSpeed); + return; + } + // TODO: should do some checks to see if player is not moving through terrain // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 876ab51f5..7a3270541 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -50,6 +50,7 @@ public: virtual void DataReceived(const char * a_Data, int a_Size) = 0; // Sending stuff to clients (alphabetically sorted): + virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0; virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) = 0; virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index 4fef5623e..72a1d3b0c 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -63,6 +63,7 @@ enum PACKET_ENT_TELEPORT = 0x22, PACKET_ENT_HEAD_LOOK = 0x23, PACKET_ENT_STATUS = 0x26, + PACKET_ATTACH_ENTITY = 0x27, PACKET_METADATA = 0x28, PACKET_PRE_CHUNK = 0x32, PACKET_MAP_CHUNK = 0x33, @@ -122,6 +123,19 @@ cProtocol125::cProtocol125(cClientHandle * a_Client) : +void cProtocol125::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ATTACH_ENTITY); + WriteInt(a_Entity.GetUniqueID()); + WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID()); + Flush(); +} + + + + + void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) { UNUSED(a_BlockType); diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index ad50c5796..b3dd79069 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -27,6 +27,7 @@ public: virtual void DataReceived(const char * a_Data, int a_Size) override; /// Sending stuff to clients (alphabetically sorted): + virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index ccce8890d..8a40376a3 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -88,6 +88,16 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size) +void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendAttachEntity(a_Entity, a_Vehicle); +} + + + + + void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) { ASSERT(m_Protocol != NULL); diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index fdced8bbe..a4cec69f8 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -52,6 +52,7 @@ public: virtual void DataReceived(const char * a_Data, int a_Size) override; /// Sending stuff to clients (alphabetically sorted): + virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; diff --git a/source/World.cpp b/source/World.cpp index 2cfe56d57..6ff9395c1 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -219,7 +219,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_bEnabledPVP = IniFile.GetValueSetB("PVP", "Enabled", true); m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false); - m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode ); + m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); m_Lighting.Start(this); m_Storage.Start(this, StorageSchema); @@ -230,7 +230,7 @@ cWorld::cWorld(const AString & a_WorldName) : cIniFile IniFile2("settings.ini"); if (IniFile2.ReadFile()) { - m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true ); + m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks // TODO: Move this into cServer instead: @@ -238,7 +238,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_Description = IniFile2.GetValue("Server", "Description", "MCServer! - In C++!").c_str(); } - m_ChunkMap = new cChunkMap(this ); + m_ChunkMap = new cChunkMap(this); m_ChunkSender.Start(this); @@ -277,11 +277,11 @@ cWorld::~cWorld() { { cCSLock Lock(m_CSEntities); - while( m_AllEntities.begin() != m_AllEntities.end() ) + while (m_AllEntities.begin() != m_AllEntities.end()) { cEntity* Entity = *m_AllEntities.begin(); - m_AllEntities.remove( Entity ); - if ( !Entity->IsDestroyed() ) + m_AllEntities.remove(Entity); + if (!Entity->IsDestroyed()) { Entity->Destroy(); } @@ -368,7 +368,7 @@ void cWorld::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) void cWorld::InitializeSpawn(void) { int ChunkX = 0, ChunkY = 0, ChunkZ = 0; - BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ ); + BlockToChunk((int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ); // For the debugging builds, don't make the server build too much world upon start: #if defined(_DEBUG) || defined(ANDROID_NDK) @@ -382,7 +382,7 @@ void cWorld::InitializeSpawn(void) { for (int z = 0; z < ViewDist; z++) { - m_ChunkMap->TouchChunk( x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader + m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader } } @@ -422,7 +422,7 @@ void cWorld::InitializeSpawn(void) } // TODO: Better spawn detection - move spawn out of the water if it isn't set in the INI already - m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height + m_SpawnY = (double)GetHeight((int)m_SpawnX, (int)m_SpawnZ) + 1.6f; // +1.6f eye height } @@ -470,8 +470,8 @@ void cWorld::Tick(float a_Dt) { LOGD("Destroying entity #%i", (*itr)->GetUniqueID()); cEntity * RemoveMe = *itr; - itr = m_AllEntities.erase( itr ); - m_RemoveEntityQueue.push_back( RemoveMe ); + itr = m_AllEntities.erase(itr); + m_RemoveEntityQueue.push_back(RemoveMe); continue; } (*itr)->Tick(a_Dt, m_TickRand); @@ -506,7 +506,7 @@ void cWorld::Tick(float a_Dt) SaveAllChunks(); } - if (m_WorldAge - m_LastUnload > 10 * 20 ) // Unload every 10 seconds + if (m_WorldAge - m_LastUnload > 10 * 20) // Unload every 10 seconds { UnloadUnusedChunks(); } @@ -532,13 +532,13 @@ void cWorld::Tick(float a_Dt) int tempZ = *cii; cii++; int state = *cii; cii++; - if ( (state == 11111) && ( (int)GetBlock( tempX, tempY, tempZ ) == E_BLOCK_REDSTONE_TORCH_OFF ) ) + if ((state == 11111) && ((int)GetBlock(tempX, tempY, tempZ) == E_BLOCK_REDSTONE_TORCH_OFF)) { - FastSetBlock( tempX, tempY, tempZ, E_BLOCK_REDSTONE_TORCH_ON, (int)GetBlockMeta( tempX, tempY, tempZ ) ); + FastSetBlock(tempX, tempY, tempZ, E_BLOCK_REDSTONE_TORCH_ON, (int)GetBlockMeta(tempX, tempY, tempZ)); } - else if ( (state == 00000) && ( (int)GetBlock( tempX, tempY, tempZ ) == E_BLOCK_REDSTONE_TORCH_ON ) ) + else if ((state == 00000) && ((int)GetBlock(tempX, tempY, tempZ) == E_BLOCK_REDSTONE_TORCH_ON)) { - FastSetBlock( tempX, tempY, tempZ, E_BLOCK_REDSTONE_TORCH_OFF, (int)GetBlockMeta( tempX, tempY, tempZ ) ); + FastSetBlock(tempX, tempY, tempZ, E_BLOCK_REDSTONE_TORCH_OFF, (int)GetBlockMeta(tempX, tempY, tempZ)); } } m_RSList_copy.erase(m_RSList_copy.begin(),m_RSList_copy.end()); @@ -608,13 +608,13 @@ void cWorld::TickSpawnMobs(float a_Dt) Vector3d SpawnPos; { cCSLock Lock(m_CSPlayers); - if ( m_Players.size() <= 0) + if (m_Players.size() <= 0) { return; } int RandomPlayerIdx = m_TickRand.randInt() & m_Players.size(); cPlayerList::iterator itr = m_Players.begin(); - for( int i = 1; i < RandomPlayerIdx; i++ ) + for (int i = 1; i < RandomPlayerIdx; i++) { itr++; } @@ -625,8 +625,8 @@ void cWorld::TickSpawnMobs(float a_Dt) int dayRand = m_TickRand.randInt() % 6; int nightRand = m_TickRand.randInt() % 10; - SpawnPos += Vector3d( (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32 ); - int Height = GetHeight( (int)SpawnPos.x, (int)SpawnPos.z ); + SpawnPos += Vector3d((double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32); + int Height = GetHeight((int)SpawnPos.x, (int)SpawnPos.z); if (m_TimeOfDay >= 12000 + 1000) { @@ -675,7 +675,7 @@ void cWorld::TickSpawnMobs(float a_Dt) //end random percent to spawn for day } - if( Monster ) + if (Monster) { Monster->Initialize(this); Monster->TeleportTo(SpawnPos.x, (double)(Height) + 2, SpawnPos.z); @@ -759,7 +759,7 @@ bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_ -void cWorld::GrowTree( int a_X, int a_Y, int a_Z ) +void cWorld::GrowTree(int a_X, int a_Y, int a_Z) { if (GetBlock(a_X, a_Y, a_Z) == E_BLOCK_SAPLING) { @@ -1046,7 +1046,7 @@ void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_Bloc -void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) +void cWorld::FastSetBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CSFastSetBlock); m_FastSetBlockQueue.push_back(sSetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta)); @@ -1081,7 +1081,7 @@ BLOCKTYPE cWorld::GetBlock(int a_X, int a_Y, int a_Z) -NIBBLETYPE cWorld::GetBlockMeta( int a_X, int a_Y, int a_Z ) +NIBBLETYPE cWorld::GetBlockMeta(int a_X, int a_Y, int a_Z) { // First check if it isn't queued in the m_FastSetBlockQueue: { @@ -1102,7 +1102,7 @@ NIBBLETYPE cWorld::GetBlockMeta( int a_X, int a_Y, int a_Z ) -void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, NIBBLETYPE a_MetaData ) +void cWorld::SetBlockMeta(int a_X, int a_Y, int a_Z, NIBBLETYPE a_MetaData) { m_ChunkMap->SetBlockMeta(a_X, a_Y, a_Z, a_MetaData); } @@ -1111,7 +1111,7 @@ void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, NIBBLETYPE a_MetaData ) -NIBBLETYPE cWorld::GetBlockSkyLight( int a_X, int a_Y, int a_Z ) +NIBBLETYPE cWorld::GetBlockSkyLight(int a_X, int a_Y, int a_Z) { return m_ChunkMap->GetBlockSkyLight(a_X, a_Y, a_Z); } @@ -1216,7 +1216,7 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) -bool cWorld::DigBlock( int a_X, int a_Y, int a_Z) +bool cWorld::DigBlock(int a_X, int a_Y, int a_Z) { cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z)); Handler->OnDestroyed(this, a_X, a_Y, a_Z); @@ -1227,7 +1227,7 @@ bool cWorld::DigBlock( int a_X, int a_Y, int a_Z) -void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player ) +void cWorld::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) { m_ChunkMap->SendBlockTo(a_X, a_Y, a_Z, a_Player); } @@ -1236,7 +1236,7 @@ void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player ) -int cWorld::GetHeight( int a_X, int a_Z ) +int cWorld::GetHeight(int a_X, int a_Z) { return m_ChunkMap->GetHeight(a_X, a_Z); } @@ -1245,6 +1245,15 @@ int cWorld::GetHeight( int a_X, int a_Z ) +void cWorld::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + return m_ChunkMap->BroadcastAttachEntity(a_Entity, a_Vehicle); +} + + + + + void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSPlayers); @@ -1479,7 +1488,7 @@ void cWorld::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY -void cWorld::BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude ) +void cWorld::BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude) { m_ChunkMap->BroadcastBlockBreakAnimation(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage, a_Exclude); } @@ -1488,7 +1497,7 @@ void cWorld::BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_Bl -void cWorld::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) +void cWorld::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) { m_ChunkMap->BroadcastUseBed(a_Entity, a_BlockX, a_BlockY, a_BlockZ); } @@ -1636,7 +1645,7 @@ bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const -void cWorld::UnloadUnusedChunks(void ) +void cWorld::UnloadUnusedChunks(void) { m_LastUnload = m_WorldAge; m_ChunkMap->UnloadUnusedChunks(); @@ -1668,24 +1677,24 @@ void cWorld::SetMaxPlayers(int iMax) -void cWorld::AddPlayer( cPlayer* a_Player ) +void cWorld::AddPlayer(cPlayer* a_Player) { cCSLock Lock(m_CSPlayers); ASSERT(std::find(m_Players.begin(), m_Players.end(), a_Player) == m_Players.end()); // Is it already in the list? HOW? - m_Players.remove( a_Player ); // Make sure the player is registered only once - m_Players.push_back( a_Player ); + m_Players.remove(a_Player); // Make sure the player is registered only once + m_Players.push_back(a_Player); } -void cWorld::RemovePlayer( cPlayer* a_Player ) +void cWorld::RemovePlayer(cPlayer* a_Player) { cCSLock Lock(m_CSPlayers); - m_Players.remove( a_Player ); + m_Players.remove(a_Player); } @@ -1859,12 +1868,12 @@ bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & -bool cWorld::DoWithEntityByID( int a_UniqueID, cEntityCallback & a_Callback ) +bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) { cCSLock Lock(m_CSEntities); - for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end(); ++itr ) + for (cEntityList::iterator itr = m_AllEntities.begin(), end = m_AllEntities.end(); itr != end; ++itr) { - if( (*itr)->GetUniqueID() == a_UniqueID ) + if ((*itr)->GetUniqueID() == a_UniqueID) { return a_Callback.Item(*itr); } @@ -2056,7 +2065,7 @@ void cWorld::SaveAllChunks(void) void cWorld::AddEntity(cEntity * a_Entity) { cCSLock Lock(m_CSEntities); - m_AllEntities.push_back( a_Entity ); + m_AllEntities.push_back(a_Entity); } diff --git a/source/World.h b/source/World.h index ed0053db5..781dc3e8c 100644 --- a/source/World.h +++ b/source/World.h @@ -97,6 +97,7 @@ public: // tolua_end + void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);