1
0
This commit is contained in:
STRWarrior 2014-12-01 16:39:42 +01:00
commit cd0081bb67
31 changed files with 638 additions and 182 deletions

View File

@ -1668,13 +1668,14 @@ a_Player:OpenWindow(Window);
SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of the monster. You see the name over the monster. If you want to disable the custom name, simply set an empty string." }, SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of the monster. You see the name over the monster. If you want to disable the custom name, simply set an empty string." },
IsCustomNameAlwaysVisible = { Params = "", Return = "bool", Notes = "Is the custom name of this monster always visible? If not, you only see the name when you sight the mob." }, IsCustomNameAlwaysVisible = { Params = "", Return = "bool", Notes = "Is the custom name of this monster always visible? If not, you only see the name when you sight the mob." },
SetCustomNameAlwaysVisible = { Params = "bool", Return = "", Notes = "Sets the custom name visiblity of this monster. If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name." }, SetCustomNameAlwaysVisible = { Params = "bool", Return = "", Notes = "Sets the custom name visiblity of this monster. If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name." },
FamilyFromType = { Params = "{{cMonster#MobType|MobType}}", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "(STATIC) Returns the mob family ({{cMonster#MobFamily|mfXXX}} constants) based on the mob type ({{cMonster#MobType|mtXXX}} constants)" }, FamilyFromType = { Params = "{{Globals#MobType|MobType}}", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "(STATIC) Returns the mob family ({{cMonster#MobFamily|mfXXX}} constants) based on the mob type ({{Globals#MobType|mtXXX}} constants)" },
GetMobFamily = { Params = "", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "Returns this mob's family ({{cMonster#MobFamily|mfXXX}} constant)" }, GetMobFamily = { Params = "", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "Returns this mob's family ({{cMonster#MobFamily|mfXXX}} constant)" },
GetMobType = { Params = "", Return = "{{cMonster#MobType|MobType}}", Notes = "Returns the type of this mob ({{cMonster#MobType|mtXXX}} constant)" }, GetMobType = { Params = "", Return = "{{Globals#MobType|MobType}}", Notes = "Returns the type of this mob ({{Globals#MobType|mtXXX}} constant)" },
GetSpawnDelay = { Params = "{{cMonster#MobFamily|MobFamily}}", Return = "number", Notes = "(STATIC) Returns the spawn delay - the number of game ticks between spawn attempts - for the specified mob family." }, GetSpawnDelay = { Params = "{{cMonster#MobFamily|MobFamily}}", Return = "number", Notes = "(STATIC) Returns the spawn delay - the number of game ticks between spawn attempts - for the specified mob family." },
MobTypeToString = { Params = "{{cMonster#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{cMonster#MobType|mtXXX}} constant), or empty string if unknown type." }, MobTypeToString = { Params = "{{Globals#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{Globals#MobType|mtXXX}} constant), or empty string if unknown type." },
MobTypeToVanillaName = { Params = "{{Globals#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the vanilla name of the given mob type, or empty string if unknown type." },
MoveToPosition = { Params = "Position", Return = "", Notes = "Moves mob to the specified position" }, MoveToPosition = { Params = "Position", Return = "", Notes = "Moves mob to the specified position" },
StringToMobType = { Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{cMonster#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." }, StringToMobType = { Params = "string", Return = "{{Globals#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{Globals#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." },
GetRelativeWalkSpeed = { Params = "", Return = "number", Notes = "Returns the relative walk speed of this mob. Standard is 1.0" }, GetRelativeWalkSpeed = { Params = "", Return = "number", Notes = "Returns the relative walk speed of this mob. Standard is 1.0" },
SetRelativeWalkSpeed = { Params = "number", Return = "", Notes = "Sets the relative walk speed of this mob. Standard is 1.0" }, SetRelativeWalkSpeed = { Params = "number", Return = "", Notes = "Sets the relative walk speed of this mob. Standard is 1.0" },
}, },
@ -1725,13 +1726,6 @@ a_Player:OpenWindow(Window);
Mobs are divided into families. The following constants are used for individual family types: Mobs are divided into families. The following constants are used for individual family types:
]], ]],
}, },
MobType =
{
Include = "mt.*",
TextBefore = [[
The following constants are used for distinguishing between the individual mob types:
]],
},
}, },
Inherits = "cPawn", Inherits = "cPawn",
}, -- cMonster }, -- cMonster
@ -2571,7 +2565,7 @@ World:ForEachEntity(
return; return;
end end
local Monster = tolua.cast(a_Entity, "cMonster"); -- Get the cMonster out of cEntity, now that we know the entity represents one. local Monster = tolua.cast(a_Entity, "cMonster"); -- Get the cMonster out of cEntity, now that we know the entity represents one.
if (Monster:GetMobType() == cMonster.mtSpider) then if (Monster:GetMobType() == mtSpider) then
Monster:TeleportToCoords(Monster:GetPosX(), Monster:GetPosY() + 100, Monster:GetPosZ()); Monster:TeleportToCoords(Monster:GetPosX(), Monster:GetPosY() + 100, Monster:GetPosZ());
end end
end end
@ -2928,7 +2922,7 @@ end
StringToDamageType = {Params = "string", Return = "{{Globals#DamageType|DamageType}}", Notes = "Converts a string representation to a {{Globals#DamageType|DamageType}} enumerated value."}, StringToDamageType = {Params = "string", Return = "{{Globals#DamageType|DamageType}}", Notes = "Converts a string representation to a {{Globals#DamageType|DamageType}} enumerated value."},
StringToDimension = {Params = "string", Return = "{{Globals#WorldDimension|Dimension}}", Notes = "Converts a string representation to a {{Globals#WorldDimension|Dimension}} enumerated value"}, StringToDimension = {Params = "string", Return = "{{Globals#WorldDimension|Dimension}}", Notes = "Converts a string representation to a {{Globals#WorldDimension|Dimension}} enumerated value"},
StringToItem = {Params = "string, {{cItem|cItem}}", Return = "bool", Notes = "Parses the given string and sets the item; returns true if successful"}, StringToItem = {Params = "string, {{cItem|cItem}}", Return = "bool", Notes = "Parses the given string and sets the item; returns true if successful"},
StringToMobType = {Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "<b>DEPRECATED!</b> Please use cMonster:StringToMobType(). Converts a string representation to a {{cMonster#MobType|MobType}} enumerated value"}, StringToMobType = {Params = "string", Return = "{{Globals#MobType|MobType}}", Notes = "<b>DEPRECATED!</b> Please use cMonster:StringToMobType(). Converts a string representation to a {{Globals#MobType|MobType}} enumerated value"},
StripColorCodes = {Params = "string", Return = "string", Notes = "Removes all control codes used by MC for colors and styles"}, StripColorCodes = {Params = "string", Return = "string", Notes = "Removes all control codes used by MC for colors and styles"},
TrimString = {Params = "string", Return = "string", Notes = "Trims whitespace at both ends of the string"}, TrimString = {Params = "string", Return = "string", Notes = "Trims whitespace at both ends of the string"},
md5 = {Params = "string", Return = "string", Notes = "converts a string to an md5 hash"}, md5 = {Params = "string", Return = "string", Notes = "converts a string to an md5 hash"},
@ -3014,6 +3008,13 @@ end
gmXXX constants, the eGameMode_ constants are deprecated and will be removed from the API. gmXXX constants, the eGameMode_ constants are deprecated and will be removed from the API.
]], ]],
}, },
MobType =
{
Include = { "^mt.*" },
TextBefore = [[
The following constants are used for distinguishing between the individual mob types:
]],
},
Weather = Weather =
{ {
Include = { "^eWeather_.*", "wSunny", "wRain", "wStorm", "wThunderstorm" }, Include = { "^eWeather_.*", "wSunny", "wRain", "wStorm", "wThunderstorm" },

View File

@ -231,6 +231,43 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
}, },
}, -- cJukeboxEntity }, -- cJukeboxEntity
cMobHeadEntity =
{
Desc = [[
This class represents a mob head block entity in the world.
]],
Inherits = "cBlockEntity",
Functions =
{
SetType = { Params = "eMobHeadType", Return = "", Notes = "Set the type of the mob head" },
SetRotation = { Params = "eMobHeadRotation", Return = "", Notes = "Sets the rotation of the mob head" },
SetOwner = { Params = "string", Return = "", Notes = "Set the player name for mob heads with player type" },
GetType = { Params = "", Return = "eMobHeadType", Notes = "Returns the type of the mob head" },
GetRotation = { Params = "", Return = "eMobHeadRotation", Notes = "Returns the rotation of the mob head" },
GetOwner = { Params = "", Return = "string", Notes = "Returns the player name of the mob head" },
},
}, -- cMobHeadEntity
cMobSpawnerEntity =
{
Desc = [[
This class represents a mob spawner block entity in the world.
]],
Inherits = "cBlockEntity",
Functions =
{
UpdateActiveState = { Params = "", Return = "", Notes = "Upate the active flag from the mob spawner. This function will called every 5 seconds from the Tick() function." },
ResetTimer = { Params = "", Return = "", Notes = "Sets the spawn delay to a new random value." },
SpawnEntity = { Params = "", Return = "", Notes = "Spawns the entity. This function automaticly change the spawn delay!" },
GetEntity = { Params = "", Return = "{{Globals#MobType|MobType}}", Notes = "Returns the entity type that will be spawn by this mob spawner." },
SetEntity = { Params = "{{Globals#MobType|MobType}}", Return = "", Notes = "Sets the entity type who will be spawn by this mob spawner." },
GetSpawnDelay = { Params = "", Return = "number", Notes = "Returns the spawn delay. This is the tick delay that is needed to spawn new monsters." },
SetSpawnDelay = { Params = "number", Return = "", Notes = "Sets the spawn delay." },
GetNearbyPlayersNum = { Params = "", Return = "number", Notes = "Returns the amount of the nearby players in a 16-block radius." },
GetNearbyMonsterNum = { Params = "", Return = "number", Notes = "Returns the amount of this monster type in a 8-block radius (Y: 4-block radius)." },
},
}, -- cMobSpawnerEntity
cNoteEntity = cNoteEntity =
{ {
Desc = [[ Desc = [[

@ -1 +1 @@
Subproject commit 5b7a6d464ed3e0e5d2a438ebf119430cacab26ae Subproject commit 4183d6cfb2049d0757d811a65bd4e75ed78b9f41

View File

@ -74,6 +74,7 @@ $cfile "../BlockEntities/JukeboxEntity.h"
$cfile "../BlockEntities/NoteEntity.h" $cfile "../BlockEntities/NoteEntity.h"
$cfile "../BlockEntities/SignEntity.h" $cfile "../BlockEntities/SignEntity.h"
$cfile "../BlockEntities/MobHeadEntity.h" $cfile "../BlockEntities/MobHeadEntity.h"
$cfile "../BlockEntities/MobSpawnerEntity.h"
$cfile "../BlockEntities/FlowerPotEntity.h" $cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h" $cfile "../WebAdmin.h"
$cfile "../Root.h" $cfile "../Root.h"

View File

@ -1,3 +1,4 @@
// BeaconEntity.h // BeaconEntity.h
// Declares the cBeaconEntity class representing a single beacon in the world // Declares the cBeaconEntity class representing a single beacon in the world
@ -14,15 +15,6 @@
namespace Json
{
class Value;
}
// tolua_begin // tolua_begin
class cBeaconEntity : class cBeaconEntity :
public cBlockEntityWithItems public cBlockEntityWithItems

View File

@ -14,10 +14,11 @@
#include "FlowerPotEntity.h" #include "FlowerPotEntity.h"
#include "FurnaceEntity.h" #include "FurnaceEntity.h"
#include "HopperEntity.h" #include "HopperEntity.h"
#include "MobHeadEntity.h"
#include "MobSpawnerEntity.h"
#include "JukeboxEntity.h" #include "JukeboxEntity.h"
#include "NoteEntity.h" #include "NoteEntity.h"
#include "SignEntity.h" #include "SignEntity.h"
#include "MobHeadEntity.h"
@ -37,6 +38,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, 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_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_HOPPER: return new cHopperEntity (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_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_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); case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);

View File

@ -28,11 +28,6 @@
namespace Json
{
class Value;
};
class cChunk; class cChunk;
class cPlayer; class cPlayer;
class cWorld; class cWorld;
@ -115,7 +110,7 @@ public:
virtual void SendTo(cClientHandle & a_Client) = 0; 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. /// 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); UNUSED(a_Dt);
return false; return false;

View File

@ -18,6 +18,7 @@ SET (SRCS
HopperEntity.cpp HopperEntity.cpp
JukeboxEntity.cpp JukeboxEntity.cpp
MobHeadEntity.cpp MobHeadEntity.cpp
MobSpawnerEntity.cpp
NoteEntity.cpp NoteEntity.cpp
SignEntity.cpp) SignEntity.cpp)
@ -36,6 +37,7 @@ SET (HDRS
HopperEntity.h HopperEntity.h
JukeboxEntity.h JukeboxEntity.h
MobHeadEntity.h MobHeadEntity.h
MobSpawnerEntity.h
NoteEntity.h NoteEntity.h
SignEntity.h) SignEntity.h)

View File

@ -7,11 +7,6 @@
namespace Json
{
class Value;
};
class cClientHandle; class cClientHandle;

View File

@ -15,14 +15,6 @@
namespace Json
{
class Value;
}
// tolua_begin // tolua_begin

View File

@ -16,10 +16,6 @@
namespace Json
{
class Value;
}
class cClientHandle; class cClientHandle;

View File

@ -15,16 +15,6 @@
namespace Json
{
class Value;
}
// tolua_begin // tolua_begin
class cFlowerPotEntity : class cFlowerPotEntity :

View File

@ -8,11 +8,6 @@
namespace Json
{
class Value;
}
class cClientHandle; class cClientHandle;

View File

@ -7,15 +7,6 @@
namespace Json
{
class Value;
}
// tolua_begin // tolua_begin
class cJukeboxEntity : class cJukeboxEntity :

View File

@ -14,14 +14,6 @@
namespace Json
{
class Value;
}
// tolua_begin // tolua_begin
@ -41,22 +33,22 @@ public:
// tolua_begin // tolua_begin
/** Set the Type */ /** Set the type of the mob head */
void SetType(const eMobHeadType & a_SkullType); void SetType(const eMobHeadType & a_SkullType);
/** Set the Rotation */ /** Set the rotation of the mob head */
void SetRotation(eMobHeadRotation a_Rotation); void SetRotation(eMobHeadRotation a_Rotation);
/** Set the Player Name for Mobheads with Player type */ /** Set the player name for mob heads with player type */
void SetOwner(const AString & a_Owner); void SetOwner(const AString & a_Owner);
/** Get the Type */ /** Returns the type of the mob head */
eMobHeadType GetType(void) const { return m_Type; } eMobHeadType GetType(void) const { return m_Type; }
/** Get the Rotation */ /** Returns the rotation of the mob head */
eMobHeadRotation GetRotation(void) const { return m_Rotation; } eMobHeadRotation GetRotation(void) const { return m_Rotation; }
/** Get the setted Player Name */ /** Returns the player name of the mob head */
AString GetOwner(void) const { return m_Owner; } AString GetOwner(void) const { return m_Owner; }
// tolua_end // tolua_end

View File

@ -0,0 +1,290 @@
#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(), cMonster::MobTypeToString(MonsterType).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 = static_cast<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();
}
}
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 ((Diff(m_SpawnerPos.x, a_Entity->GetPosX()) <= 8.0) && (Diff(m_SpawnerPos.y, a_Entity->GetPosY()) <= 4.0) && (Diff(m_SpawnerPos.z, a_Entity->GetPosZ()) <= 8.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;
}

View File

@ -0,0 +1,78 @@
// MobSpawnerEntity.h
// Declares the cMobSpawnerEntity class representing a single mob spawner in the world
#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 that 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 spawn delay. This is the tick delay that is needed to spawn new monsters. */
short GetSpawnDelay(void) const { return m_SpawnDelay; }
/** Sets the spawn delay. */
void SetSpawnDelay(short a_Delay) { m_SpawnDelay = a_Delay; }
/** Returns the amount of the nearby players in a 16-block radius. */
int GetNearbyPlayersNum(void);
/** Returns the amount of this monster type in a 8-block radius (Y: 4-block radius). */
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

View File

@ -5,12 +5,6 @@
#include "RedstonePoweredEntity.h" #include "RedstonePoweredEntity.h"
namespace Json
{
class Value;
}

View File

@ -14,15 +14,6 @@
namespace Json
{
class Value;
}
// tolua_begin // tolua_begin
class cSignEntity : class cSignEntity :

View File

@ -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 virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
// No pickups // No pickups

View File

@ -16,13 +16,14 @@
#include "BlockEntities/ChestEntity.h" #include "BlockEntities/ChestEntity.h"
#include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DispenserEntity.h"
#include "BlockEntities/DropperEntity.h" #include "BlockEntities/DropperEntity.h"
#include "BlockEntities/FlowerPotEntity.h"
#include "BlockEntities/FurnaceEntity.h" #include "BlockEntities/FurnaceEntity.h"
#include "BlockEntities/HopperEntity.h" #include "BlockEntities/HopperEntity.h"
#include "BlockEntities/JukeboxEntity.h" #include "BlockEntities/JukeboxEntity.h"
#include "BlockEntities/MobHeadEntity.h"
#include "BlockEntities/MobSpawnerEntity.h"
#include "BlockEntities/NoteEntity.h" #include "BlockEntities/NoteEntity.h"
#include "BlockEntities/SignEntity.h" #include "BlockEntities/SignEntity.h"
#include "BlockEntities/MobHeadEntity.h"
#include "BlockEntities/FlowerPotEntity.h"
#include "Entities/Pickup.h" #include "Entities/Pickup.h"
#include "Item.h" #include "Item.h"
#include "Noise/Noise.h" #include "Noise/Noise.h"
@ -1348,6 +1349,7 @@ void cChunk::CreateBlockEntities(void)
case E_BLOCK_NOTE_BLOCK: case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX: case E_BLOCK_JUKEBOX:
case E_BLOCK_FLOWER_POT: case E_BLOCK_FLOWER_POT:
case E_BLOCK_MOB_SPAWNER:
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y, z + m_PosZ * Width)) 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_NOTE_BLOCK:
case E_BLOCK_JUKEBOX: case E_BLOCK_JUKEBOX:
case E_BLOCK_FLOWER_POT: 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)); AddBlockEntity(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;

View File

@ -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) 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; 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)) 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) (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) && ) &&
(a_RelY >= 62) && (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)) && (!cBlockInfo::IsTransparent(BlockBelow)) &&
(SkyLight <= 7) && (SkyLight <= 7) &&
(BlockLight <= 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) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(BlockBelow)) && (!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 // Make sure we are looking at the right chunk to spawn in
a_Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); 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); cMonster * newMob = cMonster::NewMonsterFromType(m_MobType);
if (newMob) if (newMob)

View File

@ -51,10 +51,10 @@ public :
typedef const std::set<cMonster *> tSpawnedContainer; typedef const std::set<cMonster *> tSpawnedContainer;
tSpawnedContainer & getSpawned(void); tSpawnedContainer & getSpawned(void);
protected : /** Returns true if specified type of mob can spawn on specified block */
// return 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);
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. // return a random type that can spawn on specified biome.
// returns E_ENTITY_TYPE_DONOTUSE if none is possible // returns E_ENTITY_TYPE_DONOTUSE if none is possible
eMonsterType ChooseMobType(EMCSBiome a_Biome); eMonsterType ChooseMobType(EMCSBiome a_Biome);
@ -62,7 +62,6 @@ protected :
// add toAdd inside toAddIn, if toAdd is in m_AllowedTypes // add toAdd inside toAddIn, if toAdd is in m_AllowedTypes
void addIfAllowed(eMonsterType toAdd, std::set<eMonsterType> & toAddIn); void addIfAllowed(eMonsterType toAdd, std::set<eMonsterType> & toAddIn);
protected :
cMonster::eFamily m_MonsterFamily; cMonster::eFamily m_MonsterFamily;
std::set<eMonsterType> m_AllowedTypes; std::set<eMonsterType> m_AllowedTypes;
bool m_NewPack; bool m_NewPack;

View File

@ -21,41 +21,43 @@
/** Map for eType <-> string /** Map for eType <-> string
Needs to be alpha-sorted by the strings, because binary search is used in StringToMobType() Needs to be alpha-sorted by the strings, because binary search is used in StringToMobType()
The strings need to be lowercase (for more efficient comparisons in StringToMobType()) The strings need to be lowercase (for more efficient comparisons in StringToMobType())
m_VanillaName is the name that vanilla use for this mob.
*/ */
static const struct static const struct
{ {
eMonsterType m_Type; eMonsterType m_Type;
const char * m_lcName; const char * m_lcName;
const char * m_VanillaName;
} g_MobTypeNames[] = } g_MobTypeNames[] =
{ {
{mtBat, "bat"}, {mtBat, "bat", "Bat"},
{mtBlaze, "blaze"}, {mtBlaze, "blaze", "Blaze"},
{mtCaveSpider, "cavespider"}, {mtCaveSpider, "cavespider", "CaveSpider"},
{mtChicken, "chicken"}, {mtChicken, "chicken", "Chicken"},
{mtCow, "cow"}, {mtCow, "cow", "Cow"},
{mtCreeper, "creeper"}, {mtCreeper, "creeper", "Creeper"},
{mtEnderman, "enderman"}, {mtEnderman, "enderman", "Enderman"},
{mtEnderDragon, "enderdragon"}, {mtEnderDragon, "enderdragon", "EnderDragon"},
{mtGhast, "ghast"}, {mtGhast, "ghast", "Ghast"},
{mtHorse, "horse"}, {mtHorse, "horse", "EntityHorse"},
{mtIronGolem, "irongolem"}, {mtIronGolem, "irongolem", "VillagerGolem"},
{mtMagmaCube, "magmacube"}, {mtMagmaCube, "magmacube", "LavaSlime"},
{mtMooshroom, "mooshroom"}, {mtMooshroom, "mooshroom", "MushroomCow"},
{mtOcelot, "ocelot"}, {mtOcelot, "ocelot", "Ozelot"},
{mtPig, "pig"}, {mtPig, "pig", "Pig"},
{mtSheep, "sheep"}, {mtSheep, "sheep", "Sheep"},
{mtSilverfish, "silverfish"}, {mtSilverfish, "silverfish", "Silverfish"},
{mtSkeleton, "skeleton"}, {mtSkeleton, "skeleton", "Skeleton"},
{mtSlime, "slime"}, {mtSlime, "slime", "Slime"},
{mtSnowGolem, "snowgolem"}, {mtSnowGolem, "snowgolem", "SnowMan"},
{mtSpider, "spider"}, {mtSpider, "spider", "Spider"},
{mtSquid, "squid"}, {mtSquid, "squid", "Squid"},
{mtVillager, "villager"}, {mtVillager, "villager", "Villager"},
{mtWitch, "witch"}, {mtWitch, "witch", "Witch"},
{mtWither, "wither"}, {mtWither, "wither", "WitherBoss"},
{mtWolf, "wolf"}, {mtWolf, "wolf", "Wolf"},
{mtZombie, "zombie"}, {mtZombie, "zombie", "Zombie"},
{mtZombiePigman, "zombiepigman"}, {mtZombiePigman, "zombiepigman", "PigZombie"},
} ; } ;
@ -774,39 +776,47 @@ AString cMonster::MobTypeToString(eMonsterType a_MobType)
AString cMonster::MobTypeToVanillaName(eMonsterType a_MobType)
{
// Mob types aren't sorted, so we need to search linearly:
for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
{
if (g_MobTypeNames[i].m_Type == a_MobType)
{
return g_MobTypeNames[i].m_VanillaName;
}
}
// Not found:
return "";
}
eMonsterType cMonster::StringToMobType(const AString & a_Name) eMonsterType cMonster::StringToMobType(const AString & a_Name)
{ {
AString lcName = StrToLower(a_Name); AString lcName = StrToLower(a_Name);
// Binary-search for the lowercase name: // Search MCServer name:
int lo = 0, hi = ARRAYCOUNT(g_MobTypeNames) - 1; for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
while (hi - lo > 1)
{ {
int mid = (lo + hi) / 2; if (strcmp(g_MobTypeNames[i].m_lcName, lcName.c_str()) == 0)
int res = strcmp(g_MobTypeNames[mid].m_lcName, lcName.c_str());
if (res == 0)
{ {
return g_MobTypeNames[mid].m_Type; return g_MobTypeNames[i].m_Type;
}
if (res < 0)
{
lo = mid;
}
else
{
hi = mid;
} }
} }
// Range has collapsed to at most two elements, compare each:
if (strcmp(g_MobTypeNames[lo].m_lcName, lcName.c_str()) == 0) // Not found. Search Vanilla name:
for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
{ {
return g_MobTypeNames[lo].m_Type; if (strcmp(StrToLower(g_MobTypeNames[i].m_VanillaName).c_str(), lcName.c_str()) == 0)
{
return g_MobTypeNames[i].m_Type;
}
} }
if ((lo != hi) && (strcmp(g_MobTypeNames[hi].m_lcName, lcName.c_str()) == 0))
{
return g_MobTypeNames[hi].m_Type;
}
// Not found: // Not found:
return mtInvalidType; return mtInvalidType;
} }

View File

@ -64,7 +64,7 @@ public:
virtual bool ReachedDestination(void); virtual bool ReachedDestination(void);
// tolua_begin // tolua_begin
eMonsterType GetMobType(void) const {return m_MobType; } eMonsterType GetMobType(void) const { return m_MobType; }
eFamily GetMobFamily(void) const; eFamily GetMobFamily(void) const;
// tolua_end // tolua_end
@ -133,16 +133,19 @@ public:
If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name. */ If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name. */
void SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible); void SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible);
/// Translates MobType enum to a string, empty string if unknown /** Translates MobType enum to a string, empty string if unknown */
static AString MobTypeToString(eMonsterType a_MobType); static AString MobTypeToString(eMonsterType a_MobType);
/// Translates MobType string to the enum, mtInvalidType if not recognized /** Translates MobType enum to the vanilla name of the mob, empty string if unknown. */
static AString MobTypeToVanillaName(eMonsterType a_MobType);
/** Translates MobType string to the enum, mtInvalidType if not recognized */
static eMonsterType StringToMobType(const AString & a_MobTypeName); static eMonsterType StringToMobType(const AString & a_MobTypeName);
/// Returns the mob family based on the type /** Returns the mob family based on the type */
static eFamily FamilyFromType(eMonsterType a_MobType); static eFamily FamilyFromType(eMonsterType a_MobType);
/// Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family /** Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family */
static int GetSpawnDelay(cMonster::eFamily a_MobFamily); static int GetSpawnDelay(cMonster::eFamily a_MobFamily);
// tolua_end // tolua_end

View File

@ -42,6 +42,7 @@ Implements the 1.7.x protocol classes:
#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/MobSpawnerEntity.h"
#include "../BlockEntities/FlowerPotEntity.h" #include "../BlockEntities/FlowerPotEntity.h"
#include "Bindings/PluginManager.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 Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break; 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", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay());
Writer.AddString("id", "MobSpawner");
break;
}
default: break; default: break;
} }
@ -3134,4 +3147,3 @@ void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)

View File

@ -41,6 +41,7 @@ Implements the 1.8.x protocol classes:
#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/MobSpawnerEntity.h"
#include "../BlockEntities/FlowerPotEntity.h" #include "../BlockEntities/FlowerPotEntity.h"
#include "Bindings/PluginManager.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 Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break; 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", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay());
Writer.AddString("id", "MobSpawner");
break;
}
default: break; default: break;
} }

View File

@ -18,6 +18,7 @@
#include "../BlockEntities/FurnaceEntity.h" #include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/HopperEntity.h" #include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/JukeboxEntity.h" #include "../BlockEntities/JukeboxEntity.h"
#include "../BlockEntities/MobSpawnerEntity.h"
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h" #include "../BlockEntities/SignEntity.h"
#include "../BlockEntities/MobHeadEntity.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", cMonster::MobTypeToVanillaName(a_MobSpawner->GetEntity()));
m_Writer.AddShort("Delay", a_MobSpawner->GetSpawnDelay());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note) void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note)
{ {
m_Writer.BeginCompound(""); 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_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) 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_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_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST: AddSignEntity ((cSignEntity *) 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; case E_BLOCK_TRAPPED_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;

View File

@ -32,6 +32,7 @@ class cJukeboxEntity;
class cNoteEntity; class cNoteEntity;
class cSignEntity; class cSignEntity;
class cMobHeadEntity; class cMobHeadEntity;
class cMobSpawnerEntity;
class cFlowerPotEntity; class cFlowerPotEntity;
class cFallingBlock; class cFallingBlock;
class cMinecart; class cMinecart;
@ -94,19 +95,20 @@ protected:
void AddItemGrid(const cItemGrid & a_Grid, int a_BeginSlotNum = 0); void AddItemGrid(const cItemGrid & a_Grid, int a_BeginSlotNum = 0);
// Block entities: // Block entities:
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); void AddBasicTileEntity (cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddBeaconEntity (cBeaconEntity * a_Entity); void AddBeaconEntity (cBeaconEntity * a_Entity);
void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType); void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType);
void AddDispenserEntity(cDispenserEntity * a_Entity); void AddDispenserEntity (cDispenserEntity * a_Entity);
void AddDropperEntity (cDropperEntity * a_Entity); void AddDropperEntity (cDropperEntity * a_Entity);
void AddFurnaceEntity (cFurnaceEntity * a_Furnace); void AddFurnaceEntity (cFurnaceEntity * a_Furnace);
void AddHopperEntity (cHopperEntity * a_Entity); void AddHopperEntity (cHopperEntity * a_Entity);
void AddJukeboxEntity (cJukeboxEntity * a_Jukebox); void AddJukeboxEntity (cJukeboxEntity * a_Jukebox);
void AddNoteEntity (cNoteEntity * a_Note); void AddMobSpawnerEntity (cMobSpawnerEntity * a_MobSpawner);
void AddSignEntity (cSignEntity * a_Sign); void AddNoteEntity (cNoteEntity * a_Note);
void AddMobHeadEntity (cMobHeadEntity * a_MobHead); void AddSignEntity (cSignEntity * a_Sign);
void AddMobHeadEntity (cMobHeadEntity * a_MobHead);
void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock); void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock);
void AddFlowerPotEntity(cFlowerPotEntity * a_FlowerPot); void AddFlowerPotEntity (cFlowerPotEntity * a_FlowerPot);
// Entities: // Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName); void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);

View File

@ -28,6 +28,7 @@
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h" #include "../BlockEntities/SignEntity.h"
#include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/MobSpawnerEntity.h"
#include "../BlockEntities/FlowerPotEntity.h" #include "../BlockEntities/FlowerPotEntity.h"
#include "../Mobs/Monster.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_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_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_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_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_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); 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::unique_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) 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: // Check if the data has a proper type:

View File

@ -148,6 +148,7 @@ protected:
cBlockEntity * LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); 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 * 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 * 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 * 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 * 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); cBlockEntity * LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ);