diff options
26 files changed, 549 insertions, 107 deletions
diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 0417e0464..bc27e92b0 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -1,3 +1,4 @@ + // BeaconEntity.h // Declares the cBeaconEntity class representing a single beacon in the world @@ -14,15 +15,6 @@ -namespace Json -{ - class Value; -} - - - - - // tolua_begin class cBeaconEntity : public cBlockEntityWithItems diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 3d96e891e..346970cd2 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/BlockEntity.h b/src/BlockEntities/BlockEntity.h index ffd6ee856..056a88721 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -28,11 +28,6 @@ -namespace Json -{ - class Value; -}; - class cChunk; class cPlayer; class cWorld; @@ -115,7 +110,7 @@ public: virtual void SendTo(cClientHandle & a_Client) = 0; /// Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing. - virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) + virtual bool Tick(float a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); return false; diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt index d87594b0d..5f4af288d 100644 --- a/src/BlockEntities/CMakeLists.txt +++ b/src/BlockEntities/CMakeLists.txt @@ -18,6 +18,7 @@ SET (SRCS HopperEntity.cpp JukeboxEntity.cpp MobHeadEntity.cpp + MobSpawnerEntity.cpp NoteEntity.cpp SignEntity.cpp) @@ -36,6 +37,7 @@ SET (HDRS HopperEntity.h JukeboxEntity.h MobHeadEntity.h + MobSpawnerEntity.h NoteEntity.h SignEntity.h) diff --git a/src/BlockEntities/ChestEntity.h b/src/BlockEntities/ChestEntity.h index 5ab0a4800..645dbf4bc 100644 --- a/src/BlockEntities/ChestEntity.h +++ b/src/BlockEntities/ChestEntity.h @@ -7,11 +7,6 @@ -namespace Json -{ - class Value; -}; - class cClientHandle; diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h index 8deff6964..d8ac054f0 100644 --- a/src/BlockEntities/CommandBlockEntity.h +++ b/src/BlockEntities/CommandBlockEntity.h @@ -15,14 +15,6 @@ -namespace Json -{ - class Value; -} - - - - // tolua_begin diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h index 9092bc077..6c23a402f 100644 --- a/src/BlockEntities/DropSpenserEntity.h +++ b/src/BlockEntities/DropSpenserEntity.h @@ -16,10 +16,6 @@ -namespace Json -{ - class Value; -} class cClientHandle; diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h index 005a3841a..a4246bb7d 100644 --- a/src/BlockEntities/FlowerPotEntity.h +++ b/src/BlockEntities/FlowerPotEntity.h @@ -15,16 +15,6 @@ - -namespace Json -{ - class Value; -} - - - - - // tolua_begin class cFlowerPotEntity : diff --git a/src/BlockEntities/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h index 1ad812d8b..fbe9d6c75 100644 --- a/src/BlockEntities/FurnaceEntity.h +++ b/src/BlockEntities/FurnaceEntity.h @@ -8,11 +8,6 @@ -namespace Json -{ - class Value; -} - class cClientHandle; diff --git a/src/BlockEntities/JukeboxEntity.h b/src/BlockEntities/JukeboxEntity.h index 301d018d1..000f7d87e 100644 --- a/src/BlockEntities/JukeboxEntity.h +++ b/src/BlockEntities/JukeboxEntity.h @@ -7,15 +7,6 @@ -namespace Json -{ - class Value; -} - - - - - // tolua_begin class cJukeboxEntity : diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h index de033fd16..e26c0bdd0 100644 --- a/src/BlockEntities/MobHeadEntity.h +++ b/src/BlockEntities/MobHeadEntity.h @@ -14,14 +14,6 @@ -namespace Json -{ - class Value; -} - - - - // tolua_begin diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp new file mode 100644 index 000000000..696a109d1 --- /dev/null +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -0,0 +1,335 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "MobSpawnerEntity.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_Entity(mtPig) + , m_SpawnDelay(100) + , m_IsActive(false) +{ +} + + + + + +void cMobSpawnerEntity::SendTo(cClientHandle & a_Client) +{ + a_Client.SendUpdateBlockEntity(*this); +} + + + + + +void cMobSpawnerEntity::UsedBy(cPlayer * a_Player) +{ + if (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SPAWN_EGG) + { + eMonsterType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Player->GetEquippedItem().m_ItemDamage); + if (MonsterType == eMonsterType::mtInvalidType) + { + return; + } + + m_Entity = MonsterType; + ResetTimer(); + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + LOGD("Changed monster spawner at {%d, %d, %d} to type %s.", GetPosX(), GetPosY(), GetPosZ(), 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 = (short) (200 + m_World->GetTickRandomNumber(600)); + m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ); +} + + + + + +void cMobSpawnerEntity::SpawnEntity(void) +{ + int NearbyEntities = GetNearbyMonsterNum(m_Entity); + if (NearbyEntities >= 6) + { + ResetTimer(); + return; + } + + class cCallback : public cChunkCallback + { + public: + cCallback(int a_RelX, int a_RelY, int a_RelZ, eMonsterType 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) != 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; + eMonsterType m_MobType; + int m_NearbyEntitiesNum; + } Callback(m_RelX, m_PosY, m_RelZ, m_Entity, NearbyEntities); + + if (m_World->DoWithChunk(GetChunkX(), GetChunkZ(), Callback)) + { + ResetTimer(); + } +} + + + + + +AString cMobSpawnerEntity::GetEntityName() const +{ + switch (m_Entity) + { + case mtBat: return "Bat"; + case mtBlaze: return "Blaze"; + case mtCaveSpider: return "CaveSpider"; + case mtChicken: return "Chicken"; + case mtCow: return "Cow"; + case mtCreeper: return "Creeper"; + case mtEnderDragon: return "EnderDragon"; + case mtEnderman: return "Enderman"; + case mtGhast: return "Ghast"; + case mtGiant: return "Giant"; + case mtHorse: return "EntityHorse"; + case mtIronGolem: return "VillagerGolem"; + case mtMagmaCube: return "LavaSlime"; + case mtMooshroom: return "MushroomCow"; + case mtOcelot: return "Ozelot"; + case mtPig: return "Pig"; + case mtSheep: return "Sheep"; + case mtSilverfish: return "Silverfish"; + case mtSkeleton: return "Skeleton"; + case mtSlime: return "Slime"; + case mtSnowGolem: return "SnowMan"; + case mtSpider: return "Spider"; + case mtSquid: return "Squid"; + case mtVillager: return "Villager"; + case mtWitch: return "Witch"; + case mtWither: return "WitherBoss"; + case mtWolf: return "Wolf"; + case mtZombie: return "Zombie"; + case 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::GetNearbyMonsterNum(eMonsterType 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, eMonsterType 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; + eMonsterType 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 new file mode 100644 index 000000000..073eb03ab --- /dev/null +++ b/src/BlockEntities/MobSpawnerEntity.h @@ -0,0 +1,71 @@ + +#pragma once + +#include "BlockEntity.h" +#include "../Entities/Player.h" + + + + + +// tolua_begin + +class cMobSpawnerEntity : + public cBlockEntity +{ + typedef cBlockEntity super; +public: + + // tolua_end + + cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); + + 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 + + /** 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. */ + eMonsterType GetEntity(void) const { return m_Entity; } + + /** Sets the entity type who will be spawn by this mob spawner. */ + void SetEntity(eMonsterType a_EntityType) { m_Entity = a_EntityType; } + + /** Returns the entity name. (Required by the protocol) */ + AString GetEntityName(void) const; + + /** Returns the spawn delay. */ + short GetSpawnDelay(void) const { return m_SpawnDelay; } + + /** Sets the spawn delay. */ + void SetSpawnDelay(short a_Delay) { m_SpawnDelay = a_Delay; } + + int GetNearbyPlayersNum(void); + int GetNearbyMonsterNum(eMonsterType a_EntityType); + + // tolua_end + + static const char * GetClassStatic(void) { return "cMobSpawnerEntity"; } + +private: + /** The entity to spawn. */ + eMonsterType m_Entity; + + short m_SpawnDelay; + + bool m_IsActive; +} ; // tolua_end + + + + diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index d63ff56b6..d3f85e9d2 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -5,12 +5,6 @@ #include "RedstonePoweredEntity.h" -namespace Json -{ - class Value; -} - - diff --git a/src/BlockEntities/SignEntity.h b/src/BlockEntities/SignEntity.h index 347689d0a..9480537ed 100644 --- a/src/BlockEntities/SignEntity.h +++ b/src/BlockEntities/SignEntity.h @@ -14,15 +14,6 @@ -namespace Json -{ - class Value; -} - - - - - // tolua_begin class cSignEntity : 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 a2a11f130..d271b4cb4 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/Noise.h" @@ -1348,6 +1349,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)) { @@ -1479,6 +1481,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 e461fae4c..a1d375e9e 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -126,8 +126,9 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, eMonsterType 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 6b3a913ec..e8b8f191b 100644 --- a/src/MobSpawner.h +++ b/src/MobSpawner.h @@ -51,10 +51,10 @@ public : typedef const std::set<cMonster *> tSpawnedContainer; tSpawnedContainer & getSpawned(void); -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, eMonsterType a_MobType, EMCSBiome a_Biome); + /** 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, eMonsterType a_MobType, EMCSBiome a_Biome); +protected : // return a random type that can spawn on specified biome. // returns E_ENTITY_TYPE_DONOTUSE if none is possible eMonsterType ChooseMobType(EMCSBiome a_Biome); @@ -62,7 +62,6 @@ protected : // add toAdd inside toAddIn, if toAdd is in m_AllowedTypes void addIfAllowed(eMonsterType toAdd, std::set<eMonsterType> & toAddIn); -protected : cMonster::eFamily m_MonsterFamily; std::set<eMonsterType> m_AllowedTypes; bool m_NewPack; diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index e5dcb0309..fd4e8a659 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -64,7 +64,7 @@ public: virtual bool ReachedDestination(void); // tolua_begin - eMonsterType GetMobType(void) const {return m_MobType; } + eMonsterType 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 1d108ce9c..9067131b2 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -42,6 +42,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" @@ -2662,6 +2663,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; } @@ -3134,4 +3147,3 @@ void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) - diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index 8170a494f..42f365e80 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -41,6 +41,7 @@ Implements the 1.8.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" @@ -2972,6 +2973,18 @@ void cProtocol180::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; } diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 4daa8cc7b..228df2686 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" @@ -290,6 +291,20 @@ void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox) +void cNBTChunkSerializer::AddMobSpawnerEntity(cMobSpawnerEntity * a_MobSpawner) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_MobSpawner, "MobSpawner"); + m_Writer.AddShort("Entity", static_cast<short>(a_MobSpawner->GetEntity())); + m_Writer.AddString("EntityId", a_MobSpawner->GetEntityName()); + m_Writer.AddShort("Delay", a_MobSpawner->GetSpawnDelay()); + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note) { m_Writer.BeginCompound(""); @@ -914,6 +929,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 5ffab8cc5..4c066b9af 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; @@ -94,19 +95,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); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 395aabb1b..4520751c7 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -28,6 +28,7 @@ #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/SignEntity.h" #include "../BlockEntities/MobHeadEntity.h" +#include "../BlockEntities/MobSpawnerEntity.h" #include "../BlockEntities/FlowerPotEntity.h" #include "../Mobs/Monster.h" @@ -664,6 +665,7 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LIT_FURNACE, a_BlockMeta); + case E_BLOCK_MOB_SPAWNER: return LoadMobSpawnerFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SIGN_POST); case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_TRAPPED_CHEST); @@ -1085,6 +1087,54 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag +cBlockEntity * cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) +{ + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "MobSpawner")) + { + return nullptr; + } + + std::auto_ptr<cMobSpawnerEntity> MobSpawner(new cMobSpawnerEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + + // Load entity (MCServer worlds): + int Type = a_NBT.FindChildByName(a_TagIdx, "Entity"); + if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_Short)) + { + short MonsterType = a_NBT.GetShort(Type); + if ((MonsterType >= 50) && (MonsterType <= 120)) + { + MobSpawner->SetEntity(static_cast<eMonsterType>(MonsterType)); + } + } + else + { + // Load entity (vanilla worlds): + Type = a_NBT.FindChildByName(a_TagIdx, "EntityId"); + if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_String)) + { + eMonsterType MonsterType = cMonster::StringToMobType(a_NBT.GetString(Type)); + if (MonsterType != eMonsterType::mtInvalidType) + { + MobSpawner->SetEntity(MonsterType); + } + } + } + + // Load delay: + int Delay = a_NBT.FindChildByName(a_TagIdx, "Delay"); + if ((Delay >= 0) && (a_NBT.GetType(Delay) == TAG_Short)) + { + MobSpawner->SetSpawnDelay(a_NBT.GetShort(Delay)); + } + + return MobSpawner.release(); +} + + + + + cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { // Check if the data has a proper type: diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 9c579a617..7a98a9a04 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -148,6 +148,7 @@ protected: cBlockEntity * LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadFlowerPotFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadFurnaceFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + cBlockEntity * LoadMobSpawnerFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadHopperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadJukeboxFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); |