summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml9
-rw-r--r--CONTRIBUTORS2
-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/Plugins/InfoDump.lua13
-rw-r--r--MCServer/crafting.txt1
-rw-r--r--MCServer/furnace.txt21
-rw-r--r--SetFlags.cmake35
-rw-r--r--Tools/AnvilStats/CMakeLists.txt2
-rw-r--r--Tools/MCADefrag/CMakeLists.txt11
-rw-r--r--Tools/ProtoProxy/CMakeLists.txt10
-rw-r--r--Tools/ProtoProxy/Connection.cpp5
-rw-r--r--Tools/ProtoProxy/Connection.h4
-rw-r--r--Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro19
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/DeprecatedBindings.cpp52
-rw-r--r--src/Bindings/Plugin.h2
-rw-r--r--src/Bindings/PluginLua.cpp2
-rw-r--r--src/Bindings/PluginLua.h2
-rw-r--r--src/Bindings/PluginManager.cpp11
-rw-r--r--src/Bindings/PluginManager.h2
-rw-r--r--src/BlockEntities/BeaconEntity.h10
-rw-r--r--src/BlockEntities/BlockEntity.cpp4
-rw-r--r--src/BlockEntities/BlockEntity.h7
-rw-r--r--src/BlockEntities/CMakeLists.txt2
-rw-r--r--src/BlockEntities/ChestEntity.h5
-rw-r--r--src/BlockEntities/CommandBlockEntity.h8
-rw-r--r--src/BlockEntities/DropSpenserEntity.h4
-rw-r--r--src/BlockEntities/FlowerPotEntity.h10
-rw-r--r--src/BlockEntities/FurnaceEntity.h5
-rw-r--r--src/BlockEntities/JukeboxEntity.h9
-rw-r--r--src/BlockEntities/MobHeadEntity.h20
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp290
-rw-r--r--src/BlockEntities/MobSpawnerEntity.h78
-rw-r--r--src/BlockEntities/NoteEntity.h6
-rw-r--r--src/BlockEntities/SignEntity.h9
-rw-r--r--src/Blocks/BlockBed.h5
-rw-r--r--src/Blocks/BlockDoor.cpp10
-rw-r--r--src/Blocks/BlockMobSpawner.h12
-rw-r--r--src/Blocks/BlockRail.h88
-rw-r--r--src/ByteBuffer.cpp132
-rw-r--r--src/ByteBuffer.h10
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/CheckBasicStyle.lua51
-rw-r--r--src/Chunk.cpp8
-rw-r--r--src/ClientHandle.cpp36
-rw-r--r--src/ClientHandle.h17
-rw-r--r--src/CraftingRecipes.cpp2
-rw-r--r--src/DeadlockDetect.cpp6
-rw-r--r--src/DeadlockDetect.h2
-rw-r--r--src/Entities/Entity.cpp22
-rw-r--r--src/Entities/Minecart.cpp29
-rw-r--r--src/Entities/Player.cpp41
-rw-r--r--src/Entities/Player.h2
-rw-r--r--src/FastRandom.cpp116
-rw-r--r--src/FastRandom.h47
-rw-r--r--src/Generating/Caves.cpp10
-rw-r--r--src/Generating/ChunkGenerator.cpp2
-rw-r--r--src/Generating/CompoGen.cpp14
-rw-r--r--src/Generating/ComposableGenerator.cpp10
-rw-r--r--src/Generating/DistortedHeightmap.cpp2
-rw-r--r--src/Generating/DungeonRoomsFinisher.cpp23
-rw-r--r--src/Generating/FinishGen.cpp330
-rw-r--r--src/Generating/FinishGen.h86
-rw-r--r--src/Generating/MineShafts.cpp5
-rw-r--r--src/Generating/Noise3DGenerator.cpp9
-rw-r--r--src/Globals.h14
-rw-r--r--src/HTTPServer/HTTPFormParser.h2
-rw-r--r--src/Inventory.cpp8
-rw-r--r--src/Logger.cpp4
-rw-r--r--src/MersenneTwister.h456
-rw-r--r--src/MobSpawner.cpp34
-rw-r--r--src/MobSpawner.h7
-rw-r--r--src/Mobs/AggressiveMonster.cpp2
-rw-r--r--src/Mobs/Blaze.cpp2
-rw-r--r--src/Mobs/Ghast.cpp2
-rw-r--r--src/Mobs/Monster.cpp152
-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/Mobs/Skeleton.cpp2
-rw-r--r--src/Mobs/SnowGolem.cpp2
-rw-r--r--src/Mobs/Witch.cpp1
-rw-r--r--src/Mobs/Witch.h1
-rw-r--r--src/Noise/Noise.cpp1
-rw-r--r--src/OSSupport/CMakeLists.txt10
-rw-r--r--src/OSSupport/CriticalSection.cpp52
-rw-r--r--src/OSSupport/CriticalSection.h14
-rw-r--r--src/OSSupport/Event.cpp156
-rw-r--r--src/OSSupport/Event.h35
-rw-r--r--src/OSSupport/IsThread.cpp174
-rw-r--r--src/OSSupport/IsThread.h51
-rw-r--r--src/OSSupport/Sleep.cpp19
-rw-r--r--src/OSSupport/Sleep.h7
-rw-r--r--src/OSSupport/Socket.h2
-rw-r--r--src/OSSupport/SocketThreads.cpp14
-rw-r--r--src/OSSupport/StackTrace.cpp44
-rw-r--r--src/OSSupport/StackTrace.h15
-rw-r--r--src/OSSupport/Thread.cpp137
-rw-r--r--src/OSSupport/Thread.h26
-rw-r--r--src/OSSupport/Timer.cpp37
-rw-r--r--src/OSSupport/Timer.h32
-rw-r--r--src/ProbabDistrib.cpp2
-rw-r--r--src/Protocol/MojangAPI.cpp22
-rw-r--r--src/Protocol/Protocol17x.cpp14
-rw-r--r--src/Protocol/Protocol18x.cpp13
-rw-r--r--src/Root.cpp38
-rw-r--r--src/Root.h7
-rw-r--r--src/Server.cpp19
-rw-r--r--src/Simulator/FluidSimulator.cpp6
-rw-r--r--src/StringUtils.cpp41
-rw-r--r--src/Tracer.cpp120
-rw-r--r--src/UI/SlotArea.cpp4
-rw-r--r--src/World.cpp69
-rw-r--r--src/World.h5
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp8
-rw-r--r--src/WorldStorage/MapSerializer.cpp4
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp16
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h26
-rw-r--r--src/WorldStorage/WSSAnvil.cpp203
-rw-r--r--src/WorldStorage/WSSAnvil.h1
-rw-r--r--src/XMLParser.h14
-rw-r--r--src/main.cpp9
124 files changed, 2185 insertions, 1865 deletions
diff --git a/.travis.yml b/.travis.yml
index 5260cfd17..4e8377748 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,15 @@ compiler:
before_install:
- if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]; then sudo pip install cpp_coveralls; fi
+ # g++4.8
+ - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+ - sudo apt-get update -qq
+
+install:
+ # g++4.8
+ - sudo apt-get install -qq g++-4.8
+ - export CXX="g++-4.8"
+
# Build MCServer
script: ./CIbuild.sh
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 8620a1475..9a0a675e7 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -10,6 +10,7 @@ Howaner
keyboard
Lapayo
Luksor
+M10360
marmot21
Masy98
mborland
@@ -17,6 +18,7 @@ mgueydan
MikeHunsinger
mtilden
nesco
+p-mcgowan
rs2k
SamJBarney
Sofapriester
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/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua
index de1d1f451..07a534b88 100644
--- a/MCServer/Plugins/InfoDump.lua
+++ b/MCServer/Plugins/InfoDump.lua
@@ -444,7 +444,18 @@ local function BuildPermissions(a_PluginInfo)
Permissions[info.Permission] = Permission
-- Add the command to the list of commands using this permission:
Permission.CommandsAffected = Permission.CommandsAffected or {}
- table.insert(Permission.CommandsAffected, CommandString)
+ -- First, make sure that we don't already have this command in the list,
+ -- it may have already been present in a_PluginInfo
+ local NewCommand = true
+ for _, existCmd in ipairs(Permission.CommandsAffected) do
+ if CommandString == existCmd then
+ NewCommand = false
+ break
+ end
+ end
+ if NewCommand then
+ table.insert(Permission.CommandsAffected, CommandString)
+ end
end
-- Process the command param combinations for permissions:
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/SetFlags.cmake b/SetFlags.cmake
index c0a021c25..0d1bd99b3 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -64,18 +64,12 @@ macro(set_flags)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
endif()
-
- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND (NOT GCC_VERSION VERSION_GREATER 4.6))
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
- set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++0x")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
- set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
- endif()
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
+
#on os x clang adds pthread for us but we need to add it for gcc
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_flags_cxx("-stdlib=libc++")
@@ -94,18 +88,11 @@ macro(set_flags)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
endif()
-
- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND (NOT GCC_VERSION VERSION_GREATER 4.6))
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
- set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++0x")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
- set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
- endif()
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
# We use a signed char (fixes #640 on RasPi)
add_flags_cxx("-fsigned-char")
diff --git a/Tools/AnvilStats/CMakeLists.txt b/Tools/AnvilStats/CMakeLists.txt
index 557a4c17a..688fbe493 100644
--- a/Tools/AnvilStats/CMakeLists.txt
+++ b/Tools/AnvilStats/CMakeLists.txt
@@ -53,7 +53,6 @@ set(SHARED_OSS_SRC
../../src/OSSupport/File.cpp
../../src/OSSupport/GZipFile.cpp
../../src/OSSupport/IsThread.cpp
- ../../src/OSSupport/Timer.cpp
)
set(SHARED_OSS_HDR
@@ -62,7 +61,6 @@ set(SHARED_OSS_HDR
../../src/OSSupport/File.h
../../src/OSSupport/GZipFile.h
../../src/OSSupport/IsThread.h
- ../../src/OSSupport/Timer.h
)
flatten_files(SHARED_SRC)
diff --git a/Tools/MCADefrag/CMakeLists.txt b/Tools/MCADefrag/CMakeLists.txt
index 42b42018b..82e048671 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,15 +55,21 @@ set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/File.cpp
../../src/OSSupport/IsThread.cpp
- ../../src/OSSupport/Timer.cpp
+ ../../src/OSSupport/StackTrace.cpp
)
+
set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h
../../src/OSSupport/File.h
../../src/OSSupport/IsThread.h
- ../../src/OSSupport/Timer.h
+ ../../src/OSSupport/StackTrace.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 bc3923d90..cca0c1b8b 100644
--- a/Tools/ProtoProxy/CMakeLists.txt
+++ b/Tools/ProtoProxy/CMakeLists.txt
@@ -57,14 +57,20 @@ set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/File.cpp
../../src/OSSupport/IsThread.cpp
- ../../src/OSSupport/Timer.cpp
+ ../../src/OSSupport/StackTrace.cpp
)
set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h
../../src/OSSupport/File.h
../../src/OSSupport/IsThread.h
- ../../src/OSSupport/Timer.h
+ ../../src/OSSupport/StackTrace.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/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp
index eaf4fab02..fb2d40e5b 100644
--- a/Tools/ProtoProxy/Connection.cpp
+++ b/Tools/ProtoProxy/Connection.cpp
@@ -189,7 +189,7 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) :
m_Server(a_Server),
m_ClientSocket(a_ClientSocket),
m_ServerSocket(-1),
- m_BeginTick(m_Timer.GetNowTime()),
+ m_BeginTick(std::chrono::steady_clock::now()),
m_ClientState(csUnencrypted),
m_ServerState(csUnencrypted),
m_Nonce(0),
@@ -436,7 +436,8 @@ bool cConnection::RelayFromClient(void)
double cConnection::GetRelativeTime(void)
{
- return (double)(m_Timer.GetNowTime() - m_BeginTick) / 1000;
+ Int64 msec = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_BeginTick).count();
+ return static_cast<double>(msec) / 1000;
}
diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h
index 1fc9536de..c79273f8a 100644
--- a/Tools/ProtoProxy/Connection.h
+++ b/Tools/ProtoProxy/Connection.h
@@ -10,7 +10,6 @@
#pragma once
#include "ByteBuffer.h"
-#include "OSSupport/Timer.h"
#include "PolarSSL++/AesCfb128Decryptor.h"
#include "PolarSSL++/AesCfb128Encryptor.h"
@@ -37,8 +36,7 @@ class cConnection
SOCKET m_ClientSocket;
SOCKET m_ServerSocket;
- cTimer m_Timer;
- long long m_BeginTick; // Tick when the relative time was first retrieved (used for GetRelativeTime())
+ std::chrono::steady_clock::time_point m_BeginTick; // Tick when the relative time was first retrieved (used for GetRelativeTime())
enum eConnectionState
{
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..6dd6a4e59 100644
--- a/src/Bindings/DeprecatedBindings.cpp
+++ b/src/Bindings/DeprecatedBindings.cpp
@@ -52,7 +52,9 @@ static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -78,7 +80,9 @@ static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -104,7 +108,9 @@ static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -130,7 +136,9 @@ static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -156,7 +164,9 @@ static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -182,7 +192,9 @@ static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -208,7 +220,9 @@ static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S, 2, 0, &tolua_err))
+ {
tolua_error(tolua_S, "#vinvalid type in array indexing.", &tolua_err);
+ }
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
@@ -225,6 +239,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 +346,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/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 8cc9ff0cd..08677553c 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -54,7 +54,7 @@ public:
virtual bool OnChunkUnloaded (cWorld & a_World, int a_ChunkX, int a_ChunkZ) = 0;
virtual bool OnChunkUnloading (cWorld & a_World, int a_ChunkX, int a_ChunkZ) = 0;
virtual bool OnCollectingPickup (cPlayer & a_Player, cPickup & a_Pickup) = 0;
- virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe * a_Recipe) = 0;
+ virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0;
virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0;
virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) = 0;
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 391d8bcbe..ea782ea3f 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -382,7 +382,7 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
-bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe * a_Recipe)
+bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index 6bb134efc..7de5ffec4 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -78,7 +78,7 @@ public:
virtual bool OnChunkUnloaded (cWorld & a_World, int a_ChunkX, int a_ChunkZ) override;
virtual bool OnChunkUnloading (cWorld & a_World, int a_ChunkX, int a_ChunkZ) override;
virtual bool OnCollectingPickup (cPlayer & a_Player, cPickup & a_Pickup) override;
- virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe * a_Recipe) override;
+ virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override;
virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override;
virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) override;
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index f63578885..406a540f4 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -448,7 +448,7 @@ bool cPluginManager::CallHookCollectingPickup(cPlayer & a_Player, cPickup & a_Pi
-bool cPluginManager::CallHookCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe * a_Recipe)
+bool cPluginManager::CallHookCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
FIND_HOOK(HOOK_CRAFTING_NO_RECIPE);
VERIFY_HOOK;
@@ -1459,11 +1459,16 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player,
-cPlugin * cPluginManager::GetPlugin( const AString & a_Plugin) const
+cPlugin * cPluginManager::GetPlugin(const AString & a_Plugin) const
{
for (PluginMap::const_iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr)
{
- if (itr->second == nullptr) continue;
+ if (itr->second == nullptr)
+ {
+ // The plugin is currently unloaded
+ continue;
+ }
+
if (itr->second->GetName().compare(a_Plugin) == 0)
{
return itr->second;
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index bc8c1f5e6..3a2aecc92 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -187,7 +187,7 @@ public:
bool CallHookChunkUnloaded (cWorld & a_World, int a_ChunkX, int a_ChunkZ);
bool CallHookChunkUnloading (cWorld & a_World, int a_ChunkX, int a_ChunkZ);
bool CallHookCollectingPickup (cPlayer & a_Player, cPickup & a_Pickup);
- bool CallHookCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe * a_Recipe);
+ bool CallHookCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason);
bool CallHookEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier);
bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == nullptr, it is a console cmd
diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h
index 0417e0464..bc27e92b0 100644
--- a/src/BlockEntities/BeaconEntity.h
+++ b/src/BlockEntities/BeaconEntity.h
@@ -1,3 +1,4 @@
+
// BeaconEntity.h
// Declares the cBeaconEntity class representing a single beacon in the world
@@ -14,15 +15,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cBeaconEntity :
public cBlockEntityWithItems
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index 3d96e891e..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/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt
index d87594b0d..5f4af288d 100644
--- a/src/BlockEntities/CMakeLists.txt
+++ b/src/BlockEntities/CMakeLists.txt
@@ -18,6 +18,7 @@ SET (SRCS
HopperEntity.cpp
JukeboxEntity.cpp
MobHeadEntity.cpp
+ MobSpawnerEntity.cpp
NoteEntity.cpp
SignEntity.cpp)
@@ -36,6 +37,7 @@ SET (HDRS
HopperEntity.h
JukeboxEntity.h
MobHeadEntity.h
+ MobSpawnerEntity.h
NoteEntity.h
SignEntity.h)
diff --git a/src/BlockEntities/ChestEntity.h b/src/BlockEntities/ChestEntity.h
index 5ab0a4800..645dbf4bc 100644
--- a/src/BlockEntities/ChestEntity.h
+++ b/src/BlockEntities/ChestEntity.h
@@ -7,11 +7,6 @@
-namespace Json
-{
- class Value;
-};
-
class cClientHandle;
diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h
index 8deff6964..d8ac054f0 100644
--- a/src/BlockEntities/CommandBlockEntity.h
+++ b/src/BlockEntities/CommandBlockEntity.h
@@ -15,14 +15,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
// tolua_begin
diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h
index 9092bc077..6c23a402f 100644
--- a/src/BlockEntities/DropSpenserEntity.h
+++ b/src/BlockEntities/DropSpenserEntity.h
@@ -16,10 +16,6 @@
-namespace Json
-{
- class Value;
-}
class cClientHandle;
diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h
index 005a3841a..a4246bb7d 100644
--- a/src/BlockEntities/FlowerPotEntity.h
+++ b/src/BlockEntities/FlowerPotEntity.h
@@ -15,16 +15,6 @@
-
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cFlowerPotEntity :
diff --git a/src/BlockEntities/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h
index 1ad812d8b..fbe9d6c75 100644
--- a/src/BlockEntities/FurnaceEntity.h
+++ b/src/BlockEntities/FurnaceEntity.h
@@ -8,11 +8,6 @@
-namespace Json
-{
- class Value;
-}
-
class cClientHandle;
diff --git a/src/BlockEntities/JukeboxEntity.h b/src/BlockEntities/JukeboxEntity.h
index 301d018d1..000f7d87e 100644
--- a/src/BlockEntities/JukeboxEntity.h
+++ b/src/BlockEntities/JukeboxEntity.h
@@ -7,15 +7,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cJukeboxEntity :
diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h
index de033fd16..7f08c5ab2 100644
--- a/src/BlockEntities/MobHeadEntity.h
+++ b/src/BlockEntities/MobHeadEntity.h
@@ -14,14 +14,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
// tolua_begin
@@ -41,22 +33,22 @@ public:
// 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 d63ff56b6..d3f85e9d2 100644
--- a/src/BlockEntities/NoteEntity.h
+++ b/src/BlockEntities/NoteEntity.h
@@ -5,12 +5,6 @@
#include "RedstonePoweredEntity.h"
-namespace Json
-{
- class Value;
-}
-
-
diff --git a/src/BlockEntities/SignEntity.h b/src/BlockEntities/SignEntity.h
index 347689d0a..9480537ed 100644
--- a/src/BlockEntities/SignEntity.h
+++ b/src/BlockEntities/SignEntity.h
@@ -14,15 +14,6 @@
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
// tolua_begin
class cSignEntity :
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index 9fd45644b..a8b5be899 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -52,7 +52,10 @@ public:
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 180 + (180 / 4); // So its not aligned with axis
- if (a_Rotation > 360) a_Rotation -= 360;
+ if (a_Rotation > 360)
+ {
+ a_Rotation -= 360;
+ }
a_Rotation = (a_Rotation / 360) * 4;
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 96345a2df..90b7b15c2 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -145,7 +145,10 @@ NIBBLETYPE cBlockDoorHandler::MetaMirrorXY(NIBBLETYPE a_Meta)
// in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,
// so the function can only see either the hinge position or orientation, but not both, at any given time. The class itself
// needs extra datamembers.
- if (a_Meta & 0x08) return a_Meta;
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
// Holds open/closed meta data. 0x0C == 1100.
NIBBLETYPE OtherMeta = a_Meta & 0x0C;
@@ -173,7 +176,10 @@ NIBBLETYPE cBlockDoorHandler::MetaMirrorYZ(NIBBLETYPE a_Meta)
// so the function can only see either the hinge position or orientation, but not both, at any given time.The class itself
// needs extra datamembers.
- if (a_Meta & 0x08) return a_Meta;
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
// Holds open/closed meta data. 0x0C == 1100.
NIBBLETYPE OtherMeta = a_Meta & 0x0C;
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/Blocks/BlockRail.h b/src/Blocks/BlockRail.h
index 87ce069ab..21a34d8ce 100644
--- a/src/Blocks/BlockRail.h
+++ b/src/Blocks/BlockRail.h
@@ -151,13 +151,21 @@ public:
Neighbors[6] = (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_NONE));
Neighbors[7] = (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_SOUTH, E_PURE_NONE));
if (IsUnstable(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_EAST))
+ {
Neighbors[0] = true;
+ }
if (IsUnstable(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_WEST))
+ {
Neighbors[1] = true;
+ }
if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NORTH))
+ {
Neighbors[2] = true;
+ }
if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_SOUTH))
+ {
Neighbors[3] = true;
+ }
for (int i = 0; i < 8; i++)
{
if (Neighbors[i])
@@ -167,12 +175,30 @@ public:
}
if (RailsCnt == 1)
{
- if (Neighbors[7]) return E_META_RAIL_ASCEND_ZP;
- else if (Neighbors[6]) return E_META_RAIL_ASCEND_ZM;
- else if (Neighbors[5]) return E_META_RAIL_ASCEND_XM;
- else if (Neighbors[4]) return E_META_RAIL_ASCEND_XP;
- else if (Neighbors[0] || Neighbors[1]) return E_META_RAIL_XM_XP;
- else if (Neighbors[2] || Neighbors[3]) return E_META_RAIL_ZM_ZP;
+ if (Neighbors[7])
+ {
+ return E_META_RAIL_ASCEND_ZP;
+ }
+ else if (Neighbors[6])
+ {
+ return E_META_RAIL_ASCEND_ZM;
+ }
+ else if (Neighbors[5])
+ {
+ return E_META_RAIL_ASCEND_XM;
+ }
+ else if (Neighbors[4])
+ {
+ return E_META_RAIL_ASCEND_XP;
+ }
+ else if (Neighbors[0] || Neighbors[1])
+ {
+ return E_META_RAIL_XM_XP;
+ }
+ else if (Neighbors[2] || Neighbors[3])
+ {
+ return E_META_RAIL_ZM_ZP;
+ }
ASSERT(!"Weird neighbor count");
return Meta;
}
@@ -185,16 +211,46 @@ public:
}
if (RailsCnt > 1)
{
- if (Neighbors[3] && Neighbors[0] && CanThisRailCurve()) return E_META_RAIL_CURVED_ZP_XP;
- else if (Neighbors[3] && Neighbors[1] && CanThisRailCurve()) return E_META_RAIL_CURVED_ZP_XM;
- else if (Neighbors[2] && Neighbors[0] && CanThisRailCurve()) return E_META_RAIL_CURVED_ZM_XP;
- else if (Neighbors[2] && Neighbors[1] && CanThisRailCurve()) return E_META_RAIL_CURVED_ZM_XM;
- else if (Neighbors[7] && Neighbors[2]) return E_META_RAIL_ASCEND_ZP;
- else if (Neighbors[3] && Neighbors[6]) return E_META_RAIL_ASCEND_ZM;
- else if (Neighbors[5] && Neighbors[0]) return E_META_RAIL_ASCEND_XM;
- else if (Neighbors[4] && Neighbors[1]) return E_META_RAIL_ASCEND_XP;
- else if (Neighbors[0] && Neighbors[1]) return E_META_RAIL_XM_XP;
- else if (Neighbors[2] && Neighbors[3]) return E_META_RAIL_ZM_ZP;
+ if (Neighbors[3] && Neighbors[0] && CanThisRailCurve())
+ {
+ return E_META_RAIL_CURVED_ZP_XP;
+ }
+ else if (Neighbors[3] && Neighbors[1] && CanThisRailCurve())
+ {
+ return E_META_RAIL_CURVED_ZP_XM;
+ }
+ else if (Neighbors[2] && Neighbors[0] && CanThisRailCurve())
+ {
+ return E_META_RAIL_CURVED_ZM_XP;
+ }
+ else if (Neighbors[2] && Neighbors[1] && CanThisRailCurve())
+ {
+ return E_META_RAIL_CURVED_ZM_XM;
+ }
+ else if (Neighbors[7] && Neighbors[2])
+ {
+ return E_META_RAIL_ASCEND_ZP;
+ }
+ else if (Neighbors[3] && Neighbors[6])
+ {
+ return E_META_RAIL_ASCEND_ZM;
+ }
+ else if (Neighbors[5] && Neighbors[0])
+ {
+ return E_META_RAIL_ASCEND_XM;
+ }
+ else if (Neighbors[4] && Neighbors[1])
+ {
+ return E_META_RAIL_ASCEND_XP;
+ }
+ else if (Neighbors[0] && Neighbors[1])
+ {
+ return E_META_RAIL_XM_XP;
+ }
+ else if (Neighbors[2] && Neighbors[3])
+ {
+ return E_META_RAIL_ZM_ZP;
+ }
if (CanThisRailCurve())
{
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index 012105ca1..080176dcd 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -111,26 +111,36 @@ public:
#ifdef _DEBUG
-/// Simple RAII class that uses one internal unsigned long for checking if two threads are using an object simultanously
-class cSingleThreadAccessChecker
-{
-public:
- cSingleThreadAccessChecker(unsigned long * a_ThreadID) :
- m_ThreadID(a_ThreadID)
+ /** Simple RAII class that is used for checking that no two threads are using an object simultanously.
+ It requires the monitored object to provide the storage for a thread ID.
+ It uses that storage to check if the thread ID of consecutive calls is the same all the time. */
+ class cSingleThreadAccessChecker
{
- ASSERT((*a_ThreadID == 0) || (*a_ThreadID == cIsThread::GetCurrentID()));
- }
-
- ~cSingleThreadAccessChecker()
- {
- *m_ThreadID = 0;
- }
-
-protected:
- unsigned long * m_ThreadID;
-} ;
+ public:
+ cSingleThreadAccessChecker(std::thread::id * a_ThreadID) :
+ m_ThreadID(a_ThreadID)
+ {
+ ASSERT(
+ (*a_ThreadID == std::this_thread::get_id()) || // Either the object is used by current thread...
+ (*a_ThreadID == std::thread::id()) // ... or by no thread at all
+ );
+
+ // Mark as being used by this thread:
+ *m_ThreadID = std::this_thread::get_id();
+ }
+
+ ~cSingleThreadAccessChecker()
+ {
+ // Mark as not being used by any thread:
+ *m_ThreadID = std::thread::id();
+ }
+
+ protected:
+ /** Points to the storage used for ID of the thread using the object. */
+ std::thread::id * m_ThreadID;
+ };
-#define CHECK_THREAD cSingleThreadAccessChecker Checker(const_cast<unsigned long *>(&m_ThreadID))
+ #define CHECK_THREAD cSingleThreadAccessChecker Checker(&m_ThreadID);
#else
#define CHECK_THREAD
@@ -146,9 +156,6 @@ protected:
cByteBuffer::cByteBuffer(size_t a_BufferSize) :
m_Buffer(new char[a_BufferSize + 1]),
m_BufferSize(a_BufferSize + 1),
- #ifdef _DEBUG
- m_ThreadID(0),
- #endif // _DEBUG
m_DataStart(0),
m_WritePos(0),
m_ReadPos(0)
@@ -174,7 +181,7 @@ cByteBuffer::~cByteBuffer()
bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
// Store the current free space for a check after writing:
@@ -221,7 +228,7 @@ bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
size_t cByteBuffer::GetFreeSpace(void) const
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
if (m_WritePos >= m_DataStart)
{
@@ -243,7 +250,7 @@ size_t cByteBuffer::GetFreeSpace(void) const
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
size_t cByteBuffer::GetUsedSpace(void) const
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
ASSERT(m_BufferSize >= GetFreeSpace());
ASSERT((m_BufferSize - GetFreeSpace()) >= 1);
@@ -257,7 +264,7 @@ size_t cByteBuffer::GetUsedSpace(void) const
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
size_t cByteBuffer::GetReadableSpace(void) const
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
if (m_ReadPos > m_WritePos)
{
@@ -276,7 +283,7 @@ size_t cByteBuffer::GetReadableSpace(void) const
bool cByteBuffer::CanReadBytes(size_t a_Count) const
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
return (a_Count <= GetReadableSpace());
}
@@ -287,7 +294,7 @@ bool cByteBuffer::CanReadBytes(size_t a_Count) const
bool cByteBuffer::CanWriteBytes(size_t a_Count) const
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
return (a_Count <= GetFreeSpace());
}
@@ -298,7 +305,7 @@ bool cByteBuffer::CanWriteBytes(size_t a_Count) const
bool cByteBuffer::ReadChar(char & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(1);
ReadBuf(&a_Value, 1);
@@ -311,7 +318,7 @@ bool cByteBuffer::ReadChar(char & a_Value)
bool cByteBuffer::ReadByte(unsigned char & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(1);
ReadBuf(&a_Value, 1);
@@ -324,7 +331,7 @@ bool cByteBuffer::ReadByte(unsigned char & a_Value)
bool cByteBuffer::ReadBEShort(short & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(2);
ReadBuf(&a_Value, 2);
@@ -338,7 +345,7 @@ bool cByteBuffer::ReadBEShort(short & a_Value)
bool cByteBuffer::ReadBEInt(int & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(4);
ReadBuf(&a_Value, 4);
@@ -352,7 +359,7 @@ bool cByteBuffer::ReadBEInt(int & a_Value)
bool cByteBuffer::ReadBEInt64(Int64 & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(8);
ReadBuf(&a_Value, 8);
@@ -366,7 +373,7 @@ bool cByteBuffer::ReadBEInt64(Int64 & a_Value)
bool cByteBuffer::ReadBEFloat(float & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(4);
ReadBuf(&a_Value, 4);
@@ -380,7 +387,7 @@ bool cByteBuffer::ReadBEFloat(float & a_Value)
bool cByteBuffer::ReadBEDouble(double & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(8);
ReadBuf(&a_Value, 8);
@@ -394,7 +401,7 @@ bool cByteBuffer::ReadBEDouble(double & a_Value)
bool cByteBuffer::ReadBool(bool & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(1);
char Value = 0;
@@ -409,7 +416,7 @@ bool cByteBuffer::ReadBool(bool & a_Value)
bool cByteBuffer::ReadBEUTF16String16(AString & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
short Length;
if (!ReadBEShort(Length))
@@ -430,7 +437,7 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value)
bool cByteBuffer::ReadVarInt(UInt32 & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
UInt32 Value = 0;
int Shift = 0;
@@ -452,7 +459,7 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value)
bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
UInt32 Size = 0;
if (!ReadVarInt(Size))
@@ -472,7 +479,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
bool cByteBuffer::ReadLEInt(int & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(4);
ReadBuf(&a_Value, 4);
@@ -491,6 +498,7 @@ bool cByteBuffer::ReadLEInt(int & a_Value)
bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
{
+ CHECK_THREAD
Int64 Value;
if (!ReadBEInt64(Value))
{
@@ -515,7 +523,7 @@ bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
bool cByteBuffer::WriteChar(char a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(1);
return WriteBuf(&a_Value, 1);
@@ -527,7 +535,7 @@ bool cByteBuffer::WriteChar(char a_Value)
bool cByteBuffer::WriteByte(unsigned char a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(1);
return WriteBuf(&a_Value, 1);
@@ -539,7 +547,7 @@ bool cByteBuffer::WriteByte(unsigned char a_Value)
bool cByteBuffer::WriteBEShort(short a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(2);
u_short Converted = htons((u_short)a_Value);
@@ -552,7 +560,7 @@ bool cByteBuffer::WriteBEShort(short a_Value)
bool cByteBuffer::WriteBEUShort(unsigned short a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(2);
u_short Converted = htons((u_short)a_Value);
@@ -565,7 +573,7 @@ bool cByteBuffer::WriteBEUShort(unsigned short a_Value)
bool cByteBuffer::WriteBEInt(int a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(4);
UInt32 Converted = HostToNetwork4(&a_Value);
@@ -578,7 +586,7 @@ bool cByteBuffer::WriteBEInt(int a_Value)
bool cByteBuffer::WriteBEInt64(Int64 a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(8);
UInt64 Converted = HostToNetwork8(&a_Value);
@@ -591,7 +599,7 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value)
bool cByteBuffer::WriteBEFloat(float a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(4);
UInt32 Converted = HostToNetwork4(&a_Value);
@@ -604,7 +612,7 @@ bool cByteBuffer::WriteBEFloat(float a_Value)
bool cByteBuffer::WriteBEDouble(double a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(8);
UInt64 Converted = HostToNetwork8(&a_Value);
@@ -618,7 +626,7 @@ bool cByteBuffer::WriteBEDouble(double a_Value)
bool cByteBuffer::WriteBool(bool a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
return WriteChar(a_Value ? 1 : 0);
}
@@ -629,7 +637,7 @@ bool cByteBuffer::WriteBool(bool a_Value)
bool cByteBuffer::WriteVarInt(UInt32 a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
// A 32-bit integer can be encoded by at most 5 bytes:
@@ -650,7 +658,7 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value)
bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early.
bool res = WriteVarInt((UInt32)(a_Value.size()));
@@ -667,7 +675,7 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
bool cByteBuffer::WriteLEInt(int a_Value)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
#ifdef IS_LITTLE_ENDIAN
return WriteBuf((const char *)&a_Value, 4);
@@ -683,6 +691,7 @@ bool cByteBuffer::WriteLEInt(int a_Value)
bool cByteBuffer::WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ)
{
+ CHECK_THREAD
return WriteBEInt64(((Int64)a_BlockX & 0x3FFFFFF) << 38 | ((Int64)a_BlockY & 0xFFF) << 26 | ((Int64)a_BlockZ & 0x3FFFFFF));
}
@@ -692,7 +701,7 @@ bool cByteBuffer::WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ)
bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(a_Count);
char * Dst = (char *)a_Buffer; // So that we can do byte math
@@ -725,7 +734,7 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count)
bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
PUTBYTES(a_Count);
char * Src = (char *)a_Buffer; // So that we can do byte math
@@ -755,7 +764,7 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
NEEDBYTES(a_Count);
a_String.clear();
@@ -790,7 +799,7 @@ bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars)
{
// Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
AString RawData;
if (!ReadString(RawData, a_NumChars * 2))
@@ -807,7 +816,7 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars)
bool cByteBuffer::SkipRead(size_t a_Count)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
if (!CanReadBytes(a_Count))
{
@@ -823,7 +832,7 @@ bool cByteBuffer::SkipRead(size_t a_Count)
void cByteBuffer::ReadAll(AString & a_Data)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
ReadString(a_Data, GetReadableSpace());
}
@@ -834,6 +843,7 @@ void cByteBuffer::ReadAll(AString & a_Data)
bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes)
{
+ CHECK_THREAD
if (!a_Dst.CanWriteBytes(a_NumBytes) || !CanReadBytes(a_NumBytes))
{
// There's not enough source bytes or space in the dest BB
@@ -858,7 +868,7 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes)
void cByteBuffer::CommitRead(void)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
m_DataStart = m_ReadPos;
}
@@ -869,7 +879,7 @@ void cByteBuffer::CommitRead(void)
void cByteBuffer::ResetRead(void)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
m_ReadPos = m_DataStart;
}
@@ -882,7 +892,7 @@ void cByteBuffer::ReadAgain(AString & a_Out)
{
// Return the data between m_DataStart and m_ReadPos (the data that has been read but not committed)
// Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
size_t DataStart = m_DataStart;
if (m_ReadPos < m_DataStart)
@@ -902,7 +912,7 @@ void cByteBuffer::ReadAgain(AString & a_Out)
void cByteBuffer::AdvanceReadPos(size_t a_Count)
{
- CHECK_THREAD;
+ CHECK_THREAD
CheckValid();
m_ReadPos += a_Count;
if (m_ReadPos >= m_BufferSize)
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 70de419f0..2a316fa32 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -130,13 +130,15 @@ protected:
char * m_Buffer;
size_t m_BufferSize; // Total size of the ringbuffer
- #ifdef _DEBUG
- volatile unsigned long m_ThreadID; // Thread that is currently accessing the object, checked via cSingleThreadAccessChecker
- #endif // _DEBUG
-
size_t m_DataStart; // Where the data starts in the ringbuffer
size_t m_WritePos; // Where the data ends in the ringbuffer
size_t m_ReadPos; // Where the next read will start in the ringbuffer
+
+ #ifdef _DEBUG
+ /** The ID of the thread currently accessing the object.
+ Used for checking that only one thread accesses the object at a time, via cSingleThreadAccessChecker. */
+ mutable std::thread::id m_ThreadID;
+ #endif
/** Advances the m_ReadPos by a_Count bytes */
void AdvanceReadPos(size_t a_Count);
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d6218ff42..997326cc7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -113,7 +113,6 @@ SET (HDRS
Map.h
MapManager.h
Matrix4.h
- MersenneTwister.h
MobCensus.h
MobFamilyCollecter.h
MobProximityCounter.h
diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua
index 76ae8c325..0c7b05d6d 100644
--- a/src/CheckBasicStyle.lua
+++ b/src/CheckBasicStyle.lua
@@ -92,6 +92,25 @@ end
local g_ViolationPatterns =
{
+ -- Parenthesis around comparisons:
+ {"==[^)]+&&", "Add parenthesis around comparison"},
+ {"&&[^(]+==", "Add parenthesis around comparison"},
+ {"==[^)]+||", "Add parenthesis around comparison"},
+ {"||[^(]+==", "Add parenthesis around comparison"},
+ {"!=[^)]+&&", "Add parenthesis around comparison"},
+ {"&&[^(]+!=", "Add parenthesis around comparison"},
+ {"!=[^)]+||", "Add parenthesis around comparison"},
+ {"||[^(]+!=", "Add parenthesis around comparison"},
+ {"<[^)T][^)]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
+ {"&&[^(]+<", "Add parenthesis around comparison"},
+ {"<[^)T][^)]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
+ {"||[^(]+<", "Add parenthesis around comparison"},
+ -- Cannot check ">" because of "obj->m_Flag &&". Check at least ">=":
+ {">=[^)]+&&", "Add parenthesis around comparison"},
+ {"&&[^(]+>=", "Add parenthesis around comparison"},
+ {">=[^)]+||", "Add parenthesis around comparison"},
+ {"||[^(]+>=", "Add parenthesis around comparison"},
+
-- Check against indenting using spaces:
{"^\t* +", "Indenting with a space"},
@@ -116,11 +135,11 @@ local g_ViolationPatterns =
-- Space after keywords:
{"[^_]if%(", "Needs a space after \"if\""},
- {"for%(", "Needs a space after \"for\""},
- {"while%(", "Needs a space after \"while\""},
- {"switch%(", "Needs a space after \"switch\""},
- {"catch%(", "Needs a space after \"catch\""},
- {"template<", "Needs a space after \"template\""},
+ {"%sfor%(", "Needs a space after \"for\""},
+ {"%swhile%(", "Needs a space after \"while\""},
+ {"%sswitch%(", "Needs a space after \"switch\""},
+ {"%scatch%(", "Needs a space after \"catch\""},
+ {"%stemplate<", "Needs a space after \"template\""},
-- No space after keyword's parenthesis:
{"[^%a#]if %( ", "Remove the space after \"(\""},
@@ -162,6 +181,7 @@ local function ProcessFile(a_FileName)
-- Ref.: http://stackoverflow.com/questions/10416869/iterate-over-possibly-empty-lines-in-a-way-that-matches-the-expectations-of-exis
local lineCounter = 1
local lastIndentLevel = 0
+ local isLastLineControl = false
all:gsub("\r\n", "\n") -- normalize CRLF into LF-only
string.gsub(all .. "\n", "[^\n]*\n", -- Iterate over each line, while preserving empty lines
function(a_Line)
@@ -198,6 +218,24 @@ local function ProcessFile(a_FileName)
end
lastIndentLevel = indentLevel
end
+
+ -- Check that control statements have braces on separate lines after them:
+ -- Note that if statements can be broken into multiple lines, in which case this test is not taken
+ if (isLastLineControl) then
+ if not(a_Line:find("^%s*{") or a_Line:find("^%s*#")) then
+ -- Not followed by a brace, not followed by a preprocessor
+ ReportViolation(a_FileName, lineCounter - 1, 1, 1, "Control statement needs a brace on separate line")
+ end
+ end
+ local lineWithSpace = " " .. a_Line
+ isLastLineControl =
+ lineWithSpace:find("^%s+if %b()") or
+ lineWithSpace:find("^%s+else if %b()") or
+ lineWithSpace:find("^%s+for %b()") or
+ lineWithSpace:find("^%s+switch %b()") or
+ lineWithSpace:find("^%s+else\n") or
+ lineWithSpace:find("^%s+else //") or
+ lineWithSpace:find("^%s+do %b()")
lineCounter = lineCounter + 1
end
@@ -227,6 +265,9 @@ end
+-- Remove buffering from stdout, so that the output appears immediately in IDEs:
+io.stdout:setvbuf("no")
+
-- Process all files in the AllFiles.lst file (generated by cmake):
for fnam in io.lines("AllFiles.lst") do
ProcessItem(fnam)
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index a2a11f130..017ceda26 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -16,18 +16,18 @@
#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"
#include "Root.h"
-#include "MersenneTwister.h"
#include "Entities/Player.h"
#include "BlockArea.h"
#include "Bindings/PluginManager.h"
@@ -1348,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))
{
@@ -1479,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;
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 8a39c3ecb..cc83bcab3 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -16,7 +16,6 @@
#include "Mobs/Monster.h"
#include "ChatColor.h"
#include "OSSupport/Socket.h"
-#include "OSSupport/Timer.h"
#include "Items/ItemHandler.h"
#include "Blocks/BlockHandler.h"
#include "Blocks/BlockSlab.h"
@@ -25,8 +24,6 @@
#include "Root.h"
#include "Protocol/Authenticator.h"
-#include "MersenneTwister.h"
-
#include "Protocol/ProtocolRecognizer.h"
#include "CompositeChat.h"
#include "Items/ItemSword.h"
@@ -41,18 +38,13 @@
/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
#define MAX_BLOCK_CHANGE_INTERACTIONS 20
+/** The interval for sending pings to clients.
+Vanilla sends one ping every 1 second. */
+static const std::chrono::milliseconds PING_TIME_MS = std::chrono::milliseconds(1000);
-#define RECI_RAND_MAX (1.f/RAND_MAX)
-inline int fRadRand(MTRand & r1, int a_BlockCoord)
-{
- return a_BlockCoord * 32 + (int)(16 * ((float)r1.rand() * RECI_RAND_MAX) * 16 - 8);
-}
-
-
-
int cClientHandle::s_ClientCount = 0;
@@ -76,8 +68,6 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_TimeSinceLastPacket(0),
m_Ping(1000),
m_PingID(1),
- m_PingStartTime(0),
- m_LastPingTime(1000),
m_BlockDigAnimStage(-1),
m_BlockDigAnimSpeed(0),
m_BlockDigAnimX(0),
@@ -101,9 +91,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
s_ClientCount++; // Not protected by CS because clients are always constructed from the same thread
m_UniqueID = s_ClientCount;
-
- cTimer t1;
- m_LastPingTime = t1.GetNowTime();
+ m_PingStartTime = std::chrono::steady_clock::now();
LOGD("New ClientHandle created at %p", this);
}
@@ -199,9 +187,13 @@ void cClientHandle::GenerateOfflineUUID(void)
AString cClientHandle::FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2)
{
if (ShouldAppendChatPrefixes)
+ {
return Printf("%s[%s] %s", m_Color1.c_str(), a_ChatPrefixS.c_str(), m_Color2.c_str());
+ }
else
+ {
return Printf("%s", m_Color1.c_str());
+ }
}
@@ -397,8 +389,7 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
// Delay the first ping until the client "settles down"
// This should fix #889, "BadCast exception, cannot convert bit to fm" error in client
- cTimer t1;
- m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds
+ m_PingStartTime = std::chrono::steady_clock::now() + std::chrono::seconds(3); // Send the first KeepAlive packet in 3 seconds
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
}
@@ -1779,8 +1770,7 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
{
if (a_KeepAliveID == m_PingID)
{
- cTimer t1;
- m_Ping = (short)((t1.GetNowTime() - m_PingStartTime) / 2);
+ m_Ping = std::chrono::steady_clock::now() - m_PingStartTime;
}
}
@@ -2043,13 +2033,11 @@ void cClientHandle::Tick(float a_Dt)
// Send a ping packet:
if (m_State == csPlaying)
{
- cTimer t1;
- if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()))
+ if ((m_PingStartTime + PING_TIME_MS <= std::chrono::steady_clock::now()))
{
m_PingID++;
- m_PingStartTime = t1.GetNowTime();
+ m_PingStartTime = std::chrono::steady_clock::now();
m_Protocol->SendKeepAlive(m_PingID);
- m_LastPingTime = m_PingStartTime;
}
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index b3aec86f6..0e588d839 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -215,7 +215,7 @@ public:
const AString & GetUsername(void) const;
void SetUsername( const AString & a_Username);
- inline short GetPing(void) const { return m_Ping; }
+ inline short GetPing(void) const { return static_cast<short>(std::chrono::duration_cast<std::chrono::milliseconds>(m_Ping).count()); }
/** Sets the maximal view distance. */
void SetViewDistance(int a_ViewDistance);
@@ -382,12 +382,15 @@ private:
/** Seconds since the last packet data was received (updated in Tick(), reset in DataReceived()) */
float m_TimeSinceLastPacket;
- short m_Ping;
- int m_PingID;
- long long m_PingStartTime;
- long long m_LastPingTime;
- static const unsigned short PING_TIME_MS = 1000; // Vanilla sends 1 per 20 ticks (1 second or every 1000 ms)
-
+ /** Duration of the last completed client ping. */
+ std::chrono::steady_clock::duration m_Ping;
+
+ /** ID of the last ping request sent to the client. */
+ int m_PingID;
+
+ /** Time of the last ping request sent to the client. */
+ std::chrono::steady_clock::time_point m_PingStartTime;
+
// Values required for block dig animation
int m_BlockDigAnimStage; // Current stage of the animation; -1 if not digging
int m_BlockDigAnimSpeed; // Current speed of the animation (units ???)
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index 2c2b02a69..202fb900e 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -294,7 +294,7 @@ void cCraftingRecipes::GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingG
if (Recipe.get() == nullptr)
{
// Allow plugins to intercept a no-recipe-found situation:
- cRoot::Get()->GetPluginManager()->CallHookCraftingNoRecipe(a_Player, a_CraftingGrid, &a_Recipe);
+ cRoot::Get()->GetPluginManager()->CallHookCraftingNoRecipe(a_Player, a_CraftingGrid, a_Recipe);
return;
}
for (cRecipeSlots::const_iterator itr = Recipe->m_Ingredients.begin(); itr != Recipe->m_Ingredients.end(); ++itr)
diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp
index 7f703416c..3bb897221 100644
--- a/src/DeadlockDetect.cpp
+++ b/src/DeadlockDetect.cpp
@@ -13,7 +13,7 @@
-/// Number of milliseconds per cycle
+/** Number of milliseconds per cycle */
const int CYCLE_MILLISECONDS = 100;
@@ -87,7 +87,7 @@ void cDeadlockDetect::Execute(void)
} Checker(this);
cRoot::Get()->ForEachWorld(Checker);
- cSleep::MilliSleep(CYCLE_MILLISECONDS);
+ std::this_thread::sleep_for(std::chrono::milliseconds(CYCLE_MILLISECONDS));
} // while (should run)
}
@@ -119,7 +119,7 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
if (WorldAge.m_Age == a_Age)
{
WorldAge.m_NumCyclesSame += 1;
- if (WorldAge.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS)
+ if (WorldAge.m_NumCyclesSame > (m_IntervalSec * 1000) / CYCLE_MILLISECONDS)
{
DeadlockDetected();
}
diff --git a/src/DeadlockDetect.h b/src/DeadlockDetect.h
index 6aa98acbb..57027e923 100644
--- a/src/DeadlockDetect.h
+++ b/src/DeadlockDetect.h
@@ -28,7 +28,7 @@ class cDeadlockDetect :
public:
cDeadlockDetect(void);
- /// Starts the detection. Hides cIsThread's Start, because we need some initialization
+ /** Starts the detection. Hides cIsThread's Start, because we need some initialization */
bool Start(int a_IntervalSec);
protected:
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index afc61c73f..54b9f2a20 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -665,7 +665,10 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
// Filter out damage types that are not protected by armor:
- if (!ArmorCoversAgainst(a_DamageType)) return 0;
+ if (!ArmorCoversAgainst(a_DamageType))
+ {
+ return 0;
+ }
// Add up all armor points:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
@@ -1011,9 +1014,18 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
// Block hit was within our projected path
// Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1.
// For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP
- if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f;
- if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f;
- if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f;
+ if (Tracer.HitNormal.x != 0.f)
+ {
+ NextSpeed.x = 0.f;
+ }
+ if (Tracer.HitNormal.y != 0.f)
+ {
+ NextSpeed.y = 0.f;
+ }
+ if (Tracer.HitNormal.z != 0.f)
+ {
+ NextSpeed.z = 0.f;
+ }
if (Tracer.HitNormal.y == 1.f) // Hit BLOCK_FACE_YP, we are on the ground
{
@@ -1276,7 +1288,7 @@ bool cEntity::DetectPortal()
return false;
}
- if (IsPlayer() && !((cPlayer *)this)->IsGameModeCreative() && m_PortalCooldownData.m_TicksDelayed != 80)
+ if (IsPlayer() && !((cPlayer *)this)->IsGameModeCreative() && (m_PortalCooldownData.m_TicksDelayed != 80))
{
// Delay teleportation for four seconds if the entity is a non-creative player
m_PortalCooldownData.m_TicksDelayed++;
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 22e046800..fac4f0714 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -142,8 +142,13 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if (!IsBlockRail(InsideType))
{
- Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta); // When an descending minecart hits a flat rail, it goes through the ground; check for this
- if (IsBlockRail(InsideType)) AddPosY(1); // Push cart upwards
+ // When a descending minecart hits a flat rail, it goes through the ground; check for this
+ Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta);
+ if (IsBlockRail(InsideType))
+ {
+ // Push cart upwards
+ AddPosY(1);
+ }
}
bool WasDetectorRail = false;
@@ -218,7 +223,10 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
// Execute both the entity and block collision checks
bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
- if (EntCol || BlckCol) return;
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
if (GetSpeedZ() != NO_SPEED) // Don't do anything if cart is stationary
{
@@ -243,7 +251,10 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
SetSpeedZ(NO_SPEED);
bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
- if (EntCol || BlckCol) return;
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
if (GetSpeedX() != NO_SPEED)
{
@@ -422,7 +433,10 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
SetSpeedX(0);
bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
- if (EntCol || BlckCol) return;
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
if (GetSpeedZ() != NO_SPEED)
{
@@ -445,7 +459,10 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
SetSpeedZ(NO_SPEED);
bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
- if (EntCol || BlckCol) return;
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
if (GetSpeedX() != NO_SPEED)
{
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index edcdb4799..8d2eb1e5f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -11,7 +11,6 @@
#include "../BlockEntities/BlockEntity.h"
#include "../BlockEntities/EnderChestEntity.h"
#include "../Root.h"
-#include "../OSSupport/Timer.h"
#include "../Chunk.h"
#include "../Items/ItemHandler.h"
#include "../Vector3.h"
@@ -27,7 +26,7 @@
#define PLAYER_INVENTORY_SAVE_INTERVAL 6000
// 1000 = once per second
-#define PLAYER_LIST_TIME_MS 1000
+#define PLAYER_LIST_TIME_MS std::chrono::milliseconds(1000)
@@ -91,9 +90,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) :
SetMaxHealth(MAX_HEALTH);
m_Health = MAX_HEALTH;
- cTimer t1;
- m_LastPlayerListTime = t1.GetNowTime();
-
+ m_LastPlayerListTime = std::chrono::steady_clock::now();
m_PlayerName = a_PlayerName;
cWorld * World = nullptr;
@@ -120,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);
@@ -263,11 +265,10 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
m_Inventory.UpdateItems();
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
- cTimer t1;
- if (m_LastPlayerListTime + PLAYER_LIST_TIME_MS <= t1.GetNowTime())
+ if (m_LastPlayerListTime + PLAYER_LIST_TIME_MS <= std::chrono::steady_clock::now())
{
m_World->BroadcastPlayerListUpdatePing(*this);
- m_LastPlayerListTime = t1.GetNowTime();
+ m_LastPlayerListTime = std::chrono::steady_clock::now();
}
if (IsFlying())
@@ -358,7 +359,7 @@ float cPlayer::GetXpPercentage()
bool cPlayer::SetCurrentExperience(short int a_CurrentXp)
{
- if (!(a_CurrentXp >= 0) || (a_CurrentXp > (SHRT_MAX - m_LifetimeTotalXp)))
+ if (!(a_CurrentXp >= 0) || (a_CurrentXp > (std::numeric_limits<short>().max() - m_LifetimeTotalXp)))
{
LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_CurrentXp);
return false; // oops, they gave us a dodgey number
@@ -378,18 +379,17 @@ bool cPlayer::SetCurrentExperience(short int a_CurrentXp)
short cPlayer::DeltaExperience(short a_Xp_delta)
{
- if (a_Xp_delta > (SHRT_MAX - m_CurrentXp))
+ if (a_Xp_delta > (std::numeric_limits<short>().max() - m_CurrentXp))
{
// Value was bad, abort and report
- LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.",
- a_Xp_delta);
+ LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.", a_Xp_delta);
return -1; // Should we instead just return the current Xp?
}
m_CurrentXp += a_Xp_delta;
// Make sure they didn't subtract too much
- m_CurrentXp = std::max<short int>(m_CurrentXp, 0);
+ m_CurrentXp = std::max<short>(m_CurrentXp, 0);
// Update total for score calculation
if (a_Xp_delta > 0)
@@ -397,8 +397,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta)
m_LifetimeTotalXp += a_Xp_delta;
}
- LOGD("Player \"%s\" gained/lost %d experience, total is now: %d",
- GetName().c_str(), a_Xp_delta, m_CurrentXp);
+ LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", GetName().c_str(), a_Xp_delta, m_CurrentXp);
// Set experience to be updated
m_bDirtyExperience = true;
@@ -1074,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
}
@@ -1893,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);
}
@@ -1913,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;
}
@@ -2080,7 +2079,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
void cPlayer::ApplyFoodExhaustionFromMovement()
{
- if (IsGameModeCreative())
+ if (IsGameModeCreative() || IsGameModeSpectator())
{
return;
}
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 4bb51b556..c643aaa8e 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -516,7 +516,7 @@ protected:
/** The item being dragged by the cursor while in a UI window */
cItem m_DraggingItem;
- long long m_LastPlayerListTime;
+ std::chrono::steady_clock::time_point m_LastPlayerListTime;
cClientHandle * m_ClientHandle;
diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp
index 42bf5f3f9..515dc25ea 100644
--- a/src/FastRandom.cpp
+++ b/src/FastRandom.cpp
@@ -4,13 +4,15 @@
// Implements the cFastRandom class representing a fast random number generator
#include "Globals.h"
-#include <time.h>
#include "FastRandom.h"
+////////////////////////////////////////////////////////////////////////////////
+// cFastRandom:
+
#if 0 && defined(_DEBUG)
// Self-test
// Both ints and floats are quick-tested to see if the random is calculated correctly, checking the range in ASSERTs,
@@ -83,16 +85,8 @@ public:
-
-int cFastRandom::m_SeedCounter = 0;
-
-
-
-
-
cFastRandom::cFastRandom(void) :
- m_Seed(m_SeedCounter++),
- m_Counter(0)
+ m_LinearRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count()))
{
}
@@ -102,82 +96,96 @@ cFastRandom::cFastRandom(void) :
int cFastRandom::NextInt(int a_Range)
{
- ASSERT(a_Range <= 1000000); // The random is not sufficiently linearly distributed with bigger ranges
- ASSERT(a_Range > 0);
-
- // Make the m_Counter operations as minimal as possible, to emulate atomicity
- int Counter = m_Counter++;
-
- // Use a_Range, m_Counter and m_Seed as inputs to the pseudorandom function:
- int n = a_Range + Counter * 57 + m_Seed * 57 * 57;
- n = (n << 13) ^ n;
- n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
- return ((n / 11) % a_Range);
+ std::uniform_int_distribution<> distribution(0, a_Range - 1);
+ return distribution(m_LinearRand);
}
+
int cFastRandom::NextInt(int a_Range, int a_Salt)
{
- ASSERT(a_Range <= 1000000); // The random is not sufficiently linearly distributed with bigger ranges
- ASSERT(a_Range > 0);
-
- // Make the m_Counter operations as minimal as possible, to emulate atomicity
- int Counter = m_Counter++;
-
- // Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function:
- int n = a_Range + Counter * 57 + m_Seed * 57 * 57 + a_Salt * 57 * 57 * 57;
- n = (n << 13) ^ n;
- n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
- return ((n / 11) % a_Range);
+ m_LinearRand.seed(a_Salt);
+ std::uniform_int_distribution<> distribution(0, a_Range - 1);
+ return distribution(m_LinearRand);
}
+
float cFastRandom::NextFloat(float a_Range)
{
- // Make the m_Counter operations as minimal as possible, to emulate atomicity
- int Counter = m_Counter++;
-
- // Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function:
- int n = (int)a_Range + Counter * 57 + m_Seed * 57 * 57;
- n = (n << 13) ^ n;
- n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
-
- // Convert the integer into float with the specified range:
- return (((float)n / (float)0x7fffffff) * a_Range);
+ std::uniform_real_distribution<float> distribution(0, a_Range);
+ return distribution(m_LinearRand);
}
+
float cFastRandom::NextFloat(float a_Range, int a_Salt)
{
- // Make the m_Counter operations as minimal as possible, to emulate atomicity
- int Counter = m_Counter++;
-
- // Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function:
- int n = (int)a_Range + Counter * 57 + m_Seed * 57 * 57 + a_Salt * 57 * 57 * 57;
- n = (n << 13) ^ n;
- n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
-
- // Convert the integer into float with the specified range:
- return (((float)n / (float)0x7fffffff) * a_Range);
+ m_LinearRand.seed(a_Salt);
+ std::uniform_real_distribution<float> distribution(0, a_Range);
+ return distribution(m_LinearRand);
}
+
int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
{
- cFastRandom Random;
- return Random.NextInt(a_End - a_Begin + 1) + a_Begin;
+ std::uniform_int_distribution<> distribution(a_Begin, a_End);
+ return distribution(m_LinearRand);
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// MTRand:
+
+MTRand::MTRand() :
+ m_MersenneRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count()))
+{
+}
+
+
+
+
+
+int MTRand::randInt(int a_Range)
+{
+ std::uniform_int_distribution<> distribution(0, a_Range);
+ return distribution(m_MersenneRand);
+}
+
+
+
+
+
+int MTRand::randInt()
+{
+ std::uniform_int_distribution<> distribution(0, std::numeric_limits<int>::max());
+ return distribution(m_MersenneRand);
+}
+
+
+
+
+
+double MTRand::rand(double a_Range)
+{
+ std::uniform_real_distribution<> distribution(0, a_Range);
+ return distribution(m_MersenneRand);
}
diff --git a/src/FastRandom.h b/src/FastRandom.h
index cebebad96..64a087c97 100644
--- a/src/FastRandom.h
+++ b/src/FastRandom.h
@@ -22,6 +22,7 @@ salts, the values they get will be different.
#pragma once
+#include <random>
@@ -30,18 +31,19 @@ salts, the values they get will be different.
class cFastRandom
{
public:
+
cFastRandom(void);
- /// Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M
+ /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M */
int NextInt(int a_Range);
- /// Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness
+ /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness */
int NextInt(int a_Range, int a_Salt);
- /// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M
+ /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M */
float NextFloat(float a_Range);
- /// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness
+ /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness */
float NextFloat(float a_Range, int a_Salt);
/** Returns a random float between 0 and 1. */
@@ -49,14 +51,35 @@ public:
/** Returns a random int in the range [a_Begin .. a_End] */
int GenerateRandomInteger(int a_Begin, int a_End);
-
-protected:
- int m_Seed;
- int m_Counter;
-
- /// Counter that is used to initialize the seed, incremented for each object created
- static int m_SeedCounter;
-} ;
+
+private:
+
+ std::minstd_rand m_LinearRand;
+};
+
+
+
+
+
+class MTRand
+{
+public:
+
+ MTRand(void);
+
+ /** Returns a random integer in the range [0 .. a_Range]. */
+ int randInt(int a_Range);
+
+ /** Returns a random integer in the range [0 .. MAX_INT]. */
+ int randInt(void);
+
+ /** Returns a random floating point number in the range [0 .. a_Range]. */
+ double rand(double a_Range);
+
+private:
+
+ std::mt19937 m_MersenneRand;
+};
diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp
index fc925a150..e4735cb83 100644
--- a/src/Generating/Caves.cpp
+++ b/src/Generating/Caves.cpp
@@ -692,8 +692,14 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise)
float oct1 = (a_Noise.CubicNoise3D(x * 0.1f, y * 0.1f, z * 0.1f)) * 4;
oct1 = oct1 * oct1 * oct1;
- if (oct1 < 0.f) oct1 = PI_2;
- if (oct1 > PI_2) oct1 = PI_2;
+ if (oct1 < 0.f)
+ {
+ oct1 = PI_2;
+ }
+ if (oct1 > PI_2)
+ {
+ oct1 = PI_2;
+ }
return oct1;
}
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index 3ee02c767..d2e7b47b4 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -6,7 +6,7 @@
#include "ChunkDesc.h"
#include "ComposableGenerator.h"
#include "Noise3DGenerator.h"
-#include "../MersenneTwister.h"
+#include "FastRandom.h"
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/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 4192dfa72..bda45ad92 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -294,7 +294,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
// Finishers, alpha-sorted:
- if (NoCaseCompare(*itr, "BottomLava") == 0)
+ if (NoCaseCompare(*itr, "Animals") == 0)
+ {
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPassiveMobs(Seed, a_IniFile, Dimension)));
+ }
+ else if (NoCaseCompare(*itr, "BottomLava") == 0)
{
int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
@@ -570,6 +574,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..e10cb00f8 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -26,6 +26,8 @@
#define DEF_OVERWORLD_LAVA_SPRINGS "0, 0; 10, 5; 11, 45; 48, 2; 64, 1; 255, 0"
#define DEF_END_WATER_SPRINGS "0, 1; 255, 1"
#define DEF_END_LAVA_SPRINGS "0, 1; 255, 1"
+#define DEF_ANIMAL_SPAWN_PERCENT 10
+#define DEF_NO_ANIMALS 0
@@ -65,7 +67,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 +197,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 +283,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 +296,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 +321,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 +361,7 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
}
break;
} // case E_BLOCK_GRASS
-
+
case E_BLOCK_SAND:
{
int y = Top + 1;
@@ -370,7 +372,8 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
(a_ChunkDesc.GetBlockType(x + 1, y, z) == E_BLOCK_AIR) &&
(a_ChunkDesc.GetBlockType(x - 1, y, z) == E_BLOCK_AIR) &&
(a_ChunkDesc.GetBlockType(x, y, z + 1) == E_BLOCK_AIR) &&
- (a_ChunkDesc.GetBlockType(x, y, z - 1) == E_BLOCK_AIR)
+ (a_ChunkDesc.GetBlockType(x, y, z - 1) == E_BLOCK_AIR) &&
+ IsDesertVariant(a_ChunkDesc.GetBiome(x, z))
)
{
a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_CACTUS);
@@ -391,6 +394,72 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
+bool cFinishGenSprinkleFoliage::IsDesertVariant(EMCSBiome a_Biome)
+{
+ return
+ (
+ (a_Biome == biDesertHills) ||
+ (a_Biome == biDesert) ||
+ (a_Biome == biDesertM)
+ );
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// 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:
@@ -516,7 +585,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 +785,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 +877,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 +920,7 @@ bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int
{
return false;
}
-
+
static const struct
{
int x, y, z;
@@ -882,7 +951,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;
@@ -891,3 +960,236 @@ bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int
+
+////////////////////////////////////////////////////////////////////////////////
+// cFinishGenPassiveMobs:
+
+cFinishGenPassiveMobs::cFinishGenPassiveMobs(int a_Seed, cIniFile & a_IniFile, eDimension a_Dimension) :
+ m_Noise(a_Seed)
+{
+ AString SectionName = "Animals";
+ int DefaultAnimalSpawnChunkPercentage = DEF_ANIMAL_SPAWN_PERCENT;
+ switch (a_Dimension)
+ {
+ case dimOverworld:
+ {
+ DefaultAnimalSpawnChunkPercentage = DEF_ANIMAL_SPAWN_PERCENT;
+ break;
+ }
+ case dimNether:
+ case dimEnd: // No nether or end animals (currently)
+ {
+ DefaultAnimalSpawnChunkPercentage = DEF_NO_ANIMALS;
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled world dimension");
+ DefaultAnimalSpawnChunkPercentage = DEF_NO_ANIMALS;
+ break;
+ }
+ } // switch (dimension)
+ m_AnimalProbability = a_IniFile.GetValueSetI(SectionName, "AnimalSpawnChunkPercentage", DefaultAnimalSpawnChunkPercentage);
+ if ((m_AnimalProbability < 0) || (m_AnimalProbability > 100))
+ {
+ LOGWARNING("[Animals]: AnimalSpawnChunkPercentage is invalid, using the default of \"%d\".", DefaultAnimalSpawnChunkPercentage);
+ m_AnimalProbability = DefaultAnimalSpawnChunkPercentage;
+ }
+}
+
+
+
+
+
+void cFinishGenPassiveMobs::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int chunkX = a_ChunkDesc.GetChunkX();
+ int chunkZ = a_ChunkDesc.GetChunkZ();
+ int ChanceRnd = (m_Noise.IntNoise2DInt(chunkX, chunkZ) / 7) % 100;
+ if (ChanceRnd > m_AnimalProbability)
+ {
+ return;
+ }
+
+ eMonsterType RandomMob = GetRandomMob(a_ChunkDesc);
+ if (RandomMob == mtInvalidType)
+ {
+ // No mobs here. Don't send an error, because if the biome was a desert it would return mtInvalidType as well.
+ return;
+ }
+
+ // Try spawning a pack center 10 times, should get roughly the same probability
+ for (int Tries = 0; Tries < 10; Tries++)
+ {
+ int PackCenterX = (m_Noise.IntNoise2DInt(chunkX + chunkZ, Tries) / 7) % cChunkDef::Width;
+ int PackCenterZ = (m_Noise.IntNoise2DInt(chunkX, chunkZ + Tries) / 7) % cChunkDef::Width;
+ if (TrySpawnAnimals(a_ChunkDesc, PackCenterX, a_ChunkDesc.GetHeight(PackCenterX, PackCenterZ), PackCenterZ, RandomMob))
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ int OffsetX = (m_Noise.IntNoise2DInt(chunkX + chunkZ + i, Tries) / 7) % cChunkDef::Width;
+ int OffsetZ = (m_Noise.IntNoise2DInt(chunkX, chunkZ + Tries + i) / 7) % cChunkDef::Width;
+ TrySpawnAnimals(a_ChunkDesc, OffsetX, a_ChunkDesc.GetHeight(OffsetX, OffsetZ), OffsetZ, RandomMob);
+ }
+ return;
+
+ } // if pack center spawn successful
+ } // for tries
+}
+
+
+
+
+
+bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, eMonsterType AnimalToSpawn)
+{
+ if ((a_RelY >= cChunkDef::Height - 1) || (a_RelY <= 0))
+ {
+ return false;
+ }
+
+ BLOCKTYPE BlockAtHead = a_ChunkDesc.GetBlockType(a_RelX, a_RelY + 1, a_RelZ);
+ BLOCKTYPE BlockAtFeet = a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ);
+ BLOCKTYPE BlockUnderFeet = a_ChunkDesc.GetBlockType(a_RelX, a_RelY - 1, a_RelZ);
+
+ // Check block below (opaque, grass, water), and above (air)
+ if ((AnimalToSpawn == mtSquid) && (BlockAtFeet != E_BLOCK_WATER))
+ {
+ return false;
+ }
+ if (
+ (AnimalToSpawn != mtSquid) &&
+ (BlockAtHead != E_BLOCK_AIR) &&
+ (BlockAtFeet != E_BLOCK_AIR) &&
+ (!cBlockInfo::IsTransparent(BlockUnderFeet))
+ )
+ {
+ return false;
+ }
+ if (
+ (BlockUnderFeet != E_BLOCK_GRASS) &&
+ ((AnimalToSpawn == mtSheep) || (AnimalToSpawn == mtChicken) || (AnimalToSpawn == mtPig))
+ )
+ {
+ return false;
+ }
+ if ((AnimalToSpawn == mtMooshroom) && (BlockUnderFeet != E_BLOCK_MYCELIUM))
+ {
+ return false;
+ }
+
+ double AnimalX = static_cast<double>(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX + 0.5);
+ double AnimalY = a_RelY;
+ double AnimalZ = static_cast<double>(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ + 0.5);
+
+ cMonster * NewMob = cMonster::NewMonsterFromType(AnimalToSpawn);
+ NewMob->SetPosition(AnimalX, AnimalY, AnimalZ);
+ a_ChunkDesc.GetEntities().push_back(NewMob);
+ LOGD("Spawning %s #%i at {%.02f, %.02f, %.02f}", NewMob->GetClass(), NewMob->GetUniqueID(), AnimalX, AnimalY, AnimalZ);
+
+ return true;
+}
+
+
+
+
+
+eMonsterType cFinishGenPassiveMobs::GetRandomMob(cChunkDesc & a_ChunkDesc)
+{
+
+ std::set<eMonsterType> ListOfSpawnables;
+ int chunkX = a_ChunkDesc.GetChunkX();
+ int chunkZ = a_ChunkDesc.GetChunkZ();
+ int x = (m_Noise.IntNoise2DInt(chunkX, chunkZ + 10) / 7) % cChunkDef::Width;
+ int z = (m_Noise.IntNoise2DInt(chunkX + chunkZ, chunkZ) / 7) % cChunkDef::Width;
+
+ // Check biomes first to get a list of animals
+ switch (a_ChunkDesc.GetBiome(x, z))
+ {
+ // No animals in deserts or non-overworld dimensions
+ case biNether:
+ case biEnd:
+ case biDesertHills:
+ case biDesert:
+ case biDesertM:
+ {
+ return mtInvalidType;
+ }
+
+ // Mooshroom only - no other mobs on mushroom islands
+ case biMushroomIsland:
+ case biMushroomShore:
+ {
+ return mtMooshroom;
+ }
+
+ // Add squid in ocean biomes
+ case biOcean:
+ case biFrozenOcean:
+ case biFrozenRiver:
+ case biRiver:
+ case biDeepOcean:
+ {
+ ListOfSpawnables.insert(mtSquid);
+ break;
+ }
+
+ // Add ocelots in jungle biomes
+ case biJungle:
+ case biJungleHills:
+ case biJungleEdge:
+ case biJungleM:
+ case biJungleEdgeM:
+ {
+ ListOfSpawnables.insert(mtOcelot);
+ break;
+ }
+
+ // Add horses in plains-like biomes
+ case biPlains:
+ case biSunflowerPlains:
+ case biSavanna:
+ case biSavannaPlateau:
+ case biSavannaM:
+ case biSavannaPlateauM:
+ {
+ ListOfSpawnables.insert(mtHorse);
+ break;
+ }
+
+ // Add wolves in forest and spruce forests
+ case biForest:
+ case biTaiga:
+ case biMegaTaiga:
+ case biColdTaiga:
+ case biColdTaigaM:
+ {
+ ListOfSpawnables.insert(mtWolf);
+ break;
+ }
+ // Nothing special about this biome
+ default:
+ {
+ break;
+ }
+ }
+ ListOfSpawnables.insert(mtChicken);
+ ListOfSpawnables.insert(mtCow);
+ ListOfSpawnables.insert(mtPig);
+ ListOfSpawnables.insert(mtSheep);
+
+ if (ListOfSpawnables.empty())
+ {
+ return mtInvalidType;
+ }
+
+ int RandMob = (m_Noise.IntNoise2DInt(chunkX - chunkZ + 2, chunkX + 5) / 7) % ListOfSpawnables.size();
+ auto MobIter = ListOfSpawnables.begin();
+ std::advance(MobIter, RandMob);
+
+ return *MobIter;
+}
+
+
+
+
diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h
index 991a85787..ae6dee590 100644
--- a/src/Generating/FinishGen.h
+++ b/src/Generating/FinishGen.h
@@ -18,6 +18,7 @@
#include "ComposableGenerator.h"
#include "../Noise/Noise.h"
#include "../ProbabDistrib.h"
+#include "../Mobs/Monster.h"
@@ -117,19 +118,41 @@ 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);
-
+
+ // Returns true is the specified biome is a desert or its variant
+ static bool IsDesertVariant(EMCSBiome a_biome);
+
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -167,31 +190,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 +229,7 @@ protected:
return m_IsAllowedBelow[a_BlockBelow];
}
-
+
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -223,11 +246,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 +264,7 @@ class cFinishGenPreSimulator :
{
public:
cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava);
-
+
protected:
bool m_PreSimulateFallingBlocks;
@@ -253,7 +276,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 +301,7 @@ class cFinishGenFluidSprings :
{
public:
cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension);
-
+
protected:
cNoise m_Noise;
@@ -289,10 +312,43 @@ protected:
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
- /// Tries to place a spring at the specified coords, checks neighbors. Returns true if successful
+ /** Tries to place a spring at the specified coords, checks neighbors. Returns true if successful. */
bool TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int y, int z);
} ;
+
+/** This class populates generated chunks with packs of biome-dependant animals
+Animals: cows, sheep, pigs, mooshrooms, squid, horses, wolves, ocelots */
+class cFinishGenPassiveMobs :
+ public cFinishGen
+{
+public:
+
+ cFinishGenPassiveMobs(int a_Seed, cIniFile & a_IniFile, eDimension a_Dimension);
+
+protected:
+
+ /** The noise used as the source of randomness */
+ cNoise m_Noise;
+
+ /** Chance, [0..100], that an animal pack will be generated in a chunk */
+ int m_AnimalProbability;
+
+
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ /** Returns false if an animal cannot spawn at given coords, else adds it to the chunk's entity list and returns true */
+ bool TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int x, int y, int z, eMonsterType AnimalToSpawn);
+
+ /** Picks a random animal from biome-dependant list for a random position in the chunk.
+ Returns the chosen mob type, or mtInvalid if no mob chosen. */
+ eMonsterType GetRandomMob(cChunkDesc & a_ChunkDesc);
+} ;
+
+
+
+
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 a7af87bac..b43a1a6de 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -6,7 +6,6 @@
#include "Globals.h"
#include "Noise3DGenerator.h"
#include "../OSSupport/File.h"
-#include "../OSSupport/Timer.h"
#include "../IniFile.h"
#include "../LinearInterpolation.h"
#include "../LinearUpscale.h"
@@ -529,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;
@@ -737,7 +738,7 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE
case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
- case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break;
+ case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 54; break;
case biFrozenOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break;
case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
@@ -762,7 +763,7 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE
case biNether: a_HeightAmp = 0.01f; a_MidPoint = 64; break;
case biOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break;
case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
- case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break;
+ case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 54; break;
case biRoofedForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
case biRoofedForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
case biSavanna: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
diff --git a/src/Globals.h b/src/Globals.h
index 582f5fdaa..61f500db9 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -184,9 +184,9 @@ template class SizeChecker<UInt16, 2>;
// OS-dependent stuff:
#ifdef _WIN32
- #define WIN32_LEAN_AND_MEAN
- #define _WIN32_WINNT 0x501 // We want to target WinXP and higher
+ #define WIN32_LEAN_AND_MEAN
+ #define _WIN32_WINNT _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher
#include <Windows.h>
#include <winsock2.h>
@@ -241,6 +241,7 @@ template class SizeChecker<UInt16, 2>;
// STL stuff:
+#include <chrono>
#include <vector>
#include <list>
#include <deque>
@@ -251,19 +252,20 @@ template class SizeChecker<UInt16, 2>;
#include <set>
#include <queue>
#include <limits>
+#include <chrono>
+
#ifndef TEST_GLOBALS
// Common headers (part 1, without macros):
#include "StringUtils.h"
- #include "OSSupport/Sleep.h"
#include "OSSupport/CriticalSection.h"
#include "OSSupport/Semaphore.h"
#include "OSSupport/Event.h"
- #include "OSSupport/Thread.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);
@@ -349,14 +351,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/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h
index edc6d2471..d9d29d9bc 100644
--- a/src/HTTPServer/HTTPFormParser.h
+++ b/src/HTTPServer/HTTPFormParser.h
@@ -82,7 +82,7 @@ protected:
bool m_IsValid;
/// The parser for the multipart data, if used
- std::auto_ptr<cMultipartParser> m_MultipartParser;
+ std::unique_ptr<cMultipartParser> m_MultipartParser;
/// Name of the currently parsed part in multipart data
AString m_CurrentPartName;
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index 51ac32da9..fba6f4aea 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -507,7 +507,11 @@ bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size,
int MaxStackSize = cItemHandler::GetItemHandler(a_Item.m_ItemType)->GetMaxStackSize();
for (int i = 0; i < a_Size; i++)
{
- if (m_Slots[i + a_Offset].m_ItemType == a_Item.m_ItemType && m_Slots[i + a_Offset].m_ItemCount < MaxStackSize && m_Slots[i + a_Offset].m_ItemDamage == a_Item.m_ItemDamage)
+ if (
+ (m_Slots[i + a_Offset].m_ItemType == a_Item.m_ItemType) &&
+ (m_Slots[i + a_Offset].m_ItemCount < MaxStackSize) &&
+ (m_Slots[i + a_Offset].m_ItemDamage == a_Item.m_ItemDamage)
+ )
{
int NumFree = MaxStackSize - m_Slots[i + a_Offset].m_ItemCount;
if (NumFree >= a_Item.m_ItemCount)
@@ -533,7 +537,7 @@ bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size,
if (a_Mode > 0)
{
// If we got more left, find first empty slot
- for (int i = 0; i < a_Size && a_Item.m_ItemCount > 0; i++)
+ for (int i = 0; (i < a_Size) && (a_Item.m_ItemCount > 0); i++)
{
if (m_Slots[i + a_Offset].m_ItemType == -1)
{
diff --git a/src/Logger.cpp b/src/Logger.cpp
index cb528e8ab..292622a46 100644
--- a/src/Logger.cpp
+++ b/src/Logger.cpp
@@ -45,12 +45,12 @@ void cLogger::LogSimple(AString a_Message, eLogLevel a_LogLevel)
AString Line;
#ifdef _DEBUG
- Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str());
+ Printf(Line, "[%04llx|%02d:%02d:%02d] %s\n", static_cast<UInt64>(std::hash<std::thread::id>()(std::this_thread::get_id())), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str());
#else
Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str());
#endif
-
+
cCSLock Lock(m_CriticalSection);
for (size_t i = 0; i < m_LogListeners.size(); i++)
{
diff --git a/src/MersenneTwister.h b/src/MersenneTwister.h
deleted file mode 100644
index e83a470e2..000000000
--- a/src/MersenneTwister.h
+++ /dev/null
@@ -1,456 +0,0 @@
-// MersenneTwister.h
-// Mersenne Twister random number generator -- a C++ class MTRand
-// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
-// Richard J. Wagner v1.1 28 September 2009 wagnerr@umich.edu
-
-// The Mersenne Twister is an algorithm for generating random numbers. It
-// was designed with consideration of the flaws in various other generators.
-// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
-// are far greater. The generator is also fast; it avoids multiplication and
-// division, and it benefits from caches and pipelines. For more information
-// see the inventors' web page at
-// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
-
-// Reference
-// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
-// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
-// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
-
-// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
-// Copyright (C) 2000 - 2009, Richard J. Wagner
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// 3. The names of its contributors may not be used to endorse or promote
-// products derived from this software without specific prior written
-// permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef MERSENNETWISTER_H
-#define MERSENNETWISTER_H
-
-// Not thread safe (unless auto-initialization is avoided and each thread has
-// its own MTRand object)
-
-#include <iostream>
-#include <climits>
-#include <cstdio>
-#include <ctime>
-#include <cmath>
-
-class MTRand {
-// Data
-public:
- typedef UInt32 uint32; // unsigned integer type, at least 32 bits
-
- enum { N = 624 }; // length of state vector
- enum { SAVE = N + 1 }; // length of array for save()
-
-protected:
- enum { M = 397 }; // period parameter
-
- uint32 state[N]; // internal state
- uint32 *pNext; // next value to get from state
- uint32 left; // number of values left before reload needed
-
-// Methods
-public:
- MTRand( const uint32 oneSeed ); // initialize with a simple uint32
- MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or array
- MTRand(); // auto-initialize with /dev/urandom or time() and clock()
- MTRand( const MTRand& o ); // copy
-
- // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
- // values together, otherwise the generator state can be learned after
- // reading 624 consecutive values.
-
- // Access to 32-bit random numbers
- uint32 randInt(); // integer in [0,2^32-1]
- uint32 randInt( const uint32 n ); // integer in [0,n] for n < 2^32
- double rand(); // real number in [0,1]
- double rand( const double n ); // real number in [0,n]
- double randExc(); // real number in [0,1)
- double randExc( const double n ); // real number in [0,n)
- double randDblExc(); // real number in (0,1)
- double randDblExc( const double n ); // real number in (0,n)
- double operator()(); // same as rand()
-
- // Access to 53-bit random numbers (capacity of IEEE double precision)
- double rand53(); // real number in [0,1)
-
- // Access to nonuniform random number distributions
- double randNorm( const double mean = 0.0, const double stddev = 1.0 );
-
- // Re-seeding functions with same behavior as initializers
- void seed( const uint32 oneSeed );
- void seed( uint32 *const bigSeed, const uint32 seedLength = N );
- void seed();
-
- // Saving and loading generator state
- void save( uint32* saveArray ) const; // to array of size SAVE
- void load( uint32 *const loadArray ); // from such array
- friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
- friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
- MTRand& operator=( const MTRand& o );
-
-protected:
- void initialize( const uint32 oneSeed );
- void reload();
- uint32 hiBit( const uint32 u ) const { return u & 0x80000000UL; }
- uint32 loBit( const uint32 u ) const { return u & 0x00000001UL; }
- uint32 loBits( const uint32 u ) const { return u & 0x7fffffffUL; }
- uint32 mixBits( const uint32 u, const uint32 v ) const
- { return hiBit(u) | loBits(v); }
- uint32 magic( const uint32 u ) const
- { return loBit(u) ? 0x9908b0dfUL : 0x0UL; }
- uint32 twist( const uint32 m, const uint32 s0, const uint32 s1 ) const
- { return m ^ (mixBits(s0,s1)>>1) ^ magic(s1); }
- static uint32 hash( time_t t, clock_t c );
-};
-
-// Functions are defined in order of usage to assist inlining
-
-inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
-{
- // Get a uint32 from t and c
- // Better than uint32(x) in case x is floating point in [0,1]
- // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
-
- static uint32 differ = 0; // guarantee time-based seeds will change
-
- uint32 h1 = 0;
- unsigned char *p = (unsigned char *) &t;
- for( size_t i = 0; i < sizeof(t); ++i )
- {
- h1 *= UCHAR_MAX + 2U;
- h1 += p[i];
- }
- uint32 h2 = 0;
- p = (unsigned char *) &c;
- for( size_t j = 0; j < sizeof(c); ++j )
- {
- h2 *= UCHAR_MAX + 2U;
- h2 += p[j];
- }
- return ( h1 + differ++ ) ^ h2;
-}
-
-inline void MTRand::initialize( const uint32 seed )
-{
- // Initialize generator state with seed
- // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
- // In previous versions, most significant bits (MSBs) of the seed affect
- // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
- uint32 *s = state;
- uint32 *r = state;
- uint32 i = 1;
- *s++ = seed & 0xffffffffUL;
- for( ; i < N; ++i )
- {
- *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
- r++;
- }
-}
-
-inline void MTRand::reload()
-{
- // Generate N new values in state
- // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
- static const int MmN = int(M) - int(N); // in case enums are unsigned
- uint32 *p = state;
- int i;
- for( i = N - M; i--; ++p )
- *p = twist( p[M], p[0], p[1] );
- for( i = M; --i; ++p )
- *p = twist( p[MmN], p[0], p[1] );
- *p = twist( p[MmN], p[0], state[0] );
-
- left = N, pNext = state;
-}
-
-inline void MTRand::seed( const uint32 oneSeed )
-{
- // Seed the generator with a simple uint32
- initialize(oneSeed);
- reload();
-}
-
-inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
-{
- // Seed the generator with an array of uint32's
- // There are 2^19937-1 possible initial states. This function allows
- // all of those to be accessed by providing at least 19937 bits (with a
- // default seed length of N = 624 uint32's). Any bits above the lower 32
- // in each element are discarded.
- // Just call seed() if you want to get array from /dev/urandom
- initialize(19650218UL);
- uint32 i = 1;
- uint32 j = 0;
- uint32 k = ( static_cast<uint32>(N) > seedLength ? static_cast<uint32>(N) : seedLength );
- for( ; k; --k )
- {
- state[i] =
- state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
- state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
- state[i] &= 0xffffffffUL;
- ++i; ++j;
- if( i >= N ) { state[0] = state[N-1]; i = 1; }
- if( j >= seedLength ) j = 0;
- }
- for( k = N - 1; k; --k )
- {
- state[i] =
- state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
- state[i] -= i;
- state[i] &= 0xffffffffUL;
- ++i;
- if( i >= N ) { state[0] = state[N-1]; i = 1; }
- }
- state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
- reload();
-}
-
-inline void MTRand::seed()
-{
- // Seed the generator with an array from /dev/urandom if available
- // Otherwise use a hash of time() and clock() values
-
- // First try getting an array from /dev/urandom
-
- /* // Commented out by FakeTruth because doing this 200 times a tick is SUUUUPEERRR SLOW!!~~!\D5Ne
- FILE* urandom = fopen( "/dev/urandom", "rb" );
- if( urandom )
- {
- uint32 bigSeed[N];
- register uint32 *s = bigSeed;
- register int i = N;
- register bool success = true;
- while( success && i-- )
- success = fread( s++, sizeof(uint32), 1, urandom );
- fclose(urandom);
- if( success ) { seed( bigSeed, N ); return; }
- }
- */
-
- // Was not successful, so use time() and clock() instead
- seed( hash( time(NULL), clock() ) );
-}
-
-inline MTRand::MTRand( const uint32 oneSeed )
- { seed(oneSeed); }
-
-inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
- { seed(bigSeed,seedLength); }
-
-inline MTRand::MTRand()
- { seed(); }
-
-inline MTRand::MTRand( const MTRand& o )
-{
- const uint32 *t = o.state;
- uint32 *s = state;
- int i = N;
- for( ; i--; *s++ = *t++ ) {}
- left = o.left;
- pNext = &state[N-left];
-}
-
-inline MTRand::uint32 MTRand::randInt()
-{
- // Pull a 32-bit integer from the generator state
- // Every other access function simply transforms the numbers extracted here
-
- if( left == 0 ) reload();
- --left;
-
- uint32 s1;
- s1 = *pNext++;
- s1 ^= (s1 >> 11);
- s1 ^= (s1 << 7) & 0x9d2c5680UL;
- s1 ^= (s1 << 15) & 0xefc60000UL;
- return ( s1 ^ (s1 >> 18) );
-}
-
-inline MTRand::uint32 MTRand::randInt( const uint32 n )
-{
- // Find which bits are used in n
- // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
- uint32 used = n;
- used |= used >> 1;
- used |= used >> 2;
- used |= used >> 4;
- used |= used >> 8;
- used |= used >> 16;
-
- // Draw numbers until one is found in [0,n]
- uint32 i;
- do
- i = randInt() & used; // toss unused bits to shorten search
- while( i > n );
- return i;
-}
-
-inline double MTRand::rand()
- { return double(randInt()) * (1.0/4294967295.0); }
-
-inline double MTRand::rand( const double n )
- { return rand() * n; }
-
-inline double MTRand::randExc()
- { return double(randInt()) * (1.0/4294967296.0); }
-
-inline double MTRand::randExc( const double n )
- { return randExc() * n; }
-
-inline double MTRand::randDblExc()
- { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
-
-inline double MTRand::randDblExc( const double n )
- { return randDblExc() * n; }
-
-inline double MTRand::rand53()
-{
- uint32 a = randInt() >> 5, b = randInt() >> 6;
- return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
-}
-
-inline double MTRand::randNorm( const double mean, const double stddev )
-{
- // Return a real number from a normal (Gaussian) distribution with given
- // mean and standard deviation by polar form of Box-Muller transformation
- double x, y, r;
- do
- {
- x = 2.0 * rand() - 1.0;
- y = 2.0 * rand() - 1.0;
- r = x * x + y * y;
- }
- while ( r >= 1.0 || r == 0.0 );
- double s = sqrt( -2.0 * log(r) / r );
- return mean + x * s * stddev;
-}
-
-inline double MTRand::operator()()
-{
- return rand();
-}
-
-inline void MTRand::save( uint32* saveArray ) const
-{
- const uint32 *s = state;
- uint32 *sa = saveArray;
- int i = N;
- for( ; i--; *sa++ = *s++ ) {}
- *sa = left;
-}
-
-inline void MTRand::load( uint32 *const loadArray )
-{
- uint32 *s = state;
- uint32 *la = loadArray;
- int i = N;
- for( ; i--; *s++ = *la++ ) {}
- left = *la;
- pNext = &state[N-left];
-}
-
-inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
-{
- const MTRand::uint32 *s = mtrand.state;
- int i = mtrand.N;
- for( ; i--; os << *s++ << "\t" ) {}
- return os << mtrand.left;
-}
-
-inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
-{
- MTRand::uint32 *s = mtrand.state;
- int i = mtrand.N;
- for( ; i--; is >> *s++ ) {}
- is >> mtrand.left;
- mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
- return is;
-}
-
-inline MTRand& MTRand::operator=( const MTRand& o )
-{
- if( this == &o ) return (*this);
- const uint32 *t = o.state;
- uint32 *s = state;
- int i = N;
- for( ; i--; *s++ = *t++ ) {}
- left = o.left;
- pNext = &state[N-left];
- return (*this);
-}
-
-#endif // MERSENNETWISTER_H
-
-// Change log:
-//
-// v0.1 - First release on 15 May 2000
-// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
-// - Translated from C to C++
-// - Made completely ANSI compliant
-// - Designed convenient interface for initialization, seeding, and
-// obtaining numbers in default or user-defined ranges
-// - Added automatic seeding from /dev/urandom or time() and clock()
-// - Provided functions for saving and loading generator state
-//
-// v0.2 - Fixed bug which reloaded generator one step too late
-//
-// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
-//
-// v0.4 - Removed trailing newline in saved generator format to be consistent
-// with output format of built-in types
-//
-// v0.5 - Improved portability by replacing static const int's with enum's and
-// clarifying return values in seed(); suggested by Eric Heimburg
-// - Removed MAXINT constant; use 0xffffffffUL instead
-//
-// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
-// - Changed integer [0,n] generator to give better uniformity
-//
-// v0.7 - Fixed operator precedence ambiguity in reload()
-// - Added access for real numbers in (0,1) and (0,n)
-//
-// v0.8 - Included time.h header to properly support time_t and clock_t
-//
-// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
-// - Allowed for seeding with arrays of any length
-// - Added access for real numbers in [0,1) with 53-bit resolution
-// - Added access for real numbers from normal (Gaussian) distributions
-// - Increased overall speed by optimizing twist()
-// - Doubled speed of integer [0,n] generation
-// - Fixed out-of-range number generation on 64-bit machines
-// - Improved portability by substituting literal constants for long enum's
-// - Changed license from GNU LGPL to BSD
-//
-// v1.1 - Corrected parameter label in randNorm from "variance" to "stddev"
-// - Changed randNorm algorithm from basic to polar form for efficiency
-// - Updated includes from deprecated <xxxx.h> to standard <cxxxx> forms
-// - Cleaned declarations and definitions to please Intel compiler
-// - Revised twist() operator to work on ones'-complement machines
-// - Fixed reload() function to work when N and M are unsigned
-// - Added copy constructor and copy operator from Salvador Espana
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index e461fae4c..ee9e569a7 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -61,7 +61,7 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
{
std::set<eMonsterType> allowedMobs;
- if (a_Biome == biMushroomIsland || a_Biome == biMushroomShore)
+ if ((a_Biome == biMushroomIsland) || (a_Biome == biMushroomShore))
{
addIfAllowed(mtMooshroom, allowedMobs);
}
@@ -84,7 +84,7 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
addIfAllowed(mtCreeper, allowedMobs);
addIfAllowed(mtSquid, allowedMobs);
- if (a_Biome != biDesert && a_Biome != biBeach && a_Biome != biOcean)
+ if ((a_Biome != biDesert) && (a_Biome != biBeach) && (a_Biome != biOcean))
{
addIfAllowed(mtSheep, allowedMobs);
addIfAllowed(mtPig, allowedMobs);
@@ -93,11 +93,11 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
addIfAllowed(mtEnderman, allowedMobs);
addIfAllowed(mtSlime, allowedMobs); // MG TODO : much more complicated rule
- if (a_Biome == biForest || a_Biome == biForestHills || a_Biome == biTaiga || a_Biome == biTaigaHills)
+ if ((a_Biome == biForest) || (a_Biome == biForestHills) || (a_Biome == biTaiga) || (a_Biome == biTaigaHills))
{
addIfAllowed(mtWolf, allowedMobs);
}
- else if (a_Biome == biJungle || a_Biome == biJungleHills)
+ else if ((a_Biome == biJungle) || (a_Biome == biJungleHills))
{
addIfAllowed(mtOcelot, allowedMobs);
}
@@ -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/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 41ef26e2a..7ca7a9d66 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -75,7 +75,9 @@ void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
}
if (m_Target == nullptr)
+ {
return;
+ }
cTracer LineOfSight(GetWorld());
Vector3d AttackDirection(m_Target->GetPosition() - GetPosition());
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index 16869c79d..1fa9d2c37 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -34,7 +34,7 @@ void cBlaze::Attack(float a_Dt)
{
m_AttackInterval += a_Dt * m_AttackRate;
- if (m_Target != nullptr && m_AttackInterval > 3.0)
+ if ((m_Target != nullptr) && (m_AttackInterval > 3.0))
{
// Setting this higher gives us more wiggle room for attackrate
Vector3d Speed = GetLookVector() * 20;
diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp
index c65c0d29a..fc8de8362 100644
--- a/src/Mobs/Ghast.cpp
+++ b/src/Mobs/Ghast.cpp
@@ -36,7 +36,7 @@ void cGhast::Attack(float a_Dt)
{
m_AttackInterval += a_Dt * m_AttackRate;
- if (m_Target != nullptr && m_AttackInterval > 3.0)
+ if ((m_Target != nullptr) && (m_AttackInterval > 3.0))
{
// Setting this higher gives us more wiggle room for attackrate
Vector3d Speed = GetLookVector() * 20;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 5319bdf91..7b8f763af 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -9,7 +9,6 @@
#include "../Entities/Player.h"
#include "../Entities/ExpOrb.h"
#include "../MonsterConfig.h"
-#include "../MersenneTwister.h"
#include "../Chunk.h"
#include "../FastRandom.h"
@@ -21,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:
@@ -275,7 +266,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
}
if ((m_Target != nullptr) && m_Target->IsDestroyed())
+ {
m_Target = nullptr;
+ }
// Burning in daylight
HandleDaylightBurning(a_Chunk);
@@ -784,39 +777,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;
}
@@ -1028,22 +1029,34 @@ void cMonster::AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel)
MTRand r1;
if (r1.randInt() % 200 < ((m_DropChanceHelmet * 200) + (a_LootingLevel * 2)))
{
- if (!GetEquippedHelmet().IsEmpty()) a_Drops.push_back(GetEquippedHelmet());
+ if (!GetEquippedHelmet().IsEmpty())
+ {
+ a_Drops.push_back(GetEquippedHelmet());
+ }
}
if (r1.randInt() % 200 < ((m_DropChanceChestplate * 200) + (a_LootingLevel * 2)))
{
- if (!GetEquippedChestplate().IsEmpty()) a_Drops.push_back(GetEquippedChestplate());
+ if (!GetEquippedChestplate().IsEmpty())
+ {
+ a_Drops.push_back(GetEquippedChestplate());
+ }
}
if (r1.randInt() % 200 < ((m_DropChanceLeggings * 200) + (a_LootingLevel * 2)))
{
- if (!GetEquippedLeggings().IsEmpty()) a_Drops.push_back(GetEquippedLeggings());
+ if (!GetEquippedLeggings().IsEmpty())
+ {
+ a_Drops.push_back(GetEquippedLeggings());
+ }
}
if (r1.randInt() % 200 < ((m_DropChanceBoots * 200) + (a_LootingLevel * 2)))
{
- if (!GetEquippedBoots().IsEmpty()) a_Drops.push_back(GetEquippedBoots());
+ if (!GetEquippedBoots().IsEmpty())
+ {
+ a_Drops.push_back(GetEquippedBoots());
+ }
}
}
@@ -1056,7 +1069,10 @@ void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel)
MTRand r1;
if (r1.randInt() % 200 < ((m_DropChanceWeapon * 200) + (a_LootingLevel * 2)))
{
- if (!GetEquippedWeapon().IsEmpty()) a_Drops.push_back(GetEquippedWeapon());
+ if (!GetEquippedWeapon().IsEmpty())
+ {
+ a_Drops.push_back(GetEquippedWeapon());
+ }
}
}
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/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index f17bc307c..da5ddc670 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -71,7 +71,7 @@ void cSkeleton::Attack(float a_Dt)
{
m_AttackInterval += a_Dt * m_AttackRate;
- if (m_Target != nullptr && m_AttackInterval > 3.0)
+ if ((m_Target != nullptr) && (m_AttackInterval > 3.0))
{
// Setting this higher gives us more wiggle room for attackrate
Vector3d Speed = GetLookVector() * 20;
diff --git a/src/Mobs/SnowGolem.cpp b/src/Mobs/SnowGolem.cpp
index 76334d970..8c4178beb 100644
--- a/src/Mobs/SnowGolem.cpp
+++ b/src/Mobs/SnowGolem.cpp
@@ -38,7 +38,7 @@ void cSnowGolem::Tick(float a_Dt, cChunk & a_Chunk)
{
BLOCKTYPE BlockBelow = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()) - 1, (int) floor(GetPosZ()));
BLOCKTYPE Block = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()));
- if (Block == E_BLOCK_AIR && cBlockInfo::IsSolid(BlockBelow))
+ if ((Block == E_BLOCK_AIR) && cBlockInfo::IsSolid(BlockBelow))
{
m_World->SetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()), E_BLOCK_SNOW, 0);
}
diff --git a/src/Mobs/Witch.cpp b/src/Mobs/Witch.cpp
index 747a11f97..a3cadbaa0 100644
--- a/src/Mobs/Witch.cpp
+++ b/src/Mobs/Witch.cpp
@@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Witch.h"
+#include "FastRandom.h"
diff --git a/src/Mobs/Witch.h b/src/Mobs/Witch.h
index 03691fef1..8230e1f98 100644
--- a/src/Mobs/Witch.h
+++ b/src/Mobs/Witch.h
@@ -2,7 +2,6 @@
#pragma once
#include "AggressiveMonster.h"
-#include "../MersenneTwister.h"
diff --git a/src/Noise/Noise.cpp b/src/Noise/Noise.cpp
index 509be7d6c..0249ab6c1 100644
--- a/src/Noise/Noise.cpp
+++ b/src/Noise/Noise.cpp
@@ -2,7 +2,6 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Noise.h"
-#include "OSSupport/Timer.h"
#define FAST_FLOOR(x) (((x) < 0) ? (((int)x) - 1) : ((int)x))
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index c3eabeef6..e943ceb18 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -13,11 +13,10 @@ SET (SRCS
IsThread.cpp
ListenThread.cpp
Semaphore.cpp
- Sleep.cpp
Socket.cpp
SocketThreads.cpp
- Thread.cpp
- Timer.cpp)
+ StackTrace.cpp
+)
SET (HDRS
CriticalSection.h
@@ -29,11 +28,10 @@ SET (HDRS
ListenThread.h
Queue.h
Semaphore.h
- Sleep.h
Socket.h
SocketThreads.h
- Thread.h
- Timer.h)
+ StackTrace.h
+)
if(NOT MSVC)
add_library(OSSupport ${SRCS} ${HDRS})
diff --git a/src/OSSupport/CriticalSection.cpp b/src/OSSupport/CriticalSection.cpp
index 5dfc8b5f9..13a3e4d9f 100644
--- a/src/OSSupport/CriticalSection.cpp
+++ b/src/OSSupport/CriticalSection.cpp
@@ -1,6 +1,5 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-#include "IsThread.h"
@@ -9,41 +8,12 @@
////////////////////////////////////////////////////////////////////////////////
// cCriticalSection:
+#ifdef _DEBUG
cCriticalSection::cCriticalSection()
{
- #ifdef _WIN32
- InitializeCriticalSection(&m_CriticalSection);
- #else
- pthread_mutexattr_init(&m_Attributes);
- pthread_mutexattr_settype(&m_Attributes, PTHREAD_MUTEX_RECURSIVE);
-
- if (pthread_mutex_init(&m_CriticalSection, &m_Attributes) != 0)
- {
- LOGERROR("Could not initialize Critical Section!");
- }
- #endif
-
- #ifdef _DEBUG
- m_IsLocked = 0;
- #endif // _DEBUG
-}
-
-
-
-
-
-cCriticalSection::~cCriticalSection()
-{
- #ifdef _WIN32
- DeleteCriticalSection(&m_CriticalSection);
- #else
- if (pthread_mutex_destroy(&m_CriticalSection) != 0)
- {
- LOGWARNING("Could not destroy Critical Section!");
- }
- pthread_mutexattr_destroy(&m_Attributes);
- #endif
+ m_IsLocked = 0;
}
+#endif // _DEBUG
@@ -51,15 +21,11 @@ cCriticalSection::~cCriticalSection()
void cCriticalSection::Lock()
{
- #ifdef _WIN32
- EnterCriticalSection(&m_CriticalSection);
- #else
- pthread_mutex_lock(&m_CriticalSection);
- #endif
+ m_Mutex.lock();
#ifdef _DEBUG
m_IsLocked += 1;
- m_OwningThreadID = cIsThread::GetCurrentID();
+ m_OwningThreadID = std::this_thread::get_id();
#endif // _DEBUG
}
@@ -74,11 +40,7 @@ void cCriticalSection::Unlock()
m_IsLocked -= 1;
#endif // _DEBUG
- #ifdef _WIN32
- LeaveCriticalSection(&m_CriticalSection);
- #else
- pthread_mutex_unlock(&m_CriticalSection);
- #endif
+ m_Mutex.unlock();
}
@@ -97,7 +59,7 @@ bool cCriticalSection::IsLocked(void)
bool cCriticalSection::IsLockedByCurrentThread(void)
{
- return ((m_IsLocked > 0) && (m_OwningThreadID == cIsThread::GetCurrentID()));
+ return ((m_IsLocked > 0) && (m_OwningThreadID == std::this_thread::get_id()));
}
#endif // _DEBUG
diff --git a/src/OSSupport/CriticalSection.h b/src/OSSupport/CriticalSection.h
index c3c6e57f0..17fcdfc12 100644
--- a/src/OSSupport/CriticalSection.h
+++ b/src/OSSupport/CriticalSection.h
@@ -1,5 +1,7 @@
#pragma once
+#include <mutex>
+#include <thread>
@@ -8,8 +10,6 @@
class cCriticalSection
{
public:
- cCriticalSection(void);
- ~cCriticalSection();
void Lock(void);
void Unlock(void);
@@ -17,6 +17,7 @@ public:
// IsLocked/IsLockedByCurrentThread are only used in ASSERT statements, but because of the changes with ASSERT they must always be defined
// The fake versions (in Release) will not effect the program in any way
#ifdef _DEBUG
+ cCriticalSection(void);
bool IsLocked(void);
bool IsLockedByCurrentThread(void);
#else
@@ -27,15 +28,10 @@ public:
private:
#ifdef _DEBUG
int m_IsLocked; // Number of times this CS is locked
- unsigned long m_OwningThreadID;
+ std::thread::id m_OwningThreadID;
#endif // _DEBUG
- #ifdef _WIN32
- CRITICAL_SECTION m_CriticalSection;
- #else // _WIN32
- pthread_mutex_t m_CriticalSection;
- pthread_mutexattr_t m_Attributes;
- #endif // else _WIN32
+ std::recursive_mutex m_Mutex;
} ALIGN_8;
diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp
index 87bc110ce..d6ba937f9 100644
--- a/src/OSSupport/Event.cpp
+++ b/src/OSSupport/Event.cpp
@@ -12,137 +12,59 @@
-cEvent::cEvent(void)
+cEvent::cEvent(void) :
+ m_ShouldWait(true)
{
-#ifdef _WIN32
- m_Event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
- if (m_Event == nullptr)
- {
- LOGERROR("cEvent: cannot create event, GLE = %u. Aborting server.", (unsigned)GetLastError());
- abort();
- }
-#else // *nix
- m_bIsNamed = false;
- m_Event = new sem_t;
- if (sem_init(m_Event, 0, 0))
- {
- // This path is used by MacOS, because it doesn't support unnamed semaphores.
- delete m_Event;
- m_bIsNamed = true;
-
- AString EventName;
- Printf(EventName, "cEvent%p", this);
- m_Event = sem_open(EventName.c_str(), O_CREAT, 777, 0);
- if (m_Event == SEM_FAILED)
- {
- AString error = GetOSErrorString(errno);
- LOGERROR("cEvent: Cannot create event, err = %s. Aborting server.", error.c_str());
- abort();
- }
- // Unlink the semaphore immediately - it will continue to function but will not pollute the namespace
- // We don't store the name, so can't call this in the destructor
- if (sem_unlink(EventName.c_str()) != 0)
- {
- AString error = GetOSErrorString(errno);
- LOGWARN("ERROR: Could not unlink cEvent. (%s)", error.c_str());
- }
- }
-#endif // *nix
}
-cEvent::~cEvent()
+void cEvent::Wait(void)
{
-#ifdef _WIN32
- CloseHandle(m_Event);
-#else
- if (m_bIsNamed)
- {
- if (sem_close(m_Event) != 0)
- {
- AString error = GetOSErrorString(errno);
- LOGERROR("ERROR: Could not close cEvent. (%s)", error.c_str());
- }
- }
- else
+ std::unique_lock<std::mutex> Lock(m_Mutex);
+ while (m_ShouldWait)
{
- sem_destroy(m_Event);
- delete m_Event;
- m_Event = nullptr;
+ m_CondVar.wait(Lock);
}
-#endif
+ m_ShouldWait = true;
}
-void cEvent::Wait(void)
+bool cEvent::Wait(unsigned a_TimeoutMSec)
{
- #ifdef _WIN32
- DWORD res = WaitForSingleObject(m_Event, INFINITE);
- if (res != WAIT_OBJECT_0)
- {
- LOGWARN("cEvent: waiting for the event failed: %u, GLE = %u. Continuing, but server may be unstable.", (unsigned)res, (unsigned)GetLastError());
- }
- #else
- int res = sem_wait(m_Event);
- if (res != 0)
- {
- AString error = GetOSErrorString(errno);
- LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str());
- }
- #endif
-}
-
-
-
-
-
-bool cEvent::Wait(int a_TimeoutMSec)
-{
- #ifdef _WIN32
- DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMSec);
- switch (res)
+ auto dst = std::chrono::system_clock::now() + std::chrono::milliseconds(a_TimeoutMSec);
+ std::unique_lock<std::mutex> Lock(m_Mutex); // We assume that this lock is acquired without much delay - we are the only user of the mutex
+ while (m_ShouldWait && (std::chrono::system_clock::now() <= dst))
+ {
+ switch (m_CondVar.wait_until(Lock, dst))
{
- case WAIT_OBJECT_0: return true; // Regular event signalled
- case WAIT_TIMEOUT: return false; // Regular event timeout
- default:
+ case std::cv_status::no_timeout:
{
- LOGWARN("cEvent: waiting for the event failed: %u, GLE = %u. Continuing, but server may be unstable.", (unsigned)res, (unsigned)GetLastError());
- return false;
+ // The wait was successful, check for spurious wakeup:
+ if (!m_ShouldWait)
+ {
+ m_ShouldWait = true;
+ return true;
+ }
+ // This was a spurious wakeup, wait again:
+ continue;
}
- }
- #else
- // Get the current time:
- timespec timeout;
- if (clock_gettime(CLOCK_REALTIME, &timeout) == -1)
- {
- LOGWARN("cEvent: Getting current time failed: %i, err = %s. Continuing, but the server may be unstable.", errno, GetOSErrorString(errno).c_str());
- return false;
- }
-
- // Add the specified timeout:
- timeout.tv_sec += a_TimeoutMSec / 1000;
- timeout.tv_nsec += (a_TimeoutMSec % 1000) * 1000000; // 1 msec = 1000000 usec
-
- // Wait with timeout:
- int res = sem_timedwait(m_Event, &timeout);
- switch (res)
- {
- case 0: return true; // Regular event signalled
- case ETIMEDOUT: return false; // Regular even timeout
- default:
+
+ case std::cv_status::timeout:
{
- AString error = GetOSErrorString(errno);
- LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str());
+ // The wait timed out, return failure:
return false;
}
- }
- #endif
+ } // switch (wait_until())
+ } // while (m_ShouldWait && not timeout)
+
+ // The wait timed out in the while() condition:
+ return false;
}
@@ -151,19 +73,11 @@ bool cEvent::Wait(int a_TimeoutMSec)
void cEvent::Set(void)
{
- #ifdef _WIN32
- if (!SetEvent(m_Event))
- {
- LOGWARN("cEvent: Could not set cEvent: GLE = %u", (unsigned)GetLastError());
- }
- #else
- int res = sem_post(m_Event);
- if (res != 0)
- {
- AString error = GetOSErrorString(errno);
- LOGWARN("cEvent: Could not set cEvent: %i, err = %s", res, error.c_str());
- }
- #endif
+ {
+ std::unique_lock<std::mutex> Lock(m_Mutex);
+ m_ShouldWait = false;
+ }
+ m_CondVar.notify_one();
}
diff --git a/src/OSSupport/Event.h b/src/OSSupport/Event.h
index e2fa65a05..572388a3f 100644
--- a/src/OSSupport/Event.h
+++ b/src/OSSupport/Event.h
@@ -1,16 +1,17 @@
// Event.h
-// Interfaces to the cEvent object representing an OS-specific synchronization primitive that can be waited-for
-// Implemented as an Event on Win and as a 1-semaphore on *nix
+// Interfaces to the cEvent object representing a synchronization primitive that can be waited-for
+// Implemented using C++11 condition variable and mutex
#pragma once
-#ifndef CEVENT_H_INCLUDED
-#define CEVENT_H_INCLUDED
+
+#include <mutex>
+#include <condition_variable>
@@ -20,31 +21,31 @@ class cEvent
{
public:
cEvent(void);
- ~cEvent();
+ /** Waits until the event has been set.
+ If the event has been set before it has been waited for, Wait() returns immediately. */
void Wait(void);
+
+ /** Sets the event - releases one thread that has been waiting in Wait().
+ If there was no thread waiting, the next call to Wait() will not block. */
void Set (void);
/** Waits for the event until either it is signalled, or the (relative) timeout is passed.
Returns true if the event was signalled, false if the timeout was hit or there was an error. */
- bool Wait(int a_TimeoutMSec);
+ bool Wait(unsigned a_TimeoutMSec);
private:
- #ifdef _WIN32
- HANDLE m_Event;
- #else
- sem_t * m_Event;
- bool m_bIsNamed;
- #endif
-} ;
-
-
-
+ /** Used for checking for spurious wakeups. */
+ bool m_ShouldWait;
+ /** Mutex protecting m_ShouldWait from multithreaded access. */
+ std::mutex m_Mutex;
+ /** The condition variable used as the Event. */
+ std::condition_variable m_CondVar;
+} ;
-#endif // CEVENT_H_INCLUDED
diff --git a/src/OSSupport/IsThread.cpp b/src/OSSupport/IsThread.cpp
index 1a436623a..94bed1f56 100644
--- a/src/OSSupport/IsThread.cpp
+++ b/src/OSSupport/IsThread.cpp
@@ -5,49 +5,40 @@
// This class will eventually suupersede the old cThread class
#include "Globals.h"
-
#include "IsThread.h"
-// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here:
#if defined(_MSC_VER) && defined(_DEBUG)
-//
-// Usage: SetThreadName (-1, "MainThread");
-//
-
-// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
-
-const DWORD MS_VC_EXCEPTION = 0x406D1388;
-
-#pragma pack(push, 8)
-typedef struct tagTHREADNAME_INFO
-{
- DWORD dwType; // Must be 0x1000.
- LPCSTR szName; // Pointer to name (in user addr space).
- DWORD dwThreadID; // Thread ID (-1 = caller thread).
- DWORD dwFlags; // Reserved for future use, must be zero.
-} THREADNAME_INFO;
-#pragma pack(pop)
-
-static void SetThreadName(DWORD dwThreadID, const char * threadName)
-{
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = threadName;
- info.dwThreadID = dwThreadID;
- info.dwFlags = 0;
+ // Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
- __try
- {
- RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
+ const DWORD MS_VC_EXCEPTION = 0x406D1388;
+ #pragma pack(push, 8)
+ struct THREADNAME_INFO
+ {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1 = caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+ };
+ #pragma pack(pop)
+
+ /** Sets the name of a thread with the specified ID
+ (When in MSVC, the debugger provides "thread naming" by catching special exceptions)
+ */
+ static void SetThreadName(std::thread * a_Thread, const char * a_ThreadName)
{
+ THREADNAME_INFO info { 0x1000, a_ThreadName, GetThreadId(a_Thread->native_handle()), 0 };
+ __try
+ {
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
}
-}
#endif // _MSC_VER && _DEBUG
@@ -57,13 +48,9 @@ static void SetThreadName(DWORD dwThreadID, const char * threadName)
////////////////////////////////////////////////////////////////////////////////
// cIsThread:
-cIsThread::cIsThread(const AString & iThreadName) :
+cIsThread::cIsThread(const AString & a_ThreadName) :
m_ShouldTerminate(false),
- m_ThreadName(iThreadName),
- #ifdef _WIN32
- m_ThreadID(0),
- #endif
- m_Handle(NULL_HANDLE)
+ m_ThreadName(a_ThreadName)
{
}
@@ -83,35 +70,24 @@ cIsThread::~cIsThread()
bool cIsThread::Start(void)
{
- ASSERT(m_Handle == NULL_HANDLE); // Has already started one thread?
- #ifdef _WIN32
- // Create the thread suspended, so that the mHandle variable is valid in the thread procedure
- m_ThreadID = 0;
- m_Handle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &m_ThreadID);
- if (m_Handle == NULL)
- {
- LOGERROR("ERROR: Could not create thread \"%s\", GLE = %u!", m_ThreadName.c_str(), (unsigned)GetLastError());
- return false;
- }
- ResumeThread(m_Handle);
-
- #if defined(_DEBUG) && defined(_MSC_VER)
- // Thread naming is available only in MSVC
- if (!m_ThreadName.empty())
- {
- SetThreadName(m_ThreadID, m_ThreadName.c_str());
- }
- #endif // _DEBUG and _MSC_VER
-
- #else // _WIN32
- if (pthread_create(&m_Handle, NULL, thrExecute, this))
+ try
+ {
+ m_Thread = std::thread(&cIsThread::Execute, this);
+
+ #if defined (_MSC_VER) && defined(_DEBUG)
+ if (!m_ThreadName.empty())
{
- LOGERROR("ERROR: Could not create thread \"%s\", !", m_ThreadName.c_str());
- return false;
+ SetThreadName(&m_Thread, m_ThreadName.c_str());
}
- #endif // else _WIN32
+ #endif
- return true;
+ return true;
+ }
+ catch (std::system_error & a_Exception)
+ {
+ LOGERROR("cIsThread::Start error %i: could not construct thread %s; %s", a_Exception.code().value(), m_ThreadName.c_str(), a_Exception.code().message().c_str());
+ return false;
+ }
}
@@ -120,10 +96,12 @@ bool cIsThread::Start(void)
void cIsThread::Stop(void)
{
- if (m_Handle == NULL_HANDLE)
+ if (!m_Thread.joinable())
{
+ // The thread hasn't been started or has already been joined
return;
}
+
m_ShouldTerminate = true;
Wait();
}
@@ -134,59 +112,23 @@ void cIsThread::Stop(void)
bool cIsThread::Wait(void)
{
- if (m_Handle == NULL_HANDLE)
+ LOGD("Waiting for thread %s to finish", m_ThreadName.c_str());
+ if (m_Thread.joinable())
{
- return true;
+ try
+ {
+ m_Thread.join();
+ return true;
+ }
+ catch (std::system_error & a_Exception)
+ {
+ LOGERROR("cIsThread::Wait error %i: could not join thread %s; %s", a_Exception.code().value(), m_ThreadName.c_str(), a_Exception.code().message().c_str());
+ return false;
+ }
}
-
- #ifdef LOGD // ProtoProxy doesn't have LOGD
- LOGD("Waiting for thread %s to finish", m_ThreadName.c_str());
- #endif // LOGD
-
- #ifdef _WIN32
- int res = WaitForSingleObject(m_Handle, INFINITE);
- m_Handle = NULL;
-
- #ifdef LOGD // ProtoProxy doesn't have LOGD
- LOGD("Thread %s finished", m_ThreadName.c_str());
- #endif // LOGD
-
- return (res == WAIT_OBJECT_0);
- #else // _WIN32
- int res = pthread_join(m_Handle, NULL);
- m_Handle = NULL_HANDLE;
-
- #ifdef LOGD // ProtoProxy doesn't have LOGD
- LOGD("Thread %s finished", m_ThreadName.c_str());
- #endif // LOGD
-
- return (res == 0);
- #endif // else _WIN32
-}
-
-
-
-
-unsigned long cIsThread::GetCurrentID(void)
-{
- #ifdef _WIN32
- return (unsigned long) GetCurrentThreadId();
- #else
- return (unsigned long) pthread_self();
- #endif
-}
-
-
-
-
-bool cIsThread::IsCurrentThread(void) const
-{
- #ifdef _WIN32
- return (GetCurrentThreadId() == m_ThreadID);
- #else
- return (m_Handle == pthread_self());
- #endif
+ LOGD("Thread %s finished", m_ThreadName.c_str());
+ return true;
}
diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h
index 5c8d28d2d..131c6950e 100644
--- a/src/OSSupport/IsThread.h
+++ b/src/OSSupport/IsThread.h
@@ -16,8 +16,7 @@ In the descending class' constructor call the Start() method to start the thread
#pragma once
-#ifndef CISTHREAD_H_INCLUDED
-#define CISTHREAD_H_INCLUDED
+#include <thread>
@@ -33,7 +32,7 @@ protected:
volatile bool m_ShouldTerminate;
public:
- cIsThread(const AString & iThreadName);
+ cIsThread(const AString & a_ThreadName);
virtual ~cIsThread();
/// Starts the thread; returns without waiting for the actual start
@@ -45,56 +44,14 @@ public:
/// Waits for the thread to finish. Doesn't signalize the ShouldTerminate flag
bool Wait(void);
- /// Returns the OS-dependent thread ID for the caller's thread
- static unsigned long GetCurrentID(void);
-
/** Returns true if the thread calling this function is the thread contained within this object. */
- bool IsCurrentThread(void) const;
+ bool IsCurrentThread(void) const { return std::this_thread::get_id() == m_Thread.get_id(); }
protected:
AString m_ThreadName;
-
- // Value used for "no handle":
- #ifdef _WIN32
- #define NULL_HANDLE NULL
- #else
- #define NULL_HANDLE 0
- #endif
-
- #ifdef _WIN32
-
- DWORD m_ThreadID;
- HANDLE m_Handle;
-
- static DWORD __stdcall thrExecute(LPVOID a_Param)
- {
- // Create a window so that the thread can be identified by 3rd party tools:
- HWND IdentificationWnd = CreateWindowA("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
-
- // Run the thread:
- ((cIsThread *)a_Param)->Execute();
-
- // Destroy the identification window:
- DestroyWindow(IdentificationWnd);
-
- return 0;
- }
-
- #else // _WIN32
-
- pthread_t m_Handle;
-
- static void * thrExecute(void * a_Param)
- {
- (static_cast<cIsThread *>(a_Param))->Execute();
- return NULL;
- }
-
- #endif // else _WIN32
+ std::thread m_Thread;
} ;
-
-#endif // CISTHREAD_H_INCLUDED
diff --git a/src/OSSupport/Sleep.cpp b/src/OSSupport/Sleep.cpp
deleted file mode 100644
index 297d668d7..000000000
--- a/src/OSSupport/Sleep.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#ifndef _WIN32
- #include <unistd.h>
-#endif
-
-
-
-
-
-void cSleep::MilliSleep( unsigned int a_MilliSeconds)
-{
-#ifdef _WIN32
- Sleep(a_MilliSeconds); // Don't tick too much
-#else
- usleep(a_MilliSeconds*1000);
-#endif
-}
diff --git a/src/OSSupport/Sleep.h b/src/OSSupport/Sleep.h
deleted file mode 100644
index 57d29682c..000000000
--- a/src/OSSupport/Sleep.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-class cSleep
-{
-public:
- static void MilliSleep( unsigned int a_MilliSeconds);
-};
diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h
index e4ec895cb..9ec8c1111 100644
--- a/src/OSSupport/Socket.h
+++ b/src/OSSupport/Socket.h
@@ -74,7 +74,7 @@ public:
inline static bool IsSocketError(int a_ReturnedValue)
{
#ifdef _WIN32
- return (a_ReturnedValue == SOCKET_ERROR || a_ReturnedValue == 0);
+ return ((a_ReturnedValue == SOCKET_ERROR) || (a_ReturnedValue == 0));
#else
return (a_ReturnedValue <= 0);
#endif
diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp
index 7a3ef4274..153d6ed1d 100644
--- a/src/OSSupport/SocketThreads.cpp
+++ b/src/OSSupport/SocketThreads.cpp
@@ -86,7 +86,8 @@ void cSocketThreads::RemoveClient(const cCallback * a_Client)
}
} // for itr - m_Threads[]
- ASSERT(!"Removing an unknown client");
+ // This client wasn't found.
+ // It's not an error, because it may have been removed by a different thread in the meantime.
}
@@ -491,10 +492,17 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read)
{
case sSlot::ssNormal:
{
- // Notify the callback that the remote has closed the socket; keep the slot
- m_Slots[i].m_Client->SocketClosed();
+ // Close the socket on our side:
m_Slots[i].m_State = sSlot::ssRemoteClosed;
m_Slots[i].m_Socket.CloseSocket();
+
+ // Notify the callback that the remote has closed the socket, *after* removing the socket:
+ cCallback * client = m_Slots[i].m_Client;
+ m_Slots[i] = m_Slots[--m_NumSlots];
+ if (client != nullptr)
+ {
+ client->SocketClosed();
+ }
break;
}
case sSlot::ssWritingRestOut:
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/OSSupport/Thread.cpp b/src/OSSupport/Thread.cpp
deleted file mode 100644
index faaccce96..000000000
--- a/src/OSSupport/Thread.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-
-
-
-
-// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here:
-#ifdef _MSC_VER
-//
-// Usage: SetThreadName (-1, "MainThread");
-//
-
-// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
-
-const DWORD MS_VC_EXCEPTION = 0x406D1388;
-
-#pragma pack(push, 8)
-typedef struct tagTHREADNAME_INFO
-{
- DWORD dwType; // Must be 0x1000.
- LPCSTR szName; // Pointer to name (in user addr space).
- DWORD dwThreadID; // Thread ID (-1 = caller thread).
- DWORD dwFlags; // Reserved for future use, must be zero.
-} THREADNAME_INFO;
-#pragma pack(pop)
-
-static void SetThreadName(DWORD dwThreadID, const char * threadName)
-{
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = threadName;
- info.dwThreadID = dwThreadID;
- info.dwFlags = 0;
-
- __try
- {
- RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- }
-}
-#endif // _MSC_VER
-
-
-
-
-
-cThread::cThread( ThreadFunc a_ThreadFunction, void* a_Param, const char* a_ThreadName /* = 0 */)
- : m_ThreadFunction( a_ThreadFunction)
- , m_Param( a_Param)
- , m_Event( new cEvent())
- , m_StopEvent( 0)
-{
- if (a_ThreadName)
- {
- m_ThreadName.assign(a_ThreadName);
- }
-}
-
-
-
-
-
-cThread::~cThread()
-{
- delete m_Event;
- m_Event = NULL;
-
- if (m_StopEvent)
- {
- m_StopEvent->Wait();
- delete m_StopEvent;
- m_StopEvent = NULL;
- }
-}
-
-
-
-
-
-void cThread::Start( bool a_bWaitOnDelete /* = true */)
-{
- if (a_bWaitOnDelete)
- m_StopEvent = new cEvent();
-
-#ifndef _WIN32
- pthread_t SndThread;
- if (pthread_create( &SndThread, NULL, MyThread, this))
- LOGERROR("ERROR: Could not create thread!");
-#else
- DWORD ThreadID = 0;
- HANDLE hThread = CreateThread(NULL // security
- , 0 // stack size
- , (LPTHREAD_START_ROUTINE) MyThread // function name
- , this // parameters
- , 0 // flags
- , &ThreadID); // thread id
- CloseHandle( hThread);
-
- #ifdef _MSC_VER
- if (!m_ThreadName.empty())
- {
- SetThreadName(ThreadID, m_ThreadName.c_str());
- }
- #endif // _MSC_VER
-#endif
-
- // Wait until thread has actually been created
- m_Event->Wait();
-}
-
-
-
-
-
-#ifdef _WIN32
-unsigned long cThread::MyThread(void* a_Param)
-#else
-void *cThread::MyThread( void *a_Param)
-#endif
-{
- cThread* self = (cThread*)a_Param;
- cEvent* StopEvent = self->m_StopEvent;
-
- ThreadFunc* ThreadFunction = self->m_ThreadFunction;
- void* ThreadParam = self->m_Param;
-
- // Set event to let other thread know this thread has been created and it's safe to delete the cThread object
- self->m_Event->Set();
-
- ThreadFunction( ThreadParam);
-
- if (StopEvent) StopEvent->Set();
- return 0;
-}
diff --git a/src/OSSupport/Thread.h b/src/OSSupport/Thread.h
deleted file mode 100644
index 7ee352c82..000000000
--- a/src/OSSupport/Thread.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-class cThread
-{
-public:
- typedef void (ThreadFunc)(void*);
- cThread( ThreadFunc a_ThreadFunction, void* a_Param, const char* a_ThreadName = 0);
- ~cThread();
-
- void Start( bool a_bWaitOnDelete = true);
- void WaitForThread();
-private:
- ThreadFunc* m_ThreadFunction;
-
-#ifdef _WIN32
- static unsigned long MyThread(void* a_Param);
-#else
- static void *MyThread( void *lpParam);
-#endif
-
- void* m_Param;
- cEvent* m_Event;
- cEvent* m_StopEvent;
-
- AString m_ThreadName;
-};
diff --git a/src/OSSupport/Timer.cpp b/src/OSSupport/Timer.cpp
deleted file mode 100644
index fd838dd0d..000000000
--- a/src/OSSupport/Timer.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Timer.h"
-
-
-
-
-
-
-cTimer::cTimer(void)
-{
- #ifdef _WIN32
- QueryPerformanceFrequency(&m_TicksPerSecond);
- #endif
-}
-
-
-
-
-
-long long cTimer::GetNowTime(void)
-{
- #ifdef _WIN32
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- return ((now.QuadPart * 1000) / m_TicksPerSecond.QuadPart);
- #else
- struct timeval now;
- gettimeofday(&now, NULL);
- return (long long)now.tv_sec * 1000 + (long long)now.tv_usec / 1000;
- #endif
-}
-
-
-
-
diff --git a/src/OSSupport/Timer.h b/src/OSSupport/Timer.h
deleted file mode 100644
index a059daa41..000000000
--- a/src/OSSupport/Timer.h
+++ /dev/null
@@ -1,32 +0,0 @@
-
-// Timer.h
-
-// Declares the cTimer class representing an OS-independent of retrieving current time with msec accuracy
-
-
-
-
-
-#pragma once
-
-
-
-
-
-class cTimer
-{
-public:
- cTimer(void);
-
- // Returns the current time expressed in milliseconds
- long long GetNowTime(void);
-private:
-
- #ifdef _WIN32
- LARGE_INTEGER m_TicksPerSecond;
- #endif
-} ;
-
-
-
-
diff --git a/src/ProbabDistrib.cpp b/src/ProbabDistrib.cpp
index 7a5869dcc..c34c75982 100644
--- a/src/ProbabDistrib.cpp
+++ b/src/ProbabDistrib.cpp
@@ -5,7 +5,7 @@
#include "Globals.h"
#include "ProbabDistrib.h"
-#include "MersenneTwister.h"
+#include "FastRandom.h"
diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp
index 67f513e44..570754204 100644
--- a/src/Protocol/MojangAPI.cpp
+++ b/src/Protocol/MojangAPI.cpp
@@ -161,26 +161,38 @@ class cMojangAPI::cUpdateThread :
{
typedef cIsThread super;
public:
- cUpdateThread() :
- super("cMojangAPI::cUpdateThread")
+ cUpdateThread(cMojangAPI & a_MojangAPI) :
+ super("cMojangAPI::cUpdateThread"),
+ m_MojangAPI(a_MojangAPI)
{
}
~cUpdateThread()
{
+ // Notify the thread that it should stop:
+ m_ShouldTerminate = true;
m_evtNotify.Set();
+
+ // Wait for the thread to actually finish work:
Stop();
}
protected:
+
+ /** The cMojangAPI instance to update. */
+ cMojangAPI & m_MojangAPI;
+
+ /** The event used for notifying that the thread should terminate, as well as timing. */
cEvent m_evtNotify;
+
+ // cIsThread override:
virtual void Execute(void) override
{
do
{
- cRoot::Get()->GetMojangAPI().Update();
- } while (!m_evtNotify.Wait(60 * 60 * 1000)); // Repeat every 60 minutes
+ m_MojangAPI.Update();
+ } while (!m_ShouldTerminate && !m_evtNotify.Wait(60 * 60 * 1000)); // Repeat every 60 minutes until termination request
}
} ;
@@ -197,7 +209,7 @@ cMojangAPI::cMojangAPI(void) :
m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER),
m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS),
m_RankMgr(nullptr),
- m_UpdateThread(new cUpdateThread())
+ m_UpdateThread(new cUpdateThread(*this))
{
}
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 2234f7fdc..29daaedcc 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -16,7 +16,6 @@
#include "Protocol/ProtocolRecognizer.h" // for protocol version constants
#include "CommandOutput.h"
#include "DeadlockDetect.h"
-#include "OSSupport/Timer.h"
#include "LoggerListeners.h"
#include "BuildInfo.h"
#include "IniFile.h"
@@ -42,7 +41,6 @@ cRoot* cRoot::s_Root = nullptr;
cRoot::cRoot(void) :
m_pDefaultWorld(nullptr),
- m_InputThread(nullptr),
m_Server(nullptr),
m_MonsterConfig(nullptr),
m_CraftingRecipes(nullptr),
@@ -68,26 +66,24 @@ cRoot::~cRoot()
-void cRoot::InputThread(void * a_Params)
+void cRoot::InputThread(cRoot & a_Params)
{
- cRoot & self = *(cRoot*)a_Params;
-
cLogCommandOutputCallback Output;
- while (!self.m_bStop && !self.m_bRestart && !m_TerminateEventRaised && std::cin.good())
+ while (!a_Params.m_bStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good())
{
AString Command;
std::getline(std::cin, Command);
if (!Command.empty())
{
- self.ExecuteConsoleCommand(TrimString(Command), Output);
+ a_Params.ExecuteConsoleCommand(TrimString(Command), Output);
}
}
if (m_TerminateEventRaised || !std::cin.good())
{
// We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server:
- self.m_bStop = true;
+ a_Params.m_bStop = true;
}
}
@@ -120,9 +116,7 @@ void cRoot::Start(void)
m_bStop = false;
while (!m_bStop)
{
- cTimer Time;
- long long mseconds = Time.GetNowTime();
-
+ auto BeginTime = std::chrono::steady_clock::now();
m_bRestart = false;
LoadGlobalSettings();
@@ -191,21 +185,25 @@ void cRoot::Start(void)
#if !defined(ANDROID_NDK)
LOGD("Starting InputThread...");
- m_InputThread = new cThread( InputThread, this, "cRoot::InputThread");
- m_InputThread->Start( false); // We should NOT wait? Otherwise we can't stop the server from other threads than the input thread
+ try
+ {
+ m_InputThread = std::thread(InputThread, std::ref(*this));
+ m_InputThread.detach();
+ }
+ catch (std::system_error & a_Exception)
+ {
+ LOGERROR("cRoot::Start (std::thread) error %i: could not construct input thread; %s", a_Exception.code().value(), a_Exception.what());
+ }
#endif
- long long finishmseconds = Time.GetNowTime();
- finishmseconds -= mseconds;
-
- LOG("Startup complete, took %lld ms!", finishmseconds);
+ LOG("Startup complete, took %ld ms!", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count());
#ifdef _WIN32
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
#endif
while (!m_bStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads
{
- cSleep::MilliSleep(1000);
+ std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (m_TerminateEventRaised)
@@ -213,10 +211,6 @@ void cRoot::Start(void)
m_bStop = true;
}
- #if !defined(ANDROID_NDK)
- delete m_InputThread; m_InputThread = nullptr;
- #endif
-
// Stop the server:
m_WebAdmin->Stop();
LOG("Shutting down server...");
diff --git a/src/Root.h b/src/Root.h
index af5a2b47b..2c512a5df 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -6,6 +6,7 @@
#include "HTTPServer/HTTPServer.h"
#include "Defines.h"
#include "RankManager.h"
+#include <thread>
@@ -180,7 +181,7 @@ private:
cCriticalSection m_CSPendingCommands;
cCommandQueue m_PendingCommands;
- cThread * m_InputThread;
+ std::thread m_InputThread;
cServer * m_Server;
cMonsterConfig * m_MonsterConfig;
@@ -215,10 +216,10 @@ private:
/// Does the actual work of executing a command
void DoExecuteConsoleCommand(const AString & a_Cmd);
-
- static void InputThread(void* a_Params);
static cRoot* s_Root;
+
+ static void InputThread(cRoot & a_Params);
}; // tolua_export
diff --git a/src/Server.cpp b/src/Server.cpp
index a1dd27c57..3eaf6e096 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -4,7 +4,6 @@
#include "Server.h"
#include "ClientHandle.h"
-#include "OSSupport/Timer.h"
#include "Mobs/Monster.h"
#include "OSSupport/Socket.h"
#include "Root.h"
@@ -20,8 +19,6 @@
#include "Protocol/ProtocolRecognizer.h"
#include "CommandOutput.h"
-#include "MersenneTwister.h"
-
#include "IniFile.h"
#include "Vector3.h"
@@ -75,22 +72,20 @@ cServer::cTickThread::cTickThread(cServer & a_Server) :
void cServer::cTickThread::Execute(void)
{
- cTimer Timer;
-
- long long msPerTick = 50;
- long long LastTime = Timer.GetNowTime();
+ auto LastTime = std::chrono::steady_clock::now();
+ static const auto msPerTick = std::chrono::milliseconds(50);
while (!m_ShouldTerminate)
{
- long long NowTime = Timer.GetNowTime();
- float DeltaTime = (float)(NowTime-LastTime);
- m_ShouldTerminate = !m_Server.Tick(DeltaTime);
- long long TickTime = Timer.GetNowTime() - NowTime;
+ auto NowTime = std::chrono::steady_clock::now();
+ auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count();
+ m_ShouldTerminate = !m_Server.Tick(static_cast<float>(msec));
+ auto TickTime = std::chrono::steady_clock::now() - NowTime;
if (TickTime < msPerTick)
{
// Stretch tick time until it's at least msPerTick
- cSleep::MilliSleep((unsigned int)(msPerTick - TickTime));
+ std::this_thread::sleep_for(msPerTick - TickTime);
}
LastTime = NowTime;
diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp
index 9c8453d04..ecd74ee52 100644
--- a/src/Simulator/FluidSimulator.cpp
+++ b/src/Simulator/FluidSimulator.cpp
@@ -133,8 +133,10 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a
/*
Disabled because of causing problems and being useless atm
char BlockBelow = m_World.GetBlock(a_X, a_Y - 1, a_Z); // If there is nothing or fluid below it -> dominating flow is down :D
- if (BlockBelow == E_BLOCK_AIR || IsAllowedBlock(BlockBelow))
+ if ((BlockBelow == E_BLOCK_AIR) || IsAllowedBlock(BlockBelow))
+ {
return Y_MINUS;
+ }
*/
NIBBLETYPE LowestPoint = m_World.GetBlockMeta(a_X, a_Y, a_Z); // Current Block Meta so only lower points will be counted
@@ -182,7 +184,9 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a
}
if (LowestPoint == m_World.GetBlockMeta(a_X, a_Y, a_Z))
+ {
return NONE;
+ }
if (a_X - X > 0)
{
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 34f2da682..5febf5d6c 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -416,24 +416,30 @@ static bool isLegalUTF8(const unsigned char * source, int length)
{
default: return false;
// Everything else falls through when "true"...
- case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 4: if (((a = (*--srcptr)) < 0x80) || (a > 0xbf)) return false;
+ case 3: if (((a = (*--srcptr)) < 0x80) || (a > 0xbf)) return false;
case 2:
{
- if ((a = (*--srcptr)) > 0xBF) return false;
+ if ((a = (*--srcptr)) > 0xbf)
+ {
+ return false;
+ }
switch (*source)
{
// no fall-through in this inner switch
- case 0xE0: if (a < 0xA0) return false; break;
- case 0xED: if (a > 0x9F) return false; break;
- case 0xF0: if (a < 0x90) return false; break;
- case 0xF4: if (a > 0x8F) return false; break;
+ case 0xe0: if (a < 0xa0) return false; break;
+ case 0xed: if (a > 0x9f) return false; break;
+ case 0xf0: if (a < 0x90) return false; break;
+ case 0xf4: if (a > 0x8f) return false; break;
default: if (a < 0x80) return false;
}
}
- case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ case 1: if ((*source >= 0x80) && (*source < 0xc2)) return false;
+ }
+ if (*source > 0xf4)
+ {
+ return false;
}
- if (*source > 0xF4) return false;
return true;
}
@@ -446,11 +452,11 @@ AString UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length)
AString UTF16;
UTF16.reserve(a_UTF8Length * 3);
- const unsigned char * source = (const unsigned char*)a_UTF8;
+ const unsigned char * source = (const unsigned char *)a_UTF8;
const unsigned char * sourceEnd = source + a_UTF8Length;
const int halfShift = 10; // used for shifting by 10 bits
const unsigned int halfBase = 0x0010000UL;
- const unsigned int halfMask = 0x3FFUL;
+ const unsigned int halfMask = 0x3ffUL;
while (source < sourceEnd)
{
@@ -481,7 +487,7 @@ AString UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length)
if (ch <= UNI_MAX_BMP)
{
// Target is a character <= 0xFFFF
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
+ if ((ch >= UNI_SUR_HIGH_START) && (ch <= UNI_SUR_LOW_END))
{
// UTF-16 surrogate values are illegal in UTF-32
ch = ' ';
@@ -520,7 +526,10 @@ are equivalent to the following loop:
{
ch += *source++;
--tmpBytesToRead;
- if (tmpBytesToRead) ch <<= 6;
+ if (tmpBytesToRead)
+ {
+ ch <<= 6;
+ }
} while (tmpBytesToRead > 0);
}
---------------------------------------------------------------------
@@ -723,15 +732,15 @@ AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_
/// Converts one Hex character in a Base64 encoding into the data value
static inline int UnBase64(char c)
{
- if (c >='A' && c <= 'Z')
+ if ((c >='A') && (c <= 'Z'))
{
return c - 'A';
}
- if (c >='a' && c <= 'z')
+ if ((c >='a') && (c <= 'z'))
{
return c - 'a' + 26;
}
- if (c >= '0' && c <= '9')
+ if ((c >= '0') && (c <= '9'))
{
return c - '0' + 52;
}
diff --git a/src/Tracer.cpp b/src/Tracer.cpp
index e125c6aa4..e604f4a5b 100644
--- a/src/Tracer.cpp
+++ b/src/Tracer.cpp
@@ -14,15 +14,15 @@
-cTracer::cTracer(cWorld * a_World)
- : m_World(a_World)
+cTracer::cTracer(cWorld * a_World):
+ m_World(a_World)
{
- m_NormalTable[0].Set(-1, 0, 0);
- m_NormalTable[1].Set( 0, 0, -1);
- m_NormalTable[2].Set( 1, 0, 0);
- m_NormalTable[3].Set( 0, 0, 1);
- m_NormalTable[4].Set( 0, 1, 0);
- m_NormalTable[5].Set( 0, -1, 0);
+ m_NormalTable[0].Set(-1, 0, 0);
+ m_NormalTable[1].Set( 0, 0, -1);
+ m_NormalTable[2].Set( 1, 0, 0);
+ m_NormalTable[3].Set( 0, 0, 1);
+ m_NormalTable[4].Set( 0, 1, 0);
+ m_NormalTable[5].Set( 0, -1, 0);
}
@@ -37,10 +37,16 @@ cTracer::~cTracer()
-float cTracer::SigNum( float a_Num)
+float cTracer::SigNum(float a_Num)
{
- if (a_Num < 0.f) return -1.f;
- if (a_Num > 0.f) return 1.f;
+ if (a_Num < 0.f)
+ {
+ return -1.f;
+ }
+ if (a_Num > 0.f)
+ {
+ return 1.f;
+ }
return 0.f;
}
@@ -59,7 +65,10 @@ void cTracer::SetValues(const Vector3f & a_Start, const Vector3f & a_Direction)
step.z = (int) SigNum(dir.z);
// normalize the direction vector
- if (dir.SqrLength() > 0.f) dir.Normalize();
+ if (dir.SqrLength() > 0.f)
+ {
+ dir.Normalize();
+ }
// how far we must move in the ray direction before
// we encounter a new voxel in x-direction
@@ -127,7 +136,7 @@ void cTracer::SetValues(const Vector3f & a_Start, const Vector3f & a_Direction)
-bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance, bool a_LineOfSight)
+bool cTracer::Trace(const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance, bool a_LineOfSight)
{
if ((a_Start.y < 0) || (a_Start.y >= cChunkDef::Height))
{
@@ -249,35 +258,42 @@ int LinesCross(float x0, float y0, float x1, float y1, float x2, float y2, float
{
// float linx, liny;
- float d=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2);
- if (std::abs(d)<0.001) {return 0;}
- float AB=((y0-y2)*(x3-x2)-(x0-x2)*(y3-y2))/d;
- if (AB>=0.0 && AB<=1.0)
+ float d = (x1 - x0) * (y3 - y2) - (y1 - y0) * (x3 - x2);
+ if (std::abs(d) < 0.001)
{
- float CD=((y0-y2)*(x1-x0)-(x0-x2)*(y1-y0))/d;
- if (CD>=0.0 && CD<=1.0)
+ return 0;
+ }
+
+ float AB = ((y0 - y2) * (x3 - x2) - (x0 - x2) * (y3 - y2)) / d;
+ if ((AB >= 0.0) && (AB <= 1.0))
+ {
+ float CD = ((y0 - y2) * (x1 - x0) - (x0 - x2) * (y1 - y0)) / d;
+ if ((CD >= 0.0) && (CD <= 1.0))
{
- // linx=x0+AB*(x1-x0);
- // liny=y0+AB*(y1-y0);
+ // linx = x0 + AB * (x1 - x0);
+ // liny = y0 + AB * (y1 - y0);
return 1;
}
}
return 0;
}
+
+
+
// intersect3D_SegmentPlane(): intersect a segment and a plane
// Input: a_Ray = a segment, and a_Plane = a plane = {Point V0; Vector n;}
// Output: *I0 = the intersect point (when it exists)
// Return: 0 = disjoint (no intersection)
// 1 = intersection in the unique point *I0
// 2 = the segment lies in the plane
-int cTracer::intersect3D_SegmentPlane( const Vector3f & a_Origin, const Vector3f & a_End, const Vector3f & a_PlanePos, const Vector3f & a_PlaneNormal)
+int cTracer::intersect3D_SegmentPlane(const Vector3f & a_Origin, const Vector3f & a_End, const Vector3f & a_PlanePos, const Vector3f & a_PlaneNormal)
{
Vector3f u = a_End - a_Origin; // a_Ray.P1 - S.P0;
Vector3f w = a_Origin - a_PlanePos; // S.P0 - Pn.V0;
- float D = a_PlaneNormal.Dot( u); // dot(Pn.n, u);
- float N = -(a_PlaneNormal.Dot( w)); // -dot(a_Plane.n, w);
+ float D = a_PlaneNormal.Dot(u); // dot(Pn.n, u);
+ float N = -(a_PlaneNormal.Dot(w)); // -dot(a_Plane.n, w);
const float EPSILON = 0.0001f;
if (fabs(D) < EPSILON)
@@ -294,12 +310,12 @@ int cTracer::intersect3D_SegmentPlane( const Vector3f & a_Origin, const Vector3f
// they are not parallel
// compute intersect param
float sI = N / D;
- if (sI < 0 || sI > 1)
+ if ((sI < 0) || (sI > 1))
{
return 0; // no intersection
}
- // Vector3f I ( a_Ray->GetOrigin() + sI * u);// S.P0 + sI * u; // compute segment intersect point
+ // Vector3f I (a_Ray->GetOrigin() + sI * u);// S.P0 + sI * u; // compute segment intersect point
RealHit = a_Origin + u * sI;
return 1;
}
@@ -311,9 +327,9 @@ int cTracer::intersect3D_SegmentPlane( const Vector3f & a_Origin, const Vector3f
int cTracer::GetHitNormal(const Vector3f & start, const Vector3f & end, const Vector3i & a_BlockPos)
{
Vector3i SmallBlockPos = a_BlockPos;
- char BlockID = m_World->GetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
+ char BlockID = m_World->GetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
- if (BlockID == E_BLOCK_AIR || IsBlockWater(BlockID))
+ if ((BlockID == E_BLOCK_AIR) || IsBlockWater(BlockID))
{
return 0;
}
@@ -324,86 +340,86 @@ int cTracer::GetHitNormal(const Vector3f & start, const Vector3f & end, const Ve
Vector3f Look = (end - start);
Look.Normalize();
- float dot = Look.Dot( Vector3f(-1, 0, 0)); // first face normal is x -1
+ float dot = Look.Dot(Vector3f(-1, 0, 0)); // first face normal is x -1
if (dot < 0)
{
- int Lines = LinesCross( start.x, start.y, end.x, end.y, BlockPos.x, BlockPos.y, BlockPos.x, BlockPos.y + 1);
+ int Lines = LinesCross(start.x, start.y, end.x, end.y, BlockPos.x, BlockPos.y, BlockPos.x, BlockPos.y + 1);
if (Lines == 1)
{
- Lines = LinesCross( start.x, start.z, end.x, end.z, BlockPos.x, BlockPos.z, BlockPos.x, BlockPos.z + 1);
+ Lines = LinesCross(start.x, start.z, end.x, end.z, BlockPos.x, BlockPos.z, BlockPos.x, BlockPos.z + 1);
if (Lines == 1)
{
- intersect3D_SegmentPlane( start, end, BlockPos, Vector3f(-1, 0, 0));
+ intersect3D_SegmentPlane(start, end, BlockPos, Vector3f(-1, 0, 0));
return 1;
}
}
}
- dot = Look.Dot( Vector3f(0, 0, -1)); // second face normal is z -1
+ dot = Look.Dot(Vector3f(0, 0, -1)); // second face normal is z -1
if (dot < 0)
{
- int Lines = LinesCross( start.z, start.y, end.z, end.y, BlockPos.z, BlockPos.y, BlockPos.z, BlockPos.y + 1);
+ int Lines = LinesCross(start.z, start.y, end.z, end.y, BlockPos.z, BlockPos.y, BlockPos.z, BlockPos.y + 1);
if (Lines == 1)
{
- Lines = LinesCross( start.z, start.x, end.z, end.x, BlockPos.z, BlockPos.x, BlockPos.z, BlockPos.x + 1);
+ Lines = LinesCross(start.z, start.x, end.z, end.x, BlockPos.z, BlockPos.x, BlockPos.z, BlockPos.x + 1);
if (Lines == 1)
{
- intersect3D_SegmentPlane( start, end, BlockPos, Vector3f(0, 0, -1));
+ intersect3D_SegmentPlane(start, end, BlockPos, Vector3f(0, 0, -1));
return 2;
}
}
}
- dot = Look.Dot( Vector3f(1, 0, 0)); // third face normal is x 1
+ dot = Look.Dot(Vector3f(1, 0, 0)); // third face normal is x 1
if (dot < 0)
{
- int Lines = LinesCross( start.x, start.y, end.x, end.y, BlockPos.x + 1, BlockPos.y, BlockPos.x + 1, BlockPos.y + 1);
+ int Lines = LinesCross(start.x, start.y, end.x, end.y, BlockPos.x + 1, BlockPos.y, BlockPos.x + 1, BlockPos.y + 1);
if (Lines == 1)
{
- Lines = LinesCross( start.x, start.z, end.x, end.z, BlockPos.x + 1, BlockPos.z, BlockPos.x + 1, BlockPos.z + 1);
+ Lines = LinesCross(start.x, start.z, end.x, end.z, BlockPos.x + 1, BlockPos.z, BlockPos.x + 1, BlockPos.z + 1);
if (Lines == 1)
{
- intersect3D_SegmentPlane( start, end, BlockPos + Vector3f(1, 0, 0), Vector3f(1, 0, 0));
+ intersect3D_SegmentPlane(start, end, BlockPos + Vector3f(1, 0, 0), Vector3f(1, 0, 0));
return 3;
}
}
}
- dot = Look.Dot( Vector3f(0, 0, 1)); // fourth face normal is z 1
+ dot = Look.Dot(Vector3f(0, 0, 1)); // fourth face normal is z 1
if (dot < 0)
{
- int Lines = LinesCross( start.z, start.y, end.z, end.y, BlockPos.z + 1, BlockPos.y, BlockPos.z + 1, BlockPos.y + 1);
+ int Lines = LinesCross(start.z, start.y, end.z, end.y, BlockPos.z + 1, BlockPos.y, BlockPos.z + 1, BlockPos.y + 1);
if (Lines == 1)
{
- Lines = LinesCross( start.z, start.x, end.z, end.x, BlockPos.z + 1, BlockPos.x, BlockPos.z + 1, BlockPos.x + 1);
+ Lines = LinesCross(start.z, start.x, end.z, end.x, BlockPos.z + 1, BlockPos.x, BlockPos.z + 1, BlockPos.x + 1);
if (Lines == 1)
{
- intersect3D_SegmentPlane( start, end, BlockPos + Vector3f(0, 0, 1), Vector3f(0, 0, 1));
+ intersect3D_SegmentPlane(start, end, BlockPos + Vector3f(0, 0, 1), Vector3f(0, 0, 1));
return 4;
}
}
}
- dot = Look.Dot( Vector3f(0, 1, 0)); // fifth face normal is y 1
+ dot = Look.Dot(Vector3f(0, 1, 0)); // fifth face normal is y 1
if (dot < 0)
{
- int Lines = LinesCross( start.y, start.x, end.y, end.x, BlockPos.y + 1, BlockPos.x, BlockPos.y + 1, BlockPos.x + 1);
+ int Lines = LinesCross(start.y, start.x, end.y, end.x, BlockPos.y + 1, BlockPos.x, BlockPos.y + 1, BlockPos.x + 1);
if (Lines == 1)
{
- Lines = LinesCross( start.y, start.z, end.y, end.z, BlockPos.y + 1, BlockPos.z, BlockPos.y + 1, BlockPos.z + 1);
+ Lines = LinesCross(start.y, start.z, end.y, end.z, BlockPos.y + 1, BlockPos.z, BlockPos.y + 1, BlockPos.z + 1);
if (Lines == 1)
{
- intersect3D_SegmentPlane( start, end, BlockPos + Vector3f(0, 1, 0), Vector3f(0, 1, 0));
+ intersect3D_SegmentPlane(start, end, BlockPos + Vector3f(0, 1, 0), Vector3f(0, 1, 0));
return 5;
}
}
}
- dot = Look.Dot( Vector3f(0, -1, 0)); // sixth face normal is y -1
+ dot = Look.Dot(Vector3f(0, -1, 0)); // sixth face normal is y -1
if (dot < 0)
{
- int Lines = LinesCross( start.y, start.x, end.y, end.x, BlockPos.y, BlockPos.x, BlockPos.y, BlockPos.x + 1);
+ int Lines = LinesCross(start.y, start.x, end.y, end.x, BlockPos.y, BlockPos.x, BlockPos.y, BlockPos.x + 1);
if (Lines == 1)
{
- Lines = LinesCross( start.y, start.z, end.y, end.z, BlockPos.y, BlockPos.z, BlockPos.y, BlockPos.z + 1);
+ Lines = LinesCross(start.y, start.z, end.y, end.z, BlockPos.y, BlockPos.z, BlockPos.y, BlockPos.z + 1);
if (Lines == 1)
{
- intersect3D_SegmentPlane( start, end, BlockPos, Vector3f(0, -1, 0));
+ intersect3D_SegmentPlane(start, end, BlockPos, Vector3f(0, -1, 0));
return 6;
}
}
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 9113ec343..e784569d9 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -1167,7 +1167,7 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player)
{
m_MaximumCost = 39;
}
- if (m_MaximumCost >= 40 && !a_Player.IsGameModeCreative())
+ if ((m_MaximumCost >= 40) && !a_Player.IsGameModeCreative())
{
Input.Empty();
}
@@ -2322,7 +2322,7 @@ cItem * cSlotAreaTemporary::GetPlayerSlots(cPlayer & a_Player)
{
return nullptr;
}
- return &(itr->second[0]);
+ return itr->second.data();
}
diff --git a/src/World.cpp b/src/World.cpp
index 100df5742..3dc083a2e 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -11,7 +11,6 @@
#include "IniFile.h"
#include "ChunkMap.h"
#include "Generating/ChunkDesc.h"
-#include "OSSupport/Timer.h"
#include "SetChunkData.h"
// Serializers
@@ -45,7 +44,6 @@
#include "MobCensus.h"
#include "MobSpawner.h"
-#include "MersenneTwister.h"
#include "Generating/Trees.h"
#include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h"
@@ -92,7 +90,6 @@ public:
m_PrepareDistance(a_PrepareDistance),
m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
m_NumPrepared(0),
- m_LastReportTime(0),
m_LastReportChunkCount(0)
{
// Start the thread:
@@ -113,7 +110,7 @@ public:
m_MaxIdx = m_PrepareDistance * m_PrepareDistance;
int maxQueue = std::min(m_MaxIdx - 1, 100); // Number of chunks to queue at once
m_NextIdx = maxQueue;
- m_LastReportTime = m_Timer.GetNowTime();
+ m_LastReportTime = std::chrono::steady_clock::now();
for (int i = 0; i < maxQueue; i++)
{
int chunkX, chunkZ;
@@ -146,16 +143,12 @@ protected:
/** Event used to signal that the preparation is finished. */
cEvent m_EvtFinished;
- /** The timer used to report progress every second. */
- cTimer m_Timer;
-
/** The timestamp of the last progress report emitted. */
- long long m_LastReportTime;
+ std::chrono::steady_clock::time_point m_LastReportTime;
/** Number of chunks prepared when the last progress report was emitted. */
int m_LastReportChunkCount;
-
// cChunkCoordCallback override:
virtual void Call(int a_ChunkX, int a_ChunkZ)
{
@@ -164,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:
@@ -176,15 +171,15 @@ protected:
}
// Report progress every 1 second:
- long long now = m_Timer.GetNowTime();
- if (now - m_LastReportTime > 1000)
+ auto Now = std::chrono::steady_clock::now();
+ if (Now - m_LastReportTime > std::chrono::seconds(1))
{
- float percentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
- float chunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / (now - m_LastReportTime);
- LOG("Preparing spawn (%s): %.02f%% done (%d chunks out of %d; %.02f chunks / sec)",
- m_World.GetName().c_str(), percentDone, m_NumPrepared, m_MaxIdx, chunkSpeed
+ float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
+ float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
+ LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks/s)",
+ m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
);
- m_LastReportTime = now;
+ m_LastReportTime = Now;
m_LastReportChunkCount = m_NumPrepared;
}
}
@@ -237,23 +232,22 @@ cWorld::cTickThread::cTickThread(cWorld & a_World) :
void cWorld::cTickThread::Execute(void)
{
- cTimer Timer;
+ auto LastTime = std::chrono::steady_clock::now();
+ static const auto msPerTick = std::chrono::milliseconds(50);
+ auto TickTime = std::chrono::steady_clock::duration(50);
- const Int64 msPerTick = 50;
- Int64 LastTime = Timer.GetNowTime();
-
- Int64 TickDuration = 50;
while (!m_ShouldTerminate)
{
- Int64 NowTime = Timer.GetNowTime();
- float DeltaTime = (float)(NowTime - LastTime);
- m_World.Tick(DeltaTime, (int)TickDuration);
- TickDuration = Timer.GetNowTime() - NowTime;
+ auto NowTime = std::chrono::steady_clock::now();
+ auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count();
+ auto LastTickMsec = std::chrono::duration_cast<std::chrono::duration<int>>(TickTime).count();
+ m_World.Tick(static_cast<float>(msec), LastTickMsec);
+ TickTime = std::chrono::steady_clock::now() - NowTime;
- if (TickDuration < msPerTick)
+ if (TickTime < msPerTick)
{
// Stretch tick time until it's at least msPerTick
- cSleep::MilliSleep((unsigned int)(msPerTick - TickDuration));
+ std::this_thread::sleep_for(msPerTick - TickTime);
}
LastTime = NowTime;
@@ -352,6 +346,10 @@ cWorld::~cWorld()
Serializer.Save();
m_MapManager.SaveMapData();
+
+ // Explicitly destroy the chunkmap, so that it's guaranteed to be destroyed before the other internals
+ // This fixes crashes on stopping the server, because chunk destructor deletes entities and those access the world.
+ m_ChunkMap.reset();
}
@@ -612,7 +610,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);
@@ -745,7 +743,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
- a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
+ a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, NaturalPatches, PreSimulator, Animals");
break;
}
case dimNether:
@@ -757,7 +755,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;
}
@@ -1807,7 +1805,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
- if (!IsValidItem(itr->m_ItemType) || itr->m_ItemType == E_BLOCK_AIR)
+ if (!IsValidItem(itr->m_ItemType) || (itr->m_ItemType == E_BLOCK_AIR))
{
// Don't spawn pickup if item isn't even valid; should prevent client crashing too
continue;
@@ -1833,7 +1831,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
{
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
- if (!IsValidItem(itr->m_ItemType) || itr->m_ItemType == E_BLOCK_AIR)
+ if (!IsValidItem(itr->m_ItemType) || (itr->m_ItemType == E_BLOCK_AIR))
{
continue;
}
@@ -2678,7 +2676,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)
{
@@ -3128,6 +3126,11 @@ bool cWorld::HasEntity(int a_UniqueID)
}
// Check if the entity is in the chunkmap:
+ if (m_ChunkMap.get() == nullptr)
+ {
+ // Chunkmap has already been destroyed, there are no entities anymore.
+ return false;
+ }
return m_ChunkMap->HasEntity(a_UniqueID);
}
diff --git a/src/World.h b/src/World.h
index ee9b93874..2f51d60a1 100644
--- a/src/World.h
+++ b/src/World.h
@@ -10,7 +10,6 @@
#define MAX_PLAYERS 65535
#include "Simulator/SimulatorManager.h"
-#include "MersenneTwister.h"
#include "ChunkMap.h"
#include "WorldStorage/WorldStorage.h"
#include "Generating/ChunkGenerator.h"
@@ -26,6 +25,7 @@
#include "MapManager.h"
#include "Blocks/WorldInterface.h"
#include "Blocks/BroadcastInterface.h"
+#include "FastRandom.h"
#include "ClientHandle.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/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp
index ecb600483..91a5b8b63 100644
--- a/src/WorldStorage/FireworksSerializer.cpp
+++ b/src/WorldStorage/FireworksSerializer.cpp
@@ -22,11 +22,11 @@ void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFa
a_Writer.AddByte("Type", a_FireworkItem.m_Type);
if (!a_FireworkItem.m_Colours.empty())
{
- a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ a_Writer.AddIntArray("Colors", a_FireworkItem.m_Colours.data(), a_FireworkItem.m_Colours.size());
}
if (!a_FireworkItem.m_FadeColours.empty())
{
- a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ a_Writer.AddIntArray("FadeColors", a_FireworkItem.m_FadeColours.data(), a_FireworkItem.m_FadeColours.size());
}
a_Writer.EndCompound();
a_Writer.EndList();
@@ -41,11 +41,11 @@ void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFa
a_Writer.AddByte("Type", a_FireworkItem.m_Type);
if (!a_FireworkItem.m_Colours.empty())
{
- a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ a_Writer.AddIntArray("Colors", a_FireworkItem.m_Colours.data(), a_FireworkItem.m_Colours.size());
}
if (!a_FireworkItem.m_FadeColours.empty())
{
- a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ a_Writer.AddIntArray("FadeColors", a_FireworkItem.m_FadeColours.data(), a_FireworkItem.m_FadeColours.size());
}
a_Writer.EndCompound();
break;
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index 4a913c81a..f2d35b318 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -112,7 +112,7 @@ void cMapSerializer::SaveMapToNBT(cFastNBTWriter & a_Writer)
a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
const cMap::cColorList & Data = m_Map->GetData();
- a_Writer.AddByteArray("colors", (char *) &Data[0], Data.size());
+ a_Writer.AddByteArray("colors", (char *)Data.data(), Data.size());
a_Writer.EndCompound();
}
@@ -190,7 +190,7 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
CurrLine = a_NBT.FindChildByName(Data, "colors");
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray))
{
- memcpy(&m_Map->m_Data[0], a_NBT.GetData(CurrLine), NumPixels);
+ memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels);
}
return true;
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 395aabb1b..5a0932bbe 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"
@@ -630,7 +631,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
// Load the proper BlockEntity type based on the block type:
BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, RelY, RelZ);
NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, RelX, RelY, RelZ);
- std::auto_ptr<cBlockEntity> be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta));
+ std::unique_ptr<cBlockEntity> be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta));
if (be.get() == nullptr)
{
continue;
@@ -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);
@@ -856,7 +858,7 @@ cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagI
return nullptr;
}
- std::auto_ptr<cBeaconEntity> Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cBeaconEntity> Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels");
if (CurrentLine >= 0)
@@ -906,7 +908,7 @@ cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagId
{
return nullptr; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
}
- std::auto_ptr<cChestEntity> Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType));
+ std::unique_ptr<cChestEntity> Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType));
LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
return Chest.release();
}
@@ -923,7 +925,7 @@ cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int
return nullptr;
}
- std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command");
if (currentLine >= 0)
@@ -965,7 +967,7 @@ cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_T
{
return nullptr; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
}
- std::auto_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items);
return Dispenser.release();
}
@@ -987,7 +989,7 @@ cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_Tag
{
return nullptr; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
}
- std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cDropperEntity> Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items);
return Dropper.release();
}
@@ -1004,7 +1006,7 @@ cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_T
return nullptr;
}
- std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
short ItemType = 0, ItemData = 0;
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item");
@@ -1041,7 +1043,7 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag
return nullptr; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
}
- std::auto_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World));
+ std::unique_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World));
// Load slots:
for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child))
@@ -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:
@@ -1098,7 +1148,7 @@ cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagI
{
return nullptr; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
}
- std::auto_ptr<cHopperEntity> Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cHopperEntity> Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items);
return Hopper.release();
}
@@ -1115,7 +1165,7 @@ cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_Tag
return nullptr;
}
- std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
int Record = a_NBT.FindChildByName(a_TagIdx, "Record");
if (Record >= 0)
{
@@ -1136,7 +1186,7 @@ cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_Tag
return nullptr;
}
- std::auto_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType");
if (currentLine >= 0)
@@ -1171,7 +1221,7 @@ cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_T
return nullptr;
}
- std::auto_ptr<cNoteEntity> NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cNoteEntity> NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
int note = a_NBT.FindChildByName(a_TagIdx, "note");
if (note >= 0)
{
@@ -1192,7 +1242,7 @@ cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx
return nullptr;
}
- std::auto_ptr<cSignEntity> Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World));
+ std::unique_ptr<cSignEntity> Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World));
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1");
if (currentLine >= 0)
@@ -1445,7 +1495,7 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cBoat> Boat(new cBoat(0, 0, 0));
+ std::unique_ptr<cBoat> Boat(new cBoat(0, 0, 0));
if (!LoadEntityBaseFromNBT(*Boat.get(), a_NBT, a_TagIdx))
{
return;
@@ -1459,7 +1509,7 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0));
+ std::unique_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0));
if (!LoadEntityBaseFromNBT(*EnderCrystal.get(), a_NBT, a_TagIdx))
{
return;
@@ -1476,12 +1526,15 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID");
int MetaIdx = a_NBT.FindChildByName(a_TagIdx, "Data");
- if ((TypeIdx < 0) || (MetaIdx < 0)) { return; }
+ if ((TypeIdx < 0) || (MetaIdx < 0))
+ {
+ return;
+ }
int Type = a_NBT.GetInt(TypeIdx);
NIBBLETYPE Meta = (NIBBLETYPE)a_NBT.GetByte(MetaIdx);
- std::auto_ptr<cFallingBlock> FallingBlock(new cFallingBlock(Vector3i(0, 0, 0), Type, Meta));
+ std::unique_ptr<cFallingBlock> FallingBlock(new cFallingBlock(Vector3i(0, 0, 0), Type, Meta));
if (!LoadEntityBaseFromNBT(*FallingBlock.get(), a_NBT, a_TagIdx))
{
return;
@@ -1495,7 +1548,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN
void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height
+ std::unique_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1514,7 +1567,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
}
- std::auto_ptr<cMinecartWithChest> Minecart(new cMinecartWithChest(0, 0, 0));
+ std::unique_ptr<cMinecartWithChest> Minecart(new cMinecartWithChest(0, 0, 0));
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1541,7 +1594,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cMinecartWithFurnace> Minecart(new cMinecartWithFurnace(0, 0, 0));
+ std::unique_ptr<cMinecartWithFurnace> Minecart(new cMinecartWithFurnace(0, 0, 0));
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1558,7 +1611,7 @@ void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cMinecartWithTNT> Minecart(new cMinecartWithTNT(0, 0, 0));
+ std::unique_ptr<cMinecartWithTNT> Minecart(new cMinecartWithTNT(0, 0, 0));
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1575,7 +1628,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cMinecartWithHopper> Minecart(new cMinecartWithHopper(0, 0, 0));
+ std::unique_ptr<cMinecartWithHopper> Minecart(new cMinecartWithHopper(0, 0, 0));
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1604,7 +1657,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
return;
}
- std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false
+ std::unique_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
{
return;
@@ -1626,7 +1679,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
+ std::unique_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
{
return;
@@ -1648,7 +1701,7 @@ void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0));
+ std::unique_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0));
if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx))
{
return;
@@ -1747,7 +1800,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT
return;
}
- std::auto_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
+ std::unique_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx))
{
return;
@@ -1772,7 +1825,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
+ std::unique_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx))
{
return;
@@ -1842,7 +1895,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0), cItem()));
+ std::unique_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0), cItem()));
if (!LoadProjectileBaseFromNBT(*SplashPotion.get(), a_NBT, a_TagIdx))
{
return;
@@ -1866,7 +1919,7 @@ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedN
void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
+ std::unique_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadProjectileBaseFromNBT(*Snowball.get(), a_NBT, a_TagIdx))
{
return;
@@ -1882,7 +1935,7 @@ void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT &
void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
+ std::unique_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadProjectileBaseFromNBT(*Egg.get(), a_NBT, a_TagIdx))
{
return;
@@ -1898,7 +1951,7 @@ void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
+ std::unique_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadProjectileBaseFromNBT(*Fireball.get(), a_NBT, a_TagIdx))
{
return;
@@ -1914,7 +1967,7 @@ void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT &
void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
+ std::unique_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadProjectileBaseFromNBT(*FireCharge.get(), a_NBT, a_TagIdx))
{
return;
@@ -1930,7 +1983,7 @@ void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
+ std::unique_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadProjectileBaseFromNBT(*Enderpearl.get(), a_NBT, a_TagIdx))
{
return;
@@ -1946,7 +1999,7 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar
void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cBat> Monster(new cBat());
+ std::unique_ptr<cBat> Monster(new cBat());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -1966,7 +2019,7 @@ void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cBlaze> Monster(new cBlaze());
+ std::unique_ptr<cBlaze> Monster(new cBlaze());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -1986,7 +2039,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cCaveSpider> Monster(new cCaveSpider());
+ std::unique_ptr<cCaveSpider> Monster(new cCaveSpider());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2006,7 +2059,7 @@ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cChicken> Monster(new cChicken());
+ std::unique_ptr<cChicken> Monster(new cChicken());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2026,7 +2079,7 @@ void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT &
void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cCow> Monster(new cCow());
+ std::unique_ptr<cCow> Monster(new cCow());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2046,7 +2099,7 @@ void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cCreeper> Monster(new cCreeper());
+ std::unique_ptr<cCreeper> Monster(new cCreeper());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2066,7 +2119,7 @@ void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT &
void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cEnderDragon> Monster(new cEnderDragon());
+ std::unique_ptr<cEnderDragon> Monster(new cEnderDragon());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2086,7 +2139,7 @@ void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNB
void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cEnderman> Monster(new cEnderman());
+ std::unique_ptr<cEnderman> Monster(new cEnderman());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2106,7 +2159,7 @@ void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT &
void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cGhast> Monster(new cGhast());
+ std::unique_ptr<cGhast> Monster(new cGhast());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2126,7 +2179,7 @@ void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cGiant> Monster(new cGiant());
+ std::unique_ptr<cGiant> Monster(new cGiant());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2146,17 +2199,19 @@ void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type");
+ int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type");
int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
int StyleIdx = a_NBT.FindChildByName(a_TagIdx, "Style");
-
- if ((TypeIdx < 0) || (ColorIdx < 0) || (StyleIdx < 0)) { return; }
+ if ((TypeIdx < 0) || (ColorIdx < 0) || (StyleIdx < 0))
+ {
+ return;
+ }
int Type = a_NBT.GetInt(TypeIdx);
int Color = a_NBT.GetInt(ColorIdx);
int Style = a_NBT.GetInt(StyleIdx);
- std::auto_ptr<cHorse> Monster(new cHorse(Type, Color, Style, 1));
+ std::unique_ptr<cHorse> Monster(new cHorse(Type, Color, Style, 1));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
@@ -2177,7 +2232,7 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cIronGolem> Monster(new cIronGolem());
+ std::unique_ptr<cIronGolem> Monster(new cIronGolem());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2206,7 +2261,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT
int Size = a_NBT.GetInt(SizeIdx);
- std::auto_ptr<cMagmaCube> Monster(new cMagmaCube(Size));
+ std::unique_ptr<cMagmaCube> Monster(new cMagmaCube(Size));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2226,7 +2281,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cMooshroom> Monster(new cMooshroom());
+ std::unique_ptr<cMooshroom> Monster(new cMooshroom());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2246,7 +2301,7 @@ void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cOcelot> Monster(new cOcelot());
+ std::unique_ptr<cOcelot> Monster(new cOcelot());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2266,7 +2321,7 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cPig> Monster(new cPig());
+ std::unique_ptr<cPig> Monster(new cPig());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2293,7 +2348,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
Color = (int)a_NBT.GetByte(ColorIdx);
}
- std::auto_ptr<cSheep> Monster(new cSheep(Color));
+ std::unique_ptr<cSheep> Monster(new cSheep(Color));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2319,7 +2374,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cSilverfish> Monster(new cSilverfish());
+ std::unique_ptr<cSilverfish> Monster(new cSilverfish());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2340,12 +2395,14 @@ void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "SkeletonType");
-
- if (TypeIdx < 0) { return; }
+ if (TypeIdx < 0)
+ {
+ return;
+ }
bool Type = ((a_NBT.GetByte(TypeIdx) == 1) ? true : false);
- std::auto_ptr<cSkeleton> Monster(new cSkeleton(Type));
+ std::unique_ptr<cSkeleton> Monster(new cSkeleton(Type));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2374,7 +2431,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
int Size = a_NBT.GetInt(SizeIdx);
- std::auto_ptr<cSlime> Monster(new cSlime(Size));
+ std::unique_ptr<cSlime> Monster(new cSlime(Size));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2394,7 +2451,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cSnowGolem> Monster(new cSnowGolem());
+ std::unique_ptr<cSnowGolem> Monster(new cSnowGolem());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2414,7 +2471,7 @@ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cSpider> Monster(new cSpider());
+ std::unique_ptr<cSpider> Monster(new cSpider());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2434,7 +2491,7 @@ void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cSquid> Monster(new cSquid());
+ std::unique_ptr<cSquid> Monster(new cSquid());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2455,12 +2512,14 @@ void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Profession");
-
- if (TypeIdx < 0) { return; }
+ if (TypeIdx < 0)
+ {
+ return;
+ }
int Type = a_NBT.GetInt(TypeIdx);
- std::auto_ptr<cVillager> Monster(new cVillager(cVillager::eVillagerType(Type)));
+ std::unique_ptr<cVillager> Monster(new cVillager(cVillager::eVillagerType(Type)));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2480,7 +2539,7 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT &
void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cWitch> Monster(new cWitch());
+ std::unique_ptr<cWitch> Monster(new cWitch());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2500,7 +2559,7 @@ void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cWither> Monster(new cWither());
+ std::unique_ptr<cWither> Monster(new cWither());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2526,7 +2585,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cWolf> Monster(new cWolf());
+ std::unique_ptr<cWolf> Monster(new cWolf());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2580,12 +2639,14 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int IsVillagerIdx = a_NBT.FindChildByName(a_TagIdx, "IsVillager");
-
- if (IsVillagerIdx < 0) { return; }
+ if (IsVillagerIdx < 0)
+ {
+ return;
+ }
bool IsVillagerZombie = ((a_NBT.GetByte(IsVillagerIdx) == 1) ? true : false);
- std::auto_ptr<cZombie> Monster(new cZombie(IsVillagerZombie));
+ std::unique_ptr<cZombie> Monster(new cZombie(IsVillagerZombie));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -2605,7 +2666,7 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cZombiePigman> Monster(new cZombiePigman());
+ std::unique_ptr<cZombiePigman> Monster(new cZombiePigman());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
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/XMLParser.h b/src/XMLParser.h
index 5b53e55cf..ea341bce6 100644
--- a/src/XMLParser.h
+++ b/src/XMLParser.h
@@ -105,11 +105,11 @@ public:
Destroy ();
// If the encoding or seperator are empty, then nullptr
- if (pszEncoding != nullptr && pszEncoding [0] == 0)
+ if ((pszEncoding != nullptr) && (pszEncoding[0] == 0))
{
pszEncoding = nullptr;
}
- if (pszSep != nullptr && pszSep [0] == 0)
+ if ((pszSep != nullptr) && (pszSep[0] == 0))
{
pszSep = nullptr;
}
@@ -147,7 +147,7 @@ public:
bool Parse (const char *pszBuffer, int nLength, bool fIsFinal = true)
{
assert (m_p != nullptr);
- return XML_Parse (m_p, pszBuffer, nLength, fIsFinal) != 0;
+ return (XML_Parse (m_p, pszBuffer, nLength, fIsFinal) != 0);
}
// @cmember Parse internal buffer
@@ -254,7 +254,9 @@ protected:
XML_SetDefaultHandlerExpand (m_p, fEnable ? DefaultHandler : nullptr);
}
else
+ {
XML_SetDefaultHandler (m_p, fEnable ? DefaultHandler : nullptr);
+ }
}
// @cmember Enable/Disable external entity ref handler
@@ -402,11 +404,17 @@ public:
{
XML_expat_version v = XML_ExpatVersionInfo ();
if (pnMajor)
+ {
*pnMajor = v .major;
+ }
if (pnMinor)
+ {
*pnMinor = v .minor;
+ }
if (pnMicro)
+ {
*pnMicro = v .micro;
+ }
}
// @cmember Get last error string
diff --git a/src/main.cpp b/src/main.cpp
index c60e13a8c..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
{
@@ -158,9 +163,9 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
cRoot::m_TerminateEventRaised = true;
LOGD("Terminate event raised from the Windows CtrlHandler");
- if (fdwCtrlType == CTRL_CLOSE_EVENT) // Console window closed via 'x' button, Windows will try to close immediately, therefore...
+ while (!g_ServerTerminated)
{
- while (!g_ServerTerminated) { cSleep::MilliSleep(100); } // Delay as much as possible to try to get the server to shut down cleanly
+ std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Delay as much as possible to try to get the server to shut down cleanly
}
return TRUE;