summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHowaner <franzi.moos@googlemail.com>2014-09-19 23:00:54 +0200
committerHowaner <franzi.moos@googlemail.com>2014-09-19 23:00:54 +0200
commit718eb227abe3b9a0e5277d663e32c6e10d51ab52 (patch)
tree5be83249ccd5b1ab4d2b87a4fa1597424d4e19b2
parentMerge branch 'master' into MobSpawner (diff)
downloadcuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.tar
cuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.tar.gz
cuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.tar.bz2
cuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.tar.lz
cuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.tar.xz
cuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.tar.zst
cuberite-718eb227abe3b9a0e5277d663e32c6e10d51ab52.zip
-rw-r--r--src/BlockEntities/BlockEntity.cpp6
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp310
-rw-r--r--src/BlockEntities/MobSpawnerEntity.h50
-rw-r--r--src/Blocks/BlockMobSpawner.h12
-rw-r--r--src/Chunk.cpp7
-rw-r--r--src/MobSpawner.cpp13
-rw-r--r--src/MobSpawner.h5
-rw-r--r--src/Mobs/Monster.h2
-rw-r--r--src/Protocol/Protocol17x.cpp14
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp15
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h26
11 files changed, 393 insertions, 67 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,37 +25,170 @@ cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c
-cMobSpawnerEntity::~cMobSpawnerEntity()
+void cMobSpawnerEntity::SendTo(cClientHandle & a_Client)
{
-
+ a_Client.SendUpdateBlockEntity(*this);
}
-bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk)
+void cMobSpawnerEntity::UsedBy(cPlayer * a_Player)
+{
+ if (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SPAWN_EGG)
+ {
+ 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;
+ }
}
-void cMobSpawnerEntity::UsedBy(cPlayer * a_Player)
+bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
- if (IsPlayingRecord())
+ // Update the active flag every 5 seconds
+ if ((m_World->GetWorldAge() % 100) == 0)
+ {
+ UpdateActiveState();
+ }
+
+ if (!m_IsActive)
+ {
+ return false;
+ }
+
+ if (m_SpawnDelay <= 0)
{
- EjectRecord();
+ SpawnEntity();
+ return true;
}
else
{
- const cItem & HeldItem = a_Player->GetEquippedItem();
- if (PlayRecord(HeldItem.m_ItemType))
+ 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)
{
- a_Player->GetInventory().RemoveOneEquippedItem();
}
+
+ 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;
+}
+
+
+
+
+
+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);
- a_Value["Record"] = m_Record;
+ 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<cMonster *> 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);