diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 2733e9462..e0d5cbd71 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -11038,6 +11038,149 @@ a_Player:OpenWindow(Window); }, Inherits = "cEntity", }, + cBoat = + { + Desc = [[ + This class represents a boat. This entity can be spawned by using {{cWorld#SpawnBoat_1|cWorld:SpawnBoat}}. + ]], + Functions = + { + GetMaterial = + { + Returns = + { + { + Name = "Material", + Type = "cBoat#eMaterial", + }, + }, + Notes = "Returns the material of the boat.", + }, + MaterialToString = + { + IsStatic = true, + Params = + { + { + Name = "Item", + Type = "cItem", + }, + }, + Returns = + { + { + Name = "Material", + Type = "string", + }, + }, + Notes = "Returns the boat material as a string.", + }, + ItemToMaterial = + { + IsStatic = true, + Params = + { + { + Name = "Item", + Type = "cItem", + }, + }, + Returns = + { + { + Name = "Material", + Type = "cBoat#eMaterial", + }, + }, + Notes = "Returns the eMaterial that should be used for a boat created from the specified item. Returns bmOak if not a boat item.", + }, + MaterialToItem = + { + IsStatic = true, + Params = + { + { + Name = "Material", + Type = "cBoat#eMaterial", + }, + }, + Returns = + { + { + Name = "Item", + Type = "cItem", + }, + }, + Notes = "Returns the boat item of the boat material", + }, + StringToMaterial = + { + IsStatic = true, + Params = + { + { + Name = "Material", + Type = "string", + }, + }, + Returns = + { + { + Name = "Material", + Type = "cBoat#eMaterial", + }, + }, + Notes = "Returns the boat material for the passed string. Returns oak if not valid.", + }, + SetMaterial = + { + Params = + { + { + Name = "Material", + Type = "cBoat#eMaterial", + }, + }, + Notes = "Set the material of the boat.", + }, + }, + Constants = + { + bmOak = + { + Notes = "", + }, + bmSpruce = + { + Notes = "", + }, + bmBirch = + { + Notes = "", + }, + bmJungle = + { + Notes = "", + }, + bmAcacia = + { + Notes = "", + }, + bmDarkOak = + { + Notes = "", + }, + }, + ConstantGroups = + { + eMaterial = + { + Include = "bm.*", + TextBefore = "These constans are the different wood materials of the boat.", + }, + }, + Inherits = "cEntity", + }, cPickup = { Desc = [[ diff --git a/Server/Plugins/APIDump/Classes/World.lua b/Server/Plugins/APIDump/Classes/World.lua index 039585e6b..3ba2d82ca 100644 --- a/Server/Plugins/APIDump/Classes/World.lua +++ b/Server/Plugins/APIDump/Classes/World.lua @@ -2902,6 +2902,10 @@ function OnAllChunksAvailable() All return values from the callbacks are i Name = "Z", Type = "number", }, + { + Name = "Material", + Type = "cBoat#eMaterial", + }, }, Returns = { @@ -2910,7 +2914,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "number", }, }, - Notes = "Spawns a boat at the specific coordinates. Returns the EntityID of the new boat, or {{cEntity#INVALID_ID|cEntity#INVALID_ID}} if no boat was created.", + Notes = "Spawns a {{cBoat|boat}} at the specific coordinates. Returns the EntityID of the new boat, or {{cEntity#INVALID_ID|cEntity#INVALID_ID}} if no boat was created.", }, SpawnExperienceOrb = { diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 55f26bc60..418e37d23 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -70,6 +70,7 @@ $cfile "../Protocol/MojangAPI.h" // Entities: $cfile "../Entities/Entity.h" +$cfile "../Entities/Boat.h" $cfile "../Entities/Pawn.h" $cfile "../Entities/ProjectileEntity.h" $cfile "../Entities/ArrowEntity.h" diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 349f15b08..2614ef9b2 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -92,6 +92,7 @@ set(BINDING_DEPENDENCIES ../Cuboid.h ../Defines.h ../Enchantments.h + ../Entities/Boat.h ../Entities/ArrowEntity.h ../Entities/Entity.h ../Entities/ExpOrb.h diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 281fe2ca6..78ce81e5b 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -222,6 +222,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } case E_ITEM_BOAT: + case E_ITEM_SPRUCE_BOAT: + case E_ITEM_BIRCH_BOAT: + case E_ITEM_JUNGLE_BOAT: + case E_ITEM_ACACIA_BOAT: + case E_ITEM_DARK_OAK_BOAT: { Vector3d SpawnPos; if (IsBlockWater(DispBlock)) @@ -244,7 +249,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) SpawnPos += GetShootVector(Meta) * 0.8; // A boat is bigger than one block. Add the shoot vector to put it outside the dispenser. SpawnPos += Vector3d(0.5, 0.5, 0.5); - if (m_World->SpawnBoat(SpawnPos.x, SpawnPos.y, SpawnPos.z)) + if (m_World->SpawnBoat(SpawnPos.x, SpawnPos.y, SpawnPos.z, cBoat::ItemToMaterial(SlotItem))) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp index f9b83eee5..cdb12123c 100644 --- a/src/Entities/Boat.cpp +++ b/src/Entities/Boat.cpp @@ -13,10 +13,10 @@ -cBoat::cBoat(double a_X, double a_Y, double a_Z) : +cBoat::cBoat(double a_X, double a_Y, double a_Z, eMaterial a_Material) : super(etBoat, a_X, a_Y, a_Z, 0.98, 0.7), m_LastDamage(0), m_ForwardDirection(0), - m_DamageTaken(0.0f), m_Type(0), + m_DamageTaken(0.0f), m_Material(a_Material), m_RightPaddleUsed(false), m_LeftPaddleUsed(false) { SetMass(20.0f); @@ -55,7 +55,7 @@ bool cBoat::DoTakeDamage(TakeDamageInfo & TDI) if (TDI.Attacker->IsPlayer()) { cItems Pickups; - Pickups.Add(cItem(E_ITEM_BOAT)); + Pickups.Add(MaterialToItem(m_Material)); m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 0, 0, 0, true); } } @@ -169,3 +169,106 @@ void cBoat::UpdatePaddles(bool a_RightPaddleUsed, bool a_LeftPaddleUsed) m_World->BroadcastEntityMetadata(*this); } + + + + + +cBoat::eMaterial cBoat::ItemToMaterial(const cItem & a_Item) +{ + switch (a_Item.m_ItemType) + { + case E_ITEM_BOAT: return bmOak; + case E_ITEM_SPRUCE_BOAT: return bmSpruce; + case E_ITEM_BIRCH_BOAT: return bmBirch; + case E_ITEM_JUNGLE_BOAT: return bmJungle; + case E_ITEM_ACACIA_BOAT: return bmAcacia; + case E_ITEM_DARK_OAK_BOAT: return bmDarkOak; + default: + { + LOGWARNING("%s: Item type not handled %d.", __FUNCTION__, a_Item.m_ItemType); + return cBoat::bmOak; + } + } +} + + + + + +AString cBoat::MaterialToString(eMaterial a_Material) +{ + switch (a_Material) + { + case bmOak: return "oak"; + case bmSpruce: return "spruce"; + case bmBirch: return "birch"; + case bmJungle: return "jungle"; + case bmAcacia: return "acacia"; + case bmDarkOak: return "dark_oak"; + } + ASSERT(!"Unhandled boat material"); + #ifndef __clang__ + return "oak"; + #endif +} + + + + + +cBoat::eMaterial cBoat::StringToMaterial(const AString & a_Material) +{ + if (a_Material == "oak") + { + return bmOak; + } + else if (a_Material == "spruce") + { + return bmSpruce; + } + else if (a_Material == "birch") + { + return bmBirch; + } + else if (a_Material == "jungle") + { + return bmJungle; + } + else if (a_Material == "acacia") + { + return bmAcacia; + } + else if (a_Material == "dark_oak") + { + return bmDarkOak; + } + else + { + return bmOak; + } +} + + + + + +cItem cBoat::MaterialToItem(eMaterial a_Material) +{ + switch (a_Material) + { + case bmOak: return cItem(E_ITEM_BOAT); + case bmSpruce: return cItem(E_ITEM_SPRUCE_BOAT); + case bmBirch: return cItem(E_ITEM_BIRCH_BOAT); + case bmJungle: return cItem(E_ITEM_JUNGLE_BOAT); + case bmAcacia: return cItem(E_ITEM_ACACIA_BOAT); + case bmDarkOak: return cItem(E_ITEM_DARK_OAK_BOAT); + } + #ifndef __clang__ + return cItem(E_ITEM_BOAT); + #endif +} + + + + diff --git a/src/Entities/Boat.h b/src/Entities/Boat.h index 5815ff88c..a6a99d683 100644 --- a/src/Entities/Boat.h +++ b/src/Entities/Boat.h @@ -13,7 +13,7 @@ - +// tolua_begin class cBoat : public cEntity @@ -21,6 +21,18 @@ class cBoat : typedef cEntity super; public: + enum eMaterial + { + bmOak, + bmSpruce, + bmBirch, + bmJungle, + bmAcacia, + bmDarkOak + }; + + // tolua_end + CLASS_PROTODEF(cBoat) // cEntity overrides: @@ -30,14 +42,34 @@ public: virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override; - cBoat(double a_X, double a_Y, double a_Z); + cBoat(double a_X, double a_Y, double a_Z, eMaterial a_Material); int GetLastDamage(void) const { return m_LastDamage; } int GetForwardDirection(void) const { return m_ForwardDirection; } float GetDamageTaken(void) const { return m_DamageTaken; } - int GetType(void) const { return m_Type; } + // tolua_begin + + /** Returns the eMaterial of the boat */ + eMaterial GetMaterial(void) const { return m_Material; } + + /** Sets the eMaterial of the boat */ + void SetMaterial(cBoat::eMaterial a_Material) { m_Material = a_Material; } + + /** Returns the eMaterial that should be used for a boat created from the specified item. Returns bmOak if not a boat item */ + static eMaterial ItemToMaterial(const cItem & a_Item); + + /** Returns the boat item of the boat material */ + static cItem MaterialToItem(eMaterial a_Material); + + /** Returns the eMaterial as string */ + static AString MaterialToString(const eMaterial a_Material); + + /** Returns the boat material for the passed string. Returns oak if not valid */ + static eMaterial StringToMaterial(const AString & a_Material); + + // tolua_end bool IsRightPaddleUsed(void) const { return m_RightPaddleUsed; } bool IsLeftPaddleUsed(void) const { return m_LeftPaddleUsed; } @@ -45,15 +77,14 @@ public: void SetLastDamage(int TimeSinceLastHit); void UpdatePaddles(bool rightPaddleUsed, bool leftPaddleUsed); - private: int m_LastDamage; int m_ForwardDirection; float m_DamageTaken; - int m_Type; + eMaterial m_Material; bool m_RightPaddleUsed; bool m_LeftPaddleUsed; -} ; +} ; // tolua_export diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index 493605483..bdfed8944 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -95,7 +95,7 @@ public: } // Spawn block at water level - cBoat * Boat = new cBoat(x + 0.5, y + 0.5, z + 0.5); + cBoat * Boat = new cBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())); if (!Boat->Initialize(*a_World)) { delete Boat; diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp index 4301b0310..4e716832e 100644 --- a/src/Protocol/Protocol_1_10.cpp +++ b/src/Protocol/Protocol_1_10.cpp @@ -523,7 +523,7 @@ void cProtocol_1_10_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Pkt.WriteBEInt8(BOAT_TYPE); a_Pkt.WriteBEInt8(METADATA_TYPE_VARINT); - a_Pkt.WriteVarInt32(static_cast(Boat.GetType())); + a_Pkt.WriteVarInt32(static_cast(Boat.GetMaterial())); a_Pkt.WriteBEInt8(BOAT_RIGHT_PADDLE_TURNING); a_Pkt.WriteBEInt8(METADATA_TYPE_BOOL); diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp index 3a13298ef..7af7c5340 100644 --- a/src/Protocol/Protocol_1_11.cpp +++ b/src/Protocol/Protocol_1_11.cpp @@ -645,7 +645,7 @@ void cProtocol_1_11_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Pkt.WriteBEInt8(BOAT_TYPE); a_Pkt.WriteBEInt8(METADATA_TYPE_VARINT); - a_Pkt.WriteVarInt32(static_cast(Boat.GetType())); + a_Pkt.WriteVarInt32(static_cast(Boat.GetMaterial())); a_Pkt.WriteBEInt8(BOAT_RIGHT_PADDLE_TURNING); a_Pkt.WriteBEInt8(METADATA_TYPE_BOOL); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index e489b3903..da8965be0 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -3688,7 +3688,7 @@ void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a a_Pkt.WriteBEInt8(8); // Index 9: Type a_Pkt.WriteBEInt8(METADATA_TYPE_VARINT); - a_Pkt.WriteVarInt32(static_cast(Boat.GetType())); + a_Pkt.WriteVarInt32(static_cast(Boat.GetMaterial())); a_Pkt.WriteBEInt8(9); // Index 10: Right paddle turning a_Pkt.WriteBEInt8(METADATA_TYPE_BOOL); diff --git a/src/World.cpp b/src/World.cpp index d4be3addb..f396aad86 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2282,9 +2282,9 @@ UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartT -UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z) +UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_Material) { - cBoat * Boat = new cBoat(a_X, a_Y, a_Z); + cBoat * Boat = new cBoat(a_X, a_Y, a_Z, a_Material); if (Boat == nullptr) { return cEntity::INVALID_ID; diff --git a/src/World.h b/src/World.h index 6ad476b94..00467e2fa 100644 --- a/src/World.h +++ b/src/World.h @@ -22,6 +22,7 @@ #include "Item.h" #include "Mobs/Monster.h" #include "Entities/ProjectileEntity.h" +#include "Entities/Boat.h" #include "ForEachChunkProvider.h" #include "Scoreboard.h" #include "MapManager.h" @@ -453,7 +454,7 @@ public: /** Spawns a boat at the given coordinates. Returns the UniqueID of the spawned boat, or cEntity::INVALID_ID on failure. */ - UInt32 SpawnBoat(double a_X, double a_Y, double a_Z); + UInt32 SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_Material); /** Spawns an experience orb at the given location with the given reward. Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */ diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e00e7aa3c..d98fc7bb5 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -421,6 +421,7 @@ void cNBTChunkSerializer::AddBoatEntity(cBoat * a_Boat) { m_Writer.BeginCompound(""); AddBasicEntity(a_Boat, "Boat"); + m_Writer.AddString("Type", cBoat::MaterialToString(a_Boat->GetMaterial())); m_Writer.EndCompound(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 47f08e9cf..1d7cedaa6 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -1659,11 +1659,17 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::unique_ptr Boat = cpp14::make_unique(0, 0, 0); + std::unique_ptr Boat = cpp14::make_unique(0, 0, 0, cBoat::bmOak); if (!LoadEntityBaseFromNBT(*Boat.get(), a_NBT, a_TagIdx)) { return; } + + int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type"); + if (TypeIdx > 0) + { + Boat->SetMaterial(cBoat::StringToMaterial(a_NBT.GetString(TypeIdx))); + } a_Entities.push_back(Boat.release()); }