summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2014-12-04 22:04:16 +0100
committerMattes D <github@xoft.cz>2014-12-04 22:04:16 +0100
commitc014f5624c1eda400c08c305978bbcef3f554ff3 (patch)
treefd15deecb2e9afa17443f9b8a8c51676ad6e0145
parentFixed indent. (diff)
parentMerge pull request #1645 from jonfabe/SpectatorModeFixes (diff)
downloadcuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.tar
cuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.tar.gz
cuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.tar.bz2
cuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.tar.lz
cuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.tar.xz
cuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.tar.zst
cuberite-c014f5624c1eda400c08c305978bbcef3f554ff3.zip
-rw-r--r--CONTRIBUTORS1
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua27
-rw-r--r--MCServer/Plugins/APIDump/Classes/BlockEntities.lua37
m---------MCServer/Plugins/Core0
-rw-r--r--MCServer/crafting.txt1
-rw-r--r--MCServer/furnace.txt21
-rw-r--r--Tools/MCADefrag/CMakeLists.txt10
-rw-r--r--Tools/ProtoProxy/CMakeLists.txt10
-rw-r--r--Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro19
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/DeprecatedBindings.cpp38
-rw-r--r--src/BlockEntities/BeaconEntity.cpp19
-rw-r--r--src/BlockEntities/BeaconEntity.h12
-rw-r--r--src/BlockEntities/BlockEntity.cpp4
-rw-r--r--src/BlockEntities/BlockEntity.h7
-rw-r--r--src/BlockEntities/BlockEntityWithItems.h2
-rw-r--r--src/BlockEntities/CMakeLists.txt2
-rw-r--r--src/BlockEntities/ChestEntity.h7
-rw-r--r--src/BlockEntities/CommandBlockEntity.h10
-rw-r--r--src/BlockEntities/DispenserEntity.h2
-rw-r--r--src/BlockEntities/DropSpenserEntity.h6
-rw-r--r--src/BlockEntities/DropperEntity.h2
-rw-r--r--src/BlockEntities/EnderChestEntity.h2
-rw-r--r--src/BlockEntities/FlowerPotEntity.h12
-rw-r--r--src/BlockEntities/FurnaceEntity.h7
-rw-r--r--src/BlockEntities/HopperEntity.h2
-rw-r--r--src/BlockEntities/JukeboxEntity.h11
-rw-r--r--src/BlockEntities/MobHeadEntity.h22
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp290
-rw-r--r--src/BlockEntities/MobSpawnerEntity.h78
-rw-r--r--src/BlockEntities/NoteEntity.h8
-rw-r--r--src/BlockEntities/SignEntity.h11
-rw-r--r--src/BlockID.cpp2
-rw-r--r--src/BlockID.h2
-rw-r--r--src/Blocks/BlockMobSpawner.h12
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/Chunk.cpp17
-rw-r--r--src/ClientHandle.cpp14
-rw-r--r--src/CraftingRecipes.cpp6
-rw-r--r--src/Entities/Minecart.h2
-rw-r--r--src/Entities/Player.cpp17
-rw-r--r--src/FurnaceRecipe.cpp6
-rw-r--r--src/Generating/ChunkGenerator.cpp6
-rw-r--r--src/Generating/CompoGen.cpp14
-rw-r--r--src/Generating/CompoGenBiomal.cpp2
-rw-r--r--src/Generating/ComposableGenerator.cpp4
-rw-r--r--src/Generating/DistortedHeightmap.cpp2
-rw-r--r--src/Generating/DungeonRoomsFinisher.cpp23
-rw-r--r--src/Generating/FinishGen.cpp78
-rw-r--r--src/Generating/FinishGen.h47
-rw-r--r--src/Generating/MineShafts.cpp5
-rw-r--r--src/Generating/Noise3DGenerator.cpp4
-rw-r--r--src/Globals.h5
-rw-r--r--src/MobSpawner.cpp26
-rw-r--r--src/MobSpawner.h7
-rw-r--r--src/Mobs/Monster.cpp124
-rw-r--r--src/Mobs/Monster.h13
-rw-r--r--src/Mobs/MonsterTypes.h10
-rw-r--r--src/Mobs/Pig.cpp8
-rw-r--r--src/Noise/OctavedNoise.h42
-rw-r--r--src/Noise/RidgedNoise.h4
-rw-r--r--src/OSSupport/CMakeLists.txt2
-rw-r--r--src/OSSupport/StackTrace.cpp44
-rw-r--r--src/OSSupport/StackTrace.h15
-rw-r--r--src/Protocol/Protocol17x.cpp14
-rw-r--r--src/Protocol/Protocol18x.cpp13
-rw-r--r--src/Root.cpp2
-rw-r--r--src/Root.h6
-rw-r--r--src/World.cpp8
-rw-r--r--src/World.h3
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp16
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h26
-rw-r--r--src/WorldStorage/WSSAnvil.cpp60
-rw-r--r--src/WorldStorage/WSSAnvil.h1
-rw-r--r--src/main.cpp7
75 files changed, 1070 insertions, 339 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 8620a1475..fffc55b2a 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -10,6 +10,7 @@ Howaner
keyboard
Lapayo
Luksor
+M10360
marmot21
Masy98
mborland
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 9b87781a6..72dcce5e4 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -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." },
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." },
- 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)" },
- 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." },
- 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" },
- 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" },
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:
]],
},
- MobType =
- {
- Include = "mt.*",
- TextBefore = [[
- The following constants are used for distinguishing between the individual mob types:
- ]],
- },
},
Inherits = "cPawn",
}, -- cMonster
@@ -2571,7 +2565,7 @@ World:ForEachEntity(
return;
end
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());
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."},
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"},
- StringToMobType = {Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "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"},
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"},
@@ -3014,6 +3008,13 @@ end
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 =
{
Include = { "^eWeather_.*", "wSunny", "wRain", "wStorm", "wThunderstorm" },
diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
index 90ebf12e6..daa658654 100644
--- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
+++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
@@ -231,6 +231,43 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
}, -- 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 =
{
Desc = [[
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core
-Subproject 4702471943511f641458c7e8e89b430a723f43e
+Subproject 4183d6cfb2049d0757d811a65bd4e75ed78b9f4
diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt
index 8e68d5cb5..4d28b1f52 100644
--- a/MCServer/crafting.txt
+++ b/MCServer/crafting.txt
@@ -75,7 +75,6 @@ Wool = String, 1:1, 1:2, 2:1, 2:2
TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
PillarQuartzBlock = QuartzSlab, 1:1, 1:2
ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
-CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
diff --git a/MCServer/furnace.txt b/MCServer/furnace.txt
index 0c12a798d..7179b5299 100644
--- a/MCServer/furnace.txt
+++ b/MCServer/furnace.txt
@@ -52,7 +52,7 @@ RawBeef = Steak
RawChicken = CookedChicken
Clay = Brick
ClayBlock = HardenedClay
-TallGrass = NetherBrickItem
+Netherrack = NetherBrickItem
RawFish = CookedFish
Log = CharCoal
Cactus = GreenDye
@@ -90,6 +90,25 @@ RawMutton = CookedMutton
! CoalBlock = 16000 # -> 800 sec
! BlazeRod = 2400 # -> 120 sec
! NoteBlock = 300 # -> 15 sec
+! HugeRedMushroom = 300 # -> 15 sec
+! HugeBrownMushroom = 300 # -> 15 sec
+! Banner = 300 # -> 15 sec
+! BlackBanner = 300 # -> 15 sec
+! RedBanner = 300 # -> 15 sec
+! GreenBanner = 300 # -> 15 sec
+! BrownBanner = 300 # -> 15 sec
+! BlueBanner = 300 # -> 15 sec
+! PurpleBanner = 300 # -> 15 sec
+! CyanBanner = 300 # -> 15 sec
+! SilverBanner = 300 # -> 15 sec
+! GrayBanner = 300 # -> 15 sec
+! PinkBanner = 300 # -> 15 sec
+! LimeBanner = 300 # -> 15 sec
+! YellowBanner = 300 # -> 15 sec
+! LightBlueBanner = 300 # -> 15 sec
+! MagentaBanner = 300 # -> 15 sec
+! OrangeBanner = 300 # -> 15 sec
+! WhiteBanner = 300 # -> 15 sec
! DaylightSensor = 300 # -> 15 sec
! FenceGate = 300 # -> 15 sec
! SpruceFenceGate = 300 # -> 15 sec
diff --git a/Tools/MCADefrag/CMakeLists.txt b/Tools/MCADefrag/CMakeLists.txt
index ea345d87c..618719d68 100644
--- a/Tools/MCADefrag/CMakeLists.txt
+++ b/Tools/MCADefrag/CMakeLists.txt
@@ -46,6 +46,7 @@ set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
)
+
flatten_files(SHARED_SRC)
flatten_files(SHARED_HDR)
source_group("Shared" FILES ${SHARED_SRC} ${SHARED_HDR})
@@ -54,13 +55,22 @@ set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/File.cpp
../../src/OSSupport/IsThread.cpp
+ ../../src/OSSupport/StackTrace.cpp
+ ../../src/OSSupport/Timer.cpp
)
set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h
../../src/OSSupport/File.h
../../src/OSSupport/IsThread.h
+ ../../src/OSSupport/StackTrace.h
+ ../../src/OSSupport/Timer.h
)
+if(WIN32)
+ list (APPEND SHARED_OSS_SRC ../../src/StackWalker.cpp)
+ list (APPEND SHARED_OSS_HDR ../../src/StackWalker.h)
+endif()
+
flatten_files(SHARED_OSS_SRC)
flatten_files(SHARED_OSS_HDR)
diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt
index b136a10ba..fc8721da0 100644
--- a/Tools/ProtoProxy/CMakeLists.txt
+++ b/Tools/ProtoProxy/CMakeLists.txt
@@ -57,12 +57,22 @@ set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/File.cpp
../../src/OSSupport/IsThread.cpp
+ ../../src/OSSupport/StackTrace.cpp
+ ../../src/OSSupport/Timer.cpp
)
set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h
../../src/OSSupport/File.h
../../src/OSSupport/IsThread.h
+ ../../src/OSSupport/StackTrace.h
+ ../../src/OSSupport/Timer.h
)
+
+if(WIN32)
+ list (APPEND SHARED_OSS_SRC ../../src/StackWalker.cpp)
+ list (APPEND SHARED_OSS_HDR ../../src/StackWalker.h)
+endif()
+
flatten_files(SHARED_SRC)
flatten_files(SHARED_HDR)
flatten_files(SHARED_OSS_SRC)
diff --git a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
index 9522491a8..cccee1305 100644
--- a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
+++ b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
@@ -17,7 +17,7 @@ SOURCES += \
BiomeView.cpp \
../../src/Generating/BioGen.cpp \
../../src/VoronoiMap.cpp \
- ../../src/Noise.cpp \
+ ../../src/Noise/Noise.cpp \
../../src/StringUtils.cpp \
../../src/LoggerListeners.cpp \
../../src/Logger.cpp \
@@ -25,7 +25,9 @@ SOURCES += \
../../src/OSSupport/File.cpp \
../../src/OSSupport/CriticalSection.cpp \
../../src/OSSupport/IsThread.cpp \
+ ../../src/OSSupport/StackTrace.cpp \
../../src/BiomeDef.cpp \
+ ../../src/StackWalker.cpp \
../../src/StringCompression.cpp \
../../src/WorldStorage/FastNBT.cpp \
../../lib/zlib/adler32.c \
@@ -62,7 +64,7 @@ HEADERS += \
../../src/Generating/IntGen.h \
../../src/Generating/ProtIntGen.h \
../../src/VoronoiMap.h \
- ../../src/Noise.h \
+ ../../src/Noise/Noise.h \
../../src/StringUtils.h \
../../src/LoggerListeners.h \
../../src/Logger.h \
@@ -70,7 +72,9 @@ HEADERS += \
../../src/OSSupport/File.h \
../../src/OSSupport/CriticalSection.h \
../../src/OSSupport/IsThread.h \
+ ../../src/OSSupport/StackTrace.h \
../../src/BiomeDef.h \
+ ../../src/StackWalker.h \
../../src/StringCompression.h \
../../src/WorldStorage/FastNBT.h \
../../lib/zlib/crc32.h \
@@ -107,4 +111,15 @@ CONFIG += C++11
OTHER_FILES +=
+win* {
+ # Add the advapi32 library for windows compiles; needed for the StackWalker:
+ LIBS += advapi32.lib
+
+ # StackWalker doesn't like how Qt inconsistently defines only UNICODE, but not _UNICODE:
+ DEFINES -= UNICODE
+}
+
+
+
+
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 7b78578ee..7e174e770 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -74,6 +74,7 @@ $cfile "../BlockEntities/JukeboxEntity.h"
$cfile "../BlockEntities/NoteEntity.h"
$cfile "../BlockEntities/SignEntity.h"
$cfile "../BlockEntities/MobHeadEntity.h"
+$cfile "../BlockEntities/MobSpawnerEntity.h"
$cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h"
$cfile "../Root.h"
diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp
index 345ab2a07..95cd9c4f7 100644
--- a/src/Bindings/DeprecatedBindings.cpp
+++ b/src/Bindings/DeprecatedBindings.cpp
@@ -225,6 +225,42 @@ static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
+/* function: StringToMobType */
+static int tolua_AllToLua_StringToMobType00(lua_State* tolua_S)
+{
+ cLuaState LuaState(tolua_S);
+
+ #ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_iscppstring(tolua_S, 1, 0, &tolua_err) ||
+ !tolua_isnoobj(tolua_S, 2, &tolua_err)
+ )
+ goto tolua_lerror;
+ else
+ #endif
+ {
+ const AString a_MobString = tolua_tocppstring(LuaState, 1, 0);
+ eMonsterType MobType = cMonster::StringToMobType(a_MobString);
+ tolua_pushnumber(LuaState, (lua_Number) MobType);
+ tolua_pushcppstring(LuaState, (const char *) a_MobString);
+ }
+
+ LOGWARNING("Warning in function call 'StringToMobType': StringToMobType() is deprecated. Please use cMonster:StringToMobType()");
+ LuaState.LogStackTrace(0);
+ return 2;
+
+ #ifndef TOLUA_RELEASE
+tolua_lerror:
+ tolua_error(LuaState, "#ferror in function 'StringToMobType'.", &tolua_err);
+ return 0;
+ #endif
+}
+
+
+
+
+
/** function: cWorld:SetSignLines */
static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
{
@@ -296,6 +332,8 @@ void DeprecatedBindings::Bind(lua_State * tolua_S)
tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, nullptr);
tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, nullptr);
+ tolua_function(tolua_S, "StringToMobType", tolua_AllToLua_StringToMobType00);
+
tolua_beginmodule(tolua_S, "cWorld");
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
tolua_endmodule(tolua_S);
diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp
index 85819446c..409f2937c 100644
--- a/src/BlockEntities/BeaconEntity.cpp
+++ b/src/BlockEntities/BeaconEntity.cpp
@@ -247,15 +247,16 @@ void cBeaconEntity::GiveEffects(void)
}
public:
- cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel)
- : m_Radius(a_Radius)
- , m_PosX(a_PosX)
- , m_PosY(a_PosY)
- , m_PosZ(a_PosZ)
- , m_PrimaryEffect(a_PrimaryEffect)
- , m_SecondaryEffect(a_SecondaryEffect)
- , m_EffectLevel(a_EffectLevel)
- {};
+ cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel):
+ m_Radius(a_Radius),
+ m_PosX(a_PosX),
+ m_PosY(a_PosY),
+ m_PosZ(a_PosZ),
+ m_PrimaryEffect(a_PrimaryEffect),
+ m_SecondaryEffect(a_SecondaryEffect),
+ m_EffectLevel(a_EffectLevel)
+ {
+ }
} PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryEffect, SecondaryEffect, EffectLevel);
GetWorld()->ForEachPlayer(PlayerCallback);
diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h
index d1db3a68f..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
@@ -32,7 +24,7 @@ class cBeaconEntity :
public:
// tolua_end
- BLOCKENTITY_PROTODEF(cBeaconEntity);
+ BLOCKENTITY_PROTODEF(cBeaconEntity)
cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index 3d96e891e..c59198e79 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"
@@ -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_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_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/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h
index 8c7d4749b..2c2ced1cb 100644
--- a/src/BlockEntities/BlockEntityWithItems.h
+++ b/src/BlockEntities/BlockEntityWithItems.h
@@ -29,7 +29,7 @@ class cBlockEntityWithItems :
public:
// tolua_end
- BLOCKENTITY_PROTODEF(cBlockEntityWithItems);
+ BLOCKENTITY_PROTODEF(cBlockEntityWithItems)
cBlockEntityWithItems(
BLOCKTYPE a_BlockType, // Type of the block that the entity represents
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 09fffb923..645dbf4bc 100644
--- a/src/BlockEntities/ChestEntity.h
+++ b/src/BlockEntities/ChestEntity.h
@@ -7,11 +7,6 @@
-namespace Json
-{
- class Value;
-};
-
class cClientHandle;
@@ -33,7 +28,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cChestEntity);
+ BLOCKENTITY_PROTODEF(cChestEntity)
/** Constructor used for normal operation */
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type);
diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h
index 217390293..d8ac054f0 100644
--- a/src/BlockEntities/CommandBlockEntity.h
+++ b/src/BlockEntities/CommandBlockEntity.h
@@ -15,14 +15,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
// tolua_begin
@@ -36,7 +28,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cCommandBlockEntity);
+ BLOCKENTITY_PROTODEF(cCommandBlockEntity)
/// Creates a new empty command block entity
cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h
index 5ba87b716..12e12942a 100644
--- a/src/BlockEntities/DispenserEntity.h
+++ b/src/BlockEntities/DispenserEntity.h
@@ -17,7 +17,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cDispenserEntity);
+ BLOCKENTITY_PROTODEF(cDispenserEntity)
/** Constructor used for normal operation */
cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h
index f77a28c28..6c23a402f 100644
--- a/src/BlockEntities/DropSpenserEntity.h
+++ b/src/BlockEntities/DropSpenserEntity.h
@@ -16,10 +16,6 @@
-namespace Json
-{
- class Value;
-}
class cClientHandle;
@@ -45,7 +41,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cDropSpenserEntity);
+ BLOCKENTITY_PROTODEF(cDropSpenserEntity)
cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cDropSpenserEntity();
diff --git a/src/BlockEntities/DropperEntity.h b/src/BlockEntities/DropperEntity.h
index 91adf660f..c638dafa8 100644
--- a/src/BlockEntities/DropperEntity.h
+++ b/src/BlockEntities/DropperEntity.h
@@ -25,7 +25,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cDropperEntity);
+ BLOCKENTITY_PROTODEF(cDropperEntity)
/// Constructor used for normal operation
cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
diff --git a/src/BlockEntities/EnderChestEntity.h b/src/BlockEntities/EnderChestEntity.h
index 17abd880a..af59cf170 100644
--- a/src/BlockEntities/EnderChestEntity.h
+++ b/src/BlockEntities/EnderChestEntity.h
@@ -18,7 +18,7 @@ class cEnderChestEntity :
public:
// tolua_end
- BLOCKENTITY_PROTODEF(cEnderChestEntity);
+ BLOCKENTITY_PROTODEF(cEnderChestEntity)
cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cEnderChestEntity();
diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h
index fc886c51f..a4246bb7d 100644
--- a/src/BlockEntities/FlowerPotEntity.h
+++ b/src/BlockEntities/FlowerPotEntity.h
@@ -15,16 +15,6 @@
-
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cFlowerPotEntity :
@@ -36,7 +26,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cFlowerPotEntity);
+ BLOCKENTITY_PROTODEF(cFlowerPotEntity)
/** Creates a new flowerpot entity at the specified block coords. a_World may be nullptr */
cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World);
diff --git a/src/BlockEntities/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h
index 71c2fe127..fbe9d6c75 100644
--- a/src/BlockEntities/FurnaceEntity.h
+++ b/src/BlockEntities/FurnaceEntity.h
@@ -8,11 +8,6 @@
-namespace Json
-{
- class Value;
-}
-
class cClientHandle;
@@ -38,7 +33,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cFurnaceEntity);
+ BLOCKENTITY_PROTODEF(cFurnaceEntity)
/** Constructor used for normal operation */
cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World);
diff --git a/src/BlockEntities/HopperEntity.h b/src/BlockEntities/HopperEntity.h
index 7070bbad3..da65aa671 100644
--- a/src/BlockEntities/HopperEntity.h
+++ b/src/BlockEntities/HopperEntity.h
@@ -31,7 +31,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cHopperEntity);
+ BLOCKENTITY_PROTODEF(cHopperEntity)
/// Constructor used for normal operation
cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
diff --git a/src/BlockEntities/JukeboxEntity.h b/src/BlockEntities/JukeboxEntity.h
index 7a69d6499..000f7d87e 100644
--- a/src/BlockEntities/JukeboxEntity.h
+++ b/src/BlockEntities/JukeboxEntity.h
@@ -7,15 +7,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cJukeboxEntity :
@@ -26,7 +17,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cJukeboxEntity);
+ BLOCKENTITY_PROTODEF(cJukeboxEntity)
cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cJukeboxEntity();
diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h
index 7132ef558..7f08c5ab2 100644
--- a/src/BlockEntities/MobHeadEntity.h
+++ b/src/BlockEntities/MobHeadEntity.h
@@ -14,14 +14,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
// tolua_begin
@@ -34,29 +26,29 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cMobHeadEntity);
+ BLOCKENTITY_PROTODEF(cMobHeadEntity)
/** Creates a new mob head entity at the specified block coords. a_World may be nullptr */
cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
// tolua_begin
- /** Set the Type */
+ /** Set the type of the mob head */
void SetType(const eMobHeadType & a_SkullType);
- /** Set the Rotation */
+ /** Set the rotation of the mob head */
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);
- /** Get the Type */
+ /** Returns the type of the mob head */
eMobHeadType GetType(void) const { return m_Type; }
- /** Get the Rotation */
+ /** Returns the rotation of the mob head */
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; }
// tolua_end
diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp
new file mode 100644
index 000000000..5edee888a
--- /dev/null
+++ b/src/BlockEntities/MobSpawnerEntity.cpp
@@ -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;
+}
+
+
+
+
diff --git a/src/BlockEntities/MobSpawnerEntity.h b/src/BlockEntities/MobSpawnerEntity.h
new file mode 100644
index 000000000..594b5301e
--- /dev/null
+++ b/src/BlockEntities/MobSpawnerEntity.h
@@ -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
+
+
+
+
diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h
index fc5f27d07..d3f85e9d2 100644
--- a/src/BlockEntities/NoteEntity.h
+++ b/src/BlockEntities/NoteEntity.h
@@ -5,12 +5,6 @@
#include "RedstonePoweredEntity.h"
-namespace Json
-{
- class Value;
-}
-
-
@@ -40,7 +34,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cNoteEntity);
+ BLOCKENTITY_PROTODEF(cNoteEntity)
/// Creates a new note entity. a_World may be nullptr
cNoteEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
diff --git a/src/BlockEntities/SignEntity.h b/src/BlockEntities/SignEntity.h
index 52baa486d..9480537ed 100644
--- a/src/BlockEntities/SignEntity.h
+++ b/src/BlockEntities/SignEntity.h
@@ -14,15 +14,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cSignEntity :
@@ -34,7 +25,7 @@ public:
// tolua_end
- BLOCKENTITY_PROTODEF(cSignEntity);
+ BLOCKENTITY_PROTODEF(cSignEntity)
/// Creates a new empty sign entity at the specified block coords and block type (wall or standing). a_World may be nullptr
cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World);
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index c98e0cad1..06f4232d3 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -200,7 +200,7 @@ public:
-BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString)
+int BlockStringToType(const AString & a_BlockTypeString)
{
int res = atoi(a_BlockTypeString.c_str());
if ((res != 0) || (a_BlockTypeString.compare("0") == 0))
diff --git a/src/BlockID.h b/src/BlockID.h
index 24de2dc8a..8f2cee02e 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -1096,7 +1096,7 @@ class cIniFile;
// tolua_begin
/// Translates a blocktype string into blocktype. Takes either a number or an items.ini alias as input. Returns -1 on failure.
-extern BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString);
+extern int BlockStringToType(const AString & a_BlockTypeString);
/// Translates an itemtype string into an item. Takes either a number, number^number, number:number or an items.ini alias as input. Returns true if successful.
extern bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item);
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/CMakeLists.txt b/src/CMakeLists.txt
index 7ba7e9469..997326cc7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -104,7 +104,6 @@ SET (HDRS
Inventory.h
Item.h
ItemGrid.h
- LeakFinder.h
LightingThread.h
LineBlockTracer.h
LinearInterpolation.h
@@ -114,7 +113,6 @@ SET (HDRS
Map.h
MapManager.h
Matrix4.h
- MemoryLeak.h
MobCensus.h
MobFamilyCollecter.h
MobProximityCounter.h
@@ -127,7 +125,6 @@ SET (HDRS
Scoreboard.h
Server.h
SetChunkData.h
- StackWalker.h
Statistics.h
StringCompression.h
StringUtils.h
@@ -175,6 +172,10 @@ if (NOT MSVC)
else ()
# MSVC-specific handling: Put all files into one project, separate by the folders:
+ # Add the MSVC-specific LeakFinder sources:
+ list (APPEND SRCS LeakFinder.cpp StackWalker.cpp)
+ list (APPEND HDRS LeakFinder.h StackWalker.h MemoryLeak.h)
+
source_group(Bindings FILES "Bindings/Bindings.cpp" "Bindings/Bindings.h")
# Add all subfolders as solution-folders:
@@ -224,7 +225,7 @@ else ()
Bindings/Bindings.cpp PROPERTIES COMPILE_FLAGS "/Yc\"string.h\" /Fp\"$(IntDir)/Bindings.pch\""
)
SET_SOURCE_FILES_PROPERTIES(
- "StackWalker.cpp LeakFinder.h" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
+ "StackWalker.cpp LeakFinder.cpp" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
)
list(APPEND SOURCE "Resources/MCServer.rc")
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index a43a95a2b..017ceda26 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"
@@ -1347,6 +1348,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))
{
@@ -1478,6 +1480,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;
@@ -1868,18 +1871,18 @@ bool cChunk::AddClient(cClientHandle * a_Client)
void cChunk::RemoveClient(cClientHandle * a_Client)
{
- for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
+ for (cClientHandleList::iterator itrC = m_LoadedByClient.begin(); itrC != m_LoadedByClient.end(); ++itrC)
{
- if (*itr != a_Client)
+ if (*itrC != a_Client)
{
continue;
}
- m_LoadedByClient.erase(itr);
+ m_LoadedByClient.erase(itrC);
if (!a_Client->IsDestroyed())
{
- for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
+ for (cEntityList::iterator itrE = m_Entities.begin(); itrE != m_Entities.end(); ++itrE)
{
/*
// DEBUG:
@@ -1888,7 +1891,7 @@ void cChunk::RemoveClient(cClientHandle * a_Client)
(*itr)->GetUniqueID(), a_Client->GetUsername().c_str()
);
*/
- a_Client->SendDestroyEntity(*(*itr));
+ a_Client->SendDestroyEntity(*(*itrE));
}
}
return;
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 33a88d07f..a8e6107e7 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1220,12 +1220,18 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
{
// TODO: Rewrite this function
- LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
- a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
+ // Distance from the block's center to the player's eye height
+ double dist = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length();
+ LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s; dist: %.02f",
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str(), dist
);
-
+
+ // Check the reach distance:
+ // _X 2014-11-25: I've maxed at 5.26 with a Survival client and 5.78 with a Creative client in my tests
+ double maxDist = m_Player->IsGameModeCreative() ? 5.78 : 5.26;
+ bool AreRealCoords = (dist <= maxDist);
+
cWorld * World = m_Player->GetWorld();
- bool AreRealCoords = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) - m_Player->GetPosition()).Length() <= 5;
if (
(a_BlockFace != BLOCK_FACE_NONE) && // The client is interacting with a specific block
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index 64fb21181..2c2b02a69 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -289,7 +289,7 @@ void cCraftingRecipes::GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingG
}
// Built-in recipes:
- std::auto_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid.GetItems(), a_CraftingGrid.GetWidth(), a_CraftingGrid.GetHeight()));
+ std::unique_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid.GetItems(), a_CraftingGrid.GetWidth(), a_CraftingGrid.GetHeight()));
a_Recipe.Clear();
if (Recipe.get() == nullptr)
{
@@ -377,7 +377,7 @@ void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine
return;
}
- std::auto_ptr<cCraftingRecipes::cRecipe> Recipe(new cCraftingRecipes::cRecipe);
+ std::unique_ptr<cCraftingRecipes::cRecipe> Recipe(new cCraftingRecipes::cRecipe);
// Parse the result:
AStringVector ResultSplit = StringSplit(Sides[0], ",");
@@ -758,7 +758,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
} // for y, for x
// The recipe has matched. Create a copy of the recipe and set its coords to match the crafting grid:
- std::auto_ptr<cRecipe> Recipe(new cRecipe);
+ std::unique_ptr<cRecipe> Recipe(new cRecipe);
Recipe->m_Result = a_Recipe->m_Result;
Recipe->m_Width = a_Recipe->m_Width;
Recipe->m_Height = a_Recipe->m_Height;
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 40e22c641..f7d0d5dda 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -128,7 +128,7 @@ public:
};
const cItem & GetSlot(int a_Idx) const { return m_Contents.GetSlot(a_Idx); }
- void SetSlot(size_t a_Idx, const cItem & a_Item) { m_Contents.SetSlot(a_Idx, a_Item); }
+ void SetSlot(size_t a_Idx, const cItem & a_Item) { m_Contents.SetSlot(static_cast<int>(a_Idx), a_Item); }
protected:
cItemGrid m_Contents;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 87f57989b..8d2eb1e5f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -117,6 +117,11 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) :
{
m_CanFly = true;
}
+ if (World->IsGameModeSpectator()) // Otherwise Player will fall out of the world on join
+ {
+ m_CanFly = true;
+ m_IsFlying = true;
+ }
}
cRoot::Get()->GetServer()->PlayerCreated(this);
@@ -1068,7 +1073,7 @@ bool cPlayer::IsGameModeAdventure(void) const
bool cPlayer::IsGameModeSpectator(void) const
{
return (m_GameMode == gmSpectator) || // Either the player is explicitly in Spectator
- ((m_GameMode == gmNotSet) && m_World->IsGameModeSpectator()); // or they inherit from the world and the world is Adventure
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeSpectator()); // or they inherit from the world and the world is Spectator
}
@@ -1887,8 +1892,8 @@ void cPlayer::UseEquippedItem(int a_Amount)
void cPlayer::TickBurning(cChunk & a_Chunk)
{
- // Don't burn in creative and stop burning in creative if necessary
- if (!IsGameModeCreative())
+ // Don't burn in creative or spectator and stop burning in creative if necessary
+ if (!IsGameModeCreative() && !IsGameModeSpectator())
{
super::TickBurning(a_Chunk);
}
@@ -1907,9 +1912,9 @@ void cPlayer::HandleFood(void)
{
// Ref.: http://www.minecraftwiki.net/wiki/Hunger
- if (IsGameModeCreative())
+ if (IsGameModeCreative() || IsGameModeSpectator())
{
- // Hunger is disabled for Creative
+ // Hunger is disabled for Creative and Spectator
return;
}
@@ -2074,7 +2079,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
void cPlayer::ApplyFoodExhaustionFromMovement()
{
- if (IsGameModeCreative())
+ if (IsGameModeCreative() || IsGameModeSpectator())
{
return;
}
diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp
index 9b3b2ecbe..112aa8146 100644
--- a/src/FurnaceRecipe.cpp
+++ b/src/FurnaceRecipe.cpp
@@ -115,7 +115,7 @@ void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, unsigned int a_Line
Line.erase(Line.begin()); // Remove the beginning "!"
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
- std::auto_ptr<cItem> Item(new cItem);
+ std::unique_ptr<cItem> Item(new cItem);
int BurnTime;
const AStringVector & Sides = StringSplit(Line, "=");
@@ -157,8 +157,8 @@ void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, unsigned int a_Li
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
int CookTime = 200;
- std::auto_ptr<cItem> InputItem(new cItem());
- std::auto_ptr<cItem> OutputItem(new cItem());
+ std::unique_ptr<cItem> InputItem(new cItem());
+ std::unique_ptr<cItem> OutputItem(new cItem());
const AStringVector & Sides = StringSplit(Line, "=");
if (Sides.size() != 2)
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index 16e003274..d2e7b47b4 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -191,13 +191,13 @@ EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default)
{
AString BlockType = a_IniFile.GetValueSet(a_SectionName, a_ValueName, a_Default);
- BLOCKTYPE Block = BlockStringToType(BlockType);
+ int Block = BlockStringToType(BlockType);
if (Block < 0)
{
LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(), a_Default.c_str());
- return BlockStringToType(a_Default);
+ return static_cast<BLOCKTYPE>(BlockStringToType(a_Default));
}
- return Block;
+ return static_cast<BLOCKTYPE>(Block);
}
diff --git a/src/Generating/CompoGen.cpp b/src/Generating/CompoGen.cpp
index 23cc64d78..cb9c04fd7 100644
--- a/src/Generating/CompoGen.cpp
+++ b/src/Generating/CompoGen.cpp
@@ -290,17 +290,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc:
BLOCKTYPE Block = E_BLOCK_AIR;
if (Val < m_Threshold) // Don't calculate if the block should be Netherrack or Soulsand when it's already decided that it's air.
{
- NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(BaseX + x)) / 8;
- NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(BaseZ + z)) / 8;
- NOISE_DATATYPE CompBlock = m_Noise1.CubicNoise3D(NoiseX, (float) (y + Segment) / 2, NoiseY);
- if (CompBlock < -0.5)
- {
- Block = E_BLOCK_SOULSAND;
- }
- else
- {
- Block = E_BLOCK_NETHERRACK;
- }
+ Block = E_BLOCK_NETHERRACK;
}
a_ChunkDesc.SetBlockType(x, y + Segment, z, Block);
}
@@ -324,7 +314,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc:
CeilingDisguise = -CeilingDisguise;
}
- int CeilingDisguiseHeight = Height - 2 - (int)CeilingDisguise * 3;
+ int CeilingDisguiseHeight = Height - 2 - FloorC(CeilingDisguise * 3);
for (int y = Height - 1; y > CeilingDisguiseHeight; y--)
{
diff --git a/src/Generating/CompoGenBiomal.cpp b/src/Generating/CompoGenBiomal.cpp
index 995851c95..030c2baa5 100644
--- a/src/Generating/CompoGenBiomal.cpp
+++ b/src/Generating/CompoGenBiomal.cpp
@@ -39,7 +39,7 @@ public:
// Fill the rest with stone:
static BlockInfo Stone = {E_BLOCK_STONE, 0};
- for (size_t i = a_Count; i < cChunkDef::Height; i++)
+ for (int i = static_cast<int>(a_Count); i < cChunkDef::Height; i++)
{
m_Pattern[i] = Stone;
}
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 4192dfa72..6b8923955 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -570,6 +570,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
GridSize, MaxOffset
)));
}
+ else if (NoCaseCompare(*itr, "SoulsandRims") == 0)
+ {
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSoulsandRims(Seed)));
+ }
else if (NoCaseCompare(*itr, "Snow") == 0)
{
m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSnow));
diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp
index e1ed9b450..37a51c18e 100644
--- a/src/Generating/DistortedHeightmap.cpp
+++ b/src/Generating/DistortedHeightmap.cpp
@@ -122,6 +122,8 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
m_NoiseDistortX(a_Seed + 1000),
m_NoiseDistortZ(a_Seed + 2000),
+ m_CurChunkX(0x7fffffff), // Set impossible coords for the chunk so that it's always considered stale
+ m_CurChunkZ(0x7fffffff),
m_BiomeGen(a_BiomeGen),
m_UnderlyingHeiGen(new cHeiGenBiomal(a_Seed, a_BiomeGen)),
m_HeightGen(m_UnderlyingHeiGen, 64),
diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp
index 7ab22c2c5..092e232ab 100644
--- a/src/Generating/DungeonRoomsFinisher.cpp
+++ b/src/Generating/DungeonRoomsFinisher.cpp
@@ -7,6 +7,7 @@
#include "DungeonRoomsFinisher.h"
#include "../FastRandom.h"
#include "../BlockEntities/ChestEntity.h"
+#include "../BlockEntities/MobSpawnerEntity.h"
@@ -57,6 +58,22 @@ public:
int SecondChestPos = (FirstChestPos + 2 + (rnd % (NumPositions - 3))) % NumPositions;
m_Chest1 = DecodeChestCoords(FirstChestPos, SizeX, SizeZ);
m_Chest2 = DecodeChestCoords(SecondChestPos, SizeX, SizeZ);
+
+ // Choose what the mobspawner will spawn.
+ // 25% chance for a spider, 25% for a skeleton and 50% chance to get a zombie spawer.
+ int MobType = (a_Noise.IntNoise3DInt(a_OriginX, m_FloorHeight, a_OriginZ) / 7) % 100;
+ if (MobType <= 25)
+ {
+ m_MonsterType = mtSkeleton;
+ }
+ else if (MobType <= 50)
+ {
+ m_MonsterType = mtSpider;
+ }
+ else
+ {
+ m_MonsterType = mtZombie;
+ }
}
protected:
@@ -76,6 +93,8 @@ protected:
/** The (absolute) coords of the second chest. The Y coord represents the chest's Meta value (facing). */
Vector3i m_Chest2;
+ /** The monster type for the mobspawner entity. */
+ eMonsterType m_MonsterType;
/** Decodes the position index along the room walls into a proper 2D position for a chest.
@@ -246,7 +265,9 @@ protected:
)
{
a_ChunkDesc.SetBlockTypeMeta(CenterX, b, CenterZ, E_BLOCK_MOB_SPAWNER, 0);
- // TODO: Set the spawned mob
+ cMobSpawnerEntity * MobSpawner = static_cast<cMobSpawnerEntity *>(a_ChunkDesc.GetBlockEntity(CenterX, b, CenterZ));
+ ASSERT((MobSpawner != nullptr) && (MobSpawner->GetBlockType() == E_BLOCK_MOB_SPAWNER));
+ MobSpawner->SetEntity(m_MonsterType);
}
}
} ;
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 2ff3e7f67..9e035926e 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -65,7 +65,7 @@ void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
{
continue;
}
-
+
// Choose what block to use.
NOISE_DATATYPE BlockType = m_Noise.IntNoise3D((int) ChunkX, y, (int) ChunkZ);
if (BlockType < -0.7)
@@ -195,10 +195,10 @@ void cFinishGenTallGrass::GenFinish(cChunkDesc & a_ChunkDesc)
{
continue;
}
-
+
// Get the top block + 1. This is the place where the grass would finaly be placed:
int y = a_ChunkDesc.GetHeight(x, z) + 1;
-
+
if (y >= 255)
{
continue;
@@ -281,7 +281,7 @@ bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_
{
return false;
}
-
+
// All conditions met, place a sugarcane here:
a_ChunkDesc.SetBlockType(a_RelX, a_RelY + 1, a_RelZ, E_BLOCK_SUGARCANE);
return true;
@@ -294,7 +294,7 @@ bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_
void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
{
// Generate small foliage (1-block):
-
+
// TODO: Update heightmap with 1-block-tall foliage
for (int z = 0; z < cChunkDef::Width; z++)
{
@@ -319,7 +319,7 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
// WEIRD, since we're using heightmap, so there should NOT be anything above it
continue;
}
-
+
const float xx = (float)BlockX;
float val1 = m_Noise.CubicNoise2D(xx * 0.1f, zz * 0.1f);
float val2 = m_Noise.CubicNoise2D(xx * 0.01f, zz * 0.01f);
@@ -359,7 +359,7 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
}
break;
} // case E_BLOCK_GRASS
-
+
case E_BLOCK_SAND:
{
int y = Top + 1;
@@ -392,6 +392,58 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
////////////////////////////////////////////////////////////////////////////////
+// cFinishGenSoulsandRims
+
+void cFinishGenSoulsandRims::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int ChunkX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int ChunkZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight();
+
+ for (int x = 0; x < 16; x++)
+ {
+ int xx = ChunkX + x;
+ for (int z = 0; z < 16; z++)
+ {
+ int zz = ChunkZ + z;
+
+ // Place soulsand rims when netherrack gets thin
+ for (int y = 2; y < MaxHeight - 2; y++)
+ {
+ // The current block is air. Let's bail ut.
+ BLOCKTYPE Block = a_ChunkDesc.GetBlockType(x, y, z);
+ if (Block == E_BLOCK_AIR)
+ {
+ continue;
+ }
+
+ if (
+ ((a_ChunkDesc.GetBlockType(x, y + 1, z) != E_BLOCK_AIR) &&
+ ( a_ChunkDesc.GetBlockType(x, y + 2, z) != E_BLOCK_AIR)) ||
+ ((a_ChunkDesc.GetBlockType(x, y - 1, z) != E_BLOCK_AIR) &&
+ ( a_ChunkDesc.GetBlockType(x, y - 2, z) != E_BLOCK_AIR))
+ )
+ {
+ continue;
+ }
+
+ NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(xx)) / 32;
+ NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(zz)) / 32;
+ NOISE_DATATYPE CompBlock = m_Noise.CubicNoise3D(NoiseX, (float) (y) / 4, NoiseY);
+ if (CompBlock < 0)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_SOULSAND);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// cFinishGenSnow:
void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
@@ -516,7 +568,7 @@ void cFinishGenSingleTopBlock::GenFinish(cChunkDesc & a_ChunkDesc)
}
int Height = a_ChunkDesc.GetHeight(x, z);
- if (Height >= cChunkDef::Height)
+ if (Height >= cChunkDef::Height - 1)
{
// Too high up
continue;
@@ -716,7 +768,7 @@ void cFinishGenPreSimulator::StationarizeFluid(
} // for y
} // for x
} // for z
-
+
// Turn fluid at the chunk edges into non-stationary fluid:
for (int y = 0; y < cChunkDef::Height; y++)
{
@@ -808,12 +860,12 @@ void cFinishGenFluidSprings::GenFinish(cChunkDesc & a_ChunkDesc)
// Not in this chunk
return;
}
-
+
// Get the height at which to try:
int Height = m_Noise.IntNoise3DInt(128 * a_ChunkDesc.GetChunkX(), 1024, 256 * a_ChunkDesc.GetChunkZ()) / 11;
Height %= m_HeightDistribution.GetSum();
Height = m_HeightDistribution.MapValue(Height);
-
+
// Try adding the spring at the height, if unsuccessful, move lower:
for (int y = Height; y > 1; y--)
{
@@ -851,7 +903,7 @@ bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int
{
return false;
}
-
+
static const struct
{
int x, y, z;
@@ -882,7 +934,7 @@ bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int
{
return false;
}
-
+
// Has exactly one air neighbor, place a spring:
a_ChunkDesc.SetBlockTypeMeta(x, y, z, m_Fluid, 0);
return true;
diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h
index 991a85787..c1100b51f 100644
--- a/src/Generating/FinishGen.h
+++ b/src/Generating/FinishGen.h
@@ -117,19 +117,38 @@ protected:
+class cFinishGenSoulsandRims :
+ public cFinishGen
+{
+public:
+ cFinishGenSoulsandRims(int a_Seed) :
+ m_Noise(a_Seed)
+ {
+ }
+
+protected:
+ cNoise m_Noise;
+
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+} ;
+
+
+
+
+
class cFinishGenSprinkleFoliage :
public cFinishGen
{
public:
cFinishGenSprinkleFoliage(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {}
-
+
protected:
cNoise m_Noise;
int m_Seed;
-
+
/// Tries to place sugarcane at the coords specified, returns true if successful
bool TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ);
-
+
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -167,31 +186,31 @@ public:
{
m_IsAllowedBelow[idx] = false;
}
-
+
// Load the allowed blocks into m_IsAllowedBelow
for (BlockList::iterator itr = a_AllowedBelow.begin(); itr != a_AllowedBelow.end(); ++itr)
{
m_IsAllowedBelow[*itr] = true;
}
-
+
// Initialize all the biome types.
for (size_t idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx)
{
m_IsBiomeAllowed[idx] = false;
}
-
+
// Load the allowed biomes into m_IsBiomeAllowed
for (BiomeList::iterator itr = a_Biomes.begin(); itr != a_Biomes.end(); ++itr)
{
m_IsBiomeAllowed[*itr] = true;
}
}
-
+
protected:
cNoise m_Noise;
BLOCKTYPE m_BlockType;
int m_Amount; ///< Relative amount of blocks to try adding. 1 = one block per 256 biome columns.
-
+
int GetNumToGen(const cChunkDef::BiomeMap & a_BiomeMap);
// Returns true if the given biome is a biome that is allowed.
@@ -206,7 +225,7 @@ protected:
return m_IsAllowedBelow[a_BlockBelow];
}
-
+
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -223,11 +242,11 @@ public:
m_Level(a_Level)
{
}
-
+
int GetLevel(void) const { return m_Level; }
protected:
int m_Level;
-
+
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -241,7 +260,7 @@ class cFinishGenPreSimulator :
{
public:
cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava);
-
+
protected:
bool m_PreSimulateFallingBlocks;
@@ -253,7 +272,7 @@ protected:
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
cChunkDef::HeightMap & a_HeightMap // Height map to update by the current data
);
-
+
/** For each fluid block:
- if all surroundings are of the same fluid, makes it stationary; otherwise makes it flowing (excl. top)
- all fluid on the chunk's edge is made flowing
@@ -278,7 +297,7 @@ class cFinishGenFluidSprings :
{
public:
cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension);
-
+
protected:
cNoise m_Noise;
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index 55b3b64dd..65588ce4b 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -20,6 +20,7 @@ in a depth-first processing. Each of the descendants will branch randomly, if no
#include "MineShafts.h"
#include "../Cuboid.h"
#include "../BlockEntities/ChestEntity.h"
+#include "../BlockEntities/MobSpawnerEntity.h"
@@ -875,7 +876,9 @@ void cMineShaftCorridor::PlaceSpawner(cChunkDesc & a_ChunkDesc)
)
{
a_ChunkDesc.SetBlockTypeMeta(SpawnerRelX, m_BoundingBox.p1.y + 1, SpawnerRelZ, E_BLOCK_MOB_SPAWNER, 0);
- // TODO: The spawner needs its accompanying cMobSpawnerEntity, when implemented
+ cMobSpawnerEntity * MobSpawner = static_cast<cMobSpawnerEntity *>(a_ChunkDesc.GetBlockEntity(SpawnerRelX, m_BoundingBox.p1.y + 1, SpawnerRelZ));
+ ASSERT((MobSpawner != nullptr) && (MobSpawner->GetBlockType() == E_BLOCK_MOB_SPAWNER));
+ MobSpawner->SetEntity(mtCaveSpider);
}
}
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index 5cf46b873..6920ad71e 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -528,7 +528,9 @@ cBiomalNoise3DComposable::cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_Bi
m_DensityNoiseA(a_Seed + 1),
m_DensityNoiseB(a_Seed + 2),
m_BaseNoise(a_Seed + 3),
- m_BiomeGen(a_BiomeGen)
+ m_BiomeGen(a_BiomeGen),
+ m_LastChunkX(0x7fffffff), // Set impossible coords for the chunk so that it's always considered stale
+ m_LastChunkZ(0x7fffffff)
{
// Generate the weight distribution for summing up neighboring biomes:
m_WeightSum = 0;
diff --git a/src/Globals.h b/src/Globals.h
index fcadc3269..b68e9fd68 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -263,6 +263,7 @@ template class SizeChecker<UInt16, 2>;
#include "OSSupport/Event.h"
#include "OSSupport/File.h"
#include "Logger.h"
+ #include "OSSupport/StackTrace.h"
#else
// Logging functions
void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
@@ -348,14 +349,14 @@ void inline LOGD(const char* a_Format, ...)
#else
#ifdef _DEBUG
- #define ASSERT( x) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__), assert(0), 0))
+ #define ASSERT( x) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__), PrintStackTrace(), assert(0), 0))
#else
#define ASSERT(x) ((void)(x))
#endif
#endif
// Pretty much the same as ASSERT() but stays in Release builds
-#define VERIFY( x) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__), exit(1), 0))
+#define VERIFY( x) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__), PrintStackTrace(), exit(1), 0))
// Same as assert but in all Self test builds
#ifdef SELF_TEST
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index e461fae4c..e477e2dac 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)
);
}
@@ -284,6 +285,19 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
)
);
}
+
+ case mtMooshroom:
+ {
+ return (
+ (TargetBlock == E_BLOCK_AIR) &&
+ (BlockAbove == E_BLOCK_AIR) &&
+ (BlockBelow == E_BLOCK_MYCELIUM) &&
+ (
+ (a_Biome == biMushroomShore) ||
+ (a_Biome == biMushroomIsland)
+ )
+ );
+ }
default:
{
@@ -322,8 +336,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.cpp b/src/Mobs/Monster.cpp
index 4f8afa0de..a1122fb31 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -20,57 +20,49 @@
/** Map for eType <-> string
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())
+m_VanillaName is the name that vanilla use for this mob.
*/
static const struct
{
eMonsterType m_Type;
const char * m_lcName;
+ const char * m_VanillaName;
} g_MobTypeNames[] =
{
- {mtBat, "bat"},
- {mtBlaze, "blaze"},
- {mtCaveSpider, "cavespider"},
- {mtChicken, "chicken"},
- {mtCow, "cow"},
- {mtCreeper, "creeper"},
- {mtEnderman, "enderman"},
- {mtEnderDragon, "enderdragon"},
- {mtGhast, "ghast"},
- {mtHorse, "horse"},
- {mtIronGolem, "irongolem"},
- {mtMagmaCube, "magmacube"},
- {mtMooshroom, "mooshroom"},
- {mtOcelot, "ocelot"},
- {mtPig, "pig"},
- {mtSheep, "sheep"},
- {mtSilverfish, "silverfish"},
- {mtSkeleton, "skeleton"},
- {mtSlime, "slime"},
- {mtSnowGolem, "snowgolem"},
- {mtSpider, "spider"},
- {mtSquid, "squid"},
- {mtVillager, "villager"},
- {mtWitch, "witch"},
- {mtWither, "wither"},
- {mtWolf, "wolf"},
- {mtZombie, "zombie"},
- {mtZombiePigman, "zombiepigman"},
+ {mtBat, "bat", "Bat"},
+ {mtBlaze, "blaze", "Blaze"},
+ {mtCaveSpider, "cavespider", "CaveSpider"},
+ {mtChicken, "chicken", "Chicken"},
+ {mtCow, "cow", "Cow"},
+ {mtCreeper, "creeper", "Creeper"},
+ {mtEnderman, "enderman", "Enderman"},
+ {mtEnderDragon, "enderdragon", "EnderDragon"},
+ {mtGhast, "ghast", "Ghast"},
+ {mtHorse, "horse", "EntityHorse"},
+ {mtIronGolem, "irongolem", "VillagerGolem"},
+ {mtMagmaCube, "magmacube", "LavaSlime"},
+ {mtMooshroom, "mooshroom", "MushroomCow"},
+ {mtOcelot, "ocelot", "Ozelot"},
+ {mtPig, "pig", "Pig"},
+ {mtSheep, "sheep", "Sheep"},
+ {mtSilverfish, "silverfish", "Silverfish"},
+ {mtSkeleton, "skeleton", "Skeleton"},
+ {mtSlime, "slime", "Slime"},
+ {mtSnowGolem, "snowgolem", "SnowMan"},
+ {mtSpider, "spider", "Spider"},
+ {mtSquid, "squid", "Squid"},
+ {mtVillager, "villager", "Villager"},
+ {mtWitch, "witch", "Witch"},
+ {mtWither, "wither", "WitherBoss"},
+ {mtWolf, "wolf", "Wolf"},
+ {mtZombie, "zombie", "Zombie"},
+ {mtZombiePigman, "zombiepigman", "PigZombie"},
} ;
-eMonsterType StringToMobType(const AString & a_MobString)
-{
- LOGWARNING("%s: Function is obsolete, use cMonster::StringToMobType() instead", __FUNCTION__);
- return cMonster::StringToMobType(a_MobString);
-}
-
-
-
-
-
////////////////////////////////////////////////////////////////////////////////
// cMonster:
@@ -783,39 +775,47 @@ AString cMonster::MobTypeToString(eMonsterType a_MobType)
-eMonsterType cMonster::StringToMobType(const AString & a_Name)
+AString cMonster::MobTypeToVanillaName(eMonsterType a_MobType)
{
- AString lcName = StrToLower(a_Name);
-
- // Binary-search for the lowercase name:
- int lo = 0, hi = ARRAYCOUNT(g_MobTypeNames) - 1;
- while (hi - lo > 1)
+ // Mob types aren't sorted, so we need to search linearly:
+ for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
{
- int mid = (lo + hi) / 2;
- int res = strcmp(g_MobTypeNames[mid].m_lcName, lcName.c_str());
- if (res == 0)
- {
- return g_MobTypeNames[mid].m_Type;
- }
- if (res < 0)
- {
- lo = mid;
- }
- else
+ if (g_MobTypeNames[i].m_Type == a_MobType)
{
- hi = mid;
+ return g_MobTypeNames[i].m_VanillaName;
}
}
- // Range has collapsed to at most two elements, compare each:
- if (strcmp(g_MobTypeNames[lo].m_lcName, lcName.c_str()) == 0)
+
+ // Not found:
+ return "";
+}
+
+
+
+
+
+eMonsterType cMonster::StringToMobType(const AString & a_Name)
+{
+ AString lcName = StrToLower(a_Name);
+
+ // Search MCServer name:
+ for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
{
- return g_MobTypeNames[lo].m_Type;
+ if (strcmp(g_MobTypeNames[i].m_lcName, lcName.c_str()) == 0)
+ {
+ return g_MobTypeNames[i].m_Type;
+ }
}
- if ((lo != hi) && (strcmp(g_MobTypeNames[hi].m_lcName, lcName.c_str()) == 0))
+
+ // Not found. Search Vanilla name:
+ for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
{
- return g_MobTypeNames[hi].m_Type;
+ if (strcmp(StrToLower(g_MobTypeNames[i].m_VanillaName).c_str(), lcName.c_str()) == 0)
+ {
+ return g_MobTypeNames[i].m_Type;
+ }
}
-
+
// Not found:
return mtInvalidType;
}
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index e5dcb0309..f04e45ac6 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
@@ -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. */
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);
- /// 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);
- /// Returns the mob family based on the type
+ /** Returns the mob family based on the type */
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);
// tolua_end
diff --git a/src/Mobs/MonsterTypes.h b/src/Mobs/MonsterTypes.h
index 852eb3446..dc6dd3992 100644
--- a/src/Mobs/MonsterTypes.h
+++ b/src/Mobs/MonsterTypes.h
@@ -2,6 +2,7 @@
#pragma once
/// This identifies individual monster type, as well as their network type-ID
+
// tolua_begin
enum eMonsterType
{
@@ -38,15 +39,6 @@ enum eMonsterType
mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN,
} ;
-
-
-
-
-/** Translates a mob string ("ocelot") to mobtype (mtOcelot).
-OBSOLETE, use cMonster::StringToMobType() instead.
-Implemented in Monster.cpp. */
-extern eMonsterType StringToMobType(const AString & a_MobString);
-
// tolua_end
diff --git a/src/Mobs/Pig.cpp b/src/Mobs/Pig.cpp
index 50b69e44f..1e4c35acd 100644
--- a/src/Mobs/Pig.cpp
+++ b/src/Mobs/Pig.cpp
@@ -49,17 +49,17 @@ void cPig::OnRightClicked(cPlayer & a_Player)
a_Player.Detach();
return;
}
-
+
if (m_Attachee->IsPlayer())
{
// Another player is already sitting in here, cannot attach
return;
}
-
+
// Detach whatever is sitting in this pig now:
m_Attachee->Detach();
}
-
+
// Attach the player to this pig
a_Player.AttachTo(this);
}
@@ -100,7 +100,7 @@ void cPig::Tick(float a_Dt, cChunk & a_Chunk)
bool cPig::DoTakeDamage(TakeDamageInfo & a_TDI)
-{
+{
if (!super::DoTakeDamage(a_TDI))
{
return false;
diff --git a/src/Noise/OctavedNoise.h b/src/Noise/OctavedNoise.h
index 855117289..efb9a0167 100644
--- a/src/Noise/OctavedNoise.h
+++ b/src/Noise/OctavedNoise.h
@@ -66,17 +66,19 @@ public:
}
// Generate the first octave directly into array:
- const cOctave & FirstOctave = m_Octaves.front();
int ArrayCount = a_SizeX * a_SizeY;
- FirstOctave.m_Noise.Generate2D(
- a_Workspace, a_SizeX, a_SizeY,
- a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
- a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency
- );
- NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
- for (int i = 0; i < ArrayCount; i++)
{
- a_Array[i] = a_Workspace[i] * Amplitude;
+ const cOctave & FirstOctave = m_Octaves.front();
+ FirstOctave.m_Noise.Generate2D(
+ a_Workspace, a_SizeX, a_SizeY,
+ a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
+ a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency
+ );
+ NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
+ for (int i = 0; i < ArrayCount; i++)
+ {
+ a_Array[i] = a_Workspace[i] * Amplitude;
+ }
}
// Add each octave:
@@ -124,18 +126,20 @@ public:
}
// Generate the first octave directly into array:
- const cOctave & FirstOctave = m_Octaves.front();
int ArrayCount = a_SizeX * a_SizeY * a_SizeZ;
- FirstOctave.m_Noise.Generate3D(
- a_Workspace, a_SizeX, a_SizeY, a_SizeZ,
- a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
- a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency,
- a_StartZ * FirstOctave.m_Frequency, a_EndZ * FirstOctave.m_Frequency
- );
- NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
- for (int i = 0; i < ArrayCount; i++)
{
- a_Array[i] = a_Workspace[i] * Amplitude;
+ const cOctave & FirstOctave = m_Octaves.front();
+ FirstOctave.m_Noise.Generate3D(
+ a_Workspace, a_SizeX, a_SizeY, a_SizeZ,
+ a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
+ a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency,
+ a_StartZ * FirstOctave.m_Frequency, a_EndZ * FirstOctave.m_Frequency
+ );
+ NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
+ for (int i = 0; i < ArrayCount; i++)
+ {
+ a_Array[i] = a_Workspace[i] * Amplitude;
+ }
}
// Add each octave:
diff --git a/src/Noise/RidgedNoise.h b/src/Noise/RidgedNoise.h
index 69b480f60..f59a0512f 100644
--- a/src/Noise/RidgedNoise.h
+++ b/src/Noise/RidgedNoise.h
@@ -54,7 +54,7 @@ public:
);
for (int i = 0; i < ArrayCount; i++)
{
- a_Array[i] = fabs(a_Array[i]);
+ a_Array[i] = std::abs(a_Array[i]);
}
}
@@ -77,7 +77,7 @@ public:
);
for (int i = 0; i < ArrayCount; i++)
{
- a_Array[i] = fabs(a_Array[i]);
+ a_Array[i] = std::abs(a_Array[i]);
}
}
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index a8479a834..e943ceb18 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -15,6 +15,7 @@ SET (SRCS
Semaphore.cpp
Socket.cpp
SocketThreads.cpp
+ StackTrace.cpp
)
SET (HDRS
@@ -29,6 +30,7 @@ SET (HDRS
Semaphore.h
Socket.h
SocketThreads.h
+ StackTrace.h
)
if(NOT MSVC)
diff --git a/src/OSSupport/StackTrace.cpp b/src/OSSupport/StackTrace.cpp
new file mode 100644
index 000000000..a56568457
--- /dev/null
+++ b/src/OSSupport/StackTrace.cpp
@@ -0,0 +1,44 @@
+
+// StackTrace.cpp
+
+// Implements the functions to print current stack traces
+
+#include "Globals.h"
+#include "StackTrace.h"
+#ifdef _WIN32
+ #include "../StackWalker.h"
+#else
+ #include <execinfo.h>
+ #include <unistd.h>
+#endif
+
+
+
+
+
+void PrintStackTrace(void)
+{
+ #ifdef _WIN32
+ // Reuse the StackWalker from the LeakFinder project already bound to MCS
+ // Define a subclass of the StackWalker that outputs everything to stdout
+ class PrintingStackWalker :
+ public StackWalker
+ {
+ virtual void OnOutput(LPCSTR szText) override
+ {
+ puts(szText);
+ }
+ } sw;
+ sw.ShowCallstack();
+ #else
+ // Use the backtrace() function to get and output the stackTrace:
+ // Code adapted from http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
+ void * stackTrace[30];
+ size_t numItems = backtrace(stackTrace, ARRAYCOUNT(stackTrace));
+ backtrace_symbols_fd(stackTrace, numItems, STDERR_FILENO);
+ #endif
+}
+
+
+
+
diff --git a/src/OSSupport/StackTrace.h b/src/OSSupport/StackTrace.h
new file mode 100644
index 000000000..228a00077
--- /dev/null
+++ b/src/OSSupport/StackTrace.h
@@ -0,0 +1,15 @@
+
+// StackTrace.h
+
+// Declares the functions to print current stack trace
+
+
+
+
+
+/** Prints the stacktrace for the current thread. */
+extern void PrintStackTrace(void);
+
+
+
+
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 1d108ce9c..1e5fe5586 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", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
+ 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..ce580d73e 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", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
+ Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay());
+ Writer.AddString("id", "MobSpawner");
+ break;
+ }
default: break;
}
diff --git a/src/Root.cpp b/src/Root.cpp
index bb3fc37ed..c69710628 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -148,7 +148,7 @@ void cRoot::Start(void)
m_WebAdmin->Init();
LOGD("Loading settings...");
- m_RankManager = new cRankManager();
+ m_RankManager.reset(new cRankManager());
m_RankManager->Initialize(m_MojangAPI);
m_CraftingRecipes = new cCraftingRecipes;
m_FurnaceRecipe = new cFurnaceRecipe();
diff --git a/src/Root.h b/src/Root.h
index 5db15c277..e70b284f9 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -87,7 +87,7 @@ public:
cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export
cAuthenticator & GetAuthenticator (void) { return m_Authenticator; }
cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; }
- cRankManager * GetRankManager (void) { return m_RankManager; }
+ cRankManager * GetRankManager (void) { return m_RankManager.get(); }
/** Queues a console command for execution through the cServer class.
The command will be executed in the tick thread
@@ -189,7 +189,9 @@ private:
cPluginManager * m_PluginManager;
cAuthenticator m_Authenticator;
cMojangAPI m_MojangAPI;
- cRankManager * m_RankManager;
+
+ std::unique_ptr<cRankManager> m_RankManager;
+
cHTTPServer m_HTTPServer;
bool m_bStop;
diff --git a/src/World.cpp b/src/World.cpp
index 1602de4bb..cbdf59b8f 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -157,6 +157,8 @@ protected:
if (m_NumPrepared >= m_MaxIdx)
{
m_EvtFinished.Set();
+ // Must return here, because "this" may have gotten deleted by the previous line
+ return;
}
// Queue another chunk, if appropriate:
@@ -602,7 +604,7 @@ void cWorld::Start(void)
}
// Adjust the enum-backed variables into their respective bounds:
- m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure);
+ m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmSpectator);
m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll);
m_Weather = (eWeather) Clamp(Weather, (int)wSunny, (int)wStorm);
@@ -747,7 +749,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
- a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
+ a_IniFile.GetValueSet("Generator", "Finishers", "SoulsandRims, WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
break;
}
@@ -2668,7 +2670,7 @@ bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback)
bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
{
- // Calls the callback for each player in the list
+ // Calls the callback for the specified player in the list
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
diff --git a/src/World.h b/src/World.h
index c5fdaeff5..d64be208e 100644
--- a/src/World.h
+++ b/src/World.h
@@ -315,7 +315,8 @@ public:
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS <<
- /** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */
+ /** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found.
+ Callback return value is ignored. If there are multiple players of the same name, only (random) one is processed by the callback. */
bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Finds a player from a partial or complete player name and calls the callback - case-insensitive */
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 4daa8cc7b..432e122b5 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", cMonster::MobTypeToVanillaName(a_MobSpawner->GetEntity()));
+ 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 0c77b4d67..ddee5e514 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::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)
{
// Check if the data has a proper type:
@@ -1807,9 +1857,10 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
int InBlockZIdx = a_NBT.FindChildByName(a_TagIdx, "zTile");
if ((InBlockXIdx > 0) && (InBlockYIdx > 0) && (InBlockZIdx > 0))
{
- if (a_NBT.GetType(InBlockXIdx) == a_NBT.GetType(InBlockYIdx) == a_NBT.GetType(InBlockZIdx))
+ eTagType typeX = a_NBT.GetType(InBlockXIdx);
+ if ((typeX == a_NBT.GetType(InBlockYIdx)) && (typeX == a_NBT.GetType(InBlockZIdx)))
{
- switch (a_NBT.GetType(InBlockXIdx))
+ switch (typeX)
{
case TAG_Int:
{
@@ -1823,6 +1874,11 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
Arrow->SetBlockHit(Vector3i((int)a_NBT.GetShort(InBlockXIdx), (int)a_NBT.GetShort(InBlockYIdx), (int)a_NBT.GetShort(InBlockZIdx)));
break;
}
+ default:
+ {
+ // No hit block, the arrow is still flying?
+ break;
+ }
}
}
}
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);
diff --git a/src/main.cpp b/src/main.cpp
index b6ee8c0a7..d4adc1ed9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -61,6 +61,7 @@ void NonCtrlHandler(int a_Signal)
std::signal(SIGSEGV, SIG_DFL);
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGSEGV: Segmentation fault");
+ PrintStackTrace();
abort();
}
case SIGABRT:
@@ -71,6 +72,7 @@ void NonCtrlHandler(int a_Signal)
std::signal(a_Signal, SIG_DFL);
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
+ PrintStackTrace();
abort();
}
case SIGINT:
@@ -137,6 +139,9 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except
g_WriteMiniDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, g_DumpFlags, (a_ExceptionInfo) ? &ExcInformation : nullptr, nullptr, nullptr);
CloseHandle(dumpFile);
+ // Print the stack trace for the basic debugging:
+ PrintStackTrace();
+
// Revert to old stack:
_asm
{
@@ -182,7 +187,7 @@ int main( int argc, char **argv)
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
InitLeakFinder();
#endif
-
+
// Magic code to produce dump-files on Windows if the server crashes:
#if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER)
HINSTANCE hDbgHelp = LoadLibrary("DBGHELP.DLL");