Merge remote-tracking branch 'origin/master' into c++11Events
This commit is contained in:
commit
8ad1afcc1b
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -534,6 +534,7 @@ end
|
||||
GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data. Returns a 32-char UUID (no dashes)" },
|
||||
GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" },
|
||||
GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" },
|
||||
GetRequestedViewDistance = { Params = "", Return = "number", Notes = "Returns the view distance that the player request, not the used view distance." },
|
||||
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
|
||||
IsUUIDOnline = { Params = "UUID", Return = "bool", Notes = "(STATIC) Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID. We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. Accepts both 32-char and 36-char UUIDs (with and without dashes). If the string given is not a valid UUID, returns false."},
|
||||
Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" },
|
||||
@ -614,7 +615,7 @@ function OnPlayerJoined(a_Player)
|
||||
-- Send an example composite chat message to the player:
|
||||
a_Player:SendMessage(cCompositeChat()
|
||||
:AddTextPart("Hello, ")
|
||||
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2") -- Colored underlined link
|
||||
:AddUrlPart(a_Player:GetName(), "http://www.mc-server.org", "u@2") -- Colored underlined link
|
||||
:AddSuggestCommandPart(", and welcome.", "/help", "u") -- Underlined suggest-command
|
||||
:AddRunCommandPart(" SetDay", "/time set 0") -- Regular text that will execute command when clicked
|
||||
:SetMessageType(mtJoin) -- It is a join-message
|
||||
@ -1667,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" },
|
||||
},
|
||||
@ -1724,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
|
||||
@ -2137,6 +2132,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
|
||||
BroadcastChatWarning = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtWarning. Use for concerning events, such as plugin reload etc." },
|
||||
CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil.<br/><br/><b>NOTE</b>This function is currently unsafe, do not use!" },
|
||||
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for all players with names partially (or fully) matching the name string provided." },
|
||||
DoWithPlayerByUUID = { Params = "PlayerUUID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is the player with the uuid, calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
|
||||
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
|
||||
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
|
||||
Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." },
|
||||
@ -2406,6 +2402,7 @@ end
|
||||
{ Params = "{{Vector3i|BlockCoords}}, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, without waking up the simulators or replacing the block entities for the previous block type. Do not use if the block being replaced has a block entity tied to it!" },
|
||||
},
|
||||
FindAndDoWithPlayer = { Params = "PlayerNameHint, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of a name similar to the specified name (weighted-match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found. Note that the name matching is very loose, so it is a good idea to check the player name in the callback function." },
|
||||
DoWithPlayerByUUID = { Params = "PlayerUUID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is the player with the uuid, calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
|
||||
ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
|
||||
ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." },
|
||||
ForEachEntity = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
|
||||
@ -2497,7 +2494,7 @@ end
|
||||
SetCommandBlocksEnabled = { Params = "IsEnabled (bool)", Return = "", Notes = "Sets whether command blocks should be enabled on the (entire) server." },
|
||||
SetShouldUseChatPrefixes = { Params = "", Return = "ShouldUse (bool)", Notes = "Sets whether coloured chat prefixes such as [INFO] is used with the SendMessageXXX() or BroadcastChatXXX(), or simply the entire message is coloured in the respective colour." },
|
||||
ShouldUseChatPrefixes = { Params = "", Return = "bool", Notes = "Returns whether coloured chat prefixes are prepended to chat messages or the entire message is simply coloured." },
|
||||
SetSignLines = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as UpdateSign()." },
|
||||
SetSignLines = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil." },
|
||||
SetTicksUntilWeatherChange = { Params = "NumTicks", Return = "", Notes = "Sets the number of ticks after which the weather will be changed." },
|
||||
SetTimeOfDay = { Params = "TimeOfDayTicks", Return = "", Notes = "Sets the time of day, expressed as number of ticks past sunrise, in the range 0 .. 24000." },
|
||||
SetWeather = { Params = "Weather", Return = "", Notes = "Sets the current weather (wSunny, wRain, wStorm) and resets the TicksUntilWeatherChange to the default value for the new weather. The normal weather-changing hooks are called for the change." },
|
||||
@ -2512,7 +2509,7 @@ end
|
||||
SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" },
|
||||
SpawnPrimedTNT = { Params = "X, Y, Z, FuseTicks, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse ticks. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
|
||||
TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." },
|
||||
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as SetSignLiens()" },
|
||||
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "(<b>DEPRECATED</b>) Please use SetSignLines()." },
|
||||
UseBlockEntity = { Params = "{{cPlayer|Player}}, BlockX, BlockY, BlockZ", Return = "", Notes = "Makes the specified Player use the block entity at the specified coords (open chest UI, etc.) If the cords are in an unloaded chunk or there's no block entity, ignores the call." },
|
||||
WakeUpSimulators = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Wakes up the simulators for the specified block." },
|
||||
WakeUpSimulatorsInArea = { Params = "MinBlockX, MaxBlockX, MinBlockY, MaxBlockY, MinBlockZ, MaxBlockZ", Return = "", Notes = "Wakes up the simulators for all the blocks in the specified area (edges inclusive)." },
|
||||
@ -2568,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
|
||||
@ -2925,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"},
|
||||
@ -3011,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" },
|
||||
|
@ -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 = [[
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 4702471943511f641458c7e8e89b430a723f43ea
|
||||
Subproject commit 4183d6cfb2049d0757d811a65bd4e75ed78b9f41
|
@ -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:
|
||||
|
@ -51,6 +51,7 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
|
||||
return a_CmdInfo.Handler(a_Split, a_Player);
|
||||
end
|
||||
-- Let the player know they need to give a subcommand:
|
||||
assert(type(a_CmdInfo.Subcommands) == "table", "Info.lua error: There is no handler for command \"" .. a_CmdString .. "\" and there are no subcommands defined at level " .. a_Level)
|
||||
ListSubcommands(a_Player, a_CmdInfo.Subcommands, a_CmdString);
|
||||
return true;
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -9,6 +9,8 @@ body {
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
height:100%;
|
||||
min-height:100%;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
@ -48,7 +50,8 @@ h1 {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
margin-top: 125px;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.contention {
|
||||
@ -58,10 +61,10 @@ h1 {
|
||||
margin: 0;
|
||||
font-family: Tahoma,Verdana,Arial,Sans-Serif;
|
||||
font-size: 13px;
|
||||
margin-bottom:75px;
|
||||
}
|
||||
|
||||
.push10 {
|
||||
padding-bottom: 75px;
|
||||
.push25 {
|
||||
}
|
||||
|
||||
#panel ul.menu {
|
||||
@ -93,10 +96,6 @@ h1 {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
#footer ul.menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@ -154,13 +153,14 @@ h1 {
|
||||
}
|
||||
|
||||
#footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 60px;
|
||||
position: fixed;
|
||||
left:0;
|
||||
bottom:0;
|
||||
height: 61px;
|
||||
width: 100%;
|
||||
background: #999;
|
||||
border-top: 1px #000 solid;
|
||||
border-bottom: 1px #000 solid;
|
||||
}
|
||||
|
||||
* html #footer {
|
||||
@ -234,10 +234,6 @@ table {
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.padtopp {
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
table {
|
||||
color: #000;
|
||||
font-size: 13px;
|
||||
@ -319,8 +315,6 @@ select {
|
||||
}
|
||||
|
||||
.pagehead {
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */
|
||||
<!-- Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */ -->
|
||||
<html>
|
||||
<head>
|
||||
<title>MCServer WebAdmin - Login</title>
|
||||
@ -61,7 +61,6 @@
|
||||
</div>
|
||||
<div class="lower">
|
||||
<div class="wrapper">
|
||||
<span id="current_time"><strong>Current time:</strong> <script type="text/javascript">document.write('Time: <strong><span id="date-time">',new Date().toLocaleString(),"</span></strong>");if(document.getElementById){onload=function(){setInterval("document.getElementById ('date-time').firstChild.data = new Date().toLocaleString()",50)}};</script></span>
|
||||
<span id="copyright">Copyright © <a href="http://www.mc-server.org" target="_blank">MCServer Team</a> 2014.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -81,7 +81,7 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
end
|
||||
|
||||
Output([[
|
||||
/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */
|
||||
<!-- Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 -->
|
||||
<html>
|
||||
<head>
|
||||
<title>]] .. Title .. [[</title>
|
||||
@ -90,7 +90,7 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div class="contention">
|
||||
<div class="contention push25">
|
||||
<div class="pagehead">
|
||||
<div class="row1">
|
||||
<div class="wrapper">
|
||||
@ -110,27 +110,27 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2 push10">
|
||||
<div class="wrapper padtopp">
|
||||
<table width="100%" border="0" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="180" valign="top">
|
||||
<table border="0" cellspacing="0" cellpadding="5" class="tborder">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="thead"><strong>Menu</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="trow1 smalltext"><a href=']] .. BaseURL .. [[' class='usercp_nav_item usercp_nav_home'>Home</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tcat"><div><span class="smalltext"><strong><font color="#000">Server Management</font></strong></span></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody style="" id="usercppms_e">
|
||||
<tr>
|
||||
<td class="trow1 smalltext">
|
||||
<div class="row2">
|
||||
<div class="wrapper">
|
||||
<table width="100%" border="0" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="180" valign="top">
|
||||
<table border="0" cellspacing="0" cellpadding="5" class="tborder">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="thead"><strong>Menu</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="trow1 smalltext"><a href=']] .. BaseURL .. [[' class='usercp_nav_item usercp_nav_home'>Home</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tcat"><div><span class="smalltext"><strong><font color="#000">Server Management</font></strong></span></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody style="" id="usercppms_e">
|
||||
<tr>
|
||||
<td class="trow1 smalltext">
|
||||
]])
|
||||
|
||||
|
||||
@ -173,7 +173,6 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="upper">
|
||||
<div class="wrapper">
|
||||
@ -188,11 +187,11 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
</div>
|
||||
<div class="lower">
|
||||
<div class="wrapper">
|
||||
<span id="current_time"><strong>Current time:</strong> <script type="text/javascript">document.write('Time: <strong><span id="date-time">',new Date().toLocaleString(),"</span></strong>");if(document.getElementById){onload=function(){setInterval("document.getElementById ('date-time').firstChild.data = new Date().toLocaleString()",50)}};</script></span>
|
||||
<span id="copyright">Copyright © <a href="http://www.mc-server.org" target="_blank">MCServer Team</a> 2014.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]])
|
||||
|
@ -1,4 +1,4 @@
|
||||
MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) [![Coverity Scan Build Status](https://scan.coverity.com/projects/1930/badge.svg)](https://scan.coverity.com/projects/1930) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
|
||||
MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer/master.svg?style=flat)](https://travis-ci.org/mc-server/MCServer) [![Coverity Scan Build Status](https://scan.coverity.com/projects/1930/badge.svg)](https://scan.coverity.com/projects/1930) [![weekly tips](http://img.shields.io/gratipay/cuberite_team.svg?style=flat)](http://gratipay.com/cuberite_team) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
|
||||
========
|
||||
|
||||
MCServer is a Minecraft server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API.
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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"
|
||||
|
@ -7,6 +7,9 @@
|
||||
|
||||
|
||||
#include "../BlockInfo.h"
|
||||
#include "../World.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "LuaState.h"
|
||||
|
||||
|
||||
|
||||
@ -49,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);
|
||||
@ -75,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);
|
||||
@ -101,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);
|
||||
@ -127,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);
|
||||
@ -153,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);
|
||||
@ -179,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);
|
||||
@ -205,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);
|
||||
@ -222,6 +239,100 @@ 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)
|
||||
{
|
||||
cLuaState LuaState(tolua_S);
|
||||
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype (LuaState, 1, "cWorld", 0, &tolua_err) ||
|
||||
!tolua_isnumber (LuaState, 2, 0, &tolua_err) ||
|
||||
!tolua_isnumber (LuaState, 3, 0, &tolua_err) ||
|
||||
!tolua_isnumber (LuaState, 4, 0, &tolua_err) ||
|
||||
!tolua_iscppstring(LuaState, 5, 0, &tolua_err) ||
|
||||
!tolua_iscppstring(LuaState, 6, 0, &tolua_err) ||
|
||||
!tolua_iscppstring(LuaState, 7, 0, &tolua_err) ||
|
||||
!tolua_iscppstring(LuaState, 8, 0, &tolua_err) ||
|
||||
!tolua_isusertype (LuaState, 9, "cPlayer", 1, &tolua_err) ||
|
||||
!tolua_isnoobj (LuaState, 10, &tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cWorld * self = (cWorld *) tolua_tousertype (LuaState, 1, nullptr);
|
||||
int BlockX = (int) tolua_tonumber (LuaState, 2, 0);
|
||||
int BlockY = (int) tolua_tonumber (LuaState, 3, 0);
|
||||
int BlockZ = (int) tolua_tonumber (LuaState, 4, 0);
|
||||
const AString Line1 = tolua_tocppstring(LuaState, 5, 0);
|
||||
const AString Line2 = tolua_tocppstring(LuaState, 6, 0);
|
||||
const AString Line3 = tolua_tocppstring(LuaState, 7, 0);
|
||||
const AString Line4 = tolua_tocppstring(LuaState, 8, 0);
|
||||
cPlayer * Player = (cPlayer *)tolua_tousertype (LuaState, 9, nullptr);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (self == nullptr)
|
||||
{
|
||||
tolua_error(LuaState, "invalid 'self' in function 'UpdateSign'", nullptr);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
bool res = self->SetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4, Player);
|
||||
tolua_pushboolean(LuaState, res ? 1 : 0);
|
||||
}
|
||||
}
|
||||
LOGWARNING("Warning in function call 'UpdateSign': UpdateSign() is deprecated. Please use SetSignLines()");
|
||||
LuaState.LogStackTrace(0);
|
||||
return 1;
|
||||
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(LuaState, "#ferror in function 'UpdateSign'.", &tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void DeprecatedBindings::Bind(lua_State * tolua_S)
|
||||
{
|
||||
tolua_beginmodule(tolua_S, nullptr);
|
||||
@ -235,6 +346,12 @@ 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);
|
||||
|
||||
tolua_endmodule(tolua_S);
|
||||
}
|
||||
|
||||
|
@ -1034,11 +1034,11 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (self == nullptr)
|
||||
{
|
||||
tolua_error(tolua_S, "invalid 'self' in function 'SetSignLines' / 'UpdateSign'", nullptr);
|
||||
tolua_error(tolua_S, "invalid 'self' in function 'SetSignLines'", nullptr);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
bool res = self->UpdateSign(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4, Player);
|
||||
bool res = self->SetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4, Player);
|
||||
tolua_pushboolean(tolua_S, res ? 1 : 0);
|
||||
}
|
||||
}
|
||||
@ -1046,7 +1046,7 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
|
||||
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S, "#ferror in function 'SetSignLines' / 'UpdateSign'.", &tolua_err);
|
||||
tolua_error(tolua_S, "#ferror in function 'SetSignLines'.", &tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@ -3368,6 +3368,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
||||
|
||||
tolua_beginmodule(tolua_S, "cRoot");
|
||||
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>);
|
||||
tolua_function(tolua_S, "DoWithPlayerByUUID", tolua_DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>);
|
||||
tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>);
|
||||
tolua_function(tolua_S, "ForEachWorld", tolua_ForEach<cRoot, cWorld, &cRoot::ForEachWorld>);
|
||||
tolua_function(tolua_S, "GetFurnaceRecipe", tolua_cRoot_GetFurnaceRecipe);
|
||||
@ -3389,6 +3390,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
||||
tolua_function(tolua_S, "DoWithFlowerPotAt", tolua_DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>);
|
||||
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
|
||||
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
|
||||
tolua_function(tolua_S, "DoWithPlayerByUUID", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>);
|
||||
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
|
||||
tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>);
|
||||
tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>);
|
||||
@ -3403,7 +3405,6 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
||||
tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask);
|
||||
tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines);
|
||||
tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight);
|
||||
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
|
||||
tolua_endmodule(tolua_S);
|
||||
|
||||
tolua_beginmodule(tolua_S, "cMapManager");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -247,15 +247,16 @@ void cBeaconEntity::GiveEffects(void)
|
||||
}
|
||||
|
||||
public:
|
||||
cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel)
|
||||
: m_Radius(a_Radius)
|
||||
, m_PosX(a_PosX)
|
||||
, m_PosY(a_PosY)
|
||||
, m_PosZ(a_PosZ)
|
||||
, m_PrimaryEffect(a_PrimaryEffect)
|
||||
, m_SecondaryEffect(a_SecondaryEffect)
|
||||
, m_EffectLevel(a_EffectLevel)
|
||||
{};
|
||||
cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel):
|
||||
m_Radius(a_Radius),
|
||||
m_PosX(a_PosX),
|
||||
m_PosY(a_PosY),
|
||||
m_PosZ(a_PosZ),
|
||||
m_PrimaryEffect(a_PrimaryEffect),
|
||||
m_SecondaryEffect(a_SecondaryEffect),
|
||||
m_EffectLevel(a_EffectLevel)
|
||||
{
|
||||
}
|
||||
|
||||
} PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryEffect, SecondaryEffect, EffectLevel);
|
||||
GetWorld()->ForEachPlayer(PlayerCallback);
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
// BeaconEntity.h
|
||||
|
||||
// Declares the cBeaconEntity class representing a single beacon in the world
|
||||
@ -14,15 +15,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
class cBeaconEntity :
|
||||
public cBlockEntityWithItems
|
||||
@ -32,7 +24,7 @@ class cBeaconEntity :
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cBeaconEntity);
|
||||
BLOCKENTITY_PROTODEF(cBeaconEntity)
|
||||
|
||||
cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -29,7 +29,7 @@ class cBlockEntityWithItems :
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cBlockEntityWithItems);
|
||||
BLOCKENTITY_PROTODEF(cBlockEntityWithItems)
|
||||
|
||||
cBlockEntityWithItems(
|
||||
BLOCKTYPE a_BlockType, // Type of the block that the entity represents
|
||||
|
@ -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)
|
||||
|
||||
|
@ -7,11 +7,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
};
|
||||
|
||||
class cClientHandle;
|
||||
|
||||
|
||||
@ -33,7 +28,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cChestEntity);
|
||||
BLOCKENTITY_PROTODEF(cChestEntity)
|
||||
|
||||
/** Constructor used for normal operation */
|
||||
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type);
|
||||
|
@ -15,14 +15,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -36,7 +28,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cCommandBlockEntity);
|
||||
BLOCKENTITY_PROTODEF(cCommandBlockEntity)
|
||||
|
||||
/// Creates a new empty command block entity
|
||||
cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cDispenserEntity);
|
||||
BLOCKENTITY_PROTODEF(cDispenserEntity)
|
||||
|
||||
/** Constructor used for normal operation */
|
||||
cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
class cClientHandle;
|
||||
|
||||
@ -45,7 +41,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cDropSpenserEntity);
|
||||
BLOCKENTITY_PROTODEF(cDropSpenserEntity)
|
||||
|
||||
cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
virtual ~cDropSpenserEntity();
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cDropperEntity);
|
||||
BLOCKENTITY_PROTODEF(cDropperEntity)
|
||||
|
||||
/// Constructor used for normal operation
|
||||
cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
@ -18,7 +18,7 @@ class cEnderChestEntity :
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cEnderChestEntity);
|
||||
BLOCKENTITY_PROTODEF(cEnderChestEntity)
|
||||
|
||||
cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
virtual ~cEnderChestEntity();
|
||||
|
@ -15,16 +15,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cFlowerPotEntity :
|
||||
@ -36,7 +26,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cFlowerPotEntity);
|
||||
BLOCKENTITY_PROTODEF(cFlowerPotEntity)
|
||||
|
||||
/** Creates a new flowerpot entity at the specified block coords. a_World may be nullptr */
|
||||
cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
@ -8,11 +8,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
class cClientHandle;
|
||||
|
||||
|
||||
@ -38,7 +33,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cFurnaceEntity);
|
||||
BLOCKENTITY_PROTODEF(cFurnaceEntity)
|
||||
|
||||
/** Constructor used for normal operation */
|
||||
cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World);
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cHopperEntity);
|
||||
BLOCKENTITY_PROTODEF(cHopperEntity)
|
||||
|
||||
/// Constructor used for normal operation
|
||||
cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
@ -7,15 +7,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cJukeboxEntity :
|
||||
@ -26,7 +17,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cJukeboxEntity);
|
||||
BLOCKENTITY_PROTODEF(cJukeboxEntity)
|
||||
|
||||
cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
virtual ~cJukeboxEntity();
|
||||
|
@ -14,14 +14,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -34,29 +26,29 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cMobHeadEntity);
|
||||
BLOCKENTITY_PROTODEF(cMobHeadEntity)
|
||||
|
||||
/** Creates a new mob head entity at the specified block coords. a_World may be nullptr */
|
||||
cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/** Set the Type */
|
||||
/** Set the type of the mob head */
|
||||
void SetType(const eMobHeadType & a_SkullType);
|
||||
|
||||
/** Set the Rotation */
|
||||
/** Set the rotation of the mob head */
|
||||
void SetRotation(eMobHeadRotation a_Rotation);
|
||||
|
||||
/** Set the Player Name for Mobheads with Player type */
|
||||
/** Set the player name for mob heads with player type */
|
||||
void SetOwner(const AString & a_Owner);
|
||||
|
||||
/** Get the Type */
|
||||
/** Returns the type of the mob head */
|
||||
eMobHeadType GetType(void) const { return m_Type; }
|
||||
|
||||
/** Get the Rotation */
|
||||
/** Returns the rotation of the mob head */
|
||||
eMobHeadRotation GetRotation(void) const { return m_Rotation; }
|
||||
|
||||
/** Get the setted Player Name */
|
||||
/** Returns the player name of the mob head */
|
||||
AString GetOwner(void) const { return m_Owner; }
|
||||
|
||||
// tolua_end
|
||||
|
290
src/BlockEntities/MobSpawnerEntity.cpp
Normal file
290
src/BlockEntities/MobSpawnerEntity.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "MobSpawnerEntity.h"
|
||||
|
||||
#include "../World.h"
|
||||
#include "../FastRandom.h"
|
||||
#include "../MobSpawner.h"
|
||||
#include "../Items/ItemSpawnEgg.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World)
|
||||
: super(E_BLOCK_MOB_SPAWNER, a_BlockX, a_BlockY, a_BlockZ, a_World)
|
||||
, m_Entity(mtPig)
|
||||
, m_SpawnDelay(100)
|
||||
, m_IsActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMobSpawnerEntity::SendTo(cClientHandle & a_Client)
|
||||
{
|
||||
a_Client.SendUpdateBlockEntity(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMobSpawnerEntity::UsedBy(cPlayer * a_Player)
|
||||
{
|
||||
if (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SPAWN_EGG)
|
||||
{
|
||||
eMonsterType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Player->GetEquippedItem().m_ItemDamage);
|
||||
if (MonsterType == eMonsterType::mtInvalidType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Entity = MonsterType;
|
||||
ResetTimer();
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
LOGD("Changed monster spawner at {%d, %d, %d} to type %s.", GetPosX(), GetPosY(), GetPosZ(), cMonster::MobTypeToString(MonsterType).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMobSpawnerEntity::UpdateActiveState(void)
|
||||
{
|
||||
if (GetNearbyPlayersNum() > 0)
|
||||
{
|
||||
m_IsActive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
// Update the active flag every 5 seconds
|
||||
if ((m_World->GetWorldAge() % 100) == 0)
|
||||
{
|
||||
UpdateActiveState();
|
||||
}
|
||||
|
||||
if (!m_IsActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_SpawnDelay <= 0)
|
||||
{
|
||||
SpawnEntity();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SpawnDelay--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMobSpawnerEntity::ResetTimer(void)
|
||||
{
|
||||
m_SpawnDelay = static_cast<short>(200 + m_World->GetTickRandomNumber(600));
|
||||
m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMobSpawnerEntity::SpawnEntity(void)
|
||||
{
|
||||
int NearbyEntities = GetNearbyMonsterNum(m_Entity);
|
||||
if (NearbyEntities >= 6)
|
||||
{
|
||||
ResetTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
class cCallback : public cChunkCallback
|
||||
{
|
||||
public:
|
||||
cCallback(int a_RelX, int a_RelY, int a_RelZ, eMonsterType a_MobType, int a_NearbyEntitiesNum) :
|
||||
m_RelX(a_RelX),
|
||||
m_RelY(a_RelY),
|
||||
m_RelZ(a_RelZ),
|
||||
m_MobType(a_MobType),
|
||||
m_NearbyEntitiesNum(a_NearbyEntitiesNum)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Item(cChunk * a_Chunk)
|
||||
{
|
||||
cFastRandom Random;
|
||||
|
||||
bool EntitiesSpawned = false;
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
if (m_NearbyEntitiesNum >= 6)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int RelX = (int) (m_RelX + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0);
|
||||
int RelY = m_RelY + Random.NextInt(3) - 1;
|
||||
int RelZ = (int) (m_RelZ + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0);
|
||||
|
||||
cChunk * Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(RelX, RelZ);
|
||||
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
EMCSBiome Biome = Chunk->GetBiomeAt(RelX, RelZ);
|
||||
|
||||
if (cMobSpawner::CanSpawnHere(Chunk, RelX, RelY, RelZ, m_MobType, Biome))
|
||||
{
|
||||
double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX;
|
||||
double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ;
|
||||
|
||||
cMonster * Monster = cMonster::NewMonsterFromType(m_MobType);
|
||||
if (Monster == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Monster->SetPosition(PosX, RelY, PosZ);
|
||||
Monster->SetYaw(Random.NextFloat() * 360.0f);
|
||||
if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != mtInvalidType)
|
||||
{
|
||||
EntitiesSpawned = true;
|
||||
Chunk->BroadcastSoundParticleEffect(2004, (int)(PosX * 8.0), (int)(RelY * 8.0), (int)(PosZ * 8.0), 0);
|
||||
m_NearbyEntitiesNum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EntitiesSpawned;
|
||||
}
|
||||
protected:
|
||||
int m_RelX, m_RelY, m_RelZ;
|
||||
eMonsterType m_MobType;
|
||||
int m_NearbyEntitiesNum;
|
||||
} Callback(m_RelX, m_PosY, m_RelZ, m_Entity, NearbyEntities);
|
||||
|
||||
if (m_World->DoWithChunk(GetChunkX(), GetChunkZ(), Callback))
|
||||
{
|
||||
ResetTimer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cMobSpawnerEntity::GetNearbyPlayersNum(void)
|
||||
{
|
||||
Vector3d SpawnerPos(m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
|
||||
int NumPlayers = 0;
|
||||
|
||||
class cCallback : public cChunkDataCallback
|
||||
{
|
||||
public:
|
||||
cCallback(Vector3d a_SpawnerPos, int & a_NumPlayers) :
|
||||
m_SpawnerPos(a_SpawnerPos),
|
||||
m_NumPlayers(a_NumPlayers)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Entity(cEntity * a_Entity) override
|
||||
{
|
||||
if (!a_Entity->IsPlayer())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_SpawnerPos - a_Entity->GetPosition()).Length() <= 16)
|
||||
{
|
||||
m_NumPlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector3d m_SpawnerPos;
|
||||
int & m_NumPlayers;
|
||||
} Callback(SpawnerPos, NumPlayers);
|
||||
|
||||
int ChunkX = GetChunkX();
|
||||
int ChunkZ = GetChunkZ();
|
||||
m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback);
|
||||
|
||||
return NumPlayers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cMobSpawnerEntity::GetNearbyMonsterNum(eMonsterType a_EntityType)
|
||||
{
|
||||
Vector3d SpawnerPos(m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
|
||||
int NumEntities = 0;
|
||||
|
||||
class cCallback : public cChunkDataCallback
|
||||
{
|
||||
public:
|
||||
cCallback(Vector3d a_SpawnerPos, eMonsterType a_EntityType, int & a_NumEntities) :
|
||||
m_SpawnerPos(a_SpawnerPos),
|
||||
m_EntityType(a_EntityType),
|
||||
m_NumEntities(a_NumEntities)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Entity(cEntity * a_Entity) override
|
||||
{
|
||||
if (!a_Entity->IsMob())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cMonster * Mob = (cMonster *)a_Entity;
|
||||
if (Mob->GetMobType() != m_EntityType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Diff(m_SpawnerPos.x, a_Entity->GetPosX()) <= 8.0) && (Diff(m_SpawnerPos.y, a_Entity->GetPosY()) <= 4.0) && (Diff(m_SpawnerPos.z, a_Entity->GetPosZ()) <= 8.0))
|
||||
{
|
||||
m_NumEntities++;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector3d m_SpawnerPos;
|
||||
eMonsterType m_EntityType;
|
||||
int & m_NumEntities;
|
||||
} Callback(SpawnerPos, a_EntityType, NumEntities);
|
||||
|
||||
int ChunkX = GetChunkX();
|
||||
int ChunkZ = GetChunkZ();
|
||||
m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback);
|
||||
|
||||
return NumEntities;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
78
src/BlockEntities/MobSpawnerEntity.h
Normal file
78
src/BlockEntities/MobSpawnerEntity.h
Normal file
@ -0,0 +1,78 @@
|
||||
// MobSpawnerEntity.h
|
||||
|
||||
// Declares the cMobSpawnerEntity class representing a single mob spawner in the world
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockEntity.h"
|
||||
#include "../Entities/Player.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cMobSpawnerEntity :
|
||||
public cBlockEntity
|
||||
{
|
||||
typedef cBlockEntity super;
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
||||
virtual void SendTo(cClientHandle & a_Client) override;
|
||||
virtual void UsedBy(cPlayer * a_Player) override;
|
||||
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/** Upate the active flag from the mob spawner. This function will called every 5 seconds from the Tick() function. */
|
||||
void UpdateActiveState(void);
|
||||
|
||||
/** Sets the spawn delay to a new random value. */
|
||||
void ResetTimer(void);
|
||||
|
||||
/** Spawns the entity. This function automaticly change the spawn delay! */
|
||||
void SpawnEntity(void);
|
||||
|
||||
/** Returns the entity type that will be spawn by this mob spawner. */
|
||||
eMonsterType GetEntity(void) const { return m_Entity; }
|
||||
|
||||
/** Sets the entity type who will be spawn by this mob spawner. */
|
||||
void SetEntity(eMonsterType a_EntityType) { m_Entity = a_EntityType; }
|
||||
|
||||
/** Returns the spawn delay. This is the tick delay that is needed to spawn new monsters. */
|
||||
short GetSpawnDelay(void) const { return m_SpawnDelay; }
|
||||
|
||||
/** Sets the spawn delay. */
|
||||
void SetSpawnDelay(short a_Delay) { m_SpawnDelay = a_Delay; }
|
||||
|
||||
/** Returns the amount of the nearby players in a 16-block radius. */
|
||||
int GetNearbyPlayersNum(void);
|
||||
|
||||
/** Returns the amount of this monster type in a 8-block radius (Y: 4-block radius). */
|
||||
int GetNearbyMonsterNum(eMonsterType a_EntityType);
|
||||
|
||||
// tolua_end
|
||||
|
||||
static const char * GetClassStatic(void) { return "cMobSpawnerEntity"; }
|
||||
|
||||
private:
|
||||
/** The entity to spawn. */
|
||||
eMonsterType m_Entity;
|
||||
|
||||
short m_SpawnDelay;
|
||||
|
||||
bool m_IsActive;
|
||||
} ; // tolua_end
|
||||
|
||||
|
||||
|
||||
|
@ -5,12 +5,6 @@
|
||||
#include "RedstonePoweredEntity.h"
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -40,7 +34,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cNoteEntity);
|
||||
BLOCKENTITY_PROTODEF(cNoteEntity)
|
||||
|
||||
/// Creates a new note entity. a_World may be nullptr
|
||||
cNoteEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||
|
@ -14,15 +14,6 @@
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cSignEntity :
|
||||
@ -34,7 +25,7 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
BLOCKENTITY_PROTODEF(cSignEntity);
|
||||
BLOCKENTITY_PROTODEF(cSignEntity)
|
||||
|
||||
/// Creates a new empty sign entity at the specified block coords and block type (wall or standing). a_World may be nullptr
|
||||
cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||
|
@ -200,7 +200,7 @@ public:
|
||||
|
||||
|
||||
|
||||
BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString)
|
||||
int BlockStringToType(const AString & a_BlockTypeString)
|
||||
{
|
||||
int res = atoi(a_BlockTypeString.c_str());
|
||||
if ((res != 0) || (a_BlockTypeString.compare("0") == 0))
|
||||
|
@ -1096,7 +1096,7 @@ class cIniFile;
|
||||
// tolua_begin
|
||||
|
||||
/// Translates a blocktype string into blocktype. Takes either a number or an items.ini alias as input. Returns -1 on failure.
|
||||
extern BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString);
|
||||
extern int BlockStringToType(const AString & a_BlockTypeString);
|
||||
|
||||
/// Translates an itemtype string into an item. Takes either a number, number^number, number:number or an items.ini alias as input. Returns true if successful.
|
||||
extern bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
#define CHECK_THREAD cSingleThreadAccessChecker Checker(const_cast<unsigned long *>(&m_ThreadID))
|
||||
// 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(&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)
|
||||
|
@ -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);
|
||||
|
@ -9,6 +9,7 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include
|
||||
set(FOLDERS
|
||||
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
|
||||
WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs
|
||||
Noise
|
||||
)
|
||||
|
||||
SET (SRCS
|
||||
@ -50,7 +51,6 @@ SET (SRCS
|
||||
MobProximityCounter.cpp
|
||||
MobSpawner.cpp
|
||||
MonsterConfig.cpp
|
||||
Noise.cpp
|
||||
ProbabDistrib.cpp
|
||||
RankManager.cpp
|
||||
RCONServer.cpp
|
||||
@ -65,7 +65,8 @@ SET (SRCS
|
||||
VoronoiMap.cpp
|
||||
WebAdmin.cpp
|
||||
World.cpp
|
||||
main.cpp)
|
||||
main.cpp
|
||||
)
|
||||
|
||||
SET (HDRS
|
||||
AllocationPool.h
|
||||
@ -103,7 +104,6 @@ SET (HDRS
|
||||
Inventory.h
|
||||
Item.h
|
||||
ItemGrid.h
|
||||
LeakFinder.h
|
||||
LightingThread.h
|
||||
LineBlockTracer.h
|
||||
LinearInterpolation.h
|
||||
@ -113,14 +113,11 @@ SET (HDRS
|
||||
Map.h
|
||||
MapManager.h
|
||||
Matrix4.h
|
||||
MemoryLeak.h
|
||||
MersenneTwister.h
|
||||
MobCensus.h
|
||||
MobFamilyCollecter.h
|
||||
MobProximityCounter.h
|
||||
MobSpawner.h
|
||||
MonsterConfig.h
|
||||
Noise.h
|
||||
ProbabDistrib.h
|
||||
RankManager.h
|
||||
RCONServer.h
|
||||
@ -128,7 +125,6 @@ SET (HDRS
|
||||
Scoreboard.h
|
||||
Server.h
|
||||
SetChunkData.h
|
||||
StackWalker.h
|
||||
Statistics.h
|
||||
StringCompression.h
|
||||
StringUtils.h
|
||||
@ -137,7 +133,8 @@ SET (HDRS
|
||||
VoronoiMap.h
|
||||
WebAdmin.h
|
||||
World.h
|
||||
XMLParser.h)
|
||||
XMLParser.h
|
||||
)
|
||||
|
||||
include_directories(".")
|
||||
include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/sqlite")
|
||||
@ -175,6 +172,10 @@ if (NOT MSVC)
|
||||
else ()
|
||||
# MSVC-specific handling: Put all files into one project, separate by the folders:
|
||||
|
||||
# Add the MSVC-specific LeakFinder sources:
|
||||
list (APPEND SRCS LeakFinder.cpp StackWalker.cpp)
|
||||
list (APPEND HDRS LeakFinder.h StackWalker.h MemoryLeak.h)
|
||||
|
||||
source_group(Bindings FILES "Bindings/Bindings.cpp" "Bindings/Bindings.h")
|
||||
|
||||
# Add all subfolders as solution-folders:
|
||||
@ -224,7 +225,7 @@ else ()
|
||||
Bindings/Bindings.cpp PROPERTIES COMPILE_FLAGS "/Yc\"string.h\" /Fp\"$(IntDir)/Bindings.pch\""
|
||||
)
|
||||
SET_SOURCE_FILES_PROPERTIES(
|
||||
"StackWalker.cpp LeakFinder.h" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
|
||||
"StackWalker.cpp LeakFinder.cpp" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
|
||||
)
|
||||
list(APPEND SOURCE "Resources/MCServer.rc")
|
||||
|
||||
@ -314,7 +315,7 @@ endif ()
|
||||
|
||||
if (NOT MSVC)
|
||||
target_link_libraries(${EXECUTABLE}
|
||||
OSSupport HTTPServer Bindings Items Blocks
|
||||
OSSupport HTTPServer Bindings Items Blocks Noise
|
||||
Protocol Generating Generating_Prefabs WorldStorage
|
||||
Mobs Entities Simulator UI BlockEntities PolarSSL++
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -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.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;
|
||||
@ -1869,18 +1871,18 @@ bool cChunk::AddClient(cClientHandle * a_Client)
|
||||
|
||||
void cChunk::RemoveClient(cClientHandle * a_Client)
|
||||
{
|
||||
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
|
||||
for (cClientHandleList::iterator itrC = m_LoadedByClient.begin(); itrC != m_LoadedByClient.end(); ++itrC)
|
||||
{
|
||||
if (*itr != a_Client)
|
||||
if (*itrC != a_Client)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_LoadedByClient.erase(itr);
|
||||
m_LoadedByClient.erase(itrC);
|
||||
|
||||
if (!a_Client->IsDestroyed())
|
||||
{
|
||||
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
|
||||
for (cEntityList::iterator itrE = m_Entities.begin(); itrE != m_Entities.end(); ++itrE)
|
||||
{
|
||||
/*
|
||||
// DEBUG:
|
||||
@ -1889,7 +1891,7 @@ void cChunk::RemoveClient(cClientHandle * a_Client)
|
||||
(*itr)->GetUniqueID(), a_Client->GetUsername().c_str()
|
||||
);
|
||||
*/
|
||||
a_Client->SendDestroyEntity(*(*itr));
|
||||
a_Client->SendDestroyEntity(*(*itrE));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -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;
|
||||
@ -65,7 +57,8 @@ int cClientHandle::s_ClientCount = 0;
|
||||
// cClientHandle:
|
||||
|
||||
cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
|
||||
m_ViewDistance(a_ViewDistance),
|
||||
m_CurrentViewDistance(a_ViewDistance),
|
||||
m_RequestedViewDistance(a_ViewDistance),
|
||||
m_IPString(a_Socket->GetIPString()),
|
||||
m_OutgoingData(64 KiB),
|
||||
m_Player(nullptr),
|
||||
@ -75,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),
|
||||
@ -93,15 +84,14 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
|
||||
m_UniqueID(0),
|
||||
m_HasSentPlayerChunk(false),
|
||||
m_Locale("en_GB"),
|
||||
m_LastPlacedSign(0, -1, 0),
|
||||
m_ProtocolVersion(0)
|
||||
{
|
||||
m_Protocol = new cProtocolRecognizer(this);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -197,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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -395,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);
|
||||
}
|
||||
@ -430,7 +423,7 @@ bool cClientHandle::StreamNextChunk(void)
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
|
||||
// High priority: Load the chunks that are in the view-direction of the player (with a radius of 3)
|
||||
for (int Range = 0; Range < m_ViewDistance; Range++)
|
||||
for (int Range = 0; Range < m_CurrentViewDistance; Range++)
|
||||
{
|
||||
Vector3d Vector = Position + LookVector * cChunkDef::Width * Range;
|
||||
|
||||
@ -447,7 +440,7 @@ bool cClientHandle::StreamNextChunk(void)
|
||||
cChunkCoords Coords(ChunkX, ChunkZ);
|
||||
|
||||
// Checks if the chunk is in distance
|
||||
if ((Diff(ChunkX, ChunkPosX) > m_ViewDistance) || (Diff(ChunkZ, ChunkPosZ) > m_ViewDistance))
|
||||
if ((Diff(ChunkX, ChunkPosX) > m_CurrentViewDistance) || (Diff(ChunkZ, ChunkPosZ) > m_CurrentViewDistance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -470,7 +463,7 @@ bool cClientHandle::StreamNextChunk(void)
|
||||
}
|
||||
|
||||
// Low priority: Add all chunks that are in range. (From the center out to the edge)
|
||||
for (int d = 0; d <= m_ViewDistance; ++d) // cycle through (square) distance, from nearest to furthest
|
||||
for (int d = 0; d <= m_CurrentViewDistance; ++d) // cycle through (square) distance, from nearest to furthest
|
||||
{
|
||||
// For each distance add chunks in a hollow square centered around current position:
|
||||
cChunkCoordsList CurcleChunks;
|
||||
@ -528,7 +521,7 @@ void cClientHandle::UnloadOutOfRangeChunks(void)
|
||||
{
|
||||
int DiffX = Diff((*itr).m_ChunkX, ChunkPosX);
|
||||
int DiffZ = Diff((*itr).m_ChunkZ, ChunkPosZ);
|
||||
if ((DiffX > m_ViewDistance) || (DiffZ > m_ViewDistance))
|
||||
if ((DiffX > m_CurrentViewDistance) || (DiffZ > m_CurrentViewDistance))
|
||||
{
|
||||
ChunksToRemove.push_back(*itr);
|
||||
itr = m_LoadedChunks.erase(itr);
|
||||
@ -543,7 +536,7 @@ void cClientHandle::UnloadOutOfRangeChunks(void)
|
||||
{
|
||||
int DiffX = Diff((*itr).m_ChunkX, ChunkPosX);
|
||||
int DiffZ = Diff((*itr).m_ChunkZ, ChunkPosZ);
|
||||
if ((DiffX > m_ViewDistance) || (DiffZ > m_ViewDistance))
|
||||
if ((DiffX > m_CurrentViewDistance) || (DiffZ > m_CurrentViewDistance))
|
||||
{
|
||||
itr = m_ChunksToSend.erase(itr);
|
||||
}
|
||||
@ -1236,12 +1229,18 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
{
|
||||
// TODO: Rewrite this function
|
||||
|
||||
LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
|
||||
// Distance from the block's center to the player's eye height
|
||||
double dist = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length();
|
||||
LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s; dist: %.02f",
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str(), dist
|
||||
);
|
||||
|
||||
|
||||
// Check the reach distance:
|
||||
// _X 2014-11-25: I've maxed at 5.26 with a Survival client and 5.78 with a Creative client in my tests
|
||||
double maxDist = m_Player->IsGameModeCreative() ? 5.78 : 5.26;
|
||||
bool AreRealCoords = (dist <= maxDist);
|
||||
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
bool AreRealCoords = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) - m_Player->GetPosition()).Length() <= 5;
|
||||
|
||||
if (
|
||||
(a_BlockFace != BLOCK_FACE_NONE) && // The client is interacting with a specific block
|
||||
@ -1500,6 +1499,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
{
|
||||
m_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
cChunkInterface ChunkInterface(World->GetChunkMap());
|
||||
NewBlock->OnPlacedByPlayer(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
||||
|
||||
@ -1677,8 +1677,11 @@ void cClientHandle::HandleUpdateSign(
|
||||
const AString & a_Line3, const AString & a_Line4
|
||||
)
|
||||
{
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
World->UpdateSign(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, m_Player);
|
||||
if (m_LastPlacedSign.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
||||
{
|
||||
m_LastPlacedSign.Set(0, -1, 0);
|
||||
m_Player->GetWorld()->SetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, m_Player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1767,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1993,13 +1995,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2257,6 +2257,7 @@ void cClientHandle::SendDisconnect(const AString & a_Reason)
|
||||
|
||||
void cClientHandle::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
m_LastPlacedSign.Set(a_BlockX, a_BlockY, a_BlockZ);
|
||||
m_Protocol->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
|
||||
}
|
||||
|
||||
@ -2847,8 +2848,15 @@ void cClientHandle::SetUsername( const AString & a_Username)
|
||||
|
||||
void cClientHandle::SetViewDistance(int a_ViewDistance)
|
||||
{
|
||||
m_ViewDistance = Clamp(a_ViewDistance, MIN_VIEW_DISTANCE, MAX_VIEW_DISTANCE);
|
||||
LOGD("Setted %s's view distance to %i", GetUsername().c_str(), m_ViewDistance);
|
||||
m_RequestedViewDistance = a_ViewDistance;
|
||||
LOGD("%s is requesting ViewDistance of %d!", GetUsername().c_str(), m_RequestedViewDistance);
|
||||
|
||||
// Set the current view distance based on the requested VD and world max VD:
|
||||
cWorld * world = m_Player->GetWorld();
|
||||
if (world != nullptr)
|
||||
{
|
||||
m_CurrentViewDistance = Clamp(a_ViewDistance, cClientHandle::MIN_VIEW_DISTANCE, world->GetMaxViewDistance());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,11 +215,17 @@ 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);
|
||||
int GetViewDistance(void) const { return m_ViewDistance; }
|
||||
|
||||
|
||||
/** Returns the view distance that the player currently have. */
|
||||
int GetViewDistance(void) const { return m_CurrentViewDistance; }
|
||||
|
||||
/** Returns the view distance that the player request, not the used view distance. */
|
||||
int GetRequestedViewDistance(void) const { return m_RequestedViewDistance; }
|
||||
|
||||
void SetLocale(AString & a_Locale) { m_Locale = a_Locale; }
|
||||
AString GetLocale(void) const { return m_Locale; }
|
||||
|
||||
@ -333,12 +339,12 @@ private:
|
||||
/** The type used for storing the names of registered plugin channels. */
|
||||
typedef std::set<AString> cChannels;
|
||||
|
||||
/** Number of chunks the player can see in each direction */
|
||||
int m_ViewDistance;
|
||||
|
||||
/** Server generates this many chunks AHEAD of player sight. */
|
||||
static const int GENERATEDISTANCE = 2;
|
||||
|
||||
/** The actual view distance used, the minimum of client's requested view distance and world's max view distance. */
|
||||
int m_CurrentViewDistance;
|
||||
|
||||
/** The requested view distance from the player. It isn't clamped with 1 and the max view distance of the world. */
|
||||
int m_RequestedViewDistance;
|
||||
|
||||
AString m_IPString;
|
||||
|
||||
AString m_Username;
|
||||
@ -372,12 +378,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 ???)
|
||||
@ -432,6 +441,9 @@ private:
|
||||
|
||||
/** Client Settings */
|
||||
AString m_Locale;
|
||||
|
||||
/** The positions from the last sign that the player placed. It's needed to verify the sign text change. */
|
||||
Vector3i m_LastPlacedSign;
|
||||
|
||||
/** The plugin channels that the client has registered. */
|
||||
cChannels m_PluginChannels;
|
||||
|
@ -289,12 +289,12 @@ void cCraftingRecipes::GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingG
|
||||
}
|
||||
|
||||
// Built-in recipes:
|
||||
std::auto_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid.GetItems(), a_CraftingGrid.GetWidth(), a_CraftingGrid.GetHeight()));
|
||||
std::unique_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid.GetItems(), a_CraftingGrid.GetWidth(), a_CraftingGrid.GetHeight()));
|
||||
a_Recipe.Clear();
|
||||
if (Recipe.get() == nullptr)
|
||||
{
|
||||
// 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)
|
||||
@ -377,7 +377,7 @@ void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine
|
||||
return;
|
||||
}
|
||||
|
||||
std::auto_ptr<cCraftingRecipes::cRecipe> Recipe(new cCraftingRecipes::cRecipe);
|
||||
std::unique_ptr<cCraftingRecipes::cRecipe> Recipe(new cCraftingRecipes::cRecipe);
|
||||
|
||||
// Parse the result:
|
||||
AStringVector ResultSplit = StringSplit(Sides[0], ",");
|
||||
@ -758,7 +758,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
|
||||
} // for y, for x
|
||||
|
||||
// The recipe has matched. Create a copy of the recipe and set its coords to match the crafting grid:
|
||||
std::auto_ptr<cRecipe> Recipe(new cRecipe);
|
||||
std::unique_ptr<cRecipe> Recipe(new cRecipe);
|
||||
Recipe->m_Result = a_Recipe->m_Result;
|
||||
Recipe->m_Width = a_Recipe->m_Width;
|
||||
Recipe->m_Height = a_Recipe->m_Height;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "Enchantments.h"
|
||||
#include "WorldStorage/FastNBT.h"
|
||||
#include "FastRandom.h"
|
||||
#include "Noise.h"
|
||||
#include "Noise/Noise.h"
|
||||
|
||||
|
||||
|
||||
|
@ -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++;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -128,7 +128,7 @@ public:
|
||||
};
|
||||
|
||||
const cItem & GetSlot(int a_Idx) const { return m_Contents.GetSlot(a_Idx); }
|
||||
void SetSlot(size_t a_Idx, const cItem & a_Item) { m_Contents.SetSlot(a_Idx, a_Item); }
|
||||
void SetSlot(size_t a_Idx, const cItem & a_Item) { m_Contents.SetSlot(static_cast<int>(a_Idx), a_Item); }
|
||||
|
||||
protected:
|
||||
cItemGrid m_Contents;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -1602,6 +1601,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
|
||||
a_World->AddPlayer(this);
|
||||
SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value
|
||||
|
||||
// Update the view distance.
|
||||
m_ClientHandle->SetViewDistance(m_ClientHandle->GetRequestedViewDistance());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1890,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);
|
||||
}
|
||||
@ -1910,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;
|
||||
}
|
||||
|
||||
@ -2077,7 +2079,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
|
||||
|
||||
void cPlayer::ApplyFoodExhaustionFromMovement()
|
||||
{
|
||||
if (IsGameModeCreative())
|
||||
if (IsGameModeCreative() || IsGameModeSpectator())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -115,7 +115,7 @@ void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, unsigned int a_Line
|
||||
Line.erase(Line.begin()); // Remove the beginning "!"
|
||||
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
|
||||
|
||||
std::auto_ptr<cItem> Item(new cItem);
|
||||
std::unique_ptr<cItem> Item(new cItem);
|
||||
int BurnTime;
|
||||
|
||||
const AStringVector & Sides = StringSplit(Line, "=");
|
||||
@ -157,8 +157,8 @@ void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, unsigned int a_Li
|
||||
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
|
||||
|
||||
int CookTime = 200;
|
||||
std::auto_ptr<cItem> InputItem(new cItem());
|
||||
std::auto_ptr<cItem> OutputItem(new cItem());
|
||||
std::unique_ptr<cItem> InputItem(new cItem());
|
||||
std::unique_ptr<cItem> OutputItem(new cItem());
|
||||
|
||||
const AStringVector & Sides = StringSplit(Line, "=");
|
||||
if (Sides.size() != 2)
|
||||
|
@ -15,7 +15,7 @@ Interfaces to the various biome generators:
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../Noise.h"
|
||||
#include "../Noise/Noise.h"
|
||||
#include "../VoronoiMap.h"
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@ SET (SRCS
|
||||
ChunkDesc.cpp
|
||||
ChunkGenerator.cpp
|
||||
CompoGen.cpp
|
||||
CompoGenBiomal.cpp
|
||||
ComposableGenerator.cpp
|
||||
DistortedHeightmap.cpp
|
||||
DungeonRoomsFinisher.cpp
|
||||
@ -30,8 +31,10 @@ SET (SRCS
|
||||
StructGen.cpp
|
||||
TestRailsGen.cpp
|
||||
Trees.cpp
|
||||
TwoHeights.cpp
|
||||
UnderwaterBaseGen.cpp
|
||||
VillageGen.cpp)
|
||||
VillageGen.cpp
|
||||
)
|
||||
|
||||
SET (HDRS
|
||||
BioGen.h
|
||||
@ -39,7 +42,9 @@ SET (HDRS
|
||||
ChunkDesc.h
|
||||
ChunkGenerator.h
|
||||
CompoGen.h
|
||||
CompoGenBiomal.h
|
||||
ComposableGenerator.h
|
||||
CompositedHeiGen.h
|
||||
DistortedHeightmap.h
|
||||
DungeonRoomsFinisher.h
|
||||
EndGen.h
|
||||
@ -58,11 +63,14 @@ SET (HDRS
|
||||
RainbowRoadsGen.h
|
||||
Ravines.h
|
||||
RoughRavines.h
|
||||
ShapeGen.cpp
|
||||
StructGen.h
|
||||
TestRailsGen.h
|
||||
Trees.h
|
||||
TwoHeights.h
|
||||
UnderwaterBaseGen.h
|
||||
VillageGen.h)
|
||||
VillageGen.h
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
add_library(Generating ${SRCS} ${HDRS})
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "GridStructGen.h"
|
||||
#include "../Noise.h"
|
||||
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "ChunkDesc.h"
|
||||
#include "../BlockArea.h"
|
||||
#include "../Cuboid.h"
|
||||
#include "../Noise.h"
|
||||
#include "../Noise/Noise.h"
|
||||
#include "../BlockEntities/BlockEntity.h"
|
||||
|
||||
|
||||
@ -152,6 +152,52 @@ int cChunkDesc::GetHeight(int a_RelX, int a_RelZ)
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::SetHeightFromShape(const Shape & a_Shape)
|
||||
{
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
for (int y = cChunkDef::Height - 1; y > 0; y--)
|
||||
{
|
||||
if (a_Shape[y + x * 256 + z * 16 * 256] != 0)
|
||||
{
|
||||
cChunkDef::SetHeight(m_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::GetShapeFromHeight(Shape & a_Shape) const
|
||||
{
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int height = cChunkDef::GetHeight(m_HeightMap, x, z);
|
||||
for (int y = 0; y <= height; y++)
|
||||
{
|
||||
a_Shape[y + x * 256 + z * 16 * 256] = 1;
|
||||
}
|
||||
|
||||
for (int y = height + 1; y < cChunkDef::Height; y++)
|
||||
{
|
||||
a_Shape[y + x * 256 + z * 16 * 256] = 0;
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::SetUseDefaultBiomes(bool a_bUseDefaultBiomes)
|
||||
{
|
||||
m_bUseDefaultBiomes = a_bUseDefaultBiomes;
|
||||
@ -366,6 +412,23 @@ HEIGHTTYPE cChunkDesc::GetMaxHeight(void) const
|
||||
|
||||
|
||||
|
||||
HEIGHTTYPE cChunkDesc::GetMinHeight(void) const
|
||||
{
|
||||
HEIGHTTYPE MinHeight = m_HeightMap[0];
|
||||
for (size_t i = 1; i < ARRAYCOUNT(m_HeightMap); i++)
|
||||
{
|
||||
if (m_HeightMap[i] < MinHeight)
|
||||
{
|
||||
MinHeight = m_HeightMap[i];
|
||||
}
|
||||
}
|
||||
return MinHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::FillRelCuboid(
|
||||
int a_MinX, int a_MaxX,
|
||||
int a_MinY, int a_MaxY,
|
||||
|
@ -29,10 +29,17 @@ class cChunkDesc
|
||||
{
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
/** The datatype used to represent the entire chunk worth of shape.
|
||||
0 = air
|
||||
1 = solid
|
||||
Indexed as [y + 256 * x + 256 * 16 * z]. */
|
||||
typedef Byte Shape[256 * 16 * 16];
|
||||
|
||||
/** Uncompressed block metas, 1 meta per byte */
|
||||
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
||||
|
||||
|
||||
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
||||
~cChunkDesc();
|
||||
|
||||
@ -57,10 +64,21 @@ public:
|
||||
EMCSBiome GetBiome(int a_RelX, int a_RelZ);
|
||||
|
||||
// These operate on the heightmap, so they could get out of sync with the data
|
||||
// Use UpdateHeightmap() to re-sync
|
||||
// Use UpdateHeightmap() to re-calculate heightmap from the block data
|
||||
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
|
||||
int GetHeight(int a_RelX, int a_RelZ);
|
||||
|
||||
// tolua_end
|
||||
|
||||
/** Sets the heightmap to match the given shape data.
|
||||
Note that this ignores overhangs; the method is mostly used by old composition generators. */
|
||||
void SetHeightFromShape(const Shape & a_Shape);
|
||||
|
||||
/** Sets the shape in a_Shape to match the heightmap stored currently in m_HeightMap. */
|
||||
void GetShapeFromHeight(Shape & a_Shape) const;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
// Default generation:
|
||||
void SetUseDefaultBiomes(bool a_bUseDefaultBiomes);
|
||||
bool IsUsingDefaultBiomes(void) const;
|
||||
@ -77,8 +95,11 @@ public:
|
||||
/** Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas */
|
||||
void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ);
|
||||
|
||||
/** Returns the maximum height value in the heightmap */
|
||||
/** Returns the maximum height value in the heightmap. */
|
||||
HEIGHTTYPE GetMaxHeight(void) const;
|
||||
|
||||
/** Returns the minimum height value in the heightmap. */
|
||||
HEIGHTTYPE GetMinHeight(void) const;
|
||||
|
||||
/** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
|
||||
void FillRelCuboid(
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "ChunkDesc.h"
|
||||
#include "ComposableGenerator.h"
|
||||
#include "Noise3DGenerator.h"
|
||||
#include "../MersenneTwister.h"
|
||||
#include "FastRandom.h"
|
||||
|
||||
|
||||
|
||||
@ -191,13 +191,13 @@ EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
|
||||
BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default)
|
||||
{
|
||||
AString BlockType = a_IniFile.GetValueSet(a_SectionName, a_ValueName, a_Default);
|
||||
BLOCKTYPE Block = BlockStringToType(BlockType);
|
||||
int Block = BlockStringToType(BlockType);
|
||||
if (Block < 0)
|
||||
{
|
||||
LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(), a_Default.c_str());
|
||||
return BlockStringToType(a_Default);
|
||||
return static_cast<BLOCKTYPE>(BlockStringToType(a_Default));
|
||||
}
|
||||
return Block;
|
||||
return static_cast<BLOCKTYPE>(Block);
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,8 +21,9 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenSameBlock:
|
||||
|
||||
void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
@ -63,7 +64,7 @@ void cCompoGenSameBlock::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenDebugBiomes:
|
||||
|
||||
void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
static BLOCKTYPE Blocks[] =
|
||||
{
|
||||
@ -92,6 +93,7 @@ void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
E_BLOCK_BEDROCK,
|
||||
} ;
|
||||
|
||||
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
@ -131,7 +133,7 @@ cCompoGenClassic::cCompoGenClassic(void) :
|
||||
|
||||
|
||||
|
||||
void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
/* The classic composition means:
|
||||
- 1 layer of grass, 3 of dirt and the rest stone, if the height > sealevel + beachheight
|
||||
@ -142,6 +144,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
*/
|
||||
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||
|
||||
// The patterns to use for different situations, must be same length!
|
||||
const BLOCKTYPE PatternGround[] = {m_BlockTop, m_BlockMiddle, m_BlockMiddle, m_BlockMiddle} ;
|
||||
@ -194,7 +197,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
|
||||
void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "ClassicSeaLevel", m_SeaLevel);
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel);
|
||||
m_BeachHeight = a_IniFile.GetValueSetI("Generator", "ClassicBeachHeight", m_BeachHeight);
|
||||
m_BeachDepth = a_IniFile.GetValueSetI("Generator", "ClassicBeachDepth", m_BeachDepth);
|
||||
m_BlockTop = (BLOCKTYPE)(GetIniItemSet(a_IniFile, "Generator", "ClassicBlockTop", "grass").m_ItemType);
|
||||
@ -209,323 +212,6 @@ void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenBiomal:
|
||||
|
||||
void cCompoGenBiomal::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
|
||||
int ChunkX = a_ChunkDesc.GetChunkX();
|
||||
int ChunkZ = a_ChunkDesc.GetChunkZ();
|
||||
|
||||
/*
|
||||
_X 2013_04_22:
|
||||
There's no point in generating the whole cubic noise at once, because the noise values are used in
|
||||
only about 20 % of the cases, so the speed gained by precalculating is lost by precalculating too much data
|
||||
*/
|
||||
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||
if (Height > m_SeaLevel)
|
||||
{
|
||||
switch (a_ChunkDesc.GetBiome(x, z))
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biExtremeHills:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biExtremeHillsPlus:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biExtremeHillsM:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biExtremeHillsPlusM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnGrass(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
FillColumnClay(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
FillColumnDirt(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnMycelium(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// TODO
|
||||
ASSERT(!"CompoGenBiomal: Biome not implemented yet!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (a_ChunkDesc.GetBiome(x, z))
|
||||
{
|
||||
case biDesert:
|
||||
case biBeach:
|
||||
{
|
||||
// Fill with water, sand, sandstone and stone
|
||||
FillColumnWaterSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Fill with water, sand/dirt/clay mix and stone
|
||||
if (m_Noise.CubicNoise2D(0.3f * (cChunkDef::Width * ChunkX + x), 0.3f * (cChunkDef::Width * ChunkZ + z)) < 0)
|
||||
{
|
||||
FillColumnWaterSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
}
|
||||
else
|
||||
{
|
||||
FillColumnWaterDirt(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch (biome)
|
||||
a_ChunkDesc.SetHeight(x, z, m_SeaLevel + 1);
|
||||
} // else (under water)
|
||||
a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalSeaLevel", m_SeaLevel) - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnGrass(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_GRASS,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnClay(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
if (a_Height - y < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, a_Height - y, a_RelZ, E_BLOCK_DIRT);
|
||||
}
|
||||
for (int y = a_Height - 4; y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_SAND,
|
||||
E_BLOCK_SAND,
|
||||
E_BLOCK_SAND,
|
||||
E_BLOCK_SANDSTONE,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnMycelium (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_MYCELIUM,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnWaterSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
FillColumnSand(a_RelX, a_RelZ, a_Height, a_BlockTypes);
|
||||
for (int y = a_Height + 1; y <= m_SeaLevel + 1; y++)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnWaterDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
// Dirt
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
for (int y = a_Height + 1; y <= m_SeaLevel + 1; y++)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnPattern(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes, const BLOCKTYPE * a_Pattern, int a_PatternSize)
|
||||
{
|
||||
for (int y = a_Height, idx = 0; (y >= 0) && (idx < a_PatternSize); y--, idx++)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, a_Pattern[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenNether:
|
||||
|
||||
@ -540,7 +226,7 @@ cCompoGenNether::cCompoGenNether(int a_Seed) :
|
||||
|
||||
|
||||
|
||||
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight();
|
||||
|
||||
@ -604,17 +290,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
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);
|
||||
}
|
||||
@ -638,7 +314,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
CeilingDisguise = -CeilingDisguise;
|
||||
}
|
||||
|
||||
int CeilingDisguiseHeight = Height - 2 - (int)CeilingDisguise * 3;
|
||||
int CeilingDisguiseHeight = Height - 2 - FloorC(CeilingDisguise * 3);
|
||||
|
||||
for (int y = Height - 1; y > CeilingDisguiseHeight; y--)
|
||||
{
|
||||
@ -696,7 +372,7 @@ cCompoGenCache::~cCompoGenCache()
|
||||
|
||||
|
||||
|
||||
void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (((m_NumHits + m_NumMisses) % 1024) == 10)
|
||||
@ -731,6 +407,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
// Use the cached data:
|
||||
memcpy(a_ChunkDesc.GetBlockTypes(), m_CacheData[Idx].m_BlockTypes, sizeof(a_ChunkDesc.GetBlockTypes()));
|
||||
memcpy(a_ChunkDesc.GetBlockMetasUncompressed(), m_CacheData[Idx].m_BlockMetas, sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
||||
memcpy(a_ChunkDesc.GetHeightMap(), m_CacheData[Idx].m_HeightMap, sizeof(a_ChunkDesc.GetHeightMap()));
|
||||
|
||||
m_NumHits++;
|
||||
m_TotalChain += i;
|
||||
@ -739,7 +416,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
|
||||
// Not in the cache:
|
||||
m_NumMisses++;
|
||||
m_Underlying->ComposeTerrain(a_ChunkDesc);
|
||||
m_Underlying->ComposeTerrain(a_ChunkDesc, a_Shape);
|
||||
|
||||
// Insert it as the first item in the MRU order:
|
||||
int Idx = m_CacheOrder[m_CacheSize - 1];
|
||||
@ -750,6 +427,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
m_CacheOrder[0] = Idx;
|
||||
memcpy(m_CacheData[Idx].m_BlockTypes, a_ChunkDesc.GetBlockTypes(), sizeof(a_ChunkDesc.GetBlockTypes()));
|
||||
memcpy(m_CacheData[Idx].m_BlockMetas, a_ChunkDesc.GetBlockMetasUncompressed(), sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
||||
memcpy(m_CacheData[Idx].m_HeightMap, a_ChunkDesc.GetHeightMap(), sizeof(a_ChunkDesc.GetHeightMap()));
|
||||
m_CacheData[Idx].m_ChunkX = ChunkX;
|
||||
m_CacheData[Idx].m_ChunkZ = ChunkZ;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../Noise.h"
|
||||
#include "../Noise/Noise.h"
|
||||
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ protected:
|
||||
bool m_IsBedrocked;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
||||
@ -55,7 +55,7 @@ public:
|
||||
protected:
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
} ;
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ protected:
|
||||
BLOCKTYPE m_BlockSea;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
||||
@ -89,40 +89,6 @@ protected:
|
||||
|
||||
|
||||
|
||||
class cCompoGenBiomal :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
cCompoGenBiomal(int a_Seed) :
|
||||
m_Noise(a_Seed + 1000),
|
||||
m_SeaLevel(62)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
cNoise m_Noise;
|
||||
int m_SeaLevel;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
|
||||
void FillColumnGrass (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnClay (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnDirt (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnSand (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnMycelium (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnWaterSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnWaterDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
|
||||
void FillColumnPattern (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes, const BLOCKTYPE * a_Pattern, int a_PatternSize);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCompoGenNether :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
@ -136,7 +102,7 @@ protected:
|
||||
int m_Threshold;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
||||
@ -153,7 +119,7 @@ public:
|
||||
~cCompoGenCache();
|
||||
|
||||
// cTerrainCompositionGen override:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
|
||||
protected:
|
||||
@ -166,6 +132,7 @@ protected:
|
||||
int m_ChunkZ;
|
||||
cChunkDef::BlockTypes m_BlockTypes;
|
||||
cChunkDesc::BlockNibbleBytes m_BlockMetas; // The metas are uncompressed, 1 meta per byte
|
||||
cChunkDef::HeightMap m_HeightMap;
|
||||
} ;
|
||||
|
||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||
|
586
src/Generating/CompoGenBiomal.cpp
Normal file
586
src/Generating/CompoGenBiomal.cpp
Normal file
@ -0,0 +1,586 @@
|
||||
|
||||
// CompoGenBiomal.cpp
|
||||
|
||||
// Implements the cCompoGenBiomal class representing the biome-aware composition generator
|
||||
|
||||
#include "Globals.h"
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../IniFile.h"
|
||||
#include "../Noise/Noise.h"
|
||||
#include "../LinearUpscale.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPattern:
|
||||
|
||||
/** This class is used to store a column pattern initialized at runtime,
|
||||
so that the program doesn't need to explicitly set 256 values for each pattern
|
||||
Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
||||
pattern - there will always be enough pattern left, even for the whole-chunk-height columns. */
|
||||
class cPattern
|
||||
{
|
||||
public:
|
||||
struct BlockInfo
|
||||
{
|
||||
BLOCKTYPE m_BlockType;
|
||||
NIBBLETYPE m_BlockMeta;
|
||||
};
|
||||
|
||||
cPattern(BlockInfo * a_TopBlocks, size_t a_Count)
|
||||
{
|
||||
// Copy the pattern into the top:
|
||||
for (size_t i = 0; i < a_Count; i++)
|
||||
{
|
||||
m_Pattern[i] = a_TopBlocks[i];
|
||||
}
|
||||
|
||||
// Fill the rest with stone:
|
||||
static BlockInfo Stone = {E_BLOCK_STONE, 0};
|
||||
for (int i = static_cast<int>(a_Count); i < cChunkDef::Height; i++)
|
||||
{
|
||||
m_Pattern[i] = Stone;
|
||||
}
|
||||
}
|
||||
|
||||
const BlockInfo * Get(void) const { return m_Pattern; }
|
||||
|
||||
protected:
|
||||
BlockInfo m_Pattern[cChunkDef::Height];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The arrays to use for the top block pattern definitions:
|
||||
|
||||
static cPattern::BlockInfo tbGrass[] =
|
||||
{
|
||||
{E_BLOCK_GRASS, 0},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbDirt[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbPodzol[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbGrassLess[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbMycelium[] =
|
||||
{
|
||||
{E_BLOCK_MYCELIUM, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbGravel[] =
|
||||
{
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbStone[] =
|
||||
{
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Ocean floor pattern top-block definitions:
|
||||
|
||||
static cPattern::BlockInfo tbOFSand[] =
|
||||
{
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SANDSTONE, 0}
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbOFClay[] =
|
||||
{
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbOFOrangeClay[] =
|
||||
{
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Individual patterns to use:
|
||||
|
||||
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
||||
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
||||
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||
|
||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||
static cPattern patOFOrangeClay(tbOFOrangeClay, ARRAYCOUNT(tbOFOrangeClay));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenBiomal:
|
||||
|
||||
class cCompoGenBiomal :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
cCompoGenBiomal(int a_Seed) :
|
||||
m_SeaLevel(62),
|
||||
m_OceanFloorSelect(a_Seed + 1),
|
||||
m_MesaFloor(a_Seed + 2)
|
||||
{
|
||||
initMesaPattern(a_Seed);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** The block height at which water is generated instead of air. */
|
||||
int m_SeaLevel;
|
||||
|
||||
/** The pattern used for mesa biomes. Initialized by seed on generator creation. */
|
||||
cPattern::BlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
||||
|
||||
/** Noise used for selecting between dirt and sand on the ocean floor. */
|
||||
cNoise m_OceanFloorSelect;
|
||||
|
||||
/** Noise used for the floor of the clay blocks in mesa biomes. */
|
||||
cNoise m_MesaFloor;
|
||||
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
ComposeColumn(a_ChunkDesc, x, z, &(a_Shape[x * 256 + z * 16 * 256]));
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Initializes the m_MesaPattern with a pattern based on the generator's seed. */
|
||||
void initMesaPattern(int a_Seed)
|
||||
{
|
||||
// In a loop, choose whether to use one, two or three layers of stained clay, then choose a color and width for each layer
|
||||
// Separate each group with another layer of hardened clay
|
||||
cNoise patternNoise((unsigned)a_Seed);
|
||||
static NIBBLETYPE allowedColors[] =
|
||||
{
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_WHITE,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_LIGHTGRAY,
|
||||
} ;
|
||||
static int layerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
||||
{
|
||||
1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2,
|
||||
3, 3,
|
||||
} ;
|
||||
int idx = ARRAYCOUNT(m_MesaPattern) - 1;
|
||||
while (idx >= 0)
|
||||
{
|
||||
// A layer group of 1 - 2 color stained clay:
|
||||
int rnd = patternNoise.IntNoise1DInt(idx) / 7;
|
||||
int numLayers = (rnd % 2) + 1;
|
||||
rnd /= 2;
|
||||
for (int lay = 0; lay < numLayers; lay++)
|
||||
{
|
||||
int numBlocks = layerSizes[(rnd % ARRAYCOUNT(layerSizes))];
|
||||
NIBBLETYPE Color = allowedColors[(rnd / 4) % ARRAYCOUNT(allowedColors)];
|
||||
if (
|
||||
((numBlocks == 3) && (numLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
||||
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
||||
{
|
||||
numBlocks = 1;
|
||||
}
|
||||
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||
rnd /= 32;
|
||||
for (int block = 0; block < numBlocks; block++, idx--)
|
||||
{
|
||||
m_MesaPattern[idx].m_BlockMeta = Color;
|
||||
m_MesaPattern[idx].m_BlockType = E_BLOCK_STAINED_CLAY;
|
||||
} // for block
|
||||
} // for lay
|
||||
|
||||
// A layer of hardened clay in between the layer group:
|
||||
int numBlocks = (rnd % 4) + 1; // All heights the same probability
|
||||
if ((numLayers == 2) && (numBlocks < 4))
|
||||
{
|
||||
// For two layers of stained clay, add an extra block of hardened clay:
|
||||
numBlocks++;
|
||||
}
|
||||
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||
for (int block = 0; block < numBlocks; block++, idx--)
|
||||
{
|
||||
m_MesaPattern[idx].m_BlockMeta = 0;
|
||||
m_MesaPattern[idx].m_BlockType = E_BLOCK_HARDENED_CLAY;
|
||||
} // for block
|
||||
} // while (idx >= 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column. */
|
||||
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||
{
|
||||
// Frequencies for the podzol floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 8;
|
||||
const NOISE_DATATYPE FrequencyZ = 8;
|
||||
|
||||
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
||||
switch (Biome)
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biExtremeHillsPlus:
|
||||
case biExtremeHills:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
// Select the pattern to use - podzol, grass or grassless dirt:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const cPattern::BlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
||||
// instead, they provide a "from bottom" pattern with varying base height,
|
||||
// usually 4 blocks below the ocean level
|
||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biExtremeHillsPlusM:
|
||||
case biExtremeHillsM:
|
||||
{
|
||||
// Select the pattern to use - gravel, stone or grass:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const cPattern::BlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled biome");
|
||||
return;
|
||||
}
|
||||
} // switch (Biome)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
||||
switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom. */
|
||||
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const cPattern::BlockInfo * a_Pattern, const Byte * a_ShapeColumn)
|
||||
{
|
||||
bool HasHadWater = false;
|
||||
int PatternIdx = 0;
|
||||
int top = std::max(m_SeaLevel, a_ChunkDesc.GetHeight(a_RelX, a_RelZ));
|
||||
for (int y = top; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].m_BlockType, a_Pattern[PatternIdx].m_BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// "air" or "water" part:
|
||||
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
||||
PatternIdx = 0;
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
if (a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean)
|
||||
{
|
||||
a_Pattern = patGravel.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||
}
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the specified column with mesa pattern, based on the column height */
|
||||
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||
{
|
||||
// Frequencies for the clay floor noise:
|
||||
const NOISE_DATATYPE FrequencyX = 50;
|
||||
const NOISE_DATATYPE FrequencyZ = 50;
|
||||
|
||||
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
||||
if (Top < m_SeaLevel)
|
||||
{
|
||||
// The terrain is below sealevel, handle as regular ocean with red sand floor:
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFOrangeClay.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
||||
if (ClayFloor >= Top)
|
||||
{
|
||||
ClayFloor = Top - 1;
|
||||
}
|
||||
|
||||
if (Top - m_SeaLevel < 5)
|
||||
{
|
||||
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
||||
for (int y = Top - 1; y >= ClayFloor; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
||||
}
|
||||
for (int y = ClayFloor - 1; y > 0; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Difficult case: use the mesa pattern and watch for overhangs:
|
||||
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
||||
const cPattern::BlockInfo * Pattern = m_MesaPattern;
|
||||
bool HasHadWater = false;
|
||||
for (int y = Top; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].m_BlockType, Pattern[PatternIdx].m_BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
||||
PatternIdx = 0;
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Returns the pattern to use for an ocean floor in the specified column.
|
||||
The returned pattern is guaranteed to be 256 blocks long. */
|
||||
const cPattern::BlockInfo * ChooseOceanFloorPattern(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the ocean floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 3;
|
||||
const NOISE_DATATYPE FrequencyZ = 3;
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
if (Val < -0.95)
|
||||
{
|
||||
return patOFClay.Get();
|
||||
}
|
||||
else if (Val < 0)
|
||||
{
|
||||
return patOFSand.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return patDirt.Get();
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed)
|
||||
{
|
||||
return std::make_shared<cCompoGenBiomal>(a_Seed);
|
||||
}
|
||||
|
||||
|
||||
|
21
src/Generating/CompoGenBiomal.h
Normal file
21
src/Generating/CompoGenBiomal.h
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
// CompoGenBiomal.h
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Returns a new instance of the Biomal composition generator. */
|
||||
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed);
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
#include "StructGen.h"
|
||||
#include "FinishGen.h"
|
||||
|
||||
#include "CompoGenBiomal.h"
|
||||
|
||||
#include "CompositedHeiGen.h"
|
||||
|
||||
#include "Caves.h"
|
||||
#include "DistortedHeightmap.h"
|
||||
#include "DungeonRoomsFinisher.h"
|
||||
@ -39,7 +43,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cTerrainCompositionGen:
|
||||
|
||||
cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
|
||||
cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, int a_Seed)
|
||||
{
|
||||
AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
|
||||
if (CompoGenName.empty())
|
||||
@ -48,59 +52,52 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
|
||||
CompoGenName = "Biomal";
|
||||
}
|
||||
|
||||
cTerrainCompositionGen * res = nullptr;
|
||||
if (NoCaseCompare(CompoGenName, "sameblock") == 0)
|
||||
// Compositor list is alpha-sorted
|
||||
cTerrainCompositionGenPtr res;
|
||||
if (NoCaseCompare(CompoGenName, "Biomal") == 0)
|
||||
{
|
||||
res = new cCompoGenSameBlock;
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
|
||||
else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
|
||||
{
|
||||
res = new cCompoGenDebugBiomes;
|
||||
// The composition that used to be provided with BiomalNoise3D is now provided by the Biomal compositor:
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "classic") == 0)
|
||||
else if (NoCaseCompare(CompoGenName, "Classic") == 0)
|
||||
{
|
||||
res = new cCompoGenClassic;
|
||||
res = std::make_shared<cCompoGenClassic>();
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "DebugBiomes") == 0)
|
||||
{
|
||||
res = std::make_shared<cCompoGenDebugBiomes>();
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
|
||||
{
|
||||
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
|
||||
// The composition that used to be provided with DistortedHeightmap is now provided by the Biomal compositor:
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "end") == 0)
|
||||
else if (NoCaseCompare(CompoGenName, "End") == 0)
|
||||
{
|
||||
res = new cEndGen(a_Seed);
|
||||
res = std::make_shared<cEndGen>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "nether") == 0)
|
||||
else if (NoCaseCompare(CompoGenName, "Nether") == 0)
|
||||
{
|
||||
res = new cCompoGenNether(a_Seed);
|
||||
res = std::make_shared<cCompoGenNether>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
|
||||
{
|
||||
res = new cNoise3DComposable(a_Seed);
|
||||
// The composition that used to be provided with Noise3D is now provided by the Biomal compositor:
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "biomal") == 0)
|
||||
else if (NoCaseCompare(CompoGenName, "SameBlock") == 0)
|
||||
{
|
||||
res = new cCompoGenBiomal(a_Seed);
|
||||
|
||||
/*
|
||||
// Performance-testing:
|
||||
LOGINFO("Measuring performance of cCompoGenBiomal...");
|
||||
clock_t BeginTick = clock();
|
||||
for (int x = 0; x < 500; x++)
|
||||
{
|
||||
cChunkDesc Desc(200 + x * 8, 200 + x * 8);
|
||||
a_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap());
|
||||
a_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap());
|
||||
res->ComposeTerrain(Desc);
|
||||
}
|
||||
clock_t Duration = clock() - BeginTick;
|
||||
LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
|
||||
//*/
|
||||
res = std::make_shared<cCompoGenSameBlock>();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
|
||||
a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
|
||||
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed);
|
||||
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_ShapeGen, a_Seed);
|
||||
}
|
||||
ASSERT(res != nullptr);
|
||||
|
||||
@ -120,7 +117,7 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
|
||||
cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
|
||||
super(a_ChunkGenerator),
|
||||
m_BiomeGen(),
|
||||
m_HeightGen(),
|
||||
m_ShapeGen(),
|
||||
m_CompositionGen()
|
||||
{
|
||||
}
|
||||
@ -134,7 +131,7 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
|
||||
super::Initialize(a_IniFile);
|
||||
|
||||
InitBiomeGen(a_IniFile);
|
||||
InitHeightGen(a_IniFile);
|
||||
InitShapeGen(a_IniFile);
|
||||
InitCompositionGen(a_IniFile);
|
||||
InitFinishGens(a_IniFile);
|
||||
}
|
||||
@ -162,16 +159,22 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
|
||||
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetBiomeMap());
|
||||
}
|
||||
|
||||
cChunkDesc::Shape shape;
|
||||
if (a_ChunkDesc.IsUsingDefaultHeight())
|
||||
{
|
||||
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap());
|
||||
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
|
||||
a_ChunkDesc.SetHeightFromShape(shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the heightmap in a_ChunkDesc into shape:
|
||||
a_ChunkDesc.GetShapeFromHeight(shape);
|
||||
}
|
||||
|
||||
bool ShouldUpdateHeightmap = false;
|
||||
if (a_ChunkDesc.IsUsingDefaultComposition())
|
||||
{
|
||||
m_CompositionGen->ComposeTerrain(a_ChunkDesc);
|
||||
ShouldUpdateHeightmap = true;
|
||||
m_CompositionGen->ComposeTerrain(a_ChunkDesc, shape);
|
||||
}
|
||||
|
||||
if (a_ChunkDesc.IsUsingDefaultFinish())
|
||||
@ -230,13 +233,15 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||
void cComposableGenerator::InitShapeGen(cIniFile & a_IniFile)
|
||||
{
|
||||
bool CacheOffByDefault = false;
|
||||
m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
|
||||
m_ShapeGen = cTerrainShapeGen::CreateShapeGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
|
||||
|
||||
/*
|
||||
// TODO
|
||||
// Add a cache, if requested:
|
||||
int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
|
||||
int CacheSize = a_IniFile.GetValueSetI("Generator", "ShapeGenCacheSize", CacheOffByDefault ? 0 : 64);
|
||||
if (CacheSize > 0)
|
||||
{
|
||||
if (CacheSize < 4)
|
||||
@ -249,6 +254,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||
LOGD("Using a cache for Heightgen of size %d.", CacheSize);
|
||||
m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -257,13 +263,19 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||
|
||||
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed());
|
||||
m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, m_ShapeGen, m_ChunkGenerator.GetSeed());
|
||||
|
||||
// Add a cache over the composition generator:
|
||||
// Even a cache of size 1 is useful due to the CompositedHeiGen cache after us doing re-composition on its misses
|
||||
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
|
||||
if (CompoGenCacheSize > 1)
|
||||
if (CompoGenCacheSize > 0)
|
||||
{
|
||||
m_CompositionGen = cTerrainCompositionGenPtr(new cCompoGenCache(m_CompositionGen, 32));
|
||||
m_CompositionGen = std::make_shared<cCompoGenCache>(m_CompositionGen, CompoGenCacheSize);
|
||||
}
|
||||
|
||||
// Create a cache of the composited heightmaps, so that finishers may use it:
|
||||
m_CompositedHeightCache = std::make_shared<cHeiGenMultiCache>(std::make_shared<cCompositedHeiGen>(m_ShapeGen, m_CompositionGen), 16, 24);
|
||||
// 24 subcaches of depth 16 each = 96 KiB of RAM. Acceptable, for the amount of work this saves.
|
||||
}
|
||||
|
||||
|
||||
@ -282,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);
|
||||
@ -329,7 +345,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
|
||||
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
|
||||
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_ShapeGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "Ice") == 0)
|
||||
{
|
||||
@ -338,7 +354,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
|
||||
{
|
||||
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_HeightGen, Probability)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_ShapeGen, Probability)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "LavaSprings") == 0)
|
||||
{
|
||||
@ -558,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));
|
||||
@ -576,7 +596,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "Trees") == 0)
|
||||
{
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_ShapeGen, m_CompositionGen)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "UnderwaterBases") == 0)
|
||||
{
|
||||
@ -584,7 +604,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
int MaxOffset = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxOffset", 128);
|
||||
int MaxDepth = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxDepth", 7);
|
||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxSize", 128);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen)));
|
||||
m_FinishGens.push_back(std::make_shared<cUnderwaterBaseGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "Villages") == 0)
|
||||
{
|
||||
@ -594,12 +614,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
|
||||
int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
|
||||
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_HeightGen)));
|
||||
m_FinishGens.push_back(std::make_shared<cVillageGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
|
||||
{
|
||||
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_HeightGen, Probability)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_ShapeGen, Probability)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "WaterSprings") == 0)
|
||||
{
|
||||
|
@ -26,20 +26,16 @@ See http://forum.mc-server.org/showthread.php?tid=409 for details.
|
||||
|
||||
// Forward-declare the shared pointers to subgenerator classes:
|
||||
class cBiomeGen;
|
||||
class cTerrainShapeGen;
|
||||
class cTerrainHeightGen;
|
||||
class cTerrainCompositionGen;
|
||||
class cFinishGen;
|
||||
typedef SharedPtr<cBiomeGen> cBiomeGenPtr;
|
||||
typedef SharedPtr<cTerrainShapeGen> cTerrainShapeGenPtr;
|
||||
typedef SharedPtr<cTerrainHeightGen> cTerrainHeightGenPtr;
|
||||
typedef SharedPtr<cTerrainCompositionGen> cTerrainCompositionGenPtr;
|
||||
typedef SharedPtr<cFinishGen> cFinishGenPtr;
|
||||
|
||||
// fwd: Noise3DGenerator.h
|
||||
class cNoise3DComposable;
|
||||
|
||||
// fwd: DistortedHeightmap.h
|
||||
class cDistortedHeightmap;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -70,28 +66,54 @@ public:
|
||||
|
||||
|
||||
|
||||
/** The interface that a terrain height generator must implement
|
||||
A terrain height generator takes chunk coords on input and outputs an array of terrain heights for that chunk.
|
||||
The output array is sequenced in the same way as the BiomeGen's biome data.
|
||||
/** The interface that a terrain shape generator must implement
|
||||
A terrain shape generator takes chunk coords on input and outputs a 3D array of "shape" for that chunk. The shape here
|
||||
represents the distinction between air and solid; there's no representation of Water since that is added by the
|
||||
composition geenrator.
|
||||
The output array is indexed [y + 256 * z + 16 * 256 * x], so that it's fast to later compose a single column of the terrain,
|
||||
which is the dominant operation following the shape generation.
|
||||
The generator may request biome information from the underlying BiomeGen, it may even request information for
|
||||
other chunks than the one it's currently generating (possibly neighbors - for averaging)
|
||||
other chunks than the one it's currently generating (neighbors - for averaging)
|
||||
*/
|
||||
class cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
virtual ~cTerrainShapeGen() {} // Force a virtual destructor in descendants
|
||||
|
||||
/** Generates the shape for the given chunk */
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) = 0;
|
||||
|
||||
/** Reads parameters from the ini file, prepares generator for use. */
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) {}
|
||||
|
||||
/** Creates the correct TerrainShapeGen descendant based on the ini file settings and the seed provided.
|
||||
a_BiomeGen is the underlying biome generator, some shape generators may depend on it providing additional biomes data around the chunk
|
||||
a_CacheOffByDefault gets set to whether the cache should be disabled by default
|
||||
Implemented in ShapeGen.cpp!
|
||||
*/
|
||||
static cTerrainShapeGenPtr CreateShapeGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** The interface that is used to query terrain height from the shape generator.
|
||||
Usually the structure generators require only the final heightmap, and generating the whole shape only to
|
||||
consume the heightmap is wasteful, so this interface is used instead; it has a cache implemented over it so
|
||||
that data is retained. */
|
||||
class cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
|
||||
|
||||
/** Generates heightmap for the given chunk */
|
||||
|
||||
/** Retrieves the heightmap for the specified chunk. */
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
|
||||
|
||||
/** Reads parameters from the ini file, prepares generator for use. */
|
||||
|
||||
/** Initializes the generator, reading its parameters from the INI file. */
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
|
||||
|
||||
/** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
|
||||
a_BiomeGen is the underlying biome generator, some height generators may depend on it to generate more biomes
|
||||
a_CacheOffByDefault gets set to whether the cache should be disabled by default
|
||||
Implemented in HeiGen.cpp!
|
||||
*/
|
||||
|
||||
/** Creates a cTerrainHeightGen descendant based on the INI file settings. */
|
||||
static cTerrainHeightGenPtr CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
||||
} ;
|
||||
|
||||
@ -109,16 +131,18 @@ class cTerrainCompositionGen
|
||||
public:
|
||||
virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants
|
||||
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0;
|
||||
/** Generates the chunk's composition into a_ChunkDesc, using the terrain shape provided in a_Shape.
|
||||
Is expected to fill a_ChunkDesc's heightmap with the data from a_Shape. */
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) = 0;
|
||||
|
||||
/** Reads parameters from the ini file, prepares generator for use. */
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
|
||||
|
||||
/** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
|
||||
a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes
|
||||
a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values
|
||||
a_BiomeGen is the underlying biome generator, some composition generators may depend on it providing additional biomes around the chunk
|
||||
a_ShapeGen is the underlying shape generator, some composition generators may depend on it providing additional shape around the chunk
|
||||
*/
|
||||
static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed);
|
||||
static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, int a_Seed);
|
||||
} ;
|
||||
|
||||
|
||||
@ -128,7 +152,7 @@ public:
|
||||
/** The interface that a finisher must implement
|
||||
Finisher implements changes to the chunk after the rough terrain has been generated.
|
||||
Examples of finishers are trees, snow, ore, lilypads and others.
|
||||
Note that a worldgenerator may contain multiple finishers.
|
||||
Note that a worldgenerator may contain multiple finishers, chained one after another.
|
||||
Also note that previously we used to distinguish between a structuregen and a finisher; this distinction is
|
||||
no longer relevant, all structure generators are considered finishers now (#398)
|
||||
*/
|
||||
@ -154,23 +178,34 @@ class cComposableGenerator :
|
||||
public:
|
||||
cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
|
||||
|
||||
// cChunkGenerator::cGenerator overrides:
|
||||
virtual void Initialize(cIniFile & a_IniFile) override;
|
||||
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||
virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
|
||||
|
||||
protected:
|
||||
// The generation composition:
|
||||
cBiomeGenPtr m_BiomeGen;
|
||||
cTerrainHeightGenPtr m_HeightGen;
|
||||
// The generator's composition:
|
||||
/** The biome generator. */
|
||||
cBiomeGenPtr m_BiomeGen;
|
||||
|
||||
/** The terrain shape generator. */
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
|
||||
/** The terrain composition generator. */
|
||||
cTerrainCompositionGenPtr m_CompositionGen;
|
||||
cFinishGenList m_FinishGens;
|
||||
|
||||
/** The cache for the heights of the composited terrain. */
|
||||
cTerrainHeightGenPtr m_CompositedHeightCache;
|
||||
|
||||
/** The finisher generators, in the order in which they are applied. */
|
||||
cFinishGenList m_FinishGens;
|
||||
|
||||
|
||||
/** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */
|
||||
/** Reads the BiomeGen settings from the ini and initializes m_BiomeGen accordingly */
|
||||
void InitBiomeGen(cIniFile & a_IniFile);
|
||||
|
||||
/** Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly */
|
||||
void InitHeightGen(cIniFile & a_IniFile);
|
||||
/** Reads the ShapeGen settings from the ini and initializes m_ShapeGen accordingly */
|
||||
void InitShapeGen(cIniFile & a_IniFile);
|
||||
|
||||
/** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
|
||||
void InitCompositionGen(cIniFile & a_IniFile);
|
||||
|
49
src/Generating/CompositedHeiGen.h
Normal file
49
src/Generating/CompositedHeiGen.h
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
// CompositedHeiGen.h
|
||||
|
||||
// Declares the cCompositedHeiGen class representing a cTerrainHeightGen descendant that calculates heightmap of the composited terrain
|
||||
// This is used to further cache heightmaps for chunks already generated for finishers that require only heightmap information
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCompositedHeiGen:
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cCompositedHeiGen(cTerrainShapeGenPtr a_ShapeGen, cTerrainCompositionGenPtr a_CompositionGen):
|
||||
m_ShapeGen(a_ShapeGen),
|
||||
m_CompositionGen(a_CompositionGen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cTerrainheightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override
|
||||
{
|
||||
cChunkDesc::Shape shape;
|
||||
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
|
||||
cChunkDesc desc(a_ChunkX, a_ChunkZ);
|
||||
desc.SetHeightFromShape(shape);
|
||||
m_CompositionGen->ComposeTerrain(desc, shape);
|
||||
memcpy(a_HeightMap, desc.GetHeightMap(), sizeof(a_HeightMap));
|
||||
}
|
||||
|
||||
protected:
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
cTerrainCompositionGenPtr m_CompositionGen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -14,163 +14,6 @@
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPattern:
|
||||
|
||||
/// This class is used to store a column pattern initialized at runtime,
|
||||
/// so that the program doesn't need to explicitly set 256 values for each pattern
|
||||
/// Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
||||
/// pattern - there will always be enough pattern left, even for the whole chunk height
|
||||
class cPattern
|
||||
{
|
||||
public:
|
||||
cPattern(cDistortedHeightmap::sBlockInfo * a_TopBlocks, size_t a_Count)
|
||||
{
|
||||
// Copy the pattern into the top:
|
||||
for (size_t i = 0; i < a_Count; i++)
|
||||
{
|
||||
m_Pattern[i] = a_TopBlocks[i];
|
||||
}
|
||||
|
||||
// Fill the rest with stone:
|
||||
static cDistortedHeightmap::sBlockInfo Stone = {E_BLOCK_STONE, 0};
|
||||
for (size_t i = a_Count; i < cChunkDef::Height; i++)
|
||||
{
|
||||
m_Pattern[i] = Stone;
|
||||
}
|
||||
}
|
||||
|
||||
const cDistortedHeightmap::sBlockInfo * Get(void) const { return m_Pattern; }
|
||||
|
||||
protected:
|
||||
cDistortedHeightmap::sBlockInfo m_Pattern[cChunkDef::Height];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The arrays to use for the top block pattern definitions:
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbGrass[] =
|
||||
{
|
||||
{E_BLOCK_GRASS, 0},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbDirt[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbPodzol[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbGrassLess[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbMycelium[] =
|
||||
{
|
||||
{E_BLOCK_MYCELIUM, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbGravel[] =
|
||||
{
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbStone[] =
|
||||
{
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Ocean floor pattern top-block definitions:
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbOFSand[] =
|
||||
{
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SANDSTONE, 0}
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbOFClay[] =
|
||||
{
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbOFRedSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Individual patterns to use:
|
||||
|
||||
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
||||
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
||||
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||
|
||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||
static cPattern patOFRedSand(tbOFRedSand, ARRAYCOUNT(tbOFRedSand));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cDistortedHeightmap:
|
||||
|
||||
@ -237,7 +80,7 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
|
||||
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 110 .. 119
|
||||
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 120 .. 128
|
||||
|
||||
// Release 1.7 /* biome variants:
|
||||
// Release 1.7 biome variants:
|
||||
/* biSunflowerPlains */ { 1.0f, 1.0f}, // 129
|
||||
/* biDesertM */ { 1.0f, 1.0f}, // 130
|
||||
/* biExtremeHillsM */ {16.0f, 16.0f}, // 131
|
||||
@ -279,8 +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_OceanFloorSelect(a_Seed + 3000),
|
||||
m_MesaFloor(a_Seed + 4000),
|
||||
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),
|
||||
@ -293,8 +136,6 @@ cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
|
||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)1, (NOISE_DATATYPE)0.5);
|
||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.5, (NOISE_DATATYPE)1);
|
||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.25, (NOISE_DATATYPE)2);
|
||||
|
||||
InitMesaPattern(a_Seed);
|
||||
}
|
||||
|
||||
|
||||
@ -309,7 +150,7 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile)
|
||||
}
|
||||
|
||||
// Read the params from the INI file:
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "DistortedHeightmapSeaLevel", 62);
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10);
|
||||
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyY", 10);
|
||||
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyZ", 10);
|
||||
@ -321,89 +162,6 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::InitMesaPattern(int a_Seed)
|
||||
{
|
||||
// Stone in the bottom half of the pattern:
|
||||
for (int i = cChunkDef::Height; i < 2 * cChunkDef::Height; i++)
|
||||
{
|
||||
m_MesaPattern[i].BlockMeta = 0;
|
||||
m_MesaPattern[i].BlockType = E_BLOCK_STONE;
|
||||
}
|
||||
|
||||
// Stained and hardened clay in the top half of the pattern
|
||||
// In a loop, choose whether to use one or two layers of stained clay, then choose a color and width for each layer
|
||||
// Separate each group with another layer of hardened clay
|
||||
cNoise PatternNoise((unsigned)a_Seed);
|
||||
static NIBBLETYPE AllowedColors[] =
|
||||
{
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_WHITE,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_LIGHTGRAY,
|
||||
} ;
|
||||
static int LayerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
||||
{
|
||||
1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2,
|
||||
3, 3,
|
||||
} ;
|
||||
int Idx = cChunkDef::Height - 1;
|
||||
while (Idx >= 0)
|
||||
{
|
||||
// A layer group of 1 - 2 color stained clay:
|
||||
int Random = PatternNoise.IntNoise1DInt(Idx) / 7;
|
||||
int NumLayers = (Random % 2) + 1;
|
||||
Random /= 2;
|
||||
for (int Lay = 0; Lay < NumLayers; Lay++)
|
||||
{
|
||||
int NumBlocks = LayerSizes[(Random % ARRAYCOUNT(LayerSizes))];
|
||||
NIBBLETYPE Color = AllowedColors[(Random / 4) % ARRAYCOUNT(AllowedColors)];
|
||||
if (
|
||||
((NumBlocks == 3) && (NumLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
||||
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
||||
{
|
||||
NumBlocks = 1;
|
||||
}
|
||||
NumBlocks = std::min(Idx + 1, NumBlocks); // Limit by Idx so that we don't have to check inside the loop
|
||||
Random /= 32;
|
||||
for (int Block = 0; Block < NumBlocks; Block++, Idx--)
|
||||
{
|
||||
m_MesaPattern[Idx].BlockMeta = Color;
|
||||
m_MesaPattern[Idx].BlockType = E_BLOCK_STAINED_CLAY;
|
||||
} // for Block
|
||||
} // for Lay
|
||||
|
||||
// A layer of hardened clay in between the layer group:
|
||||
int NumBlocks = (Random % 4) + 1; // All heights the same probability
|
||||
if ((NumLayers == 2) && (NumBlocks < 4))
|
||||
{
|
||||
// For two layers of stained clay, add an extra block of hardened clay:
|
||||
NumBlocks++;
|
||||
}
|
||||
NumBlocks = std::min(Idx + 1, NumBlocks); // Limit by Idx so that we don't have to check inside the loop
|
||||
for (int Block = 0; Block < NumBlocks; Block++, Idx--)
|
||||
{
|
||||
m_MesaPattern[Idx].BlockMeta = 0;
|
||||
m_MesaPattern[Idx].BlockType = E_BLOCK_HARDENED_CLAY;
|
||||
} // for Block
|
||||
} // while (Idx >= 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
if ((m_CurChunkX == a_ChunkX) && (m_CurChunkZ == a_ChunkZ))
|
||||
@ -474,23 +232,17 @@ void cDistortedHeightmap::GenerateHeightArray(void)
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
void cDistortedHeightmap::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
PrepareState(a_ChunkX, a_ChunkZ);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int NoiseArrayIdx = x + 17 * 257 * z;
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel - 1);
|
||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel - 1; y--)
|
||||
int idx = x + 17 * 257 * z;
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
||||
if (y < HeightMapHeight)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
a_Shape[y + x * 256 + z * 16 * 256] = (y < m_DistortedHeightmap[idx + y * 17]) ? 1 : 0;
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
@ -500,36 +252,7 @@ void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::He
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::InitializeHeightGen(cIniFile & a_IniFile)
|
||||
{
|
||||
Initialize(a_IniFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
// Prepare the internal state for generating this chunk:
|
||||
PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
||||
|
||||
// Compose:
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
ComposeColumn(a_ChunkDesc, x, z);
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
void cDistortedHeightmap::InitializeShapeGen(cIniFile & a_IniFile)
|
||||
{
|
||||
Initialize(a_IniFile);
|
||||
}
|
||||
@ -654,275 +377,3 @@ void cDistortedHeightmap::GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_R
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the podzol floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 8;
|
||||
const NOISE_DATATYPE FrequencyZ = 8;
|
||||
|
||||
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
||||
switch (Biome)
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biExtremeHillsPlus:
|
||||
case biExtremeHills:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
// Select the pattern to use - podzol, grass or grassless dirt:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const sBlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||
return;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
||||
// instead, they provide a "from bottom" pattern with varying base height,
|
||||
// usually 4 blocks below the ocean level
|
||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
||||
return;
|
||||
}
|
||||
|
||||
case biExtremeHillsPlusM:
|
||||
case biExtremeHillsM:
|
||||
{
|
||||
// Select the pattern to use - gravel, stone or grass:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const sBlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled biome");
|
||||
return;
|
||||
}
|
||||
} // switch (Biome)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const sBlockInfo * a_Pattern)
|
||||
{
|
||||
int NoiseArrayIdx = a_RelX + 17 * 257 * a_RelZ;
|
||||
bool HasHadWater = false;
|
||||
int PatternIdx = 0;
|
||||
for (int y = a_ChunkDesc.GetHeight(a_RelX, a_RelZ); y > 0; y--)
|
||||
{
|
||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
||||
|
||||
if (y < HeightMapHeight)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].BlockType, a_Pattern[PatternIdx].BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// "air" or "water" part:
|
||||
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
||||
PatternIdx = 0;
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
a_Pattern = a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean ? patGravel.Get() : ChooseOceanFloorPattern(a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the clay floor noise:
|
||||
const NOISE_DATATYPE FrequencyX = 50;
|
||||
const NOISE_DATATYPE FrequencyZ = 50;
|
||||
|
||||
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
||||
if (Top < m_SeaLevel)
|
||||
{
|
||||
// The terrain is below sealevel, handle as regular ocean:
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFRedSand.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
||||
if (ClayFloor >= Top)
|
||||
{
|
||||
ClayFloor = Top - 1;
|
||||
}
|
||||
|
||||
if (Top - m_SeaLevel < 5)
|
||||
{
|
||||
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
||||
for (int y = Top - 1; y >= ClayFloor; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
||||
}
|
||||
for (int y = ClayFloor - 1; y > 0; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Difficult case: use the mesa pattern and watch for overhangs:
|
||||
int NoiseArrayIdx = a_RelX + 17 * 257 * a_RelZ;
|
||||
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
||||
const sBlockInfo * Pattern = m_MesaPattern;
|
||||
bool HasHadWater = false;
|
||||
for (int y = Top; y > 0; y--)
|
||||
{
|
||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
||||
if (y < HeightMapHeight)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].BlockType, Pattern[PatternIdx].BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
||||
PatternIdx = 0;
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
Pattern = ChooseOceanFloorPattern(a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cDistortedHeightmap::sBlockInfo * cDistortedHeightmap::ChooseOceanFloorPattern(int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the ocean floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 3;
|
||||
const NOISE_DATATYPE FrequencyZ = 3;
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
if (Val < -0.95)
|
||||
{
|
||||
return patOFClay.Get();
|
||||
}
|
||||
else if (Val < 0)
|
||||
{
|
||||
return patOFSand.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return patDirt.Get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "HeiGen.h"
|
||||
#include "../Noise.h"
|
||||
|
||||
|
||||
|
||||
@ -24,17 +23,9 @@
|
||||
|
||||
|
||||
class cDistortedHeightmap :
|
||||
public cTerrainHeightGen,
|
||||
public cTerrainCompositionGen
|
||||
public cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
/// Structure used for storing block patterns for columns
|
||||
struct sBlockInfo
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
} ;
|
||||
|
||||
cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||
|
||||
protected:
|
||||
@ -52,8 +43,6 @@ protected:
|
||||
|
||||
cPerlinNoise m_NoiseDistortX;
|
||||
cPerlinNoise m_NoiseDistortZ;
|
||||
cNoise m_OceanFloorSelect; ///< Used for selecting between dirt and sand on the ocean floor
|
||||
cNoise m_MesaFloor; ///< Used for the floor of the clay blocks in mesa biomes
|
||||
|
||||
int m_SeaLevel;
|
||||
NOISE_DATATYPE m_FrequencyX;
|
||||
@ -71,9 +60,9 @@ protected:
|
||||
cTerrainHeightGenPtr m_UnderlyingHeiGen;
|
||||
|
||||
/** Cache for m_UnderlyingHeiGen. */
|
||||
cHeiGenCache m_HeightGen;
|
||||
cHeiGenCache m_HeightGen;
|
||||
|
||||
/// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization.
|
||||
/** Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization. */
|
||||
cChunkDef::HeightMap m_CurChunkHeights;
|
||||
|
||||
// Per-biome terrain generator parameters:
|
||||
@ -88,54 +77,30 @@ protected:
|
||||
NOISE_DATATYPE m_DistortAmpX[DIM_X * DIM_Z];
|
||||
NOISE_DATATYPE m_DistortAmpZ[DIM_X * DIM_Z];
|
||||
|
||||
/// True if Initialize() has been called. Used to initialize-once even with multiple init entrypoints (HeiGen / CompoGen)
|
||||
/** True if Initialize() has been called. Used to initialize-once even with multiple init entrypoints (HeiGen / CompoGen). */
|
||||
bool m_IsInitialized;
|
||||
|
||||
/// The vertical pattern to be used for mesa biomes. Seed-dependant.
|
||||
/// One Height of pattern and one Height of stone to avoid checking pattern dimensions
|
||||
sBlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
||||
|
||||
|
||||
/// Initializes m_MesaPattern with a reasonable pattern of stained clay / hardened clay, based on the seed
|
||||
void InitMesaPattern(int a_Seed);
|
||||
|
||||
/// Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap)
|
||||
/** Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap). */
|
||||
void PrepareState(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/// Generates the m_DistortedHeightmap array for the current chunk
|
||||
/** Generates the m_DistortedHeightmap array for the current chunk. */
|
||||
void GenerateHeightArray(void);
|
||||
|
||||
/// Calculates the heightmap value (before distortion) at the specified (floating-point) coords
|
||||
/** Calculates the heightmap value (before distortion) at the specified (floating-point) coords. */
|
||||
int GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z);
|
||||
|
||||
/// Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ
|
||||
/** Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ. */
|
||||
void UpdateDistortAmps(void);
|
||||
|
||||
/// Calculates the X and Z distortion amplitudes based on the neighbors' biomes
|
||||
/** Calculates the X and Z distortion amplitudes based on the neighbors' biomes. */
|
||||
void GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_RelX, int a_RelZ, NOISE_DATATYPE & a_DistortAmpX, NOISE_DATATYPE & a_DistortAmpZ);
|
||||
|
||||
/// Reads the settings from the ini file. Skips reading if already initialized
|
||||
/** Reads the settings from the ini file. Skips reading if already initialized. */
|
||||
void Initialize(cIniFile & a_IniFile);
|
||||
|
||||
/// Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column
|
||||
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ);
|
||||
|
||||
/// Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
||||
/// switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom.
|
||||
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const sBlockInfo * a_Pattern);
|
||||
|
||||
/// Fills the specified column with mesa pattern, based on the column height
|
||||
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ);
|
||||
|
||||
/// Returns the pattern to use for an ocean floor in the specified column
|
||||
const sBlockInfo * ChooseOceanFloorPattern(int a_RelX, int a_RelZ);
|
||||
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
// cTerrainShapeGen overrides:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
@ -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,9 +93,12 @@ 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. */
|
||||
/** Decodes the position index along the room walls into a proper 2D position for a chest.
|
||||
The Y coord of the returned vector specifies the chest's meta value*/
|
||||
Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ)
|
||||
{
|
||||
if (a_PosIdx < a_SizeX)
|
||||
@ -245,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);
|
||||
}
|
||||
}
|
||||
} ;
|
||||
@ -258,9 +280,9 @@ protected:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cDungeonRoomsFinisher:
|
||||
|
||||
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
|
||||
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainShapeGenPtr a_ShapeGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
|
||||
super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024),
|
||||
m_HeightGen(a_HeightGen),
|
||||
m_ShapeGen(a_ShapeGen),
|
||||
m_MaxHalfSize((a_MaxSize + 1) / 2),
|
||||
m_MinHalfSize((a_MinSize + 1) / 2),
|
||||
m_HeightProbability(cChunkDef::Height)
|
||||
@ -293,13 +315,21 @@ cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int
|
||||
int ChunkX, ChunkZ;
|
||||
int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ;
|
||||
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
||||
cChunkDef::HeightMap HeightMap;
|
||||
m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
|
||||
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
|
||||
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
|
||||
cChunkDesc::Shape shape;
|
||||
m_ShapeGen->GenShape(ChunkX, ChunkZ, shape);
|
||||
int height = 0;
|
||||
int idx = RelX * 256 + RelZ * 16 * 256;
|
||||
for (int y = 6; y < cChunkDef::Height; y++)
|
||||
{
|
||||
if (shape[idx + y] != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, y - 5);
|
||||
}
|
||||
|
||||
// Create the dungeon room descriptor:
|
||||
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise));
|
||||
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, height, m_Noise));
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,15 +23,15 @@ class cDungeonRoomsFinisher :
|
||||
|
||||
public:
|
||||
/** Creates a new dungeon room finisher.
|
||||
a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain.
|
||||
a_ShapeGen is the underlying terrain shape generator, so that the rooms can always be placed under the terrain.
|
||||
a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across.
|
||||
a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */
|
||||
cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
|
||||
cDungeonRoomsFinisher(cTerrainShapeGenPtr a_ShapeGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
|
||||
|
||||
protected:
|
||||
|
||||
/** The height gen that is used for limiting the rooms' Y coords */
|
||||
cTerrainHeightGenPtr m_HeightGen;
|
||||
/** The shape gen that is used for limiting the rooms' Y coords */
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
|
||||
/** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */
|
||||
int m_MaxHalfSize;
|
||||
|
@ -147,13 +147,14 @@ bool cEndGen::IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
void cEndGen::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
// If the chunk is outside out range, fill the shape with zeroes:
|
||||
if (IsChunkOutsideRange(a_ChunkX, a_ChunkZ))
|
||||
{
|
||||
for (size_t i = 0; i < ARRAYCOUNT(a_HeightMap); i++)
|
||||
for (size_t i = 0; i < ARRAYCOUNT(a_Shape); i++)
|
||||
{
|
||||
a_HeightMap[i] = 0;
|
||||
a_Shape[i] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -165,15 +166,14 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, MaxY);
|
||||
for (int y = MaxY; y > 0; y--)
|
||||
for (int y = 0; y < MaxY; y++)
|
||||
{
|
||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
} // for y
|
||||
a_Shape[(x + 16 * z) * 256 + y] = (m_NoiseArray[y * 17 * 17 + z * 17 + z] > 0) ? 1 : 0;
|
||||
}
|
||||
for (int y = MaxY; y < cChunkDef::Height; y++)
|
||||
{
|
||||
a_Shape[(x + 16 * z) * 256 + y] = 0;
|
||||
}
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
@ -182,30 +182,18 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_
|
||||
|
||||
|
||||
|
||||
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
if (IsChunkOutsideRange(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()))
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
||||
|
||||
int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1);
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
for (int y = MaxY; y > 0; y--)
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0)
|
||||
if (a_Shape[(x + 16 * z) * 256 + y] != 0)
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_END_STONE, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_AIR, 0);
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_END_STONE);
|
||||
}
|
||||
} // for y
|
||||
} // for x
|
||||
|
@ -10,14 +10,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../Noise.h"
|
||||
#include "../Noise/Noise.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEndGen :
|
||||
public cTerrainHeightGen,
|
||||
public cTerrainShapeGen,
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
@ -59,10 +59,10 @@ protected:
|
||||
/// Returns true if the chunk is outside of the island's dimensions
|
||||
bool IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
// cTerrainShapeGen overrides:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "Globals.h"
|
||||
|
||||
#include "FinishGen.h"
|
||||
#include "../Noise.h"
|
||||
#include "../BlockID.h"
|
||||
#include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway()
|
||||
#include "../Simulator/FireSimulator.h"
|
||||
@ -27,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
|
||||
|
||||
|
||||
|
||||
@ -66,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)
|
||||
@ -196,10 +197,15 @@ 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;
|
||||
}
|
||||
|
||||
// Check if long grass can be placed:
|
||||
if (
|
||||
(a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) ||
|
||||
@ -277,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;
|
||||
@ -290,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++)
|
||||
{
|
||||
@ -315,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);
|
||||
@ -355,7 +361,7 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
}
|
||||
break;
|
||||
} // case E_BLOCK_GRASS
|
||||
|
||||
|
||||
case E_BLOCK_SAND:
|
||||
{
|
||||
int y = Top + 1;
|
||||
@ -366,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);
|
||||
@ -387,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:
|
||||
|
||||
@ -407,7 +480,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
case biFrozenOcean:
|
||||
{
|
||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)))
|
||||
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) && (Height < cChunkDef::Height - 1))
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
|
||||
a_ChunkDesc.SetHeight(x, z, Height + 1);
|
||||
@ -512,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;
|
||||
@ -712,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++)
|
||||
{
|
||||
@ -804,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--)
|
||||
{
|
||||
@ -847,7 +920,7 @@ bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static const struct
|
||||
{
|
||||
int x, y, z;
|
||||
@ -878,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;
|
||||
@ -887,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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -16,8 +16,9 @@
|
||||
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../Noise.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);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../Noise.h"
|
||||
#include "../Noise/Noise.h"
|
||||
|
||||
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cHeiGenFlat:
|
||||
|
||||
@ -133,15 +132,6 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap
|
||||
|
||||
|
||||
|
||||
void cHeiGenCache::InitializeHeightGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_HeiGenToCache->InitializeHeightGen(a_IniFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
||||
{
|
||||
for (int i = 0; i < m_CacheSize; i++)
|
||||
@ -159,6 +149,51 @@ bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_Rel
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cHeiGenMultiCache:
|
||||
|
||||
cHeiGenMultiCache::cHeiGenMultiCache(cTerrainHeightGenPtr a_HeiGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches):
|
||||
m_NumSubCaches(a_NumSubCaches)
|
||||
{
|
||||
// Create the individual sub-caches:
|
||||
m_SubCaches.reserve(a_NumSubCaches);
|
||||
for (size_t i = 0; i < a_NumSubCaches; i++)
|
||||
{
|
||||
m_SubCaches.push_back(std::make_shared<cHeiGenCache>(a_HeiGenToCache, a_SubCacheSize));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cHeiGenMultiCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
{
|
||||
// Get the subcache responsible for this chunk:
|
||||
const size_t cacheIdx = ((size_t)a_ChunkX + m_CoeffZ * (size_t)a_ChunkZ) % m_NumSubCaches;
|
||||
|
||||
// Ask the subcache:
|
||||
m_SubCaches[cacheIdx]->GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cHeiGenMultiCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
||||
{
|
||||
// Get the subcache responsible for this chunk:
|
||||
const size_t cacheIdx = ((size_t)a_ChunkX + m_CoeffZ * (size_t)a_ChunkZ) % m_NumSubCaches;
|
||||
|
||||
// Ask the subcache:
|
||||
return m_SubCaches[cacheIdx]->GetHeightAt(a_ChunkX, a_ChunkZ, a_RelX, a_RelZ, a_Height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cHeiGenClassic:
|
||||
|
||||
@ -750,39 +785,51 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
||||
}
|
||||
|
||||
a_CacheOffByDefault = false;
|
||||
cTerrainHeightGen * res = nullptr;
|
||||
if (NoCaseCompare(HeightGenName, "flat") == 0)
|
||||
cTerrainHeightGenPtr res;
|
||||
if (NoCaseCompare(HeightGenName, "Flat") == 0)
|
||||
{
|
||||
res = new cHeiGenFlat;
|
||||
res = std::make_shared<cHeiGenFlat>();
|
||||
a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "classic") == 0)
|
||||
{
|
||||
res = new cHeiGenClassic(a_Seed);
|
||||
res = std::make_shared<cHeiGenClassic>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
|
||||
{
|
||||
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "End") == 0)
|
||||
{
|
||||
res = new cEndGen(a_Seed);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
|
||||
{
|
||||
res = new cHeiGenMinMax(a_Seed, a_BiomeGen);
|
||||
res = std::make_shared<cHeiGenMinMax>(a_Seed, a_BiomeGen);
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
|
||||
{
|
||||
res = new cHeiGenMountains(a_Seed);
|
||||
res = std::make_shared<cHeiGenMountains>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
|
||||
{
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
|
||||
{
|
||||
res = new cNoise3DComposable(a_Seed);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "biomal") == 0)
|
||||
else if (NoCaseCompare(HeightGenName, "Biomal") == 0)
|
||||
{
|
||||
res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
|
||||
res = std::make_shared<cHeiGenBiomal>(a_Seed, a_BiomeGen);
|
||||
|
||||
/*
|
||||
// Performance-testing:
|
||||
@ -801,15 +848,14 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
||||
{
|
||||
// No match found, force-set the default and retry
|
||||
LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
|
||||
a_IniFile.DeleteValue("Generator", "HeightGen");
|
||||
a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
|
||||
return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||
}
|
||||
|
||||
// Read the settings:
|
||||
res->InitializeHeightGen(a_IniFile);
|
||||
|
||||
return cTerrainHeightGenPtr(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,10 +2,12 @@
|
||||
// HeiGen.h
|
||||
|
||||
/*
|
||||
Interfaces to the various height generators:
|
||||
Interfaces to the various height-based terrain shape generators:
|
||||
- cHeiGenFlat
|
||||
- cHeiGenClassic
|
||||
- cHeiGenBiomal
|
||||
|
||||
Also implements the heightmap cache
|
||||
*/
|
||||
|
||||
|
||||
@ -15,7 +17,79 @@ Interfaces to the various height generators:
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../Noise.h"
|
||||
#include "../Noise/Noise.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation */
|
||||
class cHeiGenCache :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
|
||||
~cHeiGenCache();
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
|
||||
/** Retrieves height at the specified point in the cache, returns true if found, false if not found */
|
||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||
|
||||
protected:
|
||||
struct sCacheData
|
||||
{
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
cChunkDef::HeightMap m_HeightMap;
|
||||
} ;
|
||||
|
||||
/** The terrain height generator that is being cached. */
|
||||
cTerrainHeightGenPtr m_HeiGenToCache;
|
||||
|
||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||
int m_CacheSize;
|
||||
int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
|
||||
sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
|
||||
|
||||
// Cache statistics
|
||||
int m_NumHits;
|
||||
int m_NumMisses;
|
||||
int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Caches heightmaps in multiple underlying caches to improve the distribution and lower the chain length. */
|
||||
class cHeiGenMultiCache:
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cHeiGenMultiCache(cTerrainHeightGenPtr a_HeightGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches);
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
|
||||
/** Retrieves height at the specified point in the cache, returns true if found, false if not found */
|
||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||
|
||||
protected:
|
||||
typedef SharedPtr<cHeiGenCache> cHeiGenCachePtr;
|
||||
typedef std::vector<cHeiGenCachePtr> cHeiGenCachePtrs;
|
||||
|
||||
|
||||
/** The coefficient used to turn Z coords into index (x + Coeff * z). */
|
||||
static const size_t m_CoeffZ = 5;
|
||||
|
||||
/** Number of sub-caches, pulled out of m_SubCaches.size() for performance reasons. */
|
||||
size_t m_NumSubCaches;
|
||||
|
||||
/** The individual sub-caches. */
|
||||
cHeiGenCachePtrs m_SubCaches;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -40,47 +114,6 @@ protected:
|
||||
|
||||
|
||||
|
||||
/// A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation
|
||||
class cHeiGenCache :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
|
||||
~cHeiGenCache();
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
/// Retrieves height at the specified point in the cache, returns true if found, false if not found
|
||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||
|
||||
protected:
|
||||
|
||||
cTerrainHeightGenPtr m_HeiGenToCache;
|
||||
|
||||
struct sCacheData
|
||||
{
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
cChunkDef::HeightMap m_HeightMap;
|
||||
} ;
|
||||
|
||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||
int m_CacheSize;
|
||||
int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
|
||||
sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
|
||||
|
||||
// Cache statistics
|
||||
int m_NumHits;
|
||||
int m_NumMisses;
|
||||
int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cHeiGenClassic :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
@ -137,7 +170,11 @@ public:
|
||||
m_BiomeGen(a_BiomeGen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
protected:
|
||||
|
||||
typedef cChunkDef::BiomeMap BiomeNeighbors[3][3];
|
||||
@ -154,11 +191,8 @@ protected:
|
||||
float m_BaseHeight;
|
||||
} ;
|
||||
static const sGenParam m_GenParam[256];
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
|
||||
|
||||
NOISE_DATATYPE GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX, int a_ChunkZ, const BiomeNeighbors & a_BiomeNeighbors);
|
||||
} ;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user