summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Server/Plugins/APIDump/Classes/BlockEntities.lua120
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp92
-rw-r--r--src/BlockEntities/MobSpawnerEntity.h60
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp6
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.cpp48
5 files changed, 240 insertions, 86 deletions
diff --git a/Server/Plugins/APIDump/Classes/BlockEntities.lua b/Server/Plugins/APIDump/Classes/BlockEntities.lua
index b5e4cdf3b..98de99bf4 100644
--- a/Server/Plugins/APIDump/Classes/BlockEntities.lua
+++ b/Server/Plugins/APIDump/Classes/BlockEntities.lua
@@ -1353,7 +1353,7 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
Type = "number",
},
},
- Notes = "Returns the amount of this monster type in a 8-block radius (Y: 4-block radius).",
+ Notes = "Returns the amount of this monster type in a radius defined by SetSpawnRange (Y: 4-block radius).",
},
GetNearbyPlayersNum =
{
@@ -1365,6 +1365,22 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
Notes = "Returns the amount of the nearby players in a 16-block radius.",
},
+ GetSpawnCount =
+ {
+ Returns =
+ {
+ Type = "number",
+ },
+ Notes = "Returns the number of entities the spawner will try to spawn on each activation.",
+ },
+ GetSpawnRange =
+ {
+ Returns =
+ {
+ Type = "number",
+ },
+ Notes = "Returns half the length of the square the spawner tries to spawn entities in.",
+ },
GetSpawnDelay =
{
Returns =
@@ -1375,6 +1391,38 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
Notes = "Returns the spawn delay. This is the tick delay that is needed to spawn new monsters.",
},
+ GetMinSpawnDelay =
+ {
+ Returns =
+ {
+ Type = "number",
+ },
+ Notes = "Returns the minimum number of ticks the spawner waits until spawning new entities automatically.",
+ },
+ GetMaxSpawnDelay =
+ {
+ Returns =
+ {
+ Type = "number",
+ },
+ Notes = "Returns the maximum number of ticks the spawner waits until spawning new entities automatically.",
+ },
+ GetMaxNearbyEntities =
+ {
+ Returns =
+ {
+ Type = "number",
+ },
+ Notes = "Returns the maximum number of entities of the same type that can be present before the spawner cannot spawn more entities.",
+ },
+ GetRequiredPlayerRange =
+ {
+ Returns =
+ {
+ Type = "number"
+ },
+ Notes = "Returns the maximum euclidean distance from a player where the spawner can be activated.",
+ },
ResetTimer =
{
Notes = "Sets the spawn delay to a new random value.",
@@ -1401,13 +1449,79 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
Notes = "Sets the spawn delay.",
},
+ SetSpawnCount =
+ {
+ Params =
+ {
+ {
+ Name = "SpawnCount",
+ Type = "number",
+ },
+ },
+ Notes = "Sets the number of entities the spawner will try to spawn in each activation. Might not spawn all of them due to spawn limitations of the entity.",
+ },
+ SetSpawnRange =
+ {
+ Params =
+ {
+ {
+ Name = "SpawnRange",
+ Type = "number",
+ },
+ },
+ Notes = "Sets half the length of the square the spawner will try to spawn entities in.",
+ },
+ SetMinSpawnDelay =
+ {
+ Params =
+ {
+ {
+ Name = "MinSpawnDelay",
+ Type = "number",
+ },
+ },
+ Notes = "Sets the minimum amount of ticks the spawner will wait before spawning new entities.",
+ },
+ SetMaxSpawnDelay =
+ {
+ Params =
+ {
+ {
+ Name = "MaxSpawnDelay",
+ Type = "number",
+ },
+ },
+ Notes = "Sets the maximum amount of ticks the spawner will wait before spawning new entities.",
+ },
+ SetMaxNearbyEntities =
+ {
+ Params =
+ {
+ {
+ Name = "MaxNearbyEntities",
+ Type = "number",
+ },
+ },
+ Notes = "Sets the maximum amount of nearby entities until the spawner will stop spawning this entity type.",
+ },
+ SetRequiredPlayerRange =
+ {
+ Params =
+ {
+ {
+ Name = "RequiredPlayerRange",
+ Type = "number",
+ },
+ },
+ Notes = "Sets the maximum euclidean distance from a player where the spawner can be activated.",
+ },
SpawnEntity =
{
- Notes = "Spawns the entity. This function automaticly change the spawn delay!",
+ Notes = "Spawns the entity. NOTE: This function resets the delay before the next automatic activation of the spawner.",
},
UpdateActiveState =
{
- Notes = "Upate the active flag from the mob spawner. This function is called every 5 seconds from the Tick() function.",
+ Notes = "Update the active flag from the mob spawner. This function is called every 5 seconds from the Tick() function.",
},
},
Inherits = "cBlockEntity",
diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp
index f5fb5c3ff..8095fc12b 100644
--- a/src/BlockEntities/MobSpawnerEntity.cpp
+++ b/src/BlockEntities/MobSpawnerEntity.cpp
@@ -33,6 +33,12 @@ void cMobSpawnerEntity::CopyFrom(const cBlockEntity & a_Src)
m_Entity = src.m_Entity;
m_IsActive = src.m_IsActive;
m_SpawnDelay = src.m_SpawnDelay;
+ m_SpawnCount = src.m_SpawnCount;
+ m_SpawnRange = src.m_SpawnRange;
+ m_MinSpawnDelay = src.m_MinSpawnDelay;
+ m_MaxSpawnDelay = src.m_MaxSpawnDelay;
+ m_MaxNearbyEntities = src.m_MaxNearbyEntities;
+ m_RequiredPlayerRange = src.m_RequiredPlayerRange;
}
@@ -114,7 +120,7 @@ bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cMobSpawnerEntity::ResetTimer(void)
{
- m_SpawnDelay = GetRandomProvider().RandInt<short>(200, 800);
+ m_SpawnDelay = GetRandomProvider().RandInt<short>(m_MinSpawnDelay, m_MaxSpawnDelay);
m_World->BroadcastBlockEntity(GetPos());
}
@@ -125,7 +131,7 @@ void cMobSpawnerEntity::ResetTimer(void)
void cMobSpawnerEntity::SpawnEntity(void)
{
auto NearbyEntities = GetNearbyMonsterNum(m_Entity);
- if (NearbyEntities >= 6)
+ if (NearbyEntities >= m_MaxNearbyEntities)
{
ResetTimer();
return;
@@ -136,18 +142,18 @@ void cMobSpawnerEntity::SpawnEntity(void)
auto & Random = GetRandomProvider();
bool HaveSpawnedEntity = false;
- for (size_t i = 0; i < 4; i++)
+ for (short I = 0; I < m_SpawnCount; I++)
{
- if (NearbyEntities >= 6)
+ if (NearbyEntities >= m_MaxNearbyEntities)
{
break;
}
auto SpawnRelPos(GetRelPos());
SpawnRelPos += Vector3i(
- static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0),
+ static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * static_cast<double>(m_SpawnRange)),
Random.RandInt(-1, 1),
- static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0)
+ static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * static_cast<double>(m_SpawnRange))
);
auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(SpawnRelPos);
@@ -191,39 +197,24 @@ void cMobSpawnerEntity::SpawnEntity(void)
int cMobSpawnerEntity::GetNearbyPlayersNum(void)
{
- auto SpawnerPos = Vector3d(0.5, 0.5, 0.5) + m_Pos;
int NumPlayers = 0;
- class cCallback : public cChunkDataCallback
+ auto Callback = [&] (cEntity & a_Entity)
{
- public:
- cCallback(Vector3d a_SpawnerPos, int & a_NumPlayers) :
- m_SpawnerPos(a_SpawnerPos),
- m_NumPlayers(a_NumPlayers)
+ if (!a_Entity.IsPlayer())
{
+ return false;
}
-
- virtual void Entity(cEntity * a_Entity) override
+ if ((m_Pos - a_Entity.GetPosition()).Length() <= m_RequiredPlayerRange)
{
- if (!a_Entity->IsPlayer())
- {
- return;
- }
-
- if ((m_SpawnerPos - a_Entity->GetPosition()).Length() <= 16)
- {
- m_NumPlayers++;
- }
+ NumPlayers++;
}
+ return false;
+ };
- protected:
- Vector3d m_SpawnerPos;
- int & m_NumPlayers;
- } Callback(SpawnerPos, NumPlayers);
+ auto PlayerBoundingBox = cBoundingBox(Vector3d(m_Pos.x, m_Pos.y - m_RequiredPlayerRange, m_Pos.z), m_RequiredPlayerRange, m_RequiredPlayerRange * 2);
- int ChunkX = GetChunkX();
- int ChunkZ = GetChunkZ();
- m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback);
+ m_World->ForEachEntityInBox(PlayerBoundingBox, Callback);
return NumPlayers;
}
@@ -234,47 +225,26 @@ int cMobSpawnerEntity::GetNearbyPlayersNum(void)
int cMobSpawnerEntity::GetNearbyMonsterNum(eMonsterType a_EntityType)
{
- auto SpawnerPos = Vector3d(0.5, 0.5, 0.5) + m_Pos;
int NumEntities = 0;
- class cCallback : public cChunkDataCallback
+ auto Callback = [&] (cEntity & a_Entity)
{
- public:
- cCallback(Vector3d a_SpawnerPos, eMonsterType a_CallbackEntityType, int & a_NumEntities) :
- m_SpawnerPos(a_SpawnerPos),
- m_EntityType(a_CallbackEntityType),
- m_NumEntities(a_NumEntities)
+ if (!a_Entity.IsMob())
{
+ return false;
}
- virtual void Entity(cEntity * a_Entity) override
+ auto & Mob = static_cast<cMonster &>(a_Entity);
+ if (Mob.GetMobType() == m_Entity)
{
- if (!a_Entity->IsMob())
- {
- return;
- }
-
- cMonster * Mob = static_cast<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++;
- }
+ NumEntities++;
}
+ return false;
+ };
- protected:
- Vector3d m_SpawnerPos;
- eMonsterType m_EntityType;
- int & m_NumEntities;
- } Callback(SpawnerPos, a_EntityType, NumEntities);
+ auto EntityBoundingBox = cBoundingBox(Vector3d(m_Pos.x, m_Pos.y - 4, m_Pos.z), m_SpawnRange, 8);
- int ChunkX = GetChunkX();
- int ChunkZ = GetChunkZ();
- m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback);
+ m_World->ForEachEntityInBox(EntityBoundingBox, Callback);
return NumEntities;
}
diff --git a/src/BlockEntities/MobSpawnerEntity.h b/src/BlockEntities/MobSpawnerEntity.h
index 0d1991e87..a037343f4 100644
--- a/src/BlockEntities/MobSpawnerEntity.h
+++ b/src/BlockEntities/MobSpawnerEntity.h
@@ -33,46 +33,68 @@ public: // tolua_export
virtual bool UsedBy(cPlayer * a_Player) override;
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ static const char * GetClassStatic(void) { return "cMobSpawnerEntity"; }
// tolua_begin
- /** Upate the active flag from the mob spawner. This function will called every 5 seconds from the Tick() function. */
+ /** Update 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! */
+ /** Spawns the entity. This function automatically 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. */
+ // Getters
+ int GetNearbyMonsterNum(eMonsterType a_EntityType);
int GetNearbyPlayersNum(void);
- /** Returns the amount of this monster type in a 8-block radius (Y: 4-block radius). */
- int GetNearbyMonsterNum(eMonsterType a_EntityType);
+ eMonsterType GetEntity(void) const { return m_Entity; }
+ short GetSpawnCount(void) const { return m_SpawnCount; }
+ short GetSpawnRange(void) const { return m_SpawnRange; }
+ short GetSpawnDelay(void) const { return m_SpawnDelay; }
+ short GetMinSpawnDelay(void) const { return m_MinSpawnDelay; }
+ short GetMaxSpawnDelay(void) const { return m_MaxSpawnDelay; }
+ short GetMaxNearbyEntities(void) const { return m_MaxNearbyEntities; }
+ short GetRequiredPlayerRange(void) const { return m_RequiredPlayerRange; }
+
+ // Setters
+ void SetEntity(eMonsterType a_EntityType) { m_Entity = a_EntityType; }
+ void SetSpawnDelay(short a_Delay) { m_SpawnDelay = a_Delay; }
+ void SetSpawnCount(short a_SpawnCount) { m_SpawnCount = a_SpawnCount; }
+ void SetSpawnRange(short a_SpawnRange) { m_SpawnRange = a_SpawnRange; }
+ void SetMinSpawnDelay(short a_Min) { m_MinSpawnDelay = a_Min; }
+ void SetMaxSpawnDelay(short a_Max) { m_MaxSpawnDelay = a_Max; }
+ void SetMaxNearbyEntities(short a_MaxNearbyEntities) { m_MaxNearbyEntities = a_MaxNearbyEntities; }
+ void SetRequiredPlayerRange(short a_RequiredPlayerRange) { m_RequiredPlayerRange = a_RequiredPlayerRange; }
// tolua_end
- static const char * GetClassStatic(void) { return "cMobSpawnerEntity"; }
-
private:
/** The entity to spawn. */
eMonsterType m_Entity;
+ /** Time in ticks until the next entity spawns */
short m_SpawnDelay;
bool m_IsActive;
+
+ /** Number of entities the spawner tries to spawn each activation. */
+ short m_SpawnCount = 4;
+
+ /** Diameter of the square the new monsters are spawned in */
+ short m_SpawnRange = 8;
+
+ short m_MinSpawnDelay = 200;
+
+ short m_MaxSpawnDelay = 800;
+
+ /** Maximum amount of the same entity type in proximity. */
+ short m_MaxNearbyEntities = 6;
+
+ /** Maximum distance to player for activation */
+ short m_RequiredPlayerRange = 16;
+
} ; // tolua_end
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 70f07557f..f78f7029f 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -547,7 +547,13 @@ public:
mWriter.BeginCompound("");
AddBasicTileEntity(a_MobSpawner, "MobSpawner");
mWriter.AddString("EntityId", cMonster::MobTypeToVanillaName(a_MobSpawner->GetEntity()));
+ mWriter.AddShort("SpawnCount", a_MobSpawner->GetSpawnCount());
+ mWriter.AddShort("SpawnRange", a_MobSpawner->GetSpawnRange());
mWriter.AddShort("Delay", a_MobSpawner->GetSpawnDelay());
+ mWriter.AddShort("MinSpawnDelay", a_MobSpawner->GetMinSpawnDelay());
+ mWriter.AddShort("MaxSpawnDelay", a_MobSpawner->GetMaxSpawnDelay());
+ mWriter.AddShort("MaxNearbyEntities", a_MobSpawner->GetMaxNearbyEntities());
+ mWriter.AddShort("RequiredPlayerRange", a_MobSpawner->GetRequiredPlayerRange());
mWriter.EndCompound();
}
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index f822f9375..03e60bb26 100755
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -1349,13 +1349,55 @@ OwnedBlockEntity cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int
}
}
+ // Load spawn count:
+ int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "SpawnCount");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
+ {
+ MobSpawner->SetSpawnCount(a_NBT.GetShort(CurrentLine));
+ }
+
+ // Load spawn range:
+ CurrentLine = a_NBT.FindChildByName(a_TagIdx, "SpawnRange");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
+ {
+ MobSpawner->SetSpawnRange(a_NBT.GetShort(CurrentLine));
+ }
+
// Load delay:
- int Delay = a_NBT.FindChildByName(a_TagIdx, "Delay");
- if ((Delay >= 0) && (a_NBT.GetType(Delay) == TAG_Short))
+ CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Delay");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
{
- MobSpawner->SetSpawnDelay(a_NBT.GetShort(Delay));
+ MobSpawner->SetSpawnDelay(a_NBT.GetShort(CurrentLine));
}
+ // Load delay range:
+ CurrentLine = a_NBT.FindChildByName(a_TagIdx, "MinSpawnDelay");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
+ {
+ MobSpawner->SetMinSpawnDelay(a_NBT.GetShort(CurrentLine));
+ }
+
+ CurrentLine = a_NBT.FindChildByName(a_TagIdx, "MaxSpawnDelay");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
+ {
+ MobSpawner->SetMaxSpawnDelay(a_NBT.GetShort(CurrentLine));
+ }
+
+ // Load MaxNearbyEntities:
+ CurrentLine = a_NBT.FindChildByName(a_TagIdx, "MaxNearbyEntities");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
+ {
+ MobSpawner->SetMaxNearbyEntities(a_NBT.GetShort(CurrentLine));
+ }
+
+ // Load RequiredPlayerRange:
+ CurrentLine = a_NBT.FindChildByName(a_TagIdx, "RequiredPlayerRange");
+ if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_Short))
+ {
+ MobSpawner->SetRequiredPlayerRange(a_NBT.GetShort(CurrentLine));
+ }
+
+
return MobSpawner;
}