From 718eb227abe3b9a0e5277d663e32c6e10d51ab52 Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 19 Sep 2014 23:00:54 +0200 Subject: [PATCH] Implemented mob spawner. --- src/BlockEntities/BlockEntity.cpp | 6 +- src/BlockEntities/MobSpawnerEntity.cpp | 328 +++++++++++++++++++++--- src/BlockEntities/MobSpawnerEntity.h | 50 ++-- src/Blocks/BlockMobSpawner.h | 12 + src/Chunk.cpp | 7 +- src/MobSpawner.cpp | 13 +- src/MobSpawner.h | 5 +- src/Mobs/Monster.h | 2 +- src/Protocol/Protocol17x.cpp | 14 +- src/WorldStorage/NBTChunkSerializer.cpp | 15 ++ src/WorldStorage/NBTChunkSerializer.h | 26 +- 11 files changed, 402 insertions(+), 76 deletions(-) diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 05ad03a3d..a969f493e 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -14,10 +14,11 @@ #include "FlowerPotEntity.h" #include "FurnaceEntity.h" #include "HopperEntity.h" +#include "MobHeadEntity.h" +#include "MobSpawnerEntity.h" #include "JukeboxEntity.h" #include "NoteEntity.h" #include "SignEntity.h" -#include "MobHeadEntity.h" @@ -35,8 +36,9 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_MOB_SPAWNER: return new cMobSpawnerEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index 1db1aad9b..2b963c3f9 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -2,22 +2,22 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "MobSpawnerEntity.h" -#include "../World.h" #include "json/json.h" +#include "../World.h" +#include "../FastRandom.h" +#include "../MobSpawner.h" +#include "../Items/ItemSpawnEgg.h" + cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(E_BLOCK_MOB_SPAWNER, a_BlockX, a_BlockY, a_BlockZ, a_World) - , m_EntityName("Pig") - , m_SpawnDelay(20) - , m_MinSpawnDelay(200) - , m_MaxSpawnDelay(800) - , m_MaxNearbyEntities(6) - , m_ActivatingRange(16) - , m_SpawnRange(4) + , m_Entity(cMonster::mtPig) + , m_SpawnDelay(100) + , m_IsActive(false) { } @@ -25,18 +25,9 @@ cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c -cMobSpawnerEntity::~cMobSpawnerEntity() +void cMobSpawnerEntity::SendTo(cClientHandle & a_Client) { - -} - - - - - -bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk) -{ - + a_Client.SendUpdateBlockEntity(*this); } @@ -45,17 +36,159 @@ bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk) void cMobSpawnerEntity::UsedBy(cPlayer * a_Player) { - if (IsPlayingRecord()) + if (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SPAWN_EGG) { - EjectRecord(); - } - else - { - const cItem & HeldItem = a_Player->GetEquippedItem(); - if (PlayRecord(HeldItem.m_ItemType)) + cMonster::eType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Player->GetEquippedItem().m_ItemDamage); + if (MonsterType == cMonster::mtInvalidType) + { + return; + } + + m_Entity = MonsterType; + ResetTimer(); + if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); } + LOGD("Changed monster spawner entity to %s!", GetEntityName().c_str()); + } +} + + + + + +void cMobSpawnerEntity::UpdateActiveState(void) +{ + if (GetNearbyPlayersNum() > 0) + { + m_IsActive = true; + } + else + { + m_IsActive = false; + } +} + + + + + +bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + // Update the active flag every 5 seconds + if ((m_World->GetWorldAge() % 100) == 0) + { + UpdateActiveState(); + } + + if (!m_IsActive) + { + return false; + } + + if (m_SpawnDelay <= 0) + { + SpawnEntity(); + return true; + } + else + { + m_SpawnDelay--; + } + return false; +} + + + + + +void cMobSpawnerEntity::ResetTimer(void) +{ + m_SpawnDelay = 200 + m_World->GetTickRandomNumber(600); + m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ); +} + + + + + +void cMobSpawnerEntity::SpawnEntity(void) +{ + int NearbyEntities = GetNearbyEntityNum(m_Entity); + if (NearbyEntities >= 6) + { + ResetTimer(); + return; + } + + class cCallback : public cChunkCallback + { + public: + cCallback(int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, int a_NearbyEntitiesNum) : + m_RelX(a_RelX), + m_RelY(a_RelY), + m_RelZ(a_RelZ), + m_MobType(a_MobType), + m_NearbyEntitiesNum(a_NearbyEntitiesNum) + { + } + + virtual bool Item(cChunk * a_Chunk) + { + cFastRandom Random; + + bool EntitiesSpawned = false; + for (size_t i = 0; i < 4; i++) + { + if (m_NearbyEntitiesNum >= 6) + { + break; + } + + int RelX = (int) (m_RelX + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0); + int RelY = m_RelY + Random.NextInt(3) - 1; + int RelZ = (int) (m_RelZ + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0); + + cChunk * Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(RelX, RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + continue; + } + EMCSBiome Biome = Chunk->GetBiomeAt(RelX, RelZ); + + if (cMobSpawner::CanSpawnHere(Chunk, RelX, RelY, RelZ, m_MobType, Biome)) + { + double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX; + double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ; + + cMonster * Monster = cMonster::NewMonsterFromType(m_MobType); + if (Monster == NULL) + { + continue; + } + + Monster->SetPosition(PosX, RelY, PosZ); + Monster->SetYaw(Random.NextFloat() * 360.0f); + if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cMonster::mtInvalidType) + { + EntitiesSpawned = true; + Chunk->BroadcastSoundParticleEffect(2004, (int)(PosX * 8.0), (int)(RelY * 8.0), (int)(PosZ * 8.0), 0); + m_NearbyEntitiesNum++; + } + } + } + return EntitiesSpawned; + } + protected: + int m_RelX, m_RelY, m_RelZ; + cMonster::eType m_MobType; + int m_NearbyEntitiesNum; + } Callback(m_RelX, m_PosY, m_RelZ, m_Entity, NearbyEntities); + + if (m_World->DoWithChunk(GetChunkX(), GetChunkZ(), Callback)) + { + ResetTimer(); } } @@ -69,8 +202,6 @@ bool cMobSpawnerEntity::LoadFromJson(const Json::Value & a_Value) m_PosY = a_Value.get("y", 0).asInt(); m_PosZ = a_Value.get("z", 0).asInt(); - m_Record = a_Value.get("Record", 0).asInt(); - return true; } @@ -83,8 +214,145 @@ void cMobSpawnerEntity::SaveToJson(Json::Value & a_Value) a_Value["x"] = m_PosX; a_Value["y"] = m_PosY; a_Value["z"] = m_PosZ; - - a_Value["Record"] = m_Record; +} + + + + + +AString cMobSpawnerEntity::GetEntityName() const +{ + switch (m_Entity) + { + case cMonster::mtBat: return "Bat"; + case cMonster::mtBlaze: return "Blaze"; + case cMonster::mtCaveSpider: return "CaveSpider"; + case cMonster::mtChicken: return "Chicken"; + case cMonster::mtCow: return "Cow"; + case cMonster::mtCreeper: return "Creeper"; + case cMonster::mtEnderDragon: return "EnderDragon"; + case cMonster::mtEnderman: return "Enderman"; + case cMonster::mtGhast: return "Ghast"; + case cMonster::mtGiant: return "Giant"; + case cMonster::mtHorse: return "EntityHorse"; + case cMonster::mtIronGolem: return "VillagerGolem"; + case cMonster::mtMagmaCube: return "LavaSlime"; + case cMonster::mtMooshroom: return "MushroomCow"; + case cMonster::mtOcelot: return "Ozelot"; + case cMonster::mtPig: return "Pig"; + case cMonster::mtSheep: return "Sheep"; + case cMonster::mtSilverfish: return "Silverfish"; + case cMonster::mtSkeleton: return "Skeleton"; + case cMonster::mtSlime: return "Slime"; + case cMonster::mtSnowGolem: return "SnowMan"; + case cMonster::mtSpider: return "Spider"; + case cMonster::mtSquid: return "Squid"; + case cMonster::mtVillager: return "Villager"; + case cMonster::mtWitch: return "Witch"; + case cMonster::mtWither: return "WitherBoss"; + case cMonster::mtWolf: return "Wolf"; + case cMonster::mtZombie: return "Zombie"; + case cMonster::mtZombiePigman: return "PigZombie"; + default: + { + ASSERT(!"Unknown monster type!"); + return "Pig"; + } + } +} + + + + + +int cMobSpawnerEntity::GetNearbyPlayersNum(void) +{ + Vector3d SpawnerPos(m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5); + int NumPlayers = 0; + + class cCallback : public cChunkDataCallback + { + public: + cCallback(Vector3d a_SpawnerPos, int & a_NumPlayers) : + m_SpawnerPos(a_SpawnerPos), + m_NumPlayers(a_NumPlayers) + { + } + + virtual void Entity(cEntity * a_Entity) override + { + if (!a_Entity->IsPlayer()) + { + return; + } + + if ((m_SpawnerPos - a_Entity->GetPosition()).Length() <= 16) + { + m_NumPlayers++; + } + } + + protected: + Vector3d m_SpawnerPos; + int & m_NumPlayers; + } Callback(SpawnerPos, NumPlayers); + + int ChunkX = GetChunkX(); + int ChunkZ = GetChunkZ(); + m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback); + + return NumPlayers; +} + + + + + +int cMobSpawnerEntity::GetNearbyEntityNum(cMonster::eType a_EntityType) +{ + Vector3d SpawnerPos(m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5); + int NumEntities = 0; + + class cCallback : public cChunkDataCallback + { + public: + cCallback(Vector3d a_SpawnerPos, cMonster::eType a_EntityType, int & a_NumEntities) : + m_SpawnerPos(a_SpawnerPos), + m_EntityType(a_EntityType), + m_NumEntities(a_NumEntities) + { + } + + virtual void Entity(cEntity * a_Entity) override + { + if (!a_Entity->IsMob()) + { + return; + } + + cMonster * Mob = (cMonster *)a_Entity; + if (Mob->GetMobType() != m_EntityType) + { + return; + } + + if (((m_SpawnerPos - a_Entity->GetPosition()).Length() <= 8) && (Diff(m_SpawnerPos.y, a_Entity->GetPosY()) <= 4.0)) + { + m_NumEntities++; + } + } + + protected: + Vector3d m_SpawnerPos; + cMonster::eType m_EntityType; + int & m_NumEntities; + } Callback(SpawnerPos, a_EntityType, NumEntities); + + int ChunkX = GetChunkX(); + int ChunkZ = GetChunkZ(); + m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback); + + return NumEntities; } diff --git a/src/BlockEntities/MobSpawnerEntity.h b/src/BlockEntities/MobSpawnerEntity.h index b173214a5..b12a97d65 100644 --- a/src/BlockEntities/MobSpawnerEntity.h +++ b/src/BlockEntities/MobSpawnerEntity.h @@ -28,41 +28,51 @@ public: // tolua_end cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - virtual ~cMobSpawnerEntity(); - - bool LoadFromJson(const Json::Value & a_Value); - virtual void SaveToJson(Json::Value & a_Value) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual void UsedBy(cPlayer * a_Player) override; virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; // tolua_begin - /** Returns the entity who will be spawn by this mob spawner. */ - const AString & GetEntityName(void) const { return m_EntityName; } + /** Upate the active flag from the mob spawner. This function will called every 5 seconds from the Tick() function. */ + void UpdateActiveState(void); + + /** Sets the spawn delay to a new random value. */ + void ResetTimer(void); + + /** Spawns the entity. This function automaticly change the spawn delay! */ + void SpawnEntity(void); + + /** Returns the entity type who will be spawn by this mob spawner. */ + cMonster::eType GetEntity(void) const { return m_Entity; } + + /** Sets the entity type who will be spawn by this mob spawner. */ + void SetEntity(cMonster::eType a_EntityType) { m_Entity = a_EntityType; } + + /** Returns the entity name. (Required by the protocol) */ + AString GetEntityName(void) const; + + /** Returns the spawn delay. */ + int GetSpawnDelay(void) const { return m_SpawnDelay; } + + int GetNearbyPlayersNum(void); + int GetNearbyEntityNum(cMonster::eType a_EntityType); // tolua_end + bool LoadFromJson(const Json::Value & a_Value); + virtual void SaveToJson(Json::Value & a_Value) override; + static const char * GetClassStatic(void) { return "cMobSpawnerEntity"; } - - virtual void UsedBy(cPlayer * a_Player) override; - virtual void SendTo(cClientHandle &) override {} private: /** The entity to spawn. */ - AString m_EntityName; + cMonster::eType m_Entity; int m_SpawnDelay; - int m_MinSpawnDelay; - int m_MaxSpawnDelay; - /** The mob spawner spawns only mobs when the count of nearby entities (without players) is lesser than this number. */ - short m_MaxNearbyEntities; - - /** The mob spawner spawns only mobs when a player is in the range of the mob spawner. */ - short m_ActivatingRange; - - /** The range coefficient for spawning entities around. */ - short m_SpawnRange; + bool m_IsActive; } ; // tolua_end diff --git a/src/Blocks/BlockMobSpawner.h b/src/Blocks/BlockMobSpawner.h index a51fbaafc..d5e7c273f 100644 --- a/src/Blocks/BlockMobSpawner.h +++ b/src/Blocks/BlockMobSpawner.h @@ -19,6 +19,18 @@ public: } + virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + { + a_ChunkInterface.UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); + } + + + virtual bool IsUseable() override + { + return true; + } + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // No pickups diff --git a/src/Chunk.cpp b/src/Chunk.cpp index e75acb03b..c799f65fd 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -16,13 +16,14 @@ #include "BlockEntities/ChestEntity.h" #include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DropperEntity.h" +#include "BlockEntities/FlowerPotEntity.h" #include "BlockEntities/FurnaceEntity.h" #include "BlockEntities/HopperEntity.h" #include "BlockEntities/JukeboxEntity.h" +#include "BlockEntities/MobHeadEntity.h" +#include "BlockEntities/MobSpawnerEntity.h" #include "BlockEntities/NoteEntity.h" #include "BlockEntities/SignEntity.h" -#include "BlockEntities/MobHeadEntity.h" -#include "BlockEntities/FlowerPotEntity.h" #include "Entities/Pickup.h" #include "Item.h" #include "Noise.h" @@ -1344,6 +1345,7 @@ void cChunk::CreateBlockEntities(void) case E_BLOCK_NOTE_BLOCK: case E_BLOCK_JUKEBOX: case E_BLOCK_FLOWER_POT: + case E_BLOCK_MOB_SPAWNER: { if (!HasBlockEntityAt(x + m_PosX * Width, y, z + m_PosZ * Width)) { @@ -1475,6 +1477,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, case E_BLOCK_NOTE_BLOCK: case E_BLOCK_JUKEBOX: case E_BLOCK_FLOWER_POT: + case E_BLOCK_MOB_SPAWNER: { AddBlockEntity(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos.x, WorldPos.y, WorldPos.z, m_World)); break; diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index db05b70af..2350ffe85 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -126,8 +126,9 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome) { + cFastRandom Random; BLOCKTYPE TargetBlock = E_BLOCK_AIR; - if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock)) + if (a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock)) { if ((a_RelY + 1 > cChunkDef::Height) || (a_RelY - 1 < 0)) { @@ -177,7 +178,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES) ) && (a_RelY >= 62) && - (m_Random.NextInt(3, a_Biome) != 0) + (Random.NextInt(3, a_Biome) != 0) ); } @@ -238,7 +239,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (!cBlockInfo::IsTransparent(BlockBelow)) && (SkyLight <= 7) && (BlockLight <= 7) && - (m_Random.NextInt(2, a_Biome) == 0) + (Random.NextInt(2, a_Biome) == 0) ); } @@ -262,7 +263,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!cBlockInfo::IsTransparent(BlockBelow)) && - (m_Random.NextInt(20, a_Biome) == 0) + (Random.NextInt(20, a_Biome) == 0) ); } @@ -322,8 +323,8 @@ cMonster* cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, // Make sure we are looking at the right chunk to spawn in a_Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - - if (CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome)) + + if ((m_AllowedTypes.find(m_MobType) != m_AllowedTypes.end()) && CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome)) { cMonster * newMob = cMonster::NewMonsterFromType(m_MobType); if (newMob) diff --git a/src/MobSpawner.h b/src/MobSpawner.h index f3c56fe2d..e139f6923 100644 --- a/src/MobSpawner.h +++ b/src/MobSpawner.h @@ -51,9 +51,10 @@ public : typedef const std::set tSpawnedContainer; tSpawnedContainer & getSpawned(void); + /** Returns true if specified type of mob can spawn on specified block */ + static bool CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome); + protected : - // return true if specified type of mob can spawn on specified block - bool CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome); // return a random type that can spawn on specified biome. // returns E_ENTITY_TYPE_DONOTUSE if none is possible diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index ca3c04c23..86c882d47 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -96,7 +96,7 @@ public: virtual bool ReachedDestination(void); // tolua_begin - eType GetMobType(void) const {return m_MobType; } + eType GetMobType(void) const { return m_MobType; } eFamily GetMobFamily(void) const; // tolua_end diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 7d80e79fb..49a62e4f3 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -40,6 +40,7 @@ Implements the 1.7.x protocol classes: #include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/MobHeadEntity.h" +#include "../BlockEntities/MobSpawnerEntity.h" #include "../BlockEntities/FlowerPotEntity.h" #include "Bindings/PluginManager.h" @@ -2695,6 +2696,18 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_MOB_SPAWNER: + { + cMobSpawnerEntity & MobSpawnerEntity = (cMobSpawnerEntity &)a_BlockEntity; + + Writer.AddInt("x", MobSpawnerEntity.GetPosX()); + Writer.AddInt("y", MobSpawnerEntity.GetPosY()); + Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); + Writer.AddString("EntityId", MobSpawnerEntity.GetEntityName()); + Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); + Writer.AddString("id", "MobSpawner"); + break; + } default: break; } @@ -3151,4 +3164,3 @@ void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) - diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 68e541eba..a2bf3f8e1 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -18,6 +18,7 @@ #include "../BlockEntities/FurnaceEntity.h" #include "../BlockEntities/HopperEntity.h" #include "../BlockEntities/JukeboxEntity.h" +#include "../BlockEntities/MobSpawnerEntity.h" #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/SignEntity.h" #include "../BlockEntities/MobHeadEntity.h" @@ -278,6 +279,19 @@ void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox) +void cNBTChunkSerializer::AddMobSpawnerEntity(cMobSpawnerEntity * a_MobSpawner) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_MobSpawner, "MobSpawner"); + m_Writer.AddString("EntityId", a_MobSpawner->GetEntityName()); + m_Writer.AddShort("Delay", (Int16)a_MobSpawner->GetSpawnDelay()); + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note) { m_Writer.BeginCompound(""); @@ -862,6 +876,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity) case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; case E_BLOCK_LIT_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; + case E_BLOCK_MOB_SPAWNER: AddMobSpawnerEntity ((cMobSpawnerEntity *) a_Entity); break; case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; case E_BLOCK_SIGN_POST: AddSignEntity ((cSignEntity *) a_Entity); break; case E_BLOCK_TRAPPED_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break; diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 4c229a65c..7ff4b0e9b 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -32,6 +32,7 @@ class cJukeboxEntity; class cNoteEntity; class cSignEntity; class cMobHeadEntity; +class cMobSpawnerEntity; class cFlowerPotEntity; class cFallingBlock; class cMinecart; @@ -93,19 +94,20 @@ protected: void AddItemGrid(const cItemGrid & a_Grid, int a_BeginSlotNum = 0); // Block entities: - void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); - void AddBeaconEntity (cBeaconEntity * a_Entity); - void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType); - void AddDispenserEntity(cDispenserEntity * a_Entity); - void AddDropperEntity (cDropperEntity * a_Entity); - void AddFurnaceEntity (cFurnaceEntity * a_Furnace); - void AddHopperEntity (cHopperEntity * a_Entity); - void AddJukeboxEntity (cJukeboxEntity * a_Jukebox); - void AddNoteEntity (cNoteEntity * a_Note); - void AddSignEntity (cSignEntity * a_Sign); - void AddMobHeadEntity (cMobHeadEntity * a_MobHead); + void AddBasicTileEntity (cBlockEntity * a_Entity, const char * a_EntityTypeID); + void AddBeaconEntity (cBeaconEntity * a_Entity); + void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType); + void AddDispenserEntity (cDispenserEntity * a_Entity); + void AddDropperEntity (cDropperEntity * a_Entity); + void AddFurnaceEntity (cFurnaceEntity * a_Furnace); + void AddHopperEntity (cHopperEntity * a_Entity); + void AddJukeboxEntity (cJukeboxEntity * a_Jukebox); + void AddMobSpawnerEntity (cMobSpawnerEntity * a_MobSpawner); + void AddNoteEntity (cNoteEntity * a_Note); + void AddSignEntity (cSignEntity * a_Sign); + void AddMobHeadEntity (cMobHeadEntity * a_MobHead); void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock); - void AddFlowerPotEntity(cFlowerPotEntity * a_FlowerPot); + void AddFlowerPotEntity (cFlowerPotEntity * a_FlowerPot); // Entities: void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);