diff options
415 files changed, 11874 insertions, 12388 deletions
diff --git a/.gitignore b/.gitignore index 6afc12116..b85b172cb 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ AllFiles.lst *.*~ *~ *.orig +## CLion +.idea ## Eclipse .cproject .project diff --git a/.gitmodules b/.gitmodules index 8e63ee0a9..d2ce2c855 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,21 @@ [submodule "MCServer/Plugins/TransAPI"] path = MCServer/Plugins/TransAPI url = https://github.com/bearbin/transapi.git +[submodule "MCServer/Plugins/ChunkWorx"] + path = MCServer/Plugins/ChunkWorx + url = https://github.com/mc-server/ChunkWorx.git +[submodule "MCServer/Plugins/ChatLog"] + path = MCServer/Plugins/ChatLog + url = https://github.com/mc-server/ChatLog.git +[submodule "MCServer/Plugins/Handy"] + path = MCServer/Plugins/Handy + url = https://github.com/mc-server/Handy.git +[submodule "MCServer/Plugins/MagicCarpet"] + path = MCServer/Plugins/MagicCarpet + url = https://github.com/mc-server/MagicCarpet.git [submodule "lib/polarssl"] path = lib/polarssl - url = https://github.com/mc-server/polarssl + url = https://github.com/mc-server/polarssl.git [submodule "lib/SQLiteCpp"] path = lib/SQLiteCpp url = https://github.com/mc-server/SQLiteCpp.git diff --git a/Android/res/values-pl/strings.xml b/Android/res/values-pl/strings.xml new file mode 100644 index 000000000..74c8044d8 --- /dev/null +++ b/Android/res/values-pl/strings.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="hello">Hello World, MCServerActivity!</string> + <string name="app_name">MCServer</string> + <string name="start">Start</string> + <string name="stop">Stop</string> + <string name="mcserver_is_running">MCServer jest włączony</string> + <string name="mcserver_is_not_running">MCServer jest wyłączony</string> + <string name="your_ip">Twoje IP …</string> + <string name="configure">Ustawienia</string> + +</resources> diff --git a/CMakeLists.txt b/CMakeLists.txt index 188cf81e3..d4e9d41e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,21 @@ if(DEFINED ENV{MCSERVER_BUILD_ID}) endif() endif() +# We need C++11 features, Visual Studio has those from VS2012, but it needs a new platform toolset for those; VS2013 supports them natively: +# Adapted from http://binglongx.wordpress.com/2013/06/28/set-non-default-platform-toolset-in-cmake/ +if(MSVC OR MSVC_IDE) + if( MSVC_VERSION LESS 1700 ) # VC10- / VS2010- + message(FATAL_ERROR "The project requires C++11 features. " + "You need at least Visual Studio 11 (Microsoft Visual Studio 2012), " + "with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012).") + elseif( MSVC_VERSION EQUAL 1700 ) # VC11 / VS2012 + message( "VC11: using Microsoft Visual Studio 2012 " + "with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012)" ) + set(CMAKE_GENERATOR_TOOLSET "v120_CTP_Nov2012" CACHE STRING "Platform Toolset" FORCE) + else() # VC12+, assuming C++11 supported. + endif() +endif() + # This has to be done before any flags have been set up. if(${BUILD_TOOLS}) add_subdirectory(Tools/MCADefrag/) @@ -81,7 +96,6 @@ set(SQLITECPP_BUILD_TESTS OFF CACHE BOOL "Build and run tests." set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "Add the internal SQLite3 source to the project." FORCE) # Include all the libraries: -add_subdirectory(lib/inifile/) add_subdirectory(lib/jsoncpp/) add_subdirectory(lib/zlib/) add_subdirectory(lib/lua/) diff --git a/COMPILING.md b/COMPILING.md index ea6b580d5..731d64653 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -4,9 +4,8 @@ To compile MCServer from source, you need CMake and make, as well as a C compile ## Windows ## -We use Microsoft Visual Studio for Windows compilation. It is possible to use other toolchains, but it isn't tested nor supported. Visual Studio versions 2008 Express and 2013 Express are being actively used for development, so either should work. -You can find download links for VS2008 Express here: http://stackoverflow.com/questions/15318560/visual-c-2008-express-download-link-dead -And VS2013 Express here: http://www.microsoft.com/en-us/download/details.aspx?id=40787 +We use Microsoft Visual Studio for Windows compilation. It is possible to use other toolchains, but it isn't tested nor supported. Visual Studio versions 2013 Express is being actively used for development. +You can find download links for VS2013 Express here: http://www.microsoft.com/en-us/download/details.aspx?id=40787 Next, you need to download and install CMake. Download from here: http://cmake.org/cmake/resources/software.html . You should download a full installation package, so that the installer will set everything up for you (especially the paths). diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2d911a11d..8620a1475 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -4,12 +4,14 @@ BasedDoge (Donated AlchemistVillage prefabs) bearbin (Alexander Harkness) derouinw Diusrex -Duralex +Duralex FakeTruth (founder) +Howaner keyboard Lapayo Luksor marmot21 +Masy98 mborland mgueydan MikeHunsinger @@ -18,6 +20,7 @@ nesco rs2k SamJBarney Sofapriester +SphinxC0re STR_Warrior structinf (xdot) Sxw1212 @@ -25,10 +28,9 @@ Taugeshtu tigerw (Tiger Wang) tonibm19 UltraCoderRU +WebFreak001 worktycho xoft Yeeeeezus (Donated AlchemistVillage prefabs) -Howaner -Masy98 Please add yourself to this list if you contribute to MCServer. diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index e6ee4ca10..9b87781a6 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -524,22 +524,29 @@ end Functions = { GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 32-char UUID (no dashes)." }, + GetClientBrand = { Params = "", Return = "string", Notes = "Returns the brand that the client has sent in their MC|Brand plugin message." }, GetIPString = { Params = "", Return = "string", Notes = "Returns the IP address of the connection, as a string. Only the address part is returned, without the port number." }, GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." }, GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" }, GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." }, + GetProtocolVersion = { Params = "", Return = "number", Notes = "Returns the protocol version number of the protocol that the client is talking. Returns zero if the protocol version is not (yet) known." }, GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" }, 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" }, SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." }, + SetClientBrand = { Params = "ClientBrand", Return = "", Notes = "Sets the value of the client's brand. Normally this value is received from the client by a MC|Brand plugin message, this function lets plugins overwrite the value." }, SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." }, SetUsername = { Params = "Name", Return = "", Notes = "Sets the username" }, SetViewDistance = { Params = "ViewDistance", Return = "", Notes = "Sets the viewdistance (number of chunks loaded for the player in each direction)" }, SendBlockChange = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sends a BlockChange packet to the client. This can be used to create fake blocks only for that player." }, + SendEntityAnimation = { Params = "{{cEntity|Entity}}, AnimationNumber", Return = "", Notes = "Sends the specified animation of the specified entity to the client. The AnimationNumber is protocol-specific." }, + SendSoundEffect = { Params = "SoundName, X, Y, Z, Volume, Pitch", Return = "", Notes = "Sends a sound effect request to the client. The sound is played at the specified coords, with the specified volume (a float, 1.0 is full volume, can be more) and pitch (0-255, 63 is 100%)" }, + SendTimeUpdate = { Params = "WorldAge, TimeOfDay, DoDaylightCycle", Return = "", Notes = "Sends the specified time update to the client. WorldAge is the total age of the world, in ticks. TimeOfDay is the current day's time, in ticks (0 - 24000). DoDaylightCycle is a bool that specifies whether the client should automatically move the sun (true) or keep it in the same place (false)." }, }, Constants = { @@ -555,9 +562,9 @@ end and commands suggested on click. The chat message can be sent by the regular chat-sending functions, {{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p> <p> - Note that most of the functions in this class are so-called modifiers - they modify the object and - then return the object itself, so that they can be chained one after another. See the Chaining - example below for details.</p> + Note that most of the functions in this class are so-called chaining modifiers - they modify the + object and then return the object itself, so that they can be chained one after another. See the + Chaining example below for details.</p> <p> Each part of the composite chat message takes a "Style" parameter, this is a string that describes the formatting. It uses the following strings, concatenated together: @@ -581,14 +588,17 @@ end { Params = "Text", Return = "", Notes = "Creates a chat message containing the specified text, parsed by the ParseText() function. This allows easy migration from old chat messages." }, }, AddRunCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, runs the specified command. Chaining." }, + AddShowAchievementPart = { Params = "PlayerName, AchievementName, [Style]", Return = "", Notes = "Adds a text that represents the 'Achievement get' message." }, AddSuggestCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, puts the specified command into the player's chat input area. Chaining." }, AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." }, AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." }, Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" }, + CreateJsonString = { Params = "[AddPrefixes]", Return = "string", Notes = "Returns the entire object serialized into JSON, as it would be sent to a client. AddPrefixes specifies whether the chat prefixes should be prepended to the message, true by default." }, ExtractText = { Params = "", Return = "string", Notes = "Returns the text from the parts that comprises the human-readable data. Used for older protocols that don't support composite chat and for console-logging." }, + GetAdditionalMessageTypeData = { Params = "", Return = "string", Notes = "Returns the AdditionalData associated with the message, such as the sender's name for mtPrivateMessage" }, GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" }, ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." }, - SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." }, + SetMessageType = { Params = "MessageType, AdditionalData", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. Also sets the additional data (string) associated with the message, which is specific for the message type - such as the sender's name for mtPrivateMessage. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.). Chaining." }, UnderlineUrls = { Params = "", Return = "self", Notes = "Makes all URL parts contained in the message underlined. Doesn't affect parts added in the future. Chaining." }, }, @@ -605,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 @@ -777,7 +787,9 @@ end</pre> AddSpeedX = { Params = "AddX", Return = "", Notes = "Adds the specified amount of speed in the X axis direction." }, AddSpeedY = { Params = "AddY", Return = "", Notes = "Adds the specified amount of speed in the Y axis direction." }, AddSpeedZ = { Params = "AddZ", Return = "", Notes = "Adds the specified amount of speed in the Z axis direction." }, + ArmorCoversAgainst = { Params = "{{cEntity|AttackerEntity}}, DamageType, RawDamage", Return = "number", Notes = "Returns the points out of a_RawDamage that the currently equipped armor would cover." }, Destroy = { Params = "", Return = "", Notes = "Schedules the entity to be destroyed" }, + GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." }, GetArmorCoverAgainst = { Params = "AttackerEntity, DamageType, RawDamage", Return = "number", Notes = "Returns the number of hitpoints out of RawDamage that the currently equipped armor would cover. See {{TakeDamageInfo}} for more information on attack damage." }, GetChunkX = { Params = "", Return = "number", Notes = "Returns the X-coord of the chunk in which the entity is placed" }, GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the chunk in which the entity is placed" }, @@ -793,6 +805,7 @@ end</pre> GetHeadYaw = { Params = "", Return = "number", Notes = "Returns the pitch of the entity's head (FIXME: Rename to GetHeadPitch() )." }, GetHealth = { Params = "", Return = "number", Notes = "Returns the current health of the entity." }, GetHeight = { Params = "", Return = "number", Notes = "Returns the height (Y size) of the entity" }, + GetInvulnerableTicks = { Params = "", Return = "number", Notes = "Returns the number of ticks that this entity will be invulnerable for. This is used for after-hit recovery - the entities are invulnerable for half a second after being hit." }, GetKnockbackAmountAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the amount of knockback that the currently equipped items would cause when attacking the ReceiverEntity." }, GetLookVector = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the vector that defines the direction in which the entity is looking" }, GetMass = { Params = "", Return = "number", Notes = "Returns the mass of the entity. Currently unused." }, @@ -810,23 +823,29 @@ end</pre> GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" }, GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" }, GetSpeedZ = { Params = "", Return = "number", Notes = "Returns the Z-part of the speed vector" }, + GetTicksAlive = { Params = "", Return = "number", Notes = "Returns the number of ticks that this entity has been alive for." }, GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity within the running server. Note that this ID is not persisted to the data files." }, GetWidth = { Params = "", Return = "number", Notes = "Returns the width (X and Z size) of the entity." }, GetWorld = { Params = "", Return = "{{cWorld}}", Notes = "Returns the world where the entity resides" }, GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. Measured in degrees, values range from -180 to +180. 0 means ZP, 90 means XM, -180 means ZM, -90 means XP." }, + HandleSpeedFromAttachee = { Params = "ForwardAmount, SidewaysAmount", Return = "", Notes = "Updates the entity's speed based on the attachee exerting the specified force forward and sideways. Used for entities being driven by other entities attached to them - usually players driving minecarts and boats." }, Heal = { Params = "Hitpoints", Return = "", Notes = "Heals the specified number of hitpoints. Hitpoints is expected to be a positive number." }, IsA = { Params = "ClassName", Return = "bool", Notes = "Returns true if the entity class is a descendant of the specified class name, or the specified class itself" }, IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." }, IsCrouched = { Params = "", Return = "bool", Notes = "Returns true if the entity is crouched. Always false for entities that don't support crouching." }, IsDestroyed = { Params = "", Return = "bool", Notes = "Returns true if the entity has been destroyed and is awaiting removal from the internal structures." }, + IsEnderCrystal = { Params = "", Return = "bool", Notes = "Returns true if the entity is an ender crystal." }, IsExpOrb = { Params = "", Return = "bool", Notes = "Returns true if the entity represents an experience orb" }, IsFallingBlock = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cFallingBlock}} entity." }, + IsFireproof = { Params = "", Return = "bool", Notes = "Returns true if the entity takes no damage from being on fire." }, IsFloater = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a fishing rod floater" }, IsInvisible = { Params = "", Return = "bool", Notes = "Returns true if the entity is invisible" }, + IsItemFrame = { Params = "", Return = "bool", Notes = "Returns true if the entity is an item frame." }, IsMinecart = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cMinecart|minecart}}" }, IsMob = { Params = "", Return = "bool", Notes = "Returns true if the entity represents any {{cMonster|mob}}." }, IsOnFire = { Params = "", Return = "bool", Notes = "Returns true if the entity is on fire" }, IsPainting = { Params = "", Return = "bool", Notes = "Returns if this entity is a painting." }, + IsPawn = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cPawn}} descendant." }, IsPickup = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPickup|pickup}}." }, IsPlayer = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPlayer|player}}" }, IsProjectile = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cProjectileEntity}} descendant." }, @@ -836,12 +855,19 @@ end</pre> IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is submerged in water (head is in a water block). Note, this function is only updated with mobs or players." }, IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is swimming in water (feet are in a water block). Note, this function is only updated with mobs or players." }, IsTNT = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cTNTEntity|TNT entity}}" }, + Killed = { Params = "{{cEntity|Victim}}", Return = "", Notes = "This entity has killed another entity (the Victim). For players, adds the scoreboard statistics about the kill." }, KilledBy = { Notes = "FIXME: Remove this from API" }, - GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." }, + MoveToWorld = + { + { Params = "{{cWorld|World}}, [ShouldSendRespawn]", Return = "bool", Notes = "Removes the entity from this world and starts moving it to the specified world. Note that to avoid deadlocks, the move is asynchronous - the entity is moved into a queue and will be moved from that queue into the destination world at some (unpredictable) time in the future. ShouldSendRespawn is used only for players, it specifies whether the player should be sent a Repawn packet upon leaving the world (The client handles respawns only between different dimensions)." }, + { Params = "WorldName, [ShouldSendRespawn]", Return = "bool", Notes = "Removes the entity from this world and starts moving it to the specified world. Note that to avoid deadlocks, the move is asynchronous - the entity is moved into a queue and will be moved from that queue into the destination world at some (unpredictable) time in the future. ShouldSendRespawn is used only for players, it specifies whether the player should be sent a Repawn packet upon leaving the world (The client handles respawns only between different dimensions)." }, + }, SetGravity = { Params = "Gravity", Return = "", Notes = "Sets the number that is used as the gravity for physics simulation. 1G (9.78) by default." }, SetHeadYaw = { Params = "HeadPitch", Return = "", Notes = "Sets the head pitch (FIXME: Rename to SetHeadPitch() )." }, SetHealth = { Params = "Hitpoints", Return = "", Notes = "Sets the entity's health to the specified amount of hitpoints. Doesn't broadcast any hurt animation. Doesn't kill the entity if health drops below zero. Use the TakeDamage() function instead for taking damage." }, SetHeight = { Params = "", Return = "", Notes = "FIXME: Remove this from API" }, + SetInvulnerableTicks = { Params = "NumTicks", Return = "", Notes = "Sets the amount of ticks for which the entity will not receive any damage from other entities." }, + SetIsFireproof = { Params = "IsFireproof", Return = "", Notes = "Sets whether the entity receives damage from being on fire." }, SetMass = { Params = "Mass", Return = "", Notes = "Sets the mass of the entity. Currently unused." }, SetMaxHealth = { Params = "MaxHitpoints", Return = "", Notes = "Sets the maximum hitpoints of the entity. If current health is above MaxHitpoints, it is capped to MaxHitpoints." }, SetPitch = { Params = "number", Return = "", Notes = "Sets the pitch (nose-down rotation) of the entity" }, @@ -856,7 +882,7 @@ end</pre> SetPosZ = { Params = "number", Return = "", Notes = "Sets the Z-coord of the entity's pivot" }, SetRoll = { Params = "number", Return = "", Notes = "Sets the roll (sideways rotation) of the entity. Currently unused." }, SetRot = { Params = "{{Vector3f|Rotation}}", Return = "", Notes = "Sets the entire rotation vector (Yaw, Pitch, Roll)" }, - SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" }, + SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves)." }, SetSpeed = { { Params = "SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Sets the current speed of the entity" }, @@ -882,18 +908,20 @@ end</pre> Constants = { etBoat = { Notes = "The entity is a {{cBoat}}" }, + etEnderCrystal = { Notes = "" }, etEntity = { Notes = "No further specialization available" }, etExpOrb = { Notes = "The entity is a {{cExpOrb}}" }, etFallingBlock = { Notes = "The entity is a {{cFallingBlock}}" }, etFloater = { Notes = "The entity is a fishing rod floater" }, + etItemFrame = { Notes = "" }, + etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" }, etMob = { Notes = "The entity is a {{cMonster}} descendant" }, etMonster = { Notes = "The entity is a {{cMonster}} descendant" }, - etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" }, - etPlayer = { Notes = "The entity is a {{cPlayer}}" }, + etPainting = { Notes = "The entity is a {{cPainting}}" }, etPickup = { Notes = "The entity is a {{cPickup}}" }, + etPlayer = { Notes = "The entity is a {{cPlayer}}" }, etProjectile = { Notes = "The entity is a {{cProjectileEntity}} descendant" }, etTNT = { Notes = "The entity is a {{cTNTEntity}}" }, - etPainting = { Notes = "The entity is a {{cPainting}}" }, }, ConstantGroups = { @@ -1043,6 +1071,7 @@ ValueName0=SomeOtherValue GetValueSetB = { Params = "KeyName, ValueName, Default", Return = "bool", Notes = "Returns the value of the specified name under the specified key, as a bool. If the value doesn't exist, creates it with the specified default." }, GetValueSetF = { Params = "KeyName, ValueName, Default", Return = "number", Notes = "Returns the value of the specified name under the specified key, as a floating-point number. If the value doesn't exist, creates it with the specified default." }, GetValueSetI = { Params = "KeyName, ValueName, Default", Return = "number", Notes = "Returns the value of the specified name under the specified key, as an integer. If the value doesn't exist, creates it with the specified default." }, + HasValue = { Params = "KeyName, ValueName", Return = "bool", Notes = "Returns true if the specified value is present." }, ReadFile = { Params = "FileName, [AllowExampleFallback]", Return = "bool", Notes = "Reads the values from the specified file. Previous in-memory contents are lost. If the file cannot be opened, and AllowExample is true, another file, \"filename.example.ini\", is loaded and then saved as \"filename.ini\". Returns true if successful, false if not." }, SetValue = { @@ -1740,6 +1769,7 @@ a_Player:OpenWindow(Window); GetItem = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item represented by this pickup" }, IsCollected = { Params = "", Return = "bool", Notes = "Returns true if this pickup has already been collected (is waiting to be destroyed)" }, IsPlayerCreated = { Params = "", Return = "bool", Notes = "Returns true if the pickup was created by a player" }, + SetAge = { Params = "AgeTicks", Return = "", Notes = "Sets the pickup's age, in ticks." }, }, Inherits = "cEntity", }, -- cPickup @@ -1764,8 +1794,8 @@ a_Player:OpenWindow(Window); ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." }, GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." }, GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player's messages (based on their rank). Prefix player messages with this code." }, - GetPlayerListName = { Return = "string", Notes = "Returns the name that is used in the playerlist." }, GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" }, + GetCustomName = { Params = "", Return = "string", Notes = "Returns the custom name of this player. If the player hasn't a custom name, it will return an empty string." }, GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." }, GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." }, GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" }, @@ -1780,18 +1810,24 @@ a_Player:OpenWindow(Window); GetGameMode = { Return = "{{Globals#GameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."}, GetIP = { Return = "string", Notes = "Returns the IP address of the player, if available. Returns an empty string if there's no IP to report."}, GetInventory = { Return = "{{cInventory|Inventory}}", Notes = "Returns the player's inventory"}, + GetLastBedPos = { Params = "", Return = "{{Vector3i}}", Notes = "Returns the position of the last bed the player has slept in, or the world's spawn if no such position was recorded." }, GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status." }, GetName = { Return = "string", Notes = "Returns the player's name" }, GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed, relative to the game default speed. Defaults to 1, but plugins may modify it for faster or slower walking." }, + GetPermissions = { Params = "", Return = "array-table of strings", Notes = "Returns the list of all permissions that the player has assigned to them through their rank." }, + GetPlayerListName = { Return = "string", Notes = "Returns the name that is used in the playerlist." }, GetResolvedPermissions = { Return = "array-table of string", Notes = "Returns all the player's permissions, as a table. The permissions are stored in the array part of the table, beginning with index 1." }, GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed, relative to the game default speed. Defaults to 1.3, but plugins may modify it for faster or slower sprinting." }, GetStance = { Return = "number", Notes = "Returns the player's stance (Y-pos of player's eyes)" }, + GetTeam = { Params = "", Return = "{{cTeam}}", Notes = "Returns the team that the player belongs to, or nil if none." }, GetThrowSpeed = { Params = "SpeedCoeff", Return = "{{Vector3d}}", Notes = "Returns the speed vector for an object thrown with the specified speed coeff. Basically returns the normalized look vector multiplied by the coeff, with a slight random variation." }, GetThrowStartPos = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the position where the projectiles should start when thrown by this player." }, + GetUUID = { Params = "", Return = "string", Notes = "Returns the (short) UUID that the player is using. Could be empty string for players that don't have a Mojang account assigned to them (in the future, bots for example)." }, GetWindow = { Params = "", Return = "{{cWindow}}", Notes = "Returns the currently open UI window. If the player doesn't have any UI window open, returns the inventory window." }, GetXpLevel = { Params = "", Return = "number", Notes = "Returns the current XP level (based on current XP amount)." }, GetXpLifetimeTotal = { Params = "", Return = "number", Notes = "Returns the amount of XP that has been accumulated throughout the player's lifetime." }, GetXpPercentage = { Params = "", Return = "number", Notes = "Returns the percentage of the experience bar - the amount of XP towards the next XP level. Between 0 and 1." }, + HasCustomName = { Params = "", Return = "bool", Notes = "Returns true if the player has a custom name." }, HasPermission = { Params = "PermissionString", Return = "bool", Notes = "Returns true if the player has the specified permission" }, Heal = { Params = "HitPoints", Return = "", Notes = "Heals the player by the specified amount of HPs. Only positive amounts are expected. Sends a health update to the client." }, IsEating = { Params = "", Return = "bool", Notes = "Returns true if the player is currently eating the item in their hand." }, @@ -1799,7 +1835,9 @@ a_Player:OpenWindow(Window); IsFlying = { Return = "bool", Notes = "Returns true if the player is flying." }, IsGameModeAdventure = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmAdventure gamemode, or has their gamemode unset and the world is a gmAdventure world." }, IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmCreative gamemode, or has their gamemode unset and the world is a gmCreative world." }, + IsGameModeSpectator = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmSpectator gamemode, or has their gamemode unset and the world is a gmSpectator world." }, IsGameModeSurvival = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmSurvival gamemode, or has their gamemode unset and the world is a gmSurvival world." }, + IsInBed = { Params = "", Return = "bool", Notes = "Returns true if the player is currently lying in a bed." }, IsOnGround = { Params = "", Return = "bool", Notes = "Returns true if the player is on ground (not falling, not jumping, not flying)" }, IsSatiated = { Params = "", Return = "bool", Notes = "Returns true if the player is satiated (cannot eat)." }, IsVisible = { Params = "", Return = "bool", Notes = "Returns true if the player is visible to other players" }, @@ -1807,6 +1845,7 @@ a_Player:OpenWindow(Window); MoveTo = { Params = "{{Vector3d|NewPosition}}", Return = "Tries to move the player into the specified position." }, MoveToWorld = { Params = "WorldName", Return = "bool", Return = "Moves the player to the specified world. Returns true if successful." }, OpenWindow = { Params = "{{cWindow|Window}}", Return = "", Notes = "Opens the specified UI window for the player." }, + PermissionMatches = { Params = "Permission, Template", Return = "bool", Notes = "(STATIC) Returns true if the specified permission matches the specified template. The template may contain wildcards." }, Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." }, SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." }, SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." }, @@ -1815,12 +1854,12 @@ a_Player:OpenWindow(Window); SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." }, SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." }, SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." }, - HasCustomName = { Params = "", Return = "bool", Notes = "Returns true if the player has a custom name." }, - GetCustomName = { Params = "", Return = "string", Notes = "Returns the custom name of this player. If the player hasn't a custom name, it will return an empty string." }, - SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of this player. If you want to disable the custom name, simply set an empty string. The custom name will be used in the tab-list, in the player nametag and in the tab-completion." }, + SendRotation = { Params = "YawDegrees, PitchDegrees", Return = "", Notes = "Sends the specified rotation to the player, forcing them to look that way" }, + SetBedPos = { Params = "{{Vector3i|Position}}", Return = "", Notes = "Sets the internal representation of the last bed position the player has slept in. The player will respawn at this position if they die." }, SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." }, SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." }, SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." }, + SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of this player. If you want to disable the custom name, simply set an empty string. The custom name will be used in the tab-list, in the player nametag and in the tab-completion." }, SetFlying = { Params = "IsFlying", Notes = "Sets if the player is flying or not." }, SetFlyingMaxSpeed = { Params = "FlyingMaxSpeed", Return = "", Notes = "Sets the flying maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client." }, SetFoodExhaustionLevel = { Params = "ExhaustionLevel", Return = "", Notes = "Sets the food exhaustion to the specified level." }, @@ -1834,7 +1873,11 @@ a_Player:OpenWindow(Window); SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client, if appropriate." }, SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." }, SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed, relative to the game default speed. The default value is 1.3. Sends the updated speed to the client, if appropriate." }, + SetTeam = { Params = "{{cTeam|Team}}", Return = "", Notes = "Moves the player to the specified team." }, SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" }, + TossEquippedItem = { Params = "[Amount]", Return = "", Notes = "Tosses the item that the player has selected in their hotbar. Amount defaults to 1." }, + TossHeldItem = { Params = "[Amount]", Return = "", Notes = "Tosses the item held by the cursor, then the player is in a UI window. Amount defaults to 1." }, + TossPickup = { Params = "{{cItem|Item}}", Return = "", Notes = "Tosses a pickup newly created from the specified item." }, XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." }, }, Constants = @@ -1984,6 +2027,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); HOOK_PLAYER_USING_ITEM = { Notes = "Called when the player is about to right-click with a usable item in their hand." }, HOOK_POST_CRAFTING = { Notes = "Called after a valid recipe has been chosen for the current contents of the crafting grid. Plugins may modify the recipe." }, HOOK_PRE_CRAFTING = { Notes = "Called before a recipe is searched for the current contents of the crafting grid. Plugins may provide a recipe and cancel the built-in search." }, + HOOK_SERVER_PING = { Notes = "Called when a client pings the server from the server list. Plugins may change the favicon, server description, players online and maximum players values." }, HOOK_SPAWNED_ENTITY = { Notes = "Called after an entity is spawned in a {{cWorld|world}}. The entity is already part of the world." }, HOOK_SPAWNED_MONSTER = { Notes = "Called after a mob is spawned in a {{cWorld|world}}. The mob is already part of the world." }, HOOK_SPAWNING_ENTITY = { Notes = "Called just before an entity is spawned in a {{cWorld|world}}." }, @@ -2033,8 +2077,10 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); AddGroupToRank = { Params = "GroupName, RankName", Return = "bool", Notes = "Adds the specified group to the specified rank. Returns true on success, false on failure - if the group name or the rank name is not found." }, AddPermissionToGroup = { Params = "Permission, GroupName", Return = "bool", Notes = "Adds the specified permission to the specified group. Returns true on success, false on failure - if the group name is not found." }, AddRank = { Params = "RankName, MsgPrefix, MsgSuffix, MsgNameColorCode", Return = "", Notes = "Adds a new rank of the specified name and with the specified message visuals. Logs an info message and does nothing if the rank already exists." }, + ClearPlayerRanks = { Params = "", Return = "", Notes = "Removes all player ranks from the database. Note that this doesn't change the cPlayer instances for the already connected players, you need to update all the instances manually." }, GetAllGroups = { Params = "", Return = "array-table of groups' names", Notes = "Returns an array-table containing the names of all the groups that are known to the manager." }, GetAllPermissions = { Params = "", Return = "array-table of permissions", Notes = "Returns an array-table containing all the permissions that are known to the manager." }, + GetAllPlayerUUIDs = { Params = "", Return = "array-table of uuids", Notes = "Returns the short uuids of all players stored in the rank DB, sorted by the players' names (case insensitive)." }, GetAllRanks = { Params = "", Return = "array-table of ranks' names", Notes = "Returns an array-table containing the names of all the ranks that are known to the manager." }, GetDefaultRank = { Params = "", Return = "string", Notes = "Returns the name of the default rank. " }, GetGroupPermissions = { Params = "GroupName", Return = "array-table of permissions", Notes = "Returns an array-table containing the permissions that the specified group contains." }, @@ -2042,6 +2088,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); GetPlayerMsgVisuals = { Params = "PlayerUUID", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals assigned to the player. If the player is not explicitly assigned a rank, the default rank's visuals are returned. If there is an error, no value is returned at all." }, GetPlayerPermissions = { Params = "PlayerUUID", Return = "array-table of permissions", Notes = "Returns the permissions that the specified player is assigned through their rank. Returns the default rank's permissions if the player has no explicit rank assigned to them. Returns an empty array on error." }, GetPlayerRankName = { Params = "PlayerUUID", Return = "RankName", Notes = "Returns the name of the rank that is assigned to the specified player. An empty string (NOT the default rank) is returned if the player has no rank assigned to them." }, + GetPlayerName = { Params = "PlayerUUID", Return = "PlayerName", Notes = "Returns the last name that the specified player has, for a player in the ranks database. An empty string is returned if the player isn't in the database." }, GetRankGroups = { Params = "RankName", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of all the groups that are assigned to the specified rank. Returns an empty table if there is no such rank." }, GetRankPermissions = { Params = "RankName", Return = "array-table of permissions", Notes = "Returns an array-table of all the permissions that are assigned to the specified rank through its groups. Returns an empty table if there is no such rank." }, GetRankVisuals = { Params = "RankName", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals for the specified rank. Returns no value if the specified rank does not exist." }, @@ -2076,14 +2123,22 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); ]], Functions = { - BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server. No formatting is done by the server." }, - BroadcastChatFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." }, - BroadcastChatFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." }, - BroadcastChatInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." }, - BroadcastChatSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." }, - BroadcastChatWarning = { Params = "Message", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. 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." }, + BroadcastChat = + { + { Params = "MessageText, MessageType", Return = "", Notes = "Broadcasts a message to all players, with its message type set to MessageType (default: mtCustom)." }, + { Params = "{{cCompositeChat|CompositeChat}}", Return = "", Notes = "Broadcasts a {{cCompositeChat|composite chat message} to all players." }, + }, + BroadcastChatDeath = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtDeath. Use for when a player has died." }, + BroadcastChatFailure = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtFailure. Use for a command that failed to run because of insufficient permissions, etc." }, + BroadcastChatFatal = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtFatal. Use for a plugin that crashed, or similar." }, + BroadcastChatInfo = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtInfo. Use for informational messages, such as command usage." }, + BroadcastChatJoin = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtJoin. Use for players joining the server." }, + BroadcastChatLeave = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtLeave. Use for players leaving the server." }, + BroadcastChatSuccess = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtSuccess. Use for success messages." }, + 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." }, @@ -2353,6 +2408,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." }, @@ -2444,7 +2500,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." }, @@ -2459,7 +2515,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)." }, @@ -2814,7 +2870,7 @@ end Globals = { Desc = [[ - These functions are available directly, without a class instance. Any plugin cal call them at any + These functions are available directly, without a class instance. Any plugin can call them at any time. ]], Functions = diff --git a/MCServer/Plugins/APIDump/Classes/Projectiles.lua b/MCServer/Plugins/APIDump/Classes/Projectiles.lua index 08c981e5d..748f58b71 100644 --- a/MCServer/Plugins/APIDump/Classes/Projectiles.lua +++ b/MCServer/Plugins/APIDump/Classes/Projectiles.lua @@ -35,12 +35,49 @@ return Inherits = "cProjectileEntity", }, -- cArrowEntity + cExpBottleEntity = + { + Desc = [[ + Represents a thrown ExpBottle. A subclass of the {{cProjectileEntity}}. + ]], + Functions = + { + }, + Inherits = "cProjectileEntity", + }, -- cExpBottleEntity + cFireChargeEntity = { - Desc = "", + Desc = [[ + Represents a fire charge that has been shot by a Blaze or a {{cDispenserEntity|Dispenser}}. A subclass + of the {{cProjectileEntity}}. + ]], Functions = {}, Inherits = "cProjectileEntity", }, -- cFireChargeEntity + + cFireworkEntity = + { + Desc = [[ + Represents a firework rocket. + ]], + Functions = + { + GetItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that has been used to create the firework rocket. The item's m_FireworkItem member contains all the firework-related data." }, + GetTicksToExplosion = { Params = "", Return = "number", Notes = "Returns the number of ticks left until the firework explodes." }, + SetItem = { Params = "{{cItem}}", Return = "", Notes = "Sets a new item to be used for the firework." }, + SetTicksToExplosion = { Params = "NumTicks", Return = "", Notes = "Sets the number of ticks left until the firework explodes." }, + }, + + Inherits = "cProjectileEntity", + }, -- cFireworkEntity + + cFloater = + { + Desc = "", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cFloater cGhastFireballEntity = { @@ -64,14 +101,14 @@ return pkArrow = { Notes = "The projectile is an {{cArrowEntity|arrow}}" }, pkEgg = { Notes = "The projectile is a {{cThrownEggEntity|thrown egg}}" }, pkEnderPearl = { Notes = "The projectile is a {{cThrownEnderPearlEntity|thrown enderpearl}}" }, - pkExpBottle = { Notes = "The projectile is a thrown exp bottle (NYI)" }, + pkExpBottle = { Notes = "The projectile is a {{cExpBottleEntity|thrown exp bottle}}" }, pkFireCharge = { Notes = "The projectile is a {{cFireChargeEntity|fire charge}}" }, - pkFirework = { Notes = "The projectile is a (flying) firework (NYI)" }, - pkFishingFloat = { Notes = "The projectile is a fishing float (NYI)" }, + pkFirework = { Notes = "The projectile is a (flying) {{cFireworkEntity|firework}}" }, + pkFishingFloat = { Notes = "The projectile is a {{cFloater|fishing float}}" }, pkGhastFireball = { Notes = "The projectile is a {{cGhastFireballEntity|ghast fireball}}" }, pkSnowball = { Notes = "The projectile is a {{cThrownSnowballEntity|thrown snowball}}" }, - pkSplashPotion = { Notes = "The projectile is a thrown splash potion (NYI)" }, - pkWitherSkull = { Notes = "The projectile is a wither skull (NYI)" }, + pkSplashPotion = { Notes = "The projectile is a {{cSplashPotionEntity|thrown splash potion}}" }, + pkWitherSkull = { Notes = "The projectile is a {{cWitherSkullEntity|wither skull}}" }, }, ConstantGroups = { @@ -84,26 +121,52 @@ return Inherits = "cEntity", }, -- cProjectileEntity + cSplashPotionEntity = + { + Desc = [[ + Represents a thrown splash potion. + ]], + Functions = + { + GetEntityEffect = { Params = "", Return = "{{cEntityEffect}}", Notes = "Returns the entity effect in this potion" }, + GetEntityEffectType = { Params = "", Return = "{{cEntityEffect|Entity effect type}}", Notes = "Returns the effect type of this potion" }, + GetPotionColor = { Params = "", Return = "number", Notes = "Returns the color index of the particles emitted by this potion" }, + SetEntityEffect = { Params = "{{cEntityEffect}}", Return = "", Notes = "Sets the entity effect for this potion" }, + SetEntityEffectType = { Params = "{{cEntityEffect|Entity effect type}}", Return = "", Notes = "Sets the effect type of this potion" }, + SetPotionColor = { Params = "number", Return = "", Notes = "Sets the color index of the particles for this potion" }, + }, + Inherits = "cProjectileEntity", + }, -- cSplashPotionEntity + cThrownEggEntity = { - Desc = "", + Desc = [[ + Represents a thrown egg. + ]], Functions = {}, Inherits = "cProjectileEntity", }, -- cThrownEggEntity cThrownEnderPearlEntity = { - Desc = "", + Desc = "Represents a thrown ender pearl.", Functions = {}, Inherits = "cProjectileEntity", }, -- cThrownEnderPearlEntity - + cThrownSnowballEntity = { - Desc = "", + Desc = "Represents a thrown snowball.", Functions = {}, Inherits = "cProjectileEntity", }, -- cThrownSnowballEntity + + cWitherSkullEntity = + { + Desc = "Represents a wither skull being shot.", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cWitherSkullEntity } diff --git a/MCServer/Plugins/APIDump/Hooks/OnServerPing.lua b/MCServer/Plugins/APIDump/Hooks/OnServerPing.lua new file mode 100644 index 000000000..76b6d1517 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnServerPing.lua @@ -0,0 +1,50 @@ +return +{ + HOOK_SERVER_PING = + { + CalledWhen = "Client pings the server from the server list.", + DefaultFnName = "OnServerPing", -- also used as pagename + Desc = [[ + A plugin may implement an OnServerPing() function and register it as a Hook to process pings from + clients in the server server list. It can change the logged in players and player capacity, as well + as the server description and the favicon, that are displayed to the client in the server list. + ]], + Params = { + { Name = "ClientHandle", Type = "{{cClientHandle}}", Notes = "The client handle that pinged the server" }, + { Name = "ServerDescription", Type = "string", Notes = "The server description" }, + { Name = "OnlinePlayersCount", Type = "number", Notes = "The number of players currently on the server" }, + { Name = "MaxPlayersCount", Type = "number", Notes = "The current player cap for the server" }, + { Name = "Favicon", Type = "string", Notes = "The base64 encoded favicon to be displayed in the server list for compatible clients" }, + }, + Returns = [[ + The plugin can return whether to continue processing of the hook with other plugins, the server description to + be displayed to the client, the currently online players, the player cap and the base64/png favicon data, in that order. + ]], + CodeExamples = { + { + Title = "Change information returned to the player", + Desc = "Tells the client that the server description is 'test', there are one more players online than there actually are, and that the player cap is zero. It also changes the favicon data.", + Code = [[ +function OnServerPing(ClientHandle, ServerDescription, OnlinePlayers, MaxPlayers, Favicon) + -- Change Server Description + ServerDescription = "Test" + + -- Change online / max players + OnlinePlayers = OnlinePlayers + 1 + MaxPlayers = 0 + + -- Change favicon + if cFile:IsFile("my-favicon.png") then + local FaviconData = cFile:ReadWholeFile("my-favicon.png") + if (FaviconData ~= "") and (FaviconData ~= nil) then + Favicon = Base64Encode(FaviconData) + end + end + + return false, ServerDescription, OnlinePlayers, MaxPlayers, Favicon +end + ]], + }, + }, + }, -- HOOK_SERVER_PING +} diff --git a/MCServer/Plugins/ChatLog b/MCServer/Plugins/ChatLog new file mode 160000 +Subproject 983d23ca37baa89f7e4dc11d71502d9c059f637 diff --git a/MCServer/Plugins/ChatLog/plugin.lua b/MCServer/Plugins/ChatLog/plugin.lua deleted file mode 100644 index adbf986e0..000000000 --- a/MCServer/Plugins/ChatLog/plugin.lua +++ /dev/null @@ -1,31 +0,0 @@ - --- plugin.lua - --- Implements the main entrypoint for the plugin, as well as all the handling needed - --- ChatLog plugin logs all chat messages into the server log - - - - - -function Initialize(Plugin) - Plugin:SetName("ChatLog") - Plugin:SetVersion(3) - - cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChat) - - LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) - return true -end - - - - - -function OnChat(Player, Message) - -- Lets get loggin' - LOGINFO("[" .. Player:GetName() .. "]: " .. StripColorCodes(Message)); - - return false -end
\ No newline at end of file diff --git a/MCServer/Plugins/ChunkWorx b/MCServer/Plugins/ChunkWorx new file mode 160000 +Subproject 894c7e32049e9d2a1e736f7d721aaacd1ae29e5 diff --git a/MCServer/Plugins/ChunkWorx/ChunkWorx.deproj b/MCServer/Plugins/ChunkWorx/ChunkWorx.deproj deleted file mode 100644 index 17420d1d7..000000000 --- a/MCServer/Plugins/ChunkWorx/ChunkWorx.deproj +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<project> - <file> - <filename>chunkworx_main.lua</filename> - </file> - <file> - <filename>chunkworx_web.lua</filename> - </file> -</project> diff --git a/MCServer/Plugins/ChunkWorx/chunkworx_main.lua b/MCServer/Plugins/ChunkWorx/chunkworx_main.lua deleted file mode 100644 index 88ecb3979..000000000 --- a/MCServer/Plugins/ChunkWorx/chunkworx_main.lua +++ /dev/null @@ -1,128 +0,0 @@ --- Global variables -PLUGIN = {} -- Reference to own plugin object -GENERATION_STATE = 0 -OPERATION_CODE = 0 -- 0 = generation -CX = 0 -CZ = 0 -CURRENT = 0 -TOTAL = 0 - --- AREA Variables -AreaStartX = -10 -AreaStartZ = -10 -AreaEndX = 10 -AreaEndZ = 10 - --- RADIAL Variables -RadialX = 0 -RadialZ = 0 -Radius = 10 - --- WORLD -WORK_WORLD = cRoot:Get():GetDefaultWorld():GetName() -WW_instance = cRoot:Get():GetDefaultWorld() -WORLDS = {} - - - - - -function Initialize(Plugin) - PLUGIN = Plugin - - PLUGIN:SetName("ChunkWorx") - PLUGIN:SetVersion(6) - - cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick) - - Plugin:AddWebTab("(Re)Generation", HandleRequest_Generation) - - GENERATION_STATE = 0 - WW_instance = cRoot:Get():GetWorld(WORK_WORLD) - if (WW_instance == nil) then - LOG("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": NO WORLD found :(") - end - - -- Read the stored values: - local SettingsIni = cIniFile(); - SettingsIni:ReadFile("ChunkWorx.ini"); -- ignore any read errors - AreaStartX = SettingsIni:GetValueSetI("Area data", "StartX", AreaStartX) - AreaStartZ = SettingsIni:GetValueSetI("Area data", "StartZ", AreaStartZ) - AreaEndX = SettingsIni:GetValueSetI("Area data", "EndX", AreaEndX) - AreaEndZ = SettingsIni:GetValueSetI("Area data", "EndZ", AreaEndZ) - RadialX = SettingsIni:GetValueSetI("Radial data", "RadialX", RadialX) - RadialZ = SettingsIni:GetValueSetI("Radial data", "RadialZ", RadialZ) - Radius = SettingsIni:GetValueSetI("Radial data", "Radius", Radius) - SettingsIni:WriteFile("ChunkWorx.ini"); - - LOG("Initialized " .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion()) - return true -end - - - - - -function OnTick( DeltaTime ) - if (GENERATION_STATE == 1 or GENERATION_STATE == 3) then - LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works STARTED!") - LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": At world: " .. WORK_WORLD) - WW_instance = cRoot:Get():GetWorld(WORK_WORLD) - if (GENERATION_STATE == 1) then GENERATION_STATE = 2 end - if (GENERATION_STATE == 3) then GENERATION_STATE = 4 end - - -- Changing in case coordinates are flipped - local shifter = AreaEndX - if (AreaStartX > AreaEndX) then - AreaEndX = AreaStartX - AreaStartX = shifter - end - shifter = AreaEndZ - if (AreaStartZ > AreaEndZ) then - AreaEndZ = AreaStartZ - AreaStartZ = shifter - end - - CX = AreaStartX - CZ = AreaStartZ - CURRENT = 0 - - if (WW_instance == nil) then - LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works ABORTED") - LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": NO WORLD found :(") - GENERATION_STATE = 0 - end - end - - - - if (GENERATION_STATE == 2 or GENERATION_STATE == 4) then - if (WW_instance:GetGeneratorQueueLength() < 200 - and WW_instance:GetLightingQueueLength() < 200 - and (WW_instance:GetStorageSaveQueueLength() + WW_instance:GetStorageLoadQueueLength()) < 80) then - local chunk_sum = (1+ AreaEndX - AreaStartX) * (1+ AreaEndZ - AreaStartZ) - TOTAL = chunk_sum - LOG("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": PROCESSING 100 chunks, (" .. CURRENT .. "/" .. chunk_sum .. ")") - for C = 1, 100 do - if (GENERATION_STATE == 2) then WW_instance:GenerateChunk(CX, CZ) end - if (GENERATION_STATE == 4) then WW_instance:RegenerateChunk(CX, CZ) end - - CX = CX + 1 - CURRENT = CURRENT + 1 - if (CX > AreaEndX) then - CX = AreaStartX - CZ = CZ + 1 - if (CZ > AreaEndZ) then - if (GENERATION_STATE == 2) then LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. " - generation ENDED!") end - if (GENERATION_STATE == 4) then LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. " - REgeneration ENDED!") end - - GENERATION_STATE = 0 - break - end - end - end - WW_instance:QueueSaveAllChunks() - WW_instance:QueueUnloadUnusedChunks() - end - end -end
\ No newline at end of file diff --git a/MCServer/Plugins/ChunkWorx/chunkworx_web.lua b/MCServer/Plugins/ChunkWorx/chunkworx_web.lua deleted file mode 100644 index 9aec38b12..000000000 --- a/MCServer/Plugins/ChunkWorx/chunkworx_web.lua +++ /dev/null @@ -1,274 +0,0 @@ - --- chunkworx_web.lua - --- WebAdmin-related functions - - - - - -local function Buttons_Player( Name ) - return "<form method='POST'><input type='hidden' name='PlayerName' value='"..Name.."'><input type='submit' name='PlayerExact' value='Exact'><input type='submit' name='Player3x3' value='3x3'></form>" -end - - - - - -local function Button_World( Name ) - return "<form method='POST'><input type='hidden' name='WorldName' value='"..Name.."'><input type='submit' name='SelectWorld' value='Select'></form>" -end - - - - - -local function SaveSettings() - local SettingsIni = cIniFile() - SettingsIni:SetValueI("Area data", "StartX", AreaStartX) - SettingsIni:SetValueI("Area data", "StartZ", AreaStartZ) - SettingsIni:SetValueI("Area data", "EndX", AreaEndX) - SettingsIni:SetValueI("Area data", "EndZ", AreaEndZ) - SettingsIni:SetValueI("Radial data", "RadialX", RadialX) - SettingsIni:SetValueI("Radial data", "RadialZ", RadialZ) - SettingsIni:SetValueI("Radial data", "Radius", Radius) - SettingsIni:WriteFile("ChunkWorx.ini") -end - - - - - -function HandleRequest_Generation( Request ) - local Content = "" - if (Request.PostParams["AGHRRRR"] ~= nil) then - GENERATION_STATE = 0 - WW_instance:QueueSaveAllChunks() - WW_instance:QueueUnloadUnusedChunks() - LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works ABORTED by admin") - end - --Content = Content .. "<head><meta http-equiv=\"refresh\" content=\"2;\"></head>" - -- PROCESSING - -------------------------------------------------------------------------------------------------- - local function ProcessingContent() - local _small_content = "" - _small_content = _small_content .. "<head><meta http-equiv=\"refresh\" content=\"2;\"></head>" - _small_content = _small_content .. "<h4>World for operations:</h4>"..WORK_WORLD - if (OPERATION_CODE == 0) then - _small_content = _small_content .. "<h4>Operation:</h4>Generation" - elseif (OPERATION_CODE == 1) then - _small_content = _small_content .. "<h4>Operation:</h4>Regeneration" - end - _small_content = _small_content .. "<h4>Area: </h4>["..AreaStartX..":"..AreaStartZ.."] ["..AreaEndX..":"..AreaEndZ.."]" - _small_content = _small_content .. "<h4>Progress:</h4>"..CURRENT.."/"..TOTAL - _small_content = _small_content .. "<br>" - _small_content = _small_content .. "<form method='POST'>" - _small_content = _small_content .. "<input type='submit' name='AGHRRRR' value='Stop'>" - _small_content = _small_content .. "</form>" - return _small_content - end - if (GENERATION_STATE == 2 or GENERATION_STATE == 4) then - Content = ProcessingContent() - return Content - end - -- SELECTING - -------------------------------------------------------------------------------------------------- - if ( Request.PostParams["FormSetWorld"] ) then - WORK_WORLD = Request.PostParams["FormWorldName"] - WW_instance = cRoot:Get():GetWorld(WORK_WORLD) - end - - if( Request.PostParams["SelectWorld"] ~= nil - and Request.PostParams["WorldName"] ~= nil ) then -- World is selected! - WORK_WORLD = Request.PostParams["WorldName"] - WW_instance = cRoot:Get():GetWorld(WORK_WORLD) - end - - if(Request.PostParams["OperationGenerate"] ~= nil) then - OPERATION_CODE = 0 - end - if(Request.PostParams["OperationReGenerate"] ~= nil) then - OPERATION_CODE = 1 - end - - if (GENERATION_STATE == 0) then - if( Request.PostParams["FormAreaStartX"] ~= nil - and Request.PostParams["FormAreaStartZ"] ~= nil - and Request.PostParams["FormAreaEndX"] ~= nil - and Request.PostParams["FormAreaEndZ"] ~= nil ) then --(Re)Generation valid! - -- COMMON (Re)gen - if( Request.PostParams["StartArea"]) then - AreaStartX = tonumber(Request.PostParams["FormAreaStartX"]) - AreaStartZ = tonumber(Request.PostParams["FormAreaStartZ"]) - AreaEndX = tonumber(Request.PostParams["FormAreaEndX"]) - AreaEndZ = tonumber(Request.PostParams["FormAreaEndZ"]) - SaveSettings(); - if (OPERATION_CODE == 0) then - GENERATION_STATE = 1 - elseif (OPERATION_CODE == 1) then - GENERATION_STATE = 3 - end - Content = ProcessingContent() - return Content - end - end - if( Request.PostParams["FormRadialX"] ~= nil - and Request.PostParams["FormRadialZ"] ~= nil - and Request.PostParams["FormRadius"] ~= nil ) then --(Re)Generation valid! - -- COMMON (Re)gen - if( Request.PostParams["StartRadial"]) then - RadialX = tonumber(Request.PostParams["FormRadialX"]) or 0 - RadialZ = tonumber(Request.PostParams["FormRadialZ"]) or 0 - Radius = tonumber(Request.PostParams["FormRadius"]) or 10 - AreaStartX = RadialX - Radius - AreaStartZ = RadialZ - Radius - AreaEndX = RadialX + Radius - AreaEndZ = RadialZ + Radius - SaveSettings() - if (OPERATION_CODE == 0) then - GENERATION_STATE = 1 - elseif (OPERATION_CODE == 1) then - GENERATION_STATE = 3 - end - Content = ProcessingContent() - return Content - end - end - -- POINT REGEN! - if( Request.PostParams["FormPointX"] ~= nil - and Request.PostParams["FormPointZ"] ~= nil ) then --ReGeneration valid! - -- EXACT - if ( Request.PostParams["PointExact"] ~= nil) then - AreaStartX = tonumber(Request.PostParams["FormPointX"]) - AreaStartZ = tonumber(Request.PostParams["FormPointZ"]) - AreaEndX = AreaStartX - AreaEndZ = AreaStartZ - GENERATION_STATE = 3 - Content = ProcessingContent() - return Content - end - -- 3x3 - if ( Request.PostParams["Point3x3"] ~= nil) then - AreaStartX = tonumber(Request.PostParams["FormPointX"]) - 1 - AreaStartZ = tonumber(Request.PostParams["FormPointZ"]) - 1 - AreaEndX = AreaStartX + 2 - AreaEndZ = AreaStartZ + 2 - GENERATION_STATE = 3 - Content = ProcessingContent() - return Content - end - end - - local GetAreaByPlayer = function(Player) - -- Player is valid only within this function, it cannot be stord and used later! - AreaStartX = Player:GetChunkX() - AreaStartZ = Player:GetChunkZ() - end - -- PLAYERS REGEN! - if( Request.PostParams["PlayerExact"] ~= nil - and Request.PostParams["PlayerName"] ~= nil ) then -- Making BOOM! I meant, regenereate... - cRoot:Get():GetWorld(WORK_WORLD):DoWithPlayer(Request.PostParams["PlayerName"],GetAreaByPlayer) - AreaEndX = AreaStartX - AreaEndZ = AreaStartZ - GENERATION_STATE = 3 - Content = ProcessingContent() - return Content - end - if( Request.PostParams["Player3x3"] ~= nil - and Request.PostParams["PlayerName"] ~= nil ) then -- Making BOOM! I meant, regenereate... - cRoot:Get():GetWorld(WORK_WORLD):DoWithPlayer(Request.PostParams["PlayerName"],GetAreaByPlayer) - AreaStartX = AreaStartX - 1 - AreaStartZ = AreaStartZ - 1 - AreaEndX = AreaStartX + 2 - AreaEndZ = AreaStartZ + 2 - GENERATION_STATE = 3 - Content = ProcessingContent() - return Content - end - end - - --Content = Content .. "<h4>World for operations: " .. WORK_WORLD .. "</h4>" - --Content = Content .. "<form method='POST'>" - --Content = Content .. "<input type='text' name='FormWorldName' value='Input world name here'><input type='submit' name='FormSetWorld' value='Set world'>" - --Content = Content .. "</form>" - - -- SELECTING WORK_WORLD - Content = Content .. "<h4>World for operations: " .. WORK_WORLD .. "</h4>" - Content = Content .. "<table>" - local WorldNum = 0 - local AddWorldToTable = function(World) - WorldNum = WorldNum + 1 - Content = Content .. "<tr>" - Content = Content .. "<td style='width: 10px;'>" .. WorldNum .. ".</td>" - Content = Content .. "<td>" .. World:GetName() .. "</td>" - Content = Content .. "<td>" .. Button_World(World:GetName()) .. "</td>" - Content = Content .. "</tr>" - end - cRoot:Get():ForEachWorld(AddWorldToTable) - if( WorldNum == 0 ) then - Content = Content .. "<tr><td>No worlds! O_O</td></tr>" - end - Content = Content .. "</table>" - Content = Content .. "<br>" - - -- SELECTING OPERATION - if (OPERATION_CODE == 0) then - Content = Content .. "<h4>Operation: Generation</h4>" - elseif (OPERATION_CODE == 1) then - Content = Content .. "<h4>Operation: Regeneration</h4>" - end - Content = Content .. "<form method='POST'>" - Content = Content .. "<input type='submit' name='OperationGenerate' value='Generation'>" - Content = Content .. "<input type='submit' name='OperationReGenerate' value='Regeneration'>" - Content = Content .. "</form>" - - -- SELECTING AREA - Content = Content .. "<h4>Area: </h4>Start X, Start Z; End X, End Z" - Content = Content .. "<form method='POST'>" - Content = Content .. "<input type='text' name='FormAreaStartX' value='" .. AreaStartX .. "'><input type='text' name='FormAreaStartZ' value='" .. AreaStartZ .. "'>" - Content = Content .. "<input type='text' name='FormAreaEndX' value='" .. AreaEndX .. "'><input type='text' name='FormAreaEndZ' value='" .. AreaEndZ .. "'>" - Content = Content .. "<input type='submit' name='StartArea' value='Start'>" - Content = Content .. "</form>" - - -- SELECTING RADIAL - Content = Content .. "<h4>Radial: </h4>Center X, Center Z, Radius" - Content = Content .. "<form method='POST'>" - Content = Content .. "<input type='text' name='FormRadialX' value='" .. RadialX .. "'><input type='text' name='FormRadialZ' value='" .. RadialZ .. "'><input type='text' name='FormRadius' value='" .. Radius .. "'>" - Content = Content .. "<input type='submit' name='StartRadial' value='Start'>" - Content = Content .. "</form>" - Content = Content .. "<br>" - Content = Content .. "<br>" - Content = Content .. "<br>" - - -- SELECTING POINT - Content = Content .. "<h4>Point regeneration:</h4> X, Z" - Content = Content .. "<form method='POST'>" - Content = Content .. "<input type='text' name='FormPointX' value='0'><input type='text' name='FormPointZ' value='0'>" - Content = Content .. "<input type='submit' name='PointExact' value='Exact'>" - Content = Content .. "<input type='submit' name='Point3x3' value='3x3'>" - Content = Content .. "</form>" - - -- SELECTING PLAYERS - Content = Content .. "<h4>Player-based regeneration:</h4>" - Content = Content .. "<table>" - local PlayerNum = 0 - local AddPlayerToTable = function( Player ) - PlayerNum = PlayerNum + 1 - Content = Content .. "<tr>" - Content = Content .. "<td style='width: 10px;'>" .. PlayerNum .. ".</td>" - Content = Content .. "<td>" .. Player:GetName() .. "</td>" - Content = Content .. "<td>" .. Buttons_Player(Player:GetName()) .. "</td>" - Content = Content .. "</tr>" - end - if (cRoot:Get():GetWorld(WORK_WORLD) == nil) then - Content = Content .. "<tr><td>Incorrect world selection</td></tr>" - else - cRoot:Get():GetWorld(WORK_WORLD):ForEachPlayer( AddPlayerToTable ) - if( PlayerNum == 0 ) then - Content = Content .. "<tr><td>No connected players</td></tr>" - end - end - Content = Content .. "</table>" - Content = Content .. "<br>" - return Content -end
\ No newline at end of file diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject bd23915df763b182610c6163c5ff2d64a075656 +Subproject 4702471943511f641458c7e8e89b430a723f43e diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index f66ac76a0..3dcd4ebee 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -10,9 +10,6 @@ g_ShowFoodStats = false; -- When true, each player's food stats are sent to the function Initialize(Plugin) - Plugin:SetName("Debuggers") - Plugin:SetVersion(1) - --[[ -- Test multiple hook handlers: cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick1); @@ -68,6 +65,8 @@ function Initialize(Plugin) PM:BindCommand("/rmitem", "debuggers", HandleRMItem, "- Remove the specified item from the inventory."); PM:BindCommand("/pickups", "debuggers", HandlePickups, "- Spawns random pickups around you"); PM:BindCommand("/poof", "debuggers", HandlePoof, "- Nudges pickups close to you away from you"); + + PM:BindConsoleCommand("sched", HandleConsoleSchedule, "Tests the world scheduling"); Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers) Plugin:AddWebTab("StressTest", HandleRequest_StressTest) @@ -1630,3 +1629,17 @@ end + +function HandleConsoleSchedule(a_Split) + LOG("Scheduling a task for 2 seconds in the future") + cRoot:Get():GetDefaultWorld():ScheduleTask(40, + function () + LOG("Scheduled function is called.") + end + ) + return true, "Task scheduled" +end + + + + diff --git a/MCServer/Plugins/Handy b/MCServer/Plugins/Handy new file mode 160000 +Subproject e64a04be39ac7790abcb09de3d4c7d8fc2a2a1e diff --git a/MCServer/Plugins/Handy/handy.lua b/MCServer/Plugins/Handy/handy.lua deleted file mode 100644 index e4e9d3f5f..000000000 --- a/MCServer/Plugins/Handy/handy.lua +++ /dev/null @@ -1,28 +0,0 @@ --- Global variables -PLUGIN = {} -- Reference to own plugin object -CHEST_WIDTH = 9 -HANDY_VERSION = 2 ---[[ - -Handy is a plugin for other plugins. It contain no commands, no hooks, but functions to ease plugins developers' life. - -API: - - -TODO: -1. GetChestSlot wrapper, so it will detect double chest neighbour chest and will be able to access it. -]] - -function Initialize(Plugin) - PLUGIN = Plugin - PLUGIN:SetName("Handy") - PLUGIN:SetVersion(HANDY_VERSION) - - PluginManager = cRoot:Get():GetPluginManager() - LOG("Initialized " .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion()) - return true -end - -function OnDisable() - LOG(PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. " is shutting down...") -end
\ No newline at end of file diff --git a/MCServer/Plugins/Handy/handy_functions.lua b/MCServer/Plugins/Handy/handy_functions.lua deleted file mode 100644 index af43f663a..000000000 --- a/MCServer/Plugins/Handy/handy_functions.lua +++ /dev/null @@ -1,216 +0,0 @@ ---[[ -General stuff -]] --- Returns Handy plugin version number -function GetHandyVersion() - return HANDY_VERSION -end --- Checks if handy is in proper version -function CheckForRequiredVersion( inVersion ) - if( inVersion > HANDY_VERSION ) then return false end - return true -end ---[[ -MCS-specific _functions and nasty hacks :D -]] -function GetChestHeightCheat( inChest ) - local chestGrid = inChest:GetContents() - LOGINFO( "This function serves no purpose now! You should consider chest:GetContents():GetHeight() now!" ) - LOGINFO( "Also, you might find Handy's new 'IsChestDouble()' useful for your case" ) - return chestGrid:GetHeight() -end -function IsChestDouble( inChest ) - local chestHeight = inChest:GetContents():GetHeight() - if( chestHeight == 3 ) then - return false - end - return true -end --- Those two checks how many items of given inItemID chest and player have, and how much they could fit inside them -function ReadChestForItem( inChest, inItemID ) - return ReadGridForItems( inChest:GetContents(), inItemID ) -end -function ReadPlayerForItem( inPlayer, inItemID ) - local inventoryFound, inventoryFree = ReadGridForItems( inPlayer:GetInventory():GetInventoryGrid(), inItemID ) - local hotbarFound, hotbarFree = ReadGridForItems( inPlayer:GetInventory():GetHotbarGrid(), inItemID ) - local itemsFound = inventoryFound + hotbarFound - local freeSpace = inventoryFree + hotbarFree - return itemsFound, freeSpace -end --- Following functions are for chest-related operations --- BEWARE! Those assume you did checked if chest has items/space in it! -function ReadGridForItems( inGrid, inItemID ) - local itemsFound = 0 - local freeSpace = 0 - local slotsCount = inGrid:GetNumSlots() - local testerItem = cItem( inItemID ) - local maxStackSize = testerItem:GetMaxStackSize() - for index = 0, (slotsCount - 1) do - slotItem = inGrid:GetSlot( index ) - if( slotItem:IsEmpty() ) then - freeSpace = freeSpace + maxStackSize - else - if( slotItem:IsStackableWith( testerItem ) ) then - itemsFound = itemsFound + slotItem.m_ItemCount - freeSpace = maxStackSize - slotItem.m_ItemCount - end - end - end - return itemsFound, freeSpace -end - -function TakeItemsFromGrid( inGrid, inItem ) - local slotsCount = inGrid:GetNumSlots() - local removedItem = cItem( inItem ) - for index = 0, (slotsCount - 1) do - slotItem = inGrid:GetSlot( index ) - if( slotItem:IsSameType( removedItem ) ) then - if( slotItem.m_ItemCount <= removedItem.m_ItemCount ) then - removedItem.m_ItemCount = removedItem.m_ItemCount - slotItem.m_ItemCount - inGrid:EmptySlot( index ) - else - removedItem.m_ItemCount = slotItem.m_ItemCount - removedItem.m_ItemCount - inGrid:SetSlot( index, removedItem ) - removedItem.m_ItemCount = 0 - end - if( removedItem.m_ItemCount <= 0 ) then break end - end - end - return removedItem.m_ItemCount -end --------------- -function TakeItemsFromChest( inChest, inItemID, inAmount ) -- MIGHT BE UNSAFE! CHECK FOR ITEMS FIRST!! - local chestGrid = inChest:GetContents() - local removedItem = cItem( inItemID, inAmount ) - TakeItemsFromGrid( chestGrid, removedItem ) -end -function PutItemsToChest( inChest, inItemID, inAmount ) - local chestGrid = inChest:GetContents() - local addedItem = cItem( inItemID, inAmount ) - chestGrid:AddItem( addedItem ) -end --- Similar to chest-related. -function TakeItemsFromPlayer( inPlayer, inItemID, inAmount ) -- MIGHT BE UNSAFE! CHECK FIRST! - local removedItem = cItem( inItemID, inAmount ) - local inventoryGrid = inPlayer:GetInventory():GetInventoryGrid() - local hotbarGrid = inPlayer:GetInventory():GetHotbarGrid() - local itemsLeft = TakeItemsFromGrid( inventoryGrid, removedItem ) - if( itemsLeft > 0 ) then - removedItem = cItem( inItemID, itemsLeft ) - TakeItemsFromGrid( hotbarGrid, removedItem ) - end -end -function GiveItemsToPlayer( inPlayer, inItemID, inAmount ) - local addedItem = cItem( inItemID, inAmount ) - local inventoryGrid = inPlayer:GetInventory():GetInventoryGrid() - local hotbarGrid = inPlayer:GetInventory():GetHotbarGrid() - local itemsAdded = inventoryGrid:AddItem( addedItem ) - if( itemsAdded < inAmount ) then - addedItem.m_ItemCount = addedItem.m_ItemCount - itemsAdded - hotbarGrid:AddItem( addedItem ) - end -end --- This function returns item max stack for a given itemID. It uses vanilla max stack size, and uses several non-common items notations; --- Those are: --- oneonerecord( because aparently 11record wasn't the best idea in lua scripting application ) --- carrotonastick( because it wasn't added to items.txt yet ) --- waitrecord( for same reason ) --- Feel free to ignore the difference, or to add those to items.txt -function GetItemMaxStack( inItemID ) - local testerItem = cItem( inItemID ) - LOGINFO( "This function serves no real purpose now, maybe consider using cItem:GetMaxStackSize()?" ) - return testerItem:GetMaxStackSize() -end -function ItemIsArmor( inItemID, inCheckForHorseArmor ) - inCheckForHorseArmor = inCheckForHorseArmor or false - if( inItemID == E_ITEM_LEATHER_CAP ) then return true end - if( inItemID == E_ITEM_LEATHER_TUNIC ) then return true end - if( inItemID == E_ITEM_LEATHER_PANTS ) then return true end - if( inItemID == E_ITEM_LEATHER_BOOTS ) then return true end - - if( inItemID == E_ITEM_CHAIN_HELMET ) then return true end - if( inItemID == E_ITEM_CHAIN_CHESTPLATE ) then return true end - if( inItemID == E_ITEM_CHAIN_LEGGINGS ) then return true end - if( inItemID == E_ITEM_CHAIN_BOOTS ) then return true end - - if( inItemID == E_ITEM_IRON_HELMET ) then return true end - if( inItemID == E_ITEM_IRON_CHESTPLATE ) then return true end - if( inItemID == E_ITEM_IRON_LEGGINGS ) then return true end - if( inItemID == E_ITEM_IRON_BOOTS ) then return true end - - if( inItemID == E_ITEM_DIAMOND_HELMET ) then return true end - if( inItemID == E_ITEM_DIAMOND_CHESTPLATE ) then return true end - if( inItemID == E_ITEM_DIAMOND_LEGGINGS ) then return true end - if( inItemID == E_ITEM_DIAMOND_BOOTS ) then return true end - - if( inItemID == E_ITEM_GOLD_HELMET ) then return true end - if( inItemID == E_ITEM_GOLD_CHESTPLATE ) then return true end - if( inItemID == E_ITEM_GOLD_LEGGINGS ) then return true end - if( inItemID == E_ITEM_GOLD_BOOTS ) then return true end - - if( inCheckForHorseArmor ) then - if( inItemID == E_ITEM_IRON_HORSE_ARMOR ) then return true end - if( inItemID == E_ITEM_GOLD_HORSE_ARMOR ) then return true end - if( inItemID == E_ITEM_DIAMOND_HORSE_ARMOR ) then return true end - end - return false -end --- Returns full-length playername for a short name( usefull for parsing commands ) -function GetExactPlayername( inPlayerName ) - local _result = inPlayerName - local function SetProcessingPlayername( inPlayer ) - _result = inPlayer:GetName() - end - cRoot:Get():FindAndDoWithPlayer( inPlayerName, SetProcessingPlayername ) - return _result -end -function GetPlayerByName( inPlayerName ) - local _player - local PlayerSetter = function( Player ) - _player = Player - end - cRoot:Get():FindAndDoWithPlayer( inPlayerName, PlayerSetter ) - return _player -end ---[[ -Not-so-usual math _functions -]] --- Rounds floating point number. Because lua guys think this function doesn't deserve to be presented in lua's math -function round( inX ) - if( inX%2 ~= 0.5 ) then - return math.floor( inX + 0.5 ) - end - return inX - 0.5 -end ---[[ -Functions I use for filework and stringswork -]] -function PluralString( inValue, inSingularString, inPluralString ) - local _value_string = tostring( inValue ) - if( _value_string[#_value_string] == "1" ) then - return inSingularString - end - return inPluralString -end -function PluralItemName( inItemID, inAmount ) -- BEWARE! TEMPORAL SOLUTION THERE! :D - local _value_string = tostring( inValue ) - local _name = "" - if( _value_string[#_value_string] == "1" ) then - -- singular names - _name = ItemTypeToString( inItemID ) - else - -- plural names - _name = ItemTypeToString( inItemID ).."s" - end - return _name -end --- for filewriting purposes. 0 = false, 1 = true -function StringToBool( inValue ) - if( inValue == "1" ) then return true end - return false -end --- same, but reversal -function BoolToString( inValue ) - if( inValue == true ) then return 1 end - return 0 -end diff --git a/MCServer/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua index c61f9c9e6..de1d1f451 100644 --- a/MCServer/Plugins/InfoDump.lua +++ b/MCServer/Plugins/InfoDump.lua @@ -20,8 +20,8 @@ only that one plugin's documentation. This mode of operation doesn't require Lua -- Check Lua version. We use 5.1-specific construct when loading the plugin info, 5.2 is not compatible! if (_VERSION ~= "Lua 5.1") then - print("Unsupported Lua version. This script requires Lua version 5.1, this Lua is version " .. (_VERSION or "<nil>")); - return; + print("Unsupported Lua version. This script requires Lua version 5.1, this Lua is version " .. (_VERSION or "<nil>")) + return end @@ -31,38 +31,38 @@ end --- Replaces generic formatting with forum-specific formatting -- Also removes the single line-ends local function ForumizeString(a_Str) - assert(type(a_Str) == "string"); + assert(type(a_Str) == "string") -- Remove the indentation, unless in the code tag: -- Only one code or /code tag per line is supported! - local IsInCode = false; + local IsInCode = false local function RemoveIndentIfNotInCode(s) if (IsInCode) then -- we're in code section, check if this line terminates it - IsInCode = (s:find("{%%/code}") ~= nil); - return s .. "\n"; + IsInCode = (s:find("{%%/code}") ~= nil) + return s .. "\n" else -- we're not in code section, check if this line starts it - IsInCode = (s:find("{%%code}") ~= nil); - return s:gsub("^%s*", "") .. "\n"; + IsInCode = (s:find("{%%code}") ~= nil) + return s:gsub("^%s*", "") .. "\n" end end - a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode); + a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode) -- Replace multiple line ends with {%p} and single line ends with a space, -- so that manual word-wrap in the Info.lua file doesn't wrap in the forum. - a_Str = a_Str:gsub("\n\n", "{%%p}"); - a_Str = a_Str:gsub("\n", " "); + a_Str = a_Str:gsub("\n\n", "{%%p}") + a_Str = a_Str:gsub("\n", " ") -- Replace the generic formatting: - a_Str = a_Str:gsub("{%%p}", "\n\n"); - a_Str = a_Str:gsub("{%%b}", "[b]"):gsub("{%%/b}", "[/b]"); - a_Str = a_Str:gsub("{%%i}", "[i]"):gsub("{%%/i}", "[/i]"); - a_Str = a_Str:gsub("{%%list}", "[list]"):gsub("{%%/list}", "[/list]"); - a_Str = a_Str:gsub("{%%li}", "[*]"):gsub("{%%/li}", ""); + a_Str = a_Str:gsub("{%%p}", "\n\n") + a_Str = a_Str:gsub("{%%b}", "[b]"):gsub("{%%/b}", "[/b]") + a_Str = a_Str:gsub("{%%i}", "[i]"):gsub("{%%/i}", "[/i]") + a_Str = a_Str:gsub("{%%list}", "[list]"):gsub("{%%/list}", "[/list]") + a_Str = a_Str:gsub("{%%li}", "[*]"):gsub("{%%/li}", "") -- TODO: Other formatting - return a_Str; + return a_Str end @@ -72,38 +72,38 @@ end --- Replaces generic formatting with forum-specific formatting -- Also removes the single line-ends local function GithubizeString(a_Str) - assert(type(a_Str) == "string"); + assert(type(a_Str) == "string") -- Remove the indentation, unless in the code tag: -- Only one code or /code tag per line is supported! - local IsInCode = false; + local IsInCode = false local function RemoveIndentIfNotInCode(s) if (IsInCode) then -- we're in code section, check if this line terminates it - IsInCode = (s:find("{%%/code}") ~= nil); - return s .. "\n"; + IsInCode = (s:find("{%%/code}") ~= nil) + return s .. "\n" else -- we're not in code section, check if this line starts it - IsInCode = (s:find("{%%code}") ~= nil); - return s:gsub("^%s*", "") .. "\n"; + IsInCode = (s:find("{%%code}") ~= nil) + return s:gsub("^%s*", "") .. "\n" end end - a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode); + a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode) -- Replace multiple line ends with {%p} and single line ends with a space, -- so that manual word-wrap in the Info.lua file doesn't wrap in the forum. - a_Str = a_Str:gsub("\n\n", "{%%p}"); - a_Str = a_Str:gsub("\n", " "); + a_Str = a_Str:gsub("\n\n", "{%%p}") + a_Str = a_Str:gsub("\n", " ") -- Replace the generic formatting: - a_Str = a_Str:gsub("{%%p}", "\n\n"); - a_Str = a_Str:gsub("{%%b}", "**"):gsub("{%%/b}", "**"); - a_Str = a_Str:gsub("{%%i}", "*"):gsub("{%%/i}", "*"); - a_Str = a_Str:gsub("{%%list}", ""):gsub("{%%/list}", ""); - a_Str = a_Str:gsub("{%%li}", " - "):gsub("{%%/li}", ""); + a_Str = a_Str:gsub("{%%p}", "\n\n") + a_Str = a_Str:gsub("{%%b}", "**"):gsub("{%%/b}", "**") + a_Str = a_Str:gsub("{%%i}", "*"):gsub("{%%/i}", "*") + a_Str = a_Str:gsub("{%%list}", ""):gsub("{%%/list}", "") + a_Str = a_Str:gsub("{%%li}", " - "):gsub("{%%/li}", "") -- TODO: Other formatting - return a_Str; + return a_Str end @@ -117,7 +117,7 @@ end local function BuildCategories(a_PluginInfo) -- The returned result -- This will contain both an array and a dict of the categories, to allow fast search - local res = {}; + local res = {} -- For each command add a reference to it into all of its categories: local function AddCommands(a_CmdPrefix, a_Commands) @@ -130,39 +130,39 @@ local function BuildCategories(a_PluginInfo) if ((info.HelpString ~= nil) and (info.HelpString ~= "")) then -- Add to each specified category: - local Category = info.Category; + local Category = info.Category if (type(Category) == "string") then - Category = {Category}; + Category = {Category} end for idx, cat in ipairs(Category or {""}) do - local CatEntry = res[cat]; + local CatEntry = res[cat] if (CatEntry == nil) then -- First time we came across this category, create it: - local NewCat = {Name = cat, Description = "", Commands = {NewCmd}}; - table.insert(res, NewCat); - res[cat] = NewCat; + local NewCat = {Name = cat, Description = "", Commands = {NewCmd}} + table.insert(res, NewCat) + res[cat] = NewCat else -- We already have this category, just add the command to its list of commands: - table.insert(CatEntry.Commands, NewCmd); + table.insert(CatEntry.Commands, NewCmd) end end -- for idx, cat - Category[] end -- if (HelpString valid) -- Recurse all subcommands: if (info.Subcommands ~= nil) then - AddCommands(a_CmdPrefix .. cmd .. " ", info.Subcommands); + AddCommands(a_CmdPrefix .. cmd .. " ", info.Subcommands) end end -- for cmd, info - a_Commands[] end -- AddCommands() - AddCommands("", a_PluginInfo.Commands); + AddCommands("", a_PluginInfo.Commands) -- Assign descriptions to categories: for name, desc in pairs(a_PluginInfo.Categories or {}) do - local CatEntry = res[name]; + local CatEntry = res[name] if (CatEntry ~= nil) then -- The result has this category, add the description: - CatEntry.Description = desc.Description; + CatEntry.Description = desc.Description end end @@ -170,12 +170,12 @@ local function BuildCategories(a_PluginInfo) for idx, cat in ipairs(res) do table.sort(cat.Commands, function (cmd1, cmd2) - return (string.lower(cmd1.CommandString) < string.lower(cmd2.CommandString)); + return (string.lower(cmd1.CommandString) < string.lower(cmd2.CommandString)) end - ); + ) end - return res; + return res end @@ -188,9 +188,9 @@ end -- colorizes command name blue and params green local function GetCommandRefForum(a_Command) if (type(a_Command) == "string") then - return "[color=blue]" .. a_Command .. "[/color]"; + return "[color=blue]" .. a_Command .. "[/color]" end - return "[color=blue]" .. a_Command.Name .. "[/color] [color=green]" .. (a_Command.Params or "") .. "[/color]"; + return "[color=blue]" .. a_Command.Name .. "[/color] [color=green]" .. (a_Command.Params or "") .. "[/color]" end @@ -201,18 +201,18 @@ end -- If a_CommandParams is nil, returns a_CommandName apostrophed -- If a_CommandParams is a string, apostrophes a_CommandName with a_CommandParams local function GetCommandRefGithub(a_CommandName, a_CommandParams) - assert(type(a_CommandName) == "string"); + assert(type(a_CommandName) == "string") if (a_CommandParams == nil) then - return "`" .. a_CommandName .. "`"; + return "`" .. a_CommandName .. "`" end - assert(type(a_CommandParams) == "table"); + assert(type(a_CommandParams) == "table") if ((a_CommandParams.Params == nil) or (a_CommandParams.Params == "")) then - return "`" .. a_CommandName .. "`"; + return "`" .. a_CommandName .. "`" end - assert(type(a_CommandParams.Params) == "string"); - return "`" .. a_CommandName .. " " .. a_CommandParams.Params .. "`"; + assert(type(a_CommandParams.Params) == "string") + return "`" .. a_CommandName .. " " .. a_CommandParams.Params .. "`" end @@ -221,25 +221,25 @@ end --- Writes the specified command detailed help array to the output file, in the forum dump format local function WriteCommandParameterCombinationsForum(a_CmdString, a_ParameterCombinations, f) - assert(type(a_CmdString) == "string"); - assert(type(a_ParameterCombinations) == "table"); - assert(f ~= nil); + assert(type(a_CmdString) == "string") + assert(type(a_ParameterCombinations) == "table") + assert(f ~= nil) if (#a_ParameterCombinations == 0) then -- No explicit parameter combinations to write - return; + return end - f:write("The following parameter combinations are recognized:\n"); + f:write("The following parameter combinations are recognized:\n") for idx, combination in ipairs(a_ParameterCombinations) do - f:write("[color=blue]", a_CmdString, "[/color] [color=green]", combination.Params or "", "[/color]"); + f:write("[color=blue]", a_CmdString, "[/color] [color=green]", combination.Params or "", "[/color]") if (combination.Help ~= nil) then - f:write(" - ", ForumizeString(combination.Help)); + f:write(" - ", ForumizeString(combination.Help)) end if (combination.Permission ~= nil) then - f:write(" (Requires permission '[color=red]", combination.Permission, "[/color]')"); + f:write(" (Requires permission '[color=red]", combination.Permission, "[/color]')") end - f:write("\n"); + f:write("\n") end end @@ -249,25 +249,25 @@ end --- Writes the specified command detailed help array to the output file, in the forum dump format local function WriteCommandParameterCombinationsGithub(a_CmdString, a_ParameterCombinations, f) - assert(type(a_CmdString) == "string"); - assert(type(a_ParameterCombinations) == "table"); - assert(f ~= nil); + assert(type(a_CmdString) == "string") + assert(type(a_ParameterCombinations) == "table") + assert(f ~= nil) if (#a_ParameterCombinations == 0) then -- No explicit parameter combinations to write - return; + return end - f:write("The following parameter combinations are recognized:\n\n"); + f:write("The following parameter combinations are recognized:\n\n") for idx, combination in ipairs(a_ParameterCombinations) do - f:write(GetCommandRefGithub(a_CmdString, combination)); + f:write(GetCommandRefGithub(a_CmdString, combination)) if (combination.Help ~= nil) then - f:write(" - ", GithubizeString(combination.Help)); + f:write(" - ", GithubizeString(combination.Help)) end if (combination.Permission ~= nil) then - f:write(" (Requires permission '**", combination.Permission, "**')"); + f:write(" (Requires permission '**", combination.Permission, "**')") end - f:write("\n"); + f:write("\n") end end @@ -278,29 +278,29 @@ end --- Writes all commands in the specified category to the output file, in the forum dump format local function WriteCommandsCategoryForum(a_Category, f) -- Write category name: - local CategoryName = a_Category.Name; + local CategoryName = a_Category.Name if (CategoryName == "") then - CategoryName = "General"; + CategoryName = "General" end - f:write("\n[size=Large]", ForumizeString(a_Category.DisplayName or CategoryName), "[/size]\n"); + f:write("\n[size=Large]", ForumizeString(a_Category.DisplayName or CategoryName), "[/size]\n") -- Write description: if (a_Category.Description ~= "") then - f:write(ForumizeString(a_Category.Description), "\n"); + f:write(ForumizeString(a_Category.Description), "\n") end -- Write commands: - f:write("\n[list]"); + f:write("\n[list]") for idx2, cmd in ipairs(a_Category.Commands) do - f:write("\n[b]", cmd.CommandString, "[/b] - ", ForumizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n"); + f:write("\n[b]", cmd.CommandString, "[/b] - ", ForumizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n") if (cmd.Info.Permission ~= nil) then - f:write("Permission required: [color=red]", cmd.Info.Permission, "[/color]\n"); + f:write("Permission required: [color=red]", cmd.Info.Permission, "[/color]\n") end if (cmd.Info.DetailedDescription ~= nil) then - f:write(ForumizeString(cmd.Info.DetailedDescription)); + f:write(ForumizeString(cmd.Info.DetailedDescription)) end if (cmd.Info.ParameterCombinations ~= nil) then - WriteCommandParameterCombinationsForum(cmd.CommandString, cmd.Info.ParameterCombinations, f); + WriteCommandParameterCombinationsForum(cmd.CommandString, cmd.Info.ParameterCombinations, f) end end f:write("[/list]\n\n") @@ -313,23 +313,23 @@ end --- Writes all commands in the specified category to the output file, in the Github dump format local function WriteCommandsCategoryGithub(a_Category, f) -- Write category name: - local CategoryName = a_Category.Name; + local CategoryName = a_Category.Name if (CategoryName == "") then - CategoryName = "General"; + CategoryName = "General" end - f:write("\n### ", GithubizeString(a_Category.DisplayName or CategoryName), "\n"); + f:write("\n### ", GithubizeString(a_Category.DisplayName or CategoryName), "\n") -- Write description: if (a_Category.Description ~= "") then - f:write(GithubizeString(a_Category.Description), "\n\n"); + f:write(GithubizeString(a_Category.Description), "\n\n") end - f:write("| Command | Permission | Description | \n") - f:write("| ------- | ---------- | ----------- | \n") + f:write("| Command | Permission | Description |\n") + f:write("| ------- | ---------- | ----------- |\n") -- Write commands: for idx2, cmd in ipairs(a_Category.Commands) do - f:write("|", cmd.CommandString, " | ", cmd.Info.Permission or "", " | ", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "| \n") + f:write("|", cmd.CommandString, " | ", cmd.Info.Permission or "", " | ", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "|\n") end f:write("\n\n") end @@ -340,24 +340,24 @@ end local function DumpCommandsForum(a_PluginInfo, f) -- Copy all Categories from a dictionary into an array: - local Categories = BuildCategories(a_PluginInfo); + local Categories = BuildCategories(a_PluginInfo) -- Sort the categories by name: table.sort(Categories, function(cat1, cat2) - return (string.lower(cat1.Name) < string.lower(cat2.Name)); + return (string.lower(cat1.Name) < string.lower(cat2.Name)) end - ); + ) if (#Categories == 0) then - return; + return end - f:write("\n[size=X-Large]Commands[/size]\n"); + f:write("\n[size=X-Large]Commands[/size]\n") -- Dump per-category commands: for idx, cat in ipairs(Categories) do - WriteCommandsCategoryForum(cat, f); + WriteCommandsCategoryForum(cat, f) end end @@ -367,24 +367,24 @@ end local function DumpCommandsGithub(a_PluginInfo, f) -- Copy all Categories from a dictionary into an array: - local Categories = BuildCategories(a_PluginInfo); + local Categories = BuildCategories(a_PluginInfo) -- Sort the categories by name: table.sort(Categories, function(cat1, cat2) - return (string.lower(cat1.Name) < string.lower(cat2.Name)); + return (string.lower(cat1.Name) < string.lower(cat2.Name)) end - ); + ) if (#Categories == 0) then - return; + return end - f:write("\n# Commands\n"); + f:write("\n# Commands\n") -- Dump per-category commands: for idx, cat in ipairs(Categories) do - WriteCommandsCategoryGithub(cat, f); + WriteCommandsCategoryGithub(cat, f) end end @@ -393,16 +393,16 @@ end local function DumpAdditionalInfoForum(a_PluginInfo, f) - local AInfo = a_PluginInfo.AdditionalInfo; + local AInfo = a_PluginInfo.AdditionalInfo if (type(AInfo) ~= "table") then -- There is no AdditionalInfo in a_PluginInfo - return; + return end for idx, info in ipairs(a_PluginInfo.AdditionalInfo) do if ((info.Title ~= nil) and (info.Contents ~= nil)) then - f:write("\n[size=X-Large]", ForumizeString(info.Title), "[/size]\n"); - f:write(ForumizeString(info.Contents), "\n"); + f:write("\n[size=X-Large]", ForumizeString(info.Title), "[/size]\n") + f:write(ForumizeString(info.Contents), "\n") end end end @@ -412,16 +412,16 @@ end local function DumpAdditionalInfoGithub(a_PluginInfo, f) - local AInfo = a_PluginInfo.AdditionalInfo; + local AInfo = a_PluginInfo.AdditionalInfo if (type(AInfo) ~= "table") then -- There is no AdditionalInfo in a_PluginInfo - return; + return end for idx, info in ipairs(a_PluginInfo.AdditionalInfo) do if ((info.Title ~= nil) and (info.Contents ~= nil)) then - f:write("\n# ", GithubizeString(info.Title), "\n"); - f:write(GithubizeString(info.Contents), "\n"); + f:write("\n# ", GithubizeString(info.Title), "\n") + f:write(GithubizeString(info.Contents), "\n") end end end @@ -434,53 +434,53 @@ end -- Each array item is {Name = "PermissionName", Info = { PermissionInfo }} local function BuildPermissions(a_PluginInfo) -- Collect all used permissions from Commands, reference the commands that use the permission: - local Permissions = a_PluginInfo.Permissions or {}; + local Permissions = a_PluginInfo.Permissions or {} local function CollectPermissions(a_CmdPrefix, a_Commands) for cmd, info in pairs(a_Commands) do - CommandString = a_CmdPrefix .. cmd; + CommandString = a_CmdPrefix .. cmd if ((info.Permission ~= nil) and (info.Permission ~= "")) then -- Add the permission to the list of permissions: - local Permission = Permissions[info.Permission] or {}; - Permissions[info.Permission] = Permission; + local Permission = Permissions[info.Permission] or {} + 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); + Permission.CommandsAffected = Permission.CommandsAffected or {} + table.insert(Permission.CommandsAffected, CommandString) end -- Process the command param combinations for permissions: - local ParamCombinations = info.ParameterCombinations or {}; + local ParamCombinations = info.ParameterCombinations or {} for idx, comb in ipairs(ParamCombinations) do if ((comb.Permission ~= nil) and (comb.Permission ~= "")) then -- Add the permission to the list of permissions: - local Permission = Permissions[comb.Permission] or {}; - Permissions[info.Permission] = Permission; + local Permission = Permissions[comb.Permission] or {} + Permissions[info.Permission] = Permission -- Add the command to the list of commands using this permission: - Permission.CommandsAffected = Permission.CommandsAffected or {}; - table.insert(Permission.CommandsAffected, {Name = CommandString, Params = comb.Params}); + Permission.CommandsAffected = Permission.CommandsAffected or {} + table.insert(Permission.CommandsAffected, {Name = CommandString, Params = comb.Params}) end end -- Process subcommands: if (info.Subcommands ~= nil) then - CollectPermissions(CommandString .. " ", info.Subcommands); + CollectPermissions(CommandString .. " ", info.Subcommands) end end end - CollectPermissions("", a_PluginInfo.Commands); + CollectPermissions("", a_PluginInfo.Commands) -- Copy the list of permissions to an array: - local PermArray = {}; + local PermArray = {} for name, perm in pairs(Permissions) do - table.insert(PermArray, {Name = name, Info = perm}); + table.insert(PermArray, {Name = name, Info = perm}) end -- Sort the permissions array: table.sort(PermArray, function(p1, p2) - return (p1.Name < p2.Name); + return (p1.Name < p2.Name) end - ); - return PermArray; + ) + return PermArray end @@ -489,32 +489,32 @@ end local function DumpPermissionsForum(a_PluginInfo, f) -- Get the processed sorted array of permissions: - local Permissions = BuildPermissions(a_PluginInfo); + local Permissions = BuildPermissions(a_PluginInfo) if ((Permissions == nil) or (#Permissions <= 0)) then - return; + return end -- Dump the permissions: - f:write("\n[size=X-Large]Permissions[/size]\n[list]\n"); + f:write("\n[size=X-Large]Permissions[/size]\n[list]\n") for idx, perm in ipairs(Permissions) do - f:write(" - [color=red]", perm.Name, "[/color] - "); - f:write(ForumizeString(perm.Info.Description or "")); - local CommandsAffected = perm.Info.CommandsAffected or {}; + f:write(" - [color=red]", perm.Name, "[/color] - ") + f:write(ForumizeString(perm.Info.Description or "")) + local CommandsAffected = perm.Info.CommandsAffected or {} if (#CommandsAffected > 0) then - f:write("\n[list] Commands affected:\n- "); - local Affects = {}; + f:write("\n[list] Commands affected:\n- ") + local Affects = {} for idx2, cmd in ipairs(CommandsAffected) do - table.insert(Affects, GetCommandRefForum(cmd)); + table.insert(Affects, GetCommandRefForum(cmd)) end - f:write(table.concat(Affects, "\n - ")); - f:write("\n[/list]"); + f:write(table.concat(Affects, "\n - ")) + f:write("\n[/list]") end if (perm.Info.RecommendedGroups ~= nil) then - f:write("\n[list] Recommended groups: ", perm.Info.RecommendedGroups, "[/list]"); + f:write("\n[list] Recommended groups: ", perm.Info.RecommendedGroups, "[/list]") end - f:write("\n"); + f:write("\n") end - f:write("[/list]"); + f:write("[/list]") end @@ -523,34 +523,35 @@ end local function DumpPermissionsGithub(a_PluginInfo, f) -- Get the processed sorted array of permissions: - local Permissions = BuildPermissions(a_PluginInfo); + local Permissions = BuildPermissions(a_PluginInfo) if ((Permissions == nil) or (#Permissions <= 0)) then - return; + return end -- Dump the permissions: - f:write("\n# Permissions\n"); + f:write("\n# Permissions\n") f:write("| Permissions | Description | Commands | Recommended groups |\n") f:write("| ----------- | ----------- | -------- | ------------------ |\n") for idx, perm in ipairs(Permissions) do - f:write(perm.Name, " | "); - f:write(GithubizeString(perm.Info.Description or ""), " | "); - local CommandsAffected = perm.Info.CommandsAffected or {}; + f:write("| ", perm.Name, " | ") + f:write(GithubizeString(perm.Info.Description or ""), " | ") + local CommandsAffected = perm.Info.CommandsAffected or {} if (#CommandsAffected > 0) then - local Affects = {}; + local Affects = {} for idx2, cmd in ipairs(CommandsAffected) do if (type(cmd) == "string") then - table.insert(Affects, GetCommandRefGithub(cmd)); + table.insert(Affects, GetCommandRefGithub(cmd)) else - table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd)); + table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd)) end end - f:write(table.concat(Affects, ", "), " | "); + f:write(table.concat(Affects, ", ")) end + f:write(" | ") if (perm.Info.RecommendedGroups ~= nil) then - f:write(perm.Info.RecommendedGroups, " |"); + f:write(perm.Info.RecommendedGroups) end - f:write("\n"); + f:write(" |\n") end end @@ -558,45 +559,53 @@ end +--- Dumps the forum-format info for the plugin +-- Returns true on success, nil and error message on failure local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo) -- Open the output file: - local f, msg = io.open(a_PluginInfo.Name .. "_forum.txt", "w"); + local f, msg = io.open(a_PluginFolder .. "/forum_info.txt", "w") if (f == nil) then - print("\tCannot dump forum info for plugin " .. a_PluginFolder .. ": " .. msg); - return; + return nil, msg end -- Write the description: - f:write(ForumizeString(a_PluginInfo.Description), "\n"); - DumpAdditionalInfoForum(a_PluginInfo, f); - DumpCommandsForum(a_PluginInfo, f); - DumpPermissionsForum(a_PluginInfo, f); + f:write(ForumizeString(a_PluginInfo.Description), "\n") + DumpAdditionalInfoForum(a_PluginInfo, f) + DumpCommandsForum(a_PluginInfo, f) + DumpPermissionsForum(a_PluginInfo, f) if (a_PluginInfo.SourceLocation ~= nil) then - f:write("[b][color=blue]Source:[/color] [url=", a_PluginInfo.SourceLocation, "]Link[/url][/b]"); + f:write("[b][color=blue]Source:[/color] [url=", a_PluginInfo.SourceLocation, "]Link[/url][/b]") end - - f:close(); + f:close() + return true end +--- Dumps the README.md file into the plugin's folder with the GitHub Markdown format +-- Returns true on success, nil and error message on failure local function DumpPluginInfoGithub(a_PluginFolder, a_PluginInfo) + -- Check the params: + assert(type(a_PluginFolder) == "string") + assert(type(a_PluginInfo) == "table") + -- Open the output file: - local f, msg = io.open(a_PluginInfo.Name .. ".md", "w"); -- TODO: Save to a_PluginFolder .. "/Readme.md" instead + local f, msg = io.open(a_PluginFolder .. "/README.md", "w") if (f == nil) then - print("\tCannot dump github info for plugin " .. a_PluginFolder .. ": " .. msg); - return; + print("\tCannot dump github info for plugin " .. a_PluginFolder .. ": " .. msg) + return nil, msg end -- Write the description: - f:write(GithubizeString(a_PluginInfo.Description), "\n"); - DumpAdditionalInfoGithub(a_PluginInfo, f); - DumpCommandsGithub(a_PluginInfo, f); - DumpPermissionsGithub(a_PluginInfo, f); + f:write(GithubizeString(a_PluginInfo.Description), "\n") + DumpAdditionalInfoGithub(a_PluginInfo, f) + DumpCommandsGithub(a_PluginInfo, f) + DumpPermissionsGithub(a_PluginInfo, f) - f:close(); + f:close() + return true end @@ -607,36 +616,54 @@ end -- Returns the g_PluginInfo table on success, or nil and error message on failure local function LoadPluginInfo(a_FolderName) -- Load and compile the Info file: - local cfg, err = loadfile(a_FolderName .. "/Info.lua"); + local cfg, err = loadfile(a_FolderName .. "/Info.lua") if (cfg == nil) then - return nil, "Cannot open 'Info.lua': " .. err; + return nil, "Cannot open 'Info.lua': " .. err end -- Execute the loaded file in a sandbox: -- This is Lua-5.1-specific and won't work in Lua 5.2! - local Sandbox = {}; - setfenv(cfg, Sandbox); - cfg(); + local Sandbox = {} + setfenv(cfg, Sandbox) + local isSuccess, errMsg = pcall(cfg) + if not(isSuccess) then + return nil, "Cannot load Info.lua: " .. (errMsg or "<unknown error>") + end + if (Sandbox.g_PluginInfo == nil) then - return nil, "Info.lua doesn't contain the g_PluginInfo declaration"; + return nil, "Info.lua doesn't contain the g_PluginInfo declaration" end - return Sandbox.g_PluginInfo; + return Sandbox.g_PluginInfo end +--- Processes the info for one plugin +-- Returns true on success, nil and error message on failure local function ProcessPluginFolder(a_FolderName) - local PluginInfo, Msg = LoadPluginInfo(a_FolderName); + -- Load the plugin info: + local PluginInfo, Msg = LoadPluginInfo(a_FolderName) if (PluginInfo == nil) then - if (Msg ~= nil) then - print("\t" .. Msg); - end - return; + return nil, "Cannot load info for plugin " .. a_FolderName .. ": " .. (Msg or "<unknown error>") + end + + -- Dump the forum format: + local isSuccess + isSuccess, Msg = DumpPluginInfoForum(a_FolderName, PluginInfo) + if not(isSuccess) then + return nil, "Cannot dump forum info for plugin " .. a_FolderName .. ": " .. (Msg or "<unknown error>") + end + + -- Dump the GitHub format: + isSuccess, Msg = DumpPluginInfoGithub(a_FolderName, PluginInfo) + if not(isSuccess) then + return nil, "Cannot dump GitHub info for plugin " .. a_FolderName .. ": " .. (Msg or "<unknown error>") end - DumpPluginInfoForum(a_FolderName, PluginInfo); - DumpPluginInfoGithub(a_FolderName, PluginInfo); + + -- All OK, return success + return true end @@ -650,7 +677,7 @@ local function LoadLFS() function() return require("lfs") end - ); + ) -- ... rather, print a nice message with instructions: if not(lfs) then @@ -663,44 +690,50 @@ local function LoadLFS() If you don't have luarocks installed, you need to install them using your OS's package manager, usually: sudo apt-get install luarocks (Ubuntu / Debian) On windows, a binary distribution can be downloaded from the LuaRocks homepage, http://luarocks.org/en/Download - ]]); + ]]) - print("Original error text: ", err); - return nil; + print("Original error text: ", err) + return nil end -- We now know that LFS is present, get it normally: - return require("lfs"); + return require("lfs") end -local Arg1 = ...; +local Arg1 = arg[1] if ((Arg1 ~= nil) and (Arg1 ~= "")) then -- Called with a plugin folder name, export only that one - ProcessPluginFolder(Arg1) + local isSuccess, msg = ProcessPluginFolder(Arg1) + if not(isSuccess) then + print(msg or "<unknown error>") + end else -- Called without any arguments, process all subfolders: - local lfs = LoadLFS(); + local lfs = LoadLFS() if (lfs == nil) then -- LFS not loaded, error has already been printed, just bail out - return; + return end - print("Processing plugin subfolders:"); + print("Processing plugin subfolders:") for fnam in lfs.dir(".") do if ((fnam ~= ".") and (fnam ~= "..")) then - local Attributes = lfs.attributes(fnam); + local Attributes = lfs.attributes(fnam) if (Attributes ~= nil) then if (Attributes.mode == "directory") then - print(fnam); - ProcessPluginFolder(fnam); + print(fnam) + local isSuccess, msg = ProcessPluginFolder(fnam) + if not(isSuccess) then + print(" " .. (msg or "<unknown error>")) + end end end end end end -print("Done."); +print("Done.") diff --git a/MCServer/Plugins/MagicCarpet b/MCServer/Plugins/MagicCarpet new file mode 160000 +Subproject 493f2dfa6d39f134e37c4c614cf8d6ffd10c825 diff --git a/MCServer/Plugins/MagicCarpet/objects.lua b/MCServer/Plugins/MagicCarpet/objects.lua deleted file mode 100644 index 8d81623a5..000000000 --- a/MCServer/Plugins/MagicCarpet/objects.lua +++ /dev/null @@ -1,97 +0,0 @@ --- Location object -cLocation = {} -function cLocation:new( x, y, z ) - local object = { x = x, y = y, z = z } - setmetatable(object, { __index = cLocation }) - return object -end - --- Offsets -cFibers = { } -function cFibers:new() - local object = { - cLocation:new( 2, -1, 2 ), - cLocation:new( 2, -1, 1 ), - cLocation:new( 2, -1, 0 ), - cLocation:new( 2, -1, -1 ), - cLocation:new( 2, -1, -2 ), - cLocation:new( 1, -1, 2 ), - cLocation:new( 1, -1, 1 ), - cLocation:new( 1, -1, 0 ), - cLocation:new( 1, -1, -1 ), - cLocation:new( 1, -1, -2 ), - cLocation:new( 0, -1, 2 ), - cLocation:new( 0, -1, 1 ), - cLocation:new( 0, -1, 0 ), - cLocation:new( 0, -1, -1 ), - cLocation:new( 0, -1, -2 ), - cLocation:new( -1, -1, 2 ), - cLocation:new( -1, -1, 1 ), - cLocation:new( -1, -1, 0 ), - cLocation:new( -1, -1, -1 ), - cLocation:new( -1, -1, -2 ), - cLocation:new( -2, -1, 2 ), - cLocation:new( -2, -1, 1 ), - cLocation:new( -2, -1, 0 ), - cLocation:new( -2, -1, -1 ), - cLocation:new( -2, -1, -2 ), - imadeit = false, - } - setmetatable(object, { __index = cFibers }) - return object; -end - --- Carpet object -cCarpet = {} -function cCarpet:new() - local object = { Location = cLocation:new(0,0,0), - Fibers = cFibers:new(), - } - setmetatable(object, { __index = cCarpet }) - return object -end - -function cCarpet:remove() - local World = cRoot:Get():GetDefaultWorld() - for i, fib in ipairs( self.Fibers ) do - local x = self.Location.x + fib.x - local y = self.Location.y + fib.y - local z = self.Location.z + fib.z - local BlockID = World:GetBlock( x, y, z ) - if( fib.imadeit == true and BlockID == E_BLOCK_GLASS ) then - World:SetBlock( x, y, z, 0, 0 ) - fib.imadeit = false - end - end -end - -function cCarpet:draw() - local World = cRoot:Get():GetDefaultWorld() - for i, fib in ipairs( self.Fibers ) do - local x = self.Location.x + fib.x - local y = self.Location.y + fib.y - local z = self.Location.z + fib.z - local BlockID = World:GetBlock( x, y, z ) - if( BlockID == 0 ) then - fib.imadeit = true - World:SetBlock( x, y, z, E_BLOCK_GLASS, 0 ) - else - fib.imadeit = false - end - end -end - -function cCarpet:moveTo( NewPos ) - local x = math.floor( NewPos.x ) - local y = math.floor( NewPos.y ) - local z = math.floor( NewPos.z ) - if( self.Location.x ~= x or self.Location.y ~= y or self.Location.z ~= z ) then - self:remove() - self.Location = cLocation:new( x, y, z ) - self:draw() - end -end - -function cCarpet:getY() - return self.Location.y -end
\ No newline at end of file diff --git a/MCServer/Plugins/MagicCarpet/plugin.lua b/MCServer/Plugins/MagicCarpet/plugin.lua deleted file mode 100644 index 417ea0e02..000000000 --- a/MCServer/Plugins/MagicCarpet/plugin.lua +++ /dev/null @@ -1,81 +0,0 @@ -local Carpets = {} -local PLUGIN - -function Initialize( Plugin ) - Plugin:SetName( "MagicCarpet" ) - Plugin:SetVersion( 2 ) - - cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving) - cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_DESTROYED, OnDisconnect) - - local PluginManager = cPluginManager:Get() - PluginManager:BindCommand("/mc", "magiccarpet", HandleCarpetCommand, " - Spawns a magical carpet"); - - PLUGIN = Plugin - - LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() ) - return true -end - - - - - -function OnDisable() - LOG( PLUGIN:GetName() .. " v." .. PLUGIN:GetVersion() .. " is shutting down..." ) - for i, Carpet in pairs( Carpets ) do - Carpet:remove() - end -end - - - - - -function HandleCarpetCommand( Split, Player ) - Carpet = Carpets[ Player ] - - if( Carpet == nil ) then - Carpets[ Player ] = cCarpet:new() - Player:SendMessageSuccess("You're on a magic carpet!") - Player:SendMessageInfo("Look straight down to descend. Jump to ascend.") - else - Carpet:remove() - Carpets[ Player ] = nil - Player:SendMessageSuccess("The carpet vanished!") - end - - return true -end - - - - - -function OnDisconnect( Reason, Player ) - local Carpet = Carpets[ Player ] - if( Carpet ~= nil ) then - Carpet:remove() - end - Carpets[ Player ] = nil -end - - - - - -function OnPlayerMoving(Player) - local Carpet = Carpets[ Player ] - if( Carpet == nil ) then - return - end - - if( Player:GetPitch() == 90 ) then - Carpet:moveTo( cLocation:new( Player:GetPosX(), Player:GetPosY() - 1, Player:GetPosZ() ) ) - else - if( Player:GetPosY() < Carpet:getY() ) then - Player:TeleportToCoords(Player:GetPosX(), Carpet:getY() + 0.2, Player:GetPosZ()) - end - Carpet:moveTo( cLocation:new( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() ) ) - end -end diff --git a/MCServer/Plugins/ProtectionAreas b/MCServer/Plugins/ProtectionAreas -Subproject 7765048fa740b8f119db72a4ccc546504f86b2a +Subproject 624580e5b522ba2799dfe5b5902b4002b1a8da3 diff --git a/MCServer/webadmin/(original).html b/MCServer/webadmin/(original).html index 239a255e5..673a93ada 100644 --- a/MCServer/webadmin/(original).html +++ b/MCServer/webadmin/(original).html @@ -1,7 +1,7 @@ <!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -<link rel="icon" href="data:application/octet-stream;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQQAAAAAAgIDBRghJ5o5TlumCg0QCQAAAAABAgIEAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgAAAAMAAAAACQwPMxsnL88jMz3/S2d6/0xoetcaIig6AAAAAAEBAQMBAQEDAAAAAAAAAAAAAAAAAQEBAwAAAAAEAwMEFhwhgRomMPwfLTj/IC86/DJHWPxKaH3/TGN0/jk+QYgEBgcFAAAAAAEBAgMAAAAAAAAAAgAAAAAKDRAuHSMpzB8rNP8dKTP8FiIp/QkXGv8sSEr/QV1u/UhnefxWdIb/P1dm0BIYHDEAAAAAAAEBAgAAAAARGB1oIC44/R0rNf8PGiL7DxUa/gwdHv8JKSP/HUdC/x9HQf81W17+Qllv+0lkef9ObYH+Ii42bAAAAAAAAAAAFyIqyBopMf8THSX6BRkY/wIbGP8HHhv/FTs1/yJhVP8lZ1b/H05I/xcuNf8jPET6UWp+/0xqfdAAAAAAAQECBxEcI9oOHh//BRgV/QwsJv8NKyb/EDEr/xU3Mv8zeW7/MHpr/ydqXP8oalz/HVtO/i9KUf9AW2zgBwkLDQEEBBgKGhfuCCMd/w4uKf4RNC7/FTcy/w8yLv8PMi7/LXFn/y55av86gW//OoV7/y11av4YTkj/GkFB8gUICh4BCActCSUf+xAxKv8TNjD/EzYx/w8xLP8PMCr/Fjgy/zp+c/8yfXP/OoN5/zN9cf86hHb/NHlt/y1xZP4LGhc0BhEORQ8zLP8SNC7+EDIt/xEzLf8PMCv/DTAs/w4xKv8vdWT/PYh4/y93bf8sdWj/N4R3/zWBdv43hHn/EysoTQgXFWEQMy//DzEs/Q8xK/8SNC3/FjUv/xEuK/8WPjf/OIBw/0OEdP83e27/N31w/zN8bP8vdWj8Mn5z/xg3MmgLHRp8FDkz/xExLPwNKyT/EjIs/xpEPP8kX1T/OY2C/0KVhv8zgG//NH9z/zuBdf8xeGX/PIF1/DSAdf8cRDyEDCMenBEvJ/8VODT4IVZM/C11af06inv/QZaG/z2Rgf84iXz/O5F+/z2Nff85iX3+OYJ2/DuBdPg5g3X/IVBIohIzLaUydGb/RJiJ/TyYiv88k4P/O4t6/j+Rg/w+j3/9PYt5/TyOgfwuhHf+Nox+/zyViP9Aloj9Q5WC/yxiVa0ECgkHEyciLh1BOWwsZV2sN39y4juNfv5Cmon/O5OF/z2Shf86kYT/NoyA/ziGeeUqZlywHEI8chAjHzQDBwUKAAAAAAAAAAAAAAAAAAAAAAQIBwsSKCQ9JU9GgDN2a8owdGjLH0xFghMpJUAFDAsNAAAAAAAAAAAAAAAAAAAAAP5/AAD8PwAA8A8AAOAHAADAAwAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAAAAAAAAAAAAAAA4AcAAPw/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBBAAAAAEAAAAAGB4leTRGUpAICQsDAAAAAAECAgQAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgABAQQAAAAADA4RHRsjK7UaJi7/U3SH/1Z1isgbJCosAAAAAAEBAgMBAQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQMAAAABAAAAABgeJGEkMz3wHSw1/yExOvxLaHn8TWuA/2SJovkzRVB1AAAAAAAAAAACAgIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQIBAQEEAAAAAAoLDhkcJS2xHy03/xkmL/0fLjb8IC85/0FabP9IZHX8O1Jj/GCFnP9KZHTBEhccIwAAAAABAQIEAQEBAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEDAAAAAgAAAAAXHSJZICw27BQeJv8aJzD7JTZC/iQ1P/8nOUX/JzpJ/0hjdf9FX3H+V3iO+01tgv9Wanj0R0dHZwAAAAAAAAABAQICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBBAAAAAAMDAwUJCouqSAwOv8XIir9Exwj/CM0P/8eLDf/IzM+/xclLv8oPlD/NUla/0Vhc/9EXnH/OU5f/DxPX/xudHn/Ulxjtg8WGxsAAAAAAQICBAEBAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAwAAAAIAAAAAFhofUTI0NugdJSv/Gicw+yQ0P/0YJC7/GCQt/xEbJP8QGSD/CxUb/yhMTf9AWmz/PVds/z5Xaf8+VWf/Q15x/jtTZPtJX3D/VneK7iUxOlsAAAAAAAAAAgECAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAACAkLER4oMKIdKTL/GCEn/RQfJ/weLDb/Gigy/x0lLP8aJS7/DiAj/wgOE/8HFRn/Gks8/0BNS/8xUFv/VXyS/0ZseP9Ye5D/XH+U/0Zhc/xFX3L9SGN2/ztPXqkPFBYUAAAAAAEBAQIAAAAAAAAAAAAAAAAAAAABAAAAABUbIUoqOkbjHy43/xIcJPseLTb9Gicv/xQgKP8NEhn/ISIk/xYkKv8MKyP/Bh0b/wYiHf8RQzz/JTE2/yNYT/8tTVX/KVRM/1N5if9dgJj/RmBy/0pmev1KZXn7Qltt/1NxhOcgKjJOAAAAAAAAAAEAAAAAAQEBBAAAAAATGiBhIjE8/xwrNPwXIyv8His1/yMzPf8OFh7/BgwS/wQSEv8IDxT/CxQa/wUfG/8HJyL/ES0m/ylrYv8YPD//E0I2/xg8Mv8UQTP/LklT/zJHWf80Slv/Ql1x/1yAmP8/VWf8Smd7/E5rgP8fKTFuAAAAAAEBAQQAAQEEAAAAABYhJ5QaJy//FSAo+RglLv8iMz3/Ex8o/wUOEv8GIR3/BB8a/wQYFv8EEBL/Ax4a/wsqJv8VODL/JGhY/xhXTP8kWUv/KWNT/ypuWf8aMDX/HCU0/yEwPv8iMD7/M0dY/0FdcP9egpr6W36T/zlQXacAAAAAAQEBBAAAAAMAAAAAFR8mrR0rNP8YJCz8Fykt/xYiKv8FCRD/BRkY/wglIf8FHhr/AxsY/wYhHf8PKyb/FTo2/xU7N/8ralj/IGRY/ydpV/8wdWr/JW1g/xw9P/8dSkn/FjQ0/xQ/O/8aMDf/TVhi/0ljdvxYe5D/R2NyvgAAAAAAAAACAAAAAQAAAAANFRzGEh0m/x0uN/wKHRn/Bg4T/wMUEv8JJyH/Dy0p/wYjH/8IJB//Gjsz/xQyK/8TNDD/DjMu/z96a/8veG3/J3Fg/zd8b/8oa1//FExD/yhjVv8aWEb/ImRa/xhXTv86SUz/QlNl/Uhmff9bfpPWAAAAAAAAAAAAAAAAAQIDAxEaI9wSIyj/CBYW/QYWE/8HGRr/CSsi/wosI/8RMSz/ES4o/wwtKP8QMy7/Cisn/w8uKv8YNzD/Pod9/zB/df82e3L/Mnho/yduWP8ueW3/N3Zq/ypyZf8nbV3/IFxT/xE4Of8zT1z+Mldc/ztRY+kHCwwNAAAAAAAAAAABBQUSER0d7wwcGP8IIxv+CSId/wsgHP8QMiz/EjYx/w4vKv8XODP/EjIu/w4yLv8KLir/Cywn/w8wKv8qcWj/MH50/ylzYf8ve2j/JnFb/zh+bf8+hHr/LXhu/zJ+bf8wcGf/E09G/x4/Qv4jVEz/IS8++QcKDR0AAAAAAAAAAAEIBiUGFBP+BxgU/wsrJP4HJSD/ES8q/w4xLv8OMi7/FjUu/xM3Mv8XOzf/FDg0/xEzL/8TODT/Cy4q/yRlW/83e3H/KG9g/zSEeP9AhXj/P35u/0GMgf8wf3b/NoR8/yxzaP8hXVT/ED88/xdQSP4gVFL/Bg4QMgAAAAAAAAAAAwsKOgUdGv8NJyH9Dy8p/w8xKf8WOjb/DDEs/xI2MP8UNzD/DTAo/xM2MP8MLib/FTUx/xU1MP8OMy7/PXdo/0KLgP8udW3/JnJo/zyFef9Ai4H/PYd+/y54a/8mcmn/O3xv/zR1aP8obmD/I2JY/CFmWf8LIBpJAAAAAAAAAAAGFBFSCSsk/wssJPwMLib/EjEo/xU3Mv8OMij/HEA4/w4zMP8OMSz/EDAq/wktJ/8NMCv/FDEp/xU3Mf89gnj/PYyA/zyDef8udWv/N4Z8/zB8cv8zd27/LnZj/0GOev9FjYD/OoR7/zuEdv8+gHD7O4Z6/xo2L2IAAAAAAAAAAAcYE20MMCn/EDEr+w4vJv8WODP/EzMv/w8yLP8TODT/DS8q/xAwKv8IKyf/DC8s/w8wK/8MLST/FTQt/zaBdv8pd2P/P4t2/zaEef85e27/Nnpt/y11bP8xeW//QJCD/zyMgf8we2n/N4N6/yduZPtBkYj/Ik5JfAAAAAAAAAAADyMfiBA0Lv8PMiz7GDk1/xAxLf8RMS3/DzIt/xAyLP8PMCf/FzQu/w4vKf8OMC3/EzQv/wgsJ/8JLCf/ImlT/zV3Zf9IkHv/OYh7/yNuaP80e2//KXJp/yNtXf82gnb/MH10/yp3av9AjoX/MH10+zB7cP8eT0mWAAAAAAAAAAARLCiiDjMu/wotJvsTODT/DC8r/wkqJf8PMCj/EDIr/w0yKv8ZOzb/FjUv/xQ2M/8TOjb/DS8r/xk8NP8ocGL/QIV0/0WBcf9Cf3D/Mnhu/zd6bv84e27/KXRk/zh7bP8tdmX/M3lt/zR6bP8veWj8MHxx/y1dUq8AAAAAAAAAAAsnJLsRMi7/DC4q/BU0Lv8OMSz/DS4p/xg4Mv8SNi//ETAq/xs/N/8aPTX/ETEs/xQvKv8YMyv/H05F/yZya/9Km4j/SI+A/zp6a/9Cf23/RYh7/zuGe/86e2v/RYuA/y57af86e2r/J29l/ypyZ/w+jIL/KWVbxwAAAAAAAAAADysn0Rc6Nf8PMS39DS8q/xUzLf8QMiz/DS8l/xEyKv8UNC//EzEs/xAtI/8QMyv/H1FN/zeBeP9CnI//Q5SF/0aRff87h3f/LXVl/yJsWv8xe3T/Q4l+/zh5Zf8reWT/Lnlm/zqHef84fHD/Im9p/Th/dP8pa2HcAAYGBwQIBw4TMy3kFjsy/xI1L/4PMSz/GTo1/xIyKv8KKyL/EzAq/xA0MP8ZQjr/JF1T/zp/cP8xiHb/LIh6/0egkf9Gn5D/NYZ2/ziGcv8whXr/NYuA/zN9dP9Ahnz/Mn91/yNrWP85emb/QYJ3/0SLe/8vd2/+NXpq/zF2ZuwHEREXBxAPIRI3MPQVNSv/GTcw/hY0Lv8UNDH/Cysn/xQ2MP8oX1f/KnFn/0ONf/8yinz/MIh9/z6JeP85in//No+H/yyBdv82iX7/QZOE/yt/aP87jnn/R417/zaFef89kIP/M3dq/0OHev84gXf/R5KA/0KJfv4yf3P/NXhn+hEeGysDDww3EjQr/hcyLP8JJx//Ciwp/yJQSv8ybmD/MYJv/zmUiP8ug3X/QIp8/zyOfP9ElYX/T5yN/0KWhf88i3f/PYh4/ziHfP9El4X/P5aC/zaMf/9Ek4b/M4R2/z2ThP85iX7/Qop9/y+BeP83emz/NHlm/zeCef4mcmn/CyAcQgQTEVQVOTH/GT85/CRYTfstdWr8QJWL/j+Thv8thHT/N4l7/zaIdP85hnL/PI58/zmOfv8+lIb/RZF+/0COe/9AkH7/Qot2/0CTgv8+mI3/MIh2/zOFcv88joL/OY+F/zeFev83in//N4x+/jyFcPw3f237OHpv+0iQf/8fRj1fCh4cTyRkWOxFnIj+TqSR/0idiP9Qo5P/M4N5/Sp9cPs+k4X8RJeL/jqLev8/j37/RpaH/z2SiP84hnn/PZKI/zCHdv86jXz/P46E/zSIfv8xiHv/J31x/y6Eef4rgG/8OYx9+zyPhv05jIH/SZ6Q/1Wyof8/lH//Oohx9yJHPV4AAAAABhAOChw2LzkmTEV3MGxcuDuHdu1Akob/QpuP/0uZiP8yh3r/MIB0/DuKffs4in38PpaD/j6ZjP89kYT/PpCC/0CNgP82g3b+MIV6/S6EevspfHP8Po5//0ihkP8+mon/N4+B/zKCdPM1c2jDH01FhBoyK0YEDQoRAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAQsKDxUuKkIsXliDMnRpwjeEcfRCloH/RJuK/zyRgP9AlIP/PYx+/TKEdvw8kIH8Q5eM/TSLf/8+lYX/SJyM/zuYjf8+lIj3O4F1ySVZU4wWMy1LBhAMFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAgIDAQICBAEBAQIAAAAAAAAAAAAAAAAAAAAACxQRFhk2MkomWFGLOXhryEiZhvRElYf/N46G/zCGef9Dk4P/O5CF9SVpYMsrWlCQFzg0UAwZFxoAAAAAAAAAAAAAAAAAAAAAAAAAAgECAgQBAgIDAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAgIDAQMCBAEBAQIAAAAAAAAAAAAAAAAAAAAACBcTHx4+OVw5dWmnK2peqBo5Ml0MHBkiAAICAQAAAAAAAAAAAAAAAAABAQEBAgIEAQICAwABAQIAAAAAAAAAAAAAAAAAAAAAAAAAAP//f////D////gf///gB///wAP//wAA//4AAH/4AAAf8AAAD+AAAAfAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAOAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAHwAAAH/gAAf//gB////n//"> +<link rel="icon" href="files/favicon.ico"> <title>{TITLE}</title> <style type="text/css" media="screen"> @@ -90,7 +90,7 @@ margin: 15px 0 10px 5px; width: 180px; height: 36px; - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAkCAMAAAAXdeBDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuVQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7OzAAAAAAAAoqKiAAAAvLy8AAAAlZWVtbW1j4+Pra2tiYmJp6enAAAAhISEoaGhAAAAgICAm5ube3t7lZWVd3d3kZGRc3NzjIyMbGxsg4ODgICAeHh43NzcdXV1cnJyy8vLWVlZbGxswcHB09PTvLy8uLi4tLS0sLCwvLy8uLi4tbW1oaGhnp6era2tm5ubqqqq39/f29vblZWV09PT4ODgz8/P3NzckZGRxcXF0tLSwsLCzs7Oy8vLyMjIt7e3vLy85ubm7u7u3d3d5+fn2tra5OTk19fX1dXV3t7e29vb2dnZ1tbW0dHRv7+/8PDw7u7u6+vr8fHx5ubm4+Pj7Ozs4eHh3t7e5+fn5OTk2tra4uLi39/f1dXV3d3d29vb2dnZ19fX1dXV0tLS9fX18/Pzzs7O7u7u8/PzycnJ6urq6Ojo7+/v5ubm7Ozs4+Pj4eHh39/f5ubm5OTk4uLi4ODg2NjY3Nzc29vb19fX8vLy9/f39fX17e3t8/Pz6+vr8fHx7+/v5+fn7e3t5eXl6+vr6enp6Ojo4ODg39/f9PT0+Pj48fHx9vb27+/v9PT07e3t8/Pz7Ozs8fHx7+/v6Ojo7u7u5+fn7Ozs5eXl6urq5OTk6enp5+fn5ubm5OTk+Pj49/f39fX19PT0+fn58vLy8fHx9fX19PT08vLy8fHx6urq+Pj49vb29fX19PT08vLy8PDw+/v7+vr6+Pj49/f39vb29fX18/Pz/f39+/v7+vr6+fn5+Pj49/f3/f39/Pz8+vr6/v7+/f39a5KrdZmxf6G2iai8kq/BnLbHpr7NsMXSuszYxNPdxmZTynBeznpqztvj0YV11Y+B2OLp2ZmM3aOY4a2j4enu5Liv6MK66/D07MzG8NbR9ODd9fj59+vo+/X0ucu1kQAAANl0Uk5TAAECAwQFBgcICQoLDA0ODxAREhMUFBUWFhcXGBgYGRkaGhsbGxwcHB0dHh4fHyEhIiQkJSYnKCgpKSorLC0uLzAxMjIzMzc4Ojo6Ozs8Pj4/P0BBQ0VISUtLTExNTk5PUFFTV1dYWVpbXFxdXl5fYGBhYmJjZGVmZ2doaWprbGxtbW5ub3BxcXJzdHV2d3l6e3x9fX5+f4CAgYGCg4SIi4yNjY6Oj4+QkJGSkpOTlJSVlZaXmJqbnJ2dnp+foKGip6+wsbKztb6/wMHCw8TOz9DR0tPf4OHv8LXp8fEAAAi/SURBVHja3Zh/dBRXFcdhZ+a9eTPzZnaXmJam0FYUEQWLrVVbqdZaf6EWQW2txN/SWiAmxFqtIlWr9bdWqkbwF6WQYIq/+WFpwSZqTahhg6RhNptkl9nsbjeb2eyv+dv73g6wlcyewXMazvGek3Dm5jLv8+689733vTn/q81ldr5zzsWxuVWr55sbCAiiBCYKAeZ1nYIgigJ4Zh2Zj+0OXesTgQ987pOEZUVVVYXISIJQPi3mJETG0kXADggIL5CRWDMy57kCaDgdBMgK1de0gi2jGsESZJt5iXpjS8utGkHiLFMDIHrNgfJBFYs1i0Ei73iifIAggIEHrNDWnuGpFFg50vEKVYbcArNye0+lUCj13aUgYbahRbInbqbu1zAf2XXpR8bN1CZZYItA1jb0pcaiJrdYorxzIRYFYN7qZC2wTOVXMuR+dqGR2hU3Y4NLFSlwJtGIfmbKNFOt4BIkQndOj5rR8dMpsETMjCae+gASJbLKSSftUsWeSJbWz3aqgXBvPGomOnWWajfRoWOjAN2uIWBedOh0NJoYPvJgW1tb+47I1Jg5Vl6AsPrkZLLU+f5bdjjpzNOzDo1pdzw2Fi2vVlBVFgRMf5oyYXl8lmIk00MJc7S8e6mhU02jerC5JzFavgyRlztWbl9j2NC3lvJbpMDFgJ6Ojh/VZb4XA5KycmhkNAXQOpG1ncDfv9HQQNsQZsK3cNvTn5SQ0lKwCveEdYWQd25BrugxUQHjAl/fPKL9Q2t747F/x82pjSpXC0Gme+EJoNt1Vb2jHI1FVlMmawFWYiQgB6mWCIcOaVgCA2ZX3BEGQyI4vAsXWN1of9Bd8diJZ0dG+3QiwuSRsq4cHf8rgzao3jMWnX5Al88oMdNnAQRPlOlwMrcvrBMYk2WrWmyIqlGqqYRJPE+kwK2a0Jr8wo9nNPzRL/QvTpupH4HsAQ4DLX+ZQQeNN02b8W6DSLWVh5mA+EbcHaKkWhF5sdGWdfREIj0dyzSCBDAJY1nGCKo/r/9uguEB/uQZLQZ8Qe+JxwZffGx0ZGixgiSsbXzOTDz2RQYdDm1PmFNrNXTee+ZKMpO8fP+DhiYjAGLF5oYux86m01nb6bqBACr+4Id1/cZHH7pUxne+HkE63fp7522A5xn9IiHgF7ppM6DuokRWjD7Av+7zDHrevEgsFgkq0vndnVtcMvmhjkUKJFvEyqf7ckkrmU7Dr1zfXQTLXyoWv95ZydnblB8UKut5BYL/Rw4Uih9S6Qav6B9CnD/oSGPj0fFouVmn+sOwUH7W9DmmHg0Nw9H4Xp0IM1Z/KOOFjDVhR7ZqMpbVO5yMlS2eGhw8VYTJOC9RtOPp9Ak7adk/picnMv/UZL5jyO0ly+4INntGP+QfOhxeXY6O9c4L31QeGettaLyHQTeuKJsALQdm3PyI0Na+UtZKl3ZSjS7uzVr23z7e0Nj00t8Wk2nnZaoeSadtK1s6uJD+xLYKLSBOTJp6sklnxXLP6AOXin6XRyRoGLsS5nObm34HctccCrdz6GsYNJ0JmquFrOjNvcV0srQrFN5tW/bh5aHQvPm/KQHFVkULDsK3n/x7s0bURZDqPtAg+DxrSlau+5JOz2gVCX434nGod4uhpDzzielo/HFdD7bXzbSbbBHJmvEAbMjK5qZTyUz/8qCuhzsZxf0qUUODaSt94n06rB3aYVulZhVLMgXRcd5SL1oM+IamCtEeTpmn/wFyt1JV9ba6a9qlZtgKUE9kjn0vb+W/FdapsYtTaBgrDCP/3bAiQX4XD01ke6B8qisdkPf5364TDcy+oQkmRu/YyGmmITKhbXXVwy10DFtSgjsgjX/KWc41IeMshQj+wTT4dBxg3cx2iGHbvCuXdN58yb560XP8Q8sSUpunzOho/xICX73trE5P33yeTgOre0KDNYLp1Y5l/xkwrm0In6UICMSArTUYVmHGMLNlTjLbGw69chj+aWjorhftHxoECWrh43HoouEluAodNNZMzVQRWQty2wJJ5NRIexU0fAz6tU2dVQomyVUM+ExCtXGspvjnLOGh0N460RcELQQkcn15/AnAFxCHbvPqPUSE9xedKyBDHPpqBm1blXc/5lKwfkRSOIbBNwQ8vQEW8x+uexaWtqEb2z2jLxSaadjb/vJWLAUCLnRtlye4bQ7CYPK7Slb+ayrMhfUqt1Ss/PeLlv17RvFVqsisEcQqx2C7+FyqfwmJXqcp2ke9oi8YGl4tSkgSAM6Fph799KcU7SSkLEgJxoSGYYVW3v5MZqIAFN8I65qqvu6RLUQLcgx4r9ukO0n7X5lsr04w0fu9on1CI5VDY4F/fN5DAnRriq3u2pMLrTm5XKVBjcvvDoPTCO8uJSePzr+3YFlp5ztNDUEjuO6pXP4rtAaDp/rI5ETBKn5MRbDl2zyifUMrDFrFgdoeTuHQyrkz4hCcEcF29PMz4lXKlVAk8r3fXHtzey8rw+8JzTtsW5POH++9dkV7twM1ehtlH/w4K6duqteWLCgphiyyJeUd7cMAkDwK0AQ9D5psAuhN5NxpfMQ9jY/y07gsK6ucSSubL1UKWYttJ5UuBY5kruA4BWjf7IOXqxRaoLPJgK5Dh36j0Mo6EJjBEo9on9AifiQeG8BSLbSA7wbou7HHvYcsSUhZ9aQ9YYFN5CJbVRnJ6pLDxYzFLVM8dDkhykA6PSDDe91UQ39X7fV4i+gZ7ceA6tW/HviCVNumwAh4f3k/ljxvmAQBkSs7TpYKheLQnusVJIIMErqxr1TI5QqVvg0gZAjfNzBwH3Lfy0DJeod31ezBO9qXsfOPexqqnQlagGa8y1MJFqviB85bW1o+QiHNTHEENrn3tnZ1tb6RsmMBkyJUcznJ5PIyyRX8OtF+jEsGG/S/fPyIOdOtKZuf2+NhonAPBLqTI6qmKQTDLPhrmbjXjnPmuW60/wtqryt07/tp3oA8z8MdCHHXjBcC7mOd6Bfk7r3udC94aDf6/9T+AzWzIkAbVeu4AAAAAElFTkSuQmCC) no-repeat left top; + background: url(files/logo.png) no-repeat left top; } h1 a { @@ -114,7 +114,7 @@ #container { - background: #fff url(data:image/gif;base64,R0lGODlhtAABAIAAAN3d3f///yH5BAAAAAAALAAAAAC0AAEAAAIMjI+py+0Po5y0WgYKADs%3D) repeat-y left top; + background: #fff url(files/background.gif) repeat-y left top; border: 1px solid #ddd; width: 918px; @@ -155,7 +155,7 @@ margin-top:100px; width: 180px; height: 36px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAkCAMAAAAXdeBDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuVQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7OzAAAAAAAAoqKiAAAAvLy8AAAAlZWVtbW1j4+Pra2tiYmJp6enAAAAhISEoaGhAAAAgICAm5ube3t7lZWVd3d3kZGRc3NzjIyMbGxsg4ODgICAeHh43NzcdXV1cnJyy8vLWVlZbGxswcHB09PTvLy8uLi4tLS0sLCwvLy8uLi4tbW1oaGhnp6era2tm5ubqqqq39/f29vblZWV09PT4ODgz8/P3NzckZGRxcXF0tLSwsLCzs7Oy8vLyMjIt7e3vLy85ubm7u7u3d3d5+fn2tra5OTk19fX1dXV3t7e29vb2dnZ1tbW0dHRv7+/8PDw7u7u6+vr8fHx5ubm4+Pj7Ozs4eHh3t7e5+fn5OTk2tra4uLi39/f1dXV3d3d29vb2dnZ19fX1dXV0tLS9fX18/Pzzs7O7u7u8/PzycnJ6urq6Ojo7+/v5ubm7Ozs4+Pj4eHh39/f5ubm5OTk4uLi4ODg2NjY3Nzc29vb19fX8vLy9/f39fX17e3t8/Pz6+vr8fHx7+/v5+fn7e3t5eXl6+vr6enp6Ojo4ODg39/f9PT0+Pj48fHx9vb27+/v9PT07e3t8/Pz7Ozs8fHx7+/v6Ojo7u7u5+fn7Ozs5eXl6urq5OTk6enp5+fn5ubm5OTk+Pj49/f39fX19PT0+fn58vLy8fHx9fX19PT08vLy8fHx6urq+Pj49vb29fX19PT08vLy8PDw+/v7+vr6+Pj49/f39vb29fX18/Pz/f39+/v7+vr6+fn5+Pj49/f3/f39/Pz8+vr6/v7+/f39a5KrdZmxf6G2iai8kq/BnLbHpr7NsMXSuszYxNPdxmZTynBeznpqztvj0YV11Y+B2OLp2ZmM3aOY4a2j4enu5Liv6MK66/D07MzG8NbR9ODd9fj59+vo+/X0ucu1kQAAANl0Uk5TAAECAwQFBgcICQoLDA0ODxAREhMUFBUWFhcXGBgYGRkaGhsbGxwcHB0dHh4fHyEhIiQkJSYnKCgpKSorLC0uLzAxMjIzMzc4Ojo6Ozs8Pj4/P0BBQ0VISUtLTExNTk5PUFFTV1dYWVpbXFxdXl5fYGBhYmJjZGVmZ2doaWprbGxtbW5ub3BxcXJzdHV2d3l6e3x9fX5+f4CAgYGCg4SIi4yNjY6Oj4+QkJGSkpOTlJSVlZaXmJqbnJ2dnp+foKGip6+wsbKztb6/wMHCw8TOz9DR0tPf4OHv8LXp8fEAAAi/SURBVHja3Zh/dBRXFcdhZ+a9eTPzZnaXmJam0FYUEQWLrVVbqdZaf6EWQW2txN/SWiAmxFqtIlWr9bdWqkbwF6WQYIq/+WFpwSZqTahhg6RhNptkl9nsbjeb2eyv+dv73g6wlcyewXMazvGek3Dm5jLv8+689733vTn/q81ldr5zzsWxuVWr55sbCAiiBCYKAeZ1nYIgigJ4Zh2Zj+0OXesTgQ987pOEZUVVVYXISIJQPi3mJETG0kXADggIL5CRWDMy57kCaDgdBMgK1de0gi2jGsESZJt5iXpjS8utGkHiLFMDIHrNgfJBFYs1i0Ei73iifIAggIEHrNDWnuGpFFg50vEKVYbcArNye0+lUCj13aUgYbahRbInbqbu1zAf2XXpR8bN1CZZYItA1jb0pcaiJrdYorxzIRYFYN7qZC2wTOVXMuR+dqGR2hU3Y4NLFSlwJtGIfmbKNFOt4BIkQndOj5rR8dMpsETMjCae+gASJbLKSSftUsWeSJbWz3aqgXBvPGomOnWWajfRoWOjAN2uIWBedOh0NJoYPvJgW1tb+47I1Jg5Vl6AsPrkZLLU+f5bdjjpzNOzDo1pdzw2Fi2vVlBVFgRMf5oyYXl8lmIk00MJc7S8e6mhU02jerC5JzFavgyRlztWbl9j2NC3lvJbpMDFgJ6Ojh/VZb4XA5KycmhkNAXQOpG1ncDfv9HQQNsQZsK3cNvTn5SQ0lKwCveEdYWQd25BrugxUQHjAl/fPKL9Q2t747F/x82pjSpXC0Gme+EJoNt1Vb2jHI1FVlMmawFWYiQgB6mWCIcOaVgCA2ZX3BEGQyI4vAsXWN1of9Bd8diJZ0dG+3QiwuSRsq4cHf8rgzao3jMWnX5Al88oMdNnAQRPlOlwMrcvrBMYk2WrWmyIqlGqqYRJPE+kwK2a0Jr8wo9nNPzRL/QvTpupH4HsAQ4DLX+ZQQeNN02b8W6DSLWVh5mA+EbcHaKkWhF5sdGWdfREIj0dyzSCBDAJY1nGCKo/r/9uguEB/uQZLQZ8Qe+JxwZffGx0ZGixgiSsbXzOTDz2RQYdDm1PmFNrNXTee+ZKMpO8fP+DhiYjAGLF5oYux86m01nb6bqBACr+4Id1/cZHH7pUxne+HkE63fp7522A5xn9IiHgF7ppM6DuokRWjD7Av+7zDHrevEgsFgkq0vndnVtcMvmhjkUKJFvEyqf7ckkrmU7Dr1zfXQTLXyoWv95ZydnblB8UKut5BYL/Rw4Uih9S6Qav6B9CnD/oSGPj0fFouVmn+sOwUH7W9DmmHg0Nw9H4Xp0IM1Z/KOOFjDVhR7ZqMpbVO5yMlS2eGhw8VYTJOC9RtOPp9Ak7adk/picnMv/UZL5jyO0ly+4INntGP+QfOhxeXY6O9c4L31QeGettaLyHQTeuKJsALQdm3PyI0Na+UtZKl3ZSjS7uzVr23z7e0Nj00t8Wk2nnZaoeSadtK1s6uJD+xLYKLSBOTJp6sklnxXLP6AOXin6XRyRoGLsS5nObm34HctccCrdz6GsYNJ0JmquFrOjNvcV0srQrFN5tW/bh5aHQvPm/KQHFVkULDsK3n/x7s0bURZDqPtAg+DxrSlau+5JOz2gVCX434nGod4uhpDzzielo/HFdD7bXzbSbbBHJmvEAbMjK5qZTyUz/8qCuhzsZxf0qUUODaSt94n06rB3aYVulZhVLMgXRcd5SL1oM+IamCtEeTpmn/wFyt1JV9ba6a9qlZtgKUE9kjn0vb+W/FdapsYtTaBgrDCP/3bAiQX4XD01ke6B8qisdkPf5364TDcy+oQkmRu/YyGmmITKhbXXVwy10DFtSgjsgjX/KWc41IeMshQj+wTT4dBxg3cx2iGHbvCuXdN58yb560XP8Q8sSUpunzOho/xICX73trE5P33yeTgOre0KDNYLp1Y5l/xkwrm0In6UICMSArTUYVmHGMLNlTjLbGw69chj+aWjorhftHxoECWrh43HoouEluAodNNZMzVQRWQty2wJJ5NRIexU0fAz6tU2dVQomyVUM+ExCtXGspvjnLOGh0N460RcELQQkcn15/AnAFxCHbvPqPUSE9xedKyBDHPpqBm1blXc/5lKwfkRSOIbBNwQ8vQEW8x+uexaWtqEb2z2jLxSaadjb/vJWLAUCLnRtlye4bQ7CYPK7Slb+ayrMhfUqt1Ss/PeLlv17RvFVqsisEcQqx2C7+FyqfwmJXqcp2ke9oi8YGl4tSkgSAM6Fph799KcU7SSkLEgJxoSGYYVW3v5MZqIAFN8I65qqvu6RLUQLcgx4r9ukO0n7X5lsr04w0fu9on1CI5VDY4F/fN5DAnRriq3u2pMLrTm5XKVBjcvvDoPTCO8uJSePzr+3YFlp5ztNDUEjuO6pXP4rtAaDp/rI5ETBKn5MRbDl2zyifUMrDFrFgdoeTuHQyrkz4hCcEcF29PMz4lXKlVAk8r3fXHtzey8rw+8JzTtsW5POH++9dkV7twM1ehtlH/w4K6duqteWLCgphiyyJeUd7cMAkDwK0AQ9D5psAuhN5NxpfMQ9jY/y07gsK6ucSSubL1UKWYttJ5UuBY5kruA4BWjf7IOXqxRaoLPJgK5Dh36j0Mo6EJjBEo9on9AifiQeG8BSLbSA7wbou7HHvYcsSUhZ9aQ9YYFN5CJbVRnJ6pLDxYzFLVM8dDkhykA6PSDDe91UQ39X7fV4i+gZ7ceA6tW/HviCVNumwAh4f3k/ljxvmAQBkSs7TpYKheLQnusVJIIMErqxr1TI5QqVvg0gZAjfNzBwH3Lfy0DJeod31ezBO9qXsfOPexqqnQlagGa8y1MJFqviB85bW1o+QiHNTHEENrn3tnZ1tb6RsmMBkyJUcznJ5PIyyRX8OtF+jEsGG/S/fPyIOdOtKZuf2+NhonAPBLqTI6qmKQTDLPhrmbjXjnPmuW60/wtqryt07/tp3oA8z8MdCHHXjBcC7mOd6Bfk7r3udC94aDf6/9T+AzWzIkAbVeu4AAAAAElFTkSuQmCC); + background-image: url(files/logo.png); } #loginHolder { diff --git a/MCServer/webadmin/files/guest.html b/MCServer/webadmin/files/guest.html new file mode 100644 index 000000000..7ae78a3f0 --- /dev/null +++ b/MCServer/webadmin/files/guest.html @@ -0,0 +1,2 @@ +Hello! Welcome to the MCServer WebAdmin.<br> +This is a default message, edit <b>files/guest.html</b> to add your own custom message. diff --git a/MCServer/webadmin/files/header.png b/MCServer/webadmin/files/header.png Binary files differnew file mode 100644 index 000000000..97b067715 --- /dev/null +++ b/MCServer/webadmin/files/header.png diff --git a/MCServer/webadmin/files/home.gif b/MCServer/webadmin/files/home.gif Binary files differnew file mode 100644 index 000000000..b10e0bed7 --- /dev/null +++ b/MCServer/webadmin/files/home.gif diff --git a/MCServer/webadmin/files/loading.gif b/MCServer/webadmin/files/loading.gif Binary files differnew file mode 100644 index 000000000..b8d06f669 --- /dev/null +++ b/MCServer/webadmin/files/loading.gif diff --git a/MCServer/webadmin/files/log_out.png b/MCServer/webadmin/files/log_out.png Binary files differnew file mode 100644 index 000000000..63232417a --- /dev/null +++ b/MCServer/webadmin/files/log_out.png diff --git a/MCServer/webadmin/files/login.css b/MCServer/webadmin/files/login.css new file mode 100644 index 000000000..5d87da4c5 --- /dev/null +++ b/MCServer/webadmin/files/login.css @@ -0,0 +1,219 @@ +/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */ +* { + margin: 0; +} + +body { + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + -webkit-font-smoothing: antialiased; + background: #fff url(header.png) repeat-x top left; + width: 100%; + min-width: 100%; + overflow: hidden; +} + +a:link { + color: #555; + text-decoration: none; +} + +a:visited { + color: #444; + text-decoration: none; +} + +a:hover, a:active { + color: #000; + text-decoration: underline; +} + +img { + border: none; +} + +h1 { + color: #069; +} + +.row1 { + border-bottom: 1px solid #000; + height: 100px; + max-height: 100px; +} + +.row2 { + margin: 0 auto; + text-align: center; + vertical-align: middle; +} + +.contention { + color: #000; + text-align: left; + line-height: 1.4; + margin: 0; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + font-size: 13px; +} + +button { + background: #fff; + color: #000; + border: 1px solid #ccc; + padding: 3px; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + margin: -3px 0; +} + +button:hover { + border-top-color: #28597a; + background: #28597a; + color: #ccc; +} + +button:active { + border-top-color: #1b435e; + background: #1b435e; +} + +.push10 { + padding-bottom: 75px; +} + +#panel .upper { + background: #dcdbdc url(tcat.png) repeat-x; + border-top: 1px solid #fff; + border-bottom: 1px solid #bbb; + padding: 7px; +} + +#footer { + z-index: 99999; +} + +#footer ul.menu { + margin: 0; + padding: 0; + list-style: none; +} + +#footer ul.menu li { + margin: 0 5px; + display: inline; +} + +#footer .upper { + background: #dcdbdc url(tcat.png) repeat-x; + border-top: 1px solid #bbb; + padding: 6px; + overflow: hidden; + font-size: 12px; +} + +#footer .upper ul.bottom_links { + float: left; + margin: 3px 0 0 -5px; +} + +#footer .lower { + background: #a1a2a2 url(thead.png) top left repeat-x; + color: #fff; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ddd; + overflow: hidden; + padding: 8px; + font-size: 11px; +} + +#footer .lower a:link, #footer .lower a:visited { + color: #fff; + font-weight: 700; +} + +#footer .lower a:hover, #footer .lower a:active { + color: #fff; + font-weight: 700; +} + +#footer .lower #current_time { + float: right; + padding-right: 6px; +} + +.wrapper { + width: 85%; + min-width: 970px; + max-width: 1500px; + margin: auto; +} + +#footer { + position: fixed; + left: 0; + bottom: 0; + height: 60px; + width: 100%; + background: #999; + border-top: 1px #000 solid; +} + +* html #footer { + position: absolute; + top: expression((0-(footer.offsetHeight)+(document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)+(ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop))+'px'); +} + +tr td.trow2:first-child { + border-left: 0; +} + +tr td.trow2:last-child { + border-right: 0; +} + +.tborder { + -moz-border-radius: 7px; + -webkit-border-radius: 7px; + border-radius: 7px; +} + +.thead, .rounded_top { + -moz-border-radius-topleft: 6px; + -moz-border-radius-topright: 6px; + -webkit-border-top-left-radius: 6px; + -webkit-border-top-right-radius: 6px; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +table { + color: #000; + font-size: 13px; +} + +.tborder { + background: #fff; + width: 100%; + margin: auto; + border: 1px solid #ccc; + padding: 1px; +} + +.thead { + background: #a1a2a2 url(thead.png) top left repeat-x; + color: #fff; + border-bottom: 1px solid #8e8f8f; + padding: 8px; +} + +.trow2 { + background: #efefef; + border: 1px solid; + border-color: #fff #ddd #ddd #fff; +} + +.padtopp { + padding-top: 25px; +} diff --git a/MCServer/webadmin/files/login.gif b/MCServer/webadmin/files/login.gif Binary files differnew file mode 100644 index 000000000..ce2cb6fc0 --- /dev/null +++ b/MCServer/webadmin/files/login.gif diff --git a/MCServer/webadmin/files/logo_login.png b/MCServer/webadmin/files/logo_login.png Binary files differnew file mode 100644 index 000000000..d2155f928 --- /dev/null +++ b/MCServer/webadmin/files/logo_login.png diff --git a/MCServer/webadmin/files/pmfolder.gif b/MCServer/webadmin/files/pmfolder.gif Binary files differnew file mode 100644 index 000000000..3fc68fdcb --- /dev/null +++ b/MCServer/webadmin/files/pmfolder.gif diff --git a/MCServer/webadmin/files/style.css b/MCServer/webadmin/files/style.css index e7ffe3999..7c0671970 100644 --- a/MCServer/webadmin/files/style.css +++ b/MCServer/webadmin/files/style.css @@ -1,326 +1,427 @@ -/* reset CSS */ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-size: 100%; - vertical-align: baseline; - background: transparent; +/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */ +* { + margin: 0; } + body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + -webkit-font-smoothing: antialiased; + background: #fff; + width: 100%; + min-width: 100%; + height:100%; + min-height:100%; + overflow-y: scroll; + overflow-x: hidden; } -/* remember to define focus styles! */ -:focus { - outline: 0; +a:link { + color: #555; + text-decoration: none; } -/* remove textarea resize at Safari */ -textarea { - resize: none; +a:visited { + color: #444; + text-decoration: none; } -/* remember to highlight inserts somehow! */ -ins { - text-decoration: none; -} -del { - text-decoration: line-through; +a:hover, a:active { + color: #000; + text-decoration: underline; } -/* tables still need 'cellspacing="0"' in the markup */ -table { - border-collapse: collapse; - border-spacing: 0; +img { + border: none; } +h1 { + color: #069; + text-shadow: 2px 2px #000; +} -/* - Origional from http://www.perspectived.com/ - Modified by Ben Phelps - Made for FakeTruth - MCServer -*/ +.row1 { + border-bottom: 1px #000 solid; + height: 100px; + max-height: 100px; + background: #fff url(header.png) repeat-x top left; +} -/* Basic ---------------------------------------- */ +.row2 { + margin: 0 auto; + text-align: center; + vertical-align: middle; + margin-top: 25px; + margin-bottom: 25px; +} -.clear { clear: both; } +.contention { + color: #000; + text-align: left; + line-height: 1.4; + margin: 0; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + font-size: 13px; + margin-bottom:75px; +} -body { - background: white; - font-family: Arial, Helvetica, sans-serif; - font-size: 12px; - color: #646464; - text-align: center; +.push25 { } -#wrapper { - text-align: left; - width: 930px; - margin: 0 auto; +#panel ul.menu { + margin: 0; + padding: 0; + list-style: none; } -/* Logo ---------------------------------------- */ +#panel ul.menu li { + margin: 0 5px; + display: inline; +} -h1 { - margin: 15px 0 10px 5px; - width: 180px; - height: 36px; - background: url(logo.png) no-repeat left top; +#panel ul.menu li a { + padding-left: 20px; + background-repeat: no-repeat; + background-position: left center; } -h1 a { - display: block; - width: 225px; - height: 28px; +#panel .upper ul.top_links { + float: right; + font-weight: 700; } -h1 span { display: none; } +#panel .upper { + background: #dcdbdc url(tcat.png) repeat-x; + border-top: 1px solid #fff; + border-bottom: 1px solid #bbb; + padding: 7px; +} -a { - color: #646464; +#footer ul.menu { + margin: 0; + padding: 0; + list-style: none; } -/* Container ---------------------------------------- */ +#footer ul.menu li { + margin: 0 5px; + display: inline; +} -#containerHolder { - background: #eee; - padding: 5px; +#footer .upper { + background: #dcdbdc url(tcat.png) repeat-x; + border-top: 1px solid #bbb; + padding: 6px; + overflow: hidden; + font-size: 12px; } +#footer .upper ul.bottom_links { + float: left; + margin: 3px 0 0 -5px; +} -#container { - background: #fff url(background.gif) repeat-y left top; - border: 1px solid #ddd; - width: 918px; +#footer .lower { + background: #a1a2a2 url(thead.png) top left repeat-x; + color: #fff; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ddd; + overflow: hidden; + padding: 8px; + font-size: 11px; +} +#footer .lower a:link,#footer .lower a:visited { + color: #fff; + font-weight: 700; } -#connectHolder { - background: #eee; - padding: 5px; - margin-bottom:8px; +#footer .lower a:hover,#footer .lower a:active { + color: #fff; + font-weight: 700; } +#footer .lower #current_time { + float: right; + padding-right: 6px; +} -#connect { - border: 1px solid #ddd; - background-color: #fff; - padding:5px; - width: 908px; +.wrapper { + width: 85%; + min-width: 970px; + max-width: 1500px; + margin: auto; } -.pics { - height: 375px; - width: 600px; -} +#footer { + position: fixed; + left:0; + bottom:0; + height: 61px; + width: 100%; + background: #999; + border-top: 1px #000 solid; + border-bottom: 1px #000 solid; +} -.pics img { - padding: 5px; - border: 1px solid #ddd; - background-color: #eee; - width: 600px; - height: 375px; - margin-left: 15px; +* html #footer { + position: absolute; + top: expression((0-(footer.offsetHeight)+(document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)+(ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop))+'px'); } -/* Login -------------------------------------- */ +tr td.trow1:first-child, tr td.trow2:first-child { + border-left: 0; +} -#loginLogo { - margin: 0 auto; - margin-top:100px; - width: 180px; - height: 36px; - background-image: url(logo.png); +tr td.trow1:last-child, tr td.trow2:last-child { + border-right: 0; } -#loginHolder { - background: #eee; - padding: 5px; - width: 310px; - margin: 0 auto; - height: 90px; - margin-top:20px; +.tborder { + -moz-border-radius: 7px; + -webkit-border-radius: 7px; + border-radius: 7px; } -#login { - padding:10px; - width: 288px; - height: 68px; - border: 1px solid #ddd; - background:#fff; - text-align: left; +.thead { + -moz-border-radius-topleft: 6px; + -moz-border-radius-topright: 6px; + -webkit-border-top-left-radius: 6px; + -webkit-border-top-right-radius: 6px; + border-top-left-radius: 6px; + border-top-right-radius: 6px; } +table { + color: #000; + font-size: 13px; +} -/* Sidebar ---------------------------------------- */ +.tborder { + background: #fff; + width: 100%; + margin: auto; + border: 1px solid #ccc; + padding: 1px; +} -#sidebar { - width: 179px; - float: left; +.thead { + background: #a1a2a2 url(thead.png) top left repeat-x; + color: #fff; + border-bottom: 1px solid #8e8f8f; + padding: 8px; } -#sidebar .sideNav { width: 179px; } +.tcat { + background: #dcdbdc url(tcat.png) repeat-x; + color: #fff; + border-bottom: 1px solid #bbb; + padding: 6px; + font-size: 12px; +} -#sidebar .sideNav li { border-bottom: 1px solid #ddd; width: 179px; } +.trow1 { + background: #f5f5f5; + border: 1px solid; + border-color: #fff #ddd #ddd #fff; +} -#sidebar .sideNav li a { - display: block; - color: #646464; - background: #f6f6f6; - text-decoration: none; - height: 29px; - line-height: 29px; - padding: 0 19px; - width: 141px; +.trow2 { + background: #efefef; + border: 1px solid; + border-color: #fff #ddd #ddd #fff; + padding: 15px; + box-sizing: border-box; + -moz-box-sizing: border-box; } -#sidebar .sideNav li a:hover { background: #fdfcf6; } +table { + color: #000; + font-size: 13px; + text-align: left; +} -#sidebar .sideNav li a.active, #sidebar .sideNav li a.active:hover { - background: #f0f7fa; - color: #c66653; +.tborder { + background: #fff; + width: 100%; + margin: auto; + border: 1px solid #ccc; + padding: 1px; } -/* Breadcrumb ---------------------------------------- */ +.thead { + background: #a1a2a2 url(thead.png) top left repeat-x; + color: #fff; + border-bottom: 1px solid #8e8f8f; + padding: 8px; +} -h2 { - width: 718px; - float: right; - color: #646464; - font-size: 16px; - line-height: 16px; - font-weight: bold; - margin: 20px 0 0 0; - padding: 0 0 10px 0; - border-bottom: 1px solid #ddd; +.tcat { + background: #dcdbdc url(tcat.png) repeat-x; + color: #fff; + border-bottom: 1px solid #bbb; + padding: 6px; + font-size: 12px; } -h2 a { - color: #646464; - text-decoration: none; +.trow1 { + background: #f5f5f5; + border: 1px solid; + border-color: #fff #ddd #ddd #fff; } -h2 a.active { color: #c66653; } +.trow2 { + background: #efefef; + border: 1px solid; + border-color: #fff #ddd #ddd #fff; +} -h2 a:hover { text-decoration: underline; } +.smalltext { + font-size: 11px; +} -/* Content ---------------------------------------- */ +textarea { + background: #fff; + color: #000; + border: 1px solid #ccc; + padding: 2px; + line-height: 1.4; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + font-size: 13px; +} -#main { - width: 700px; - float: right; - padding: 0 19px 0 0; +select { + background: #fff; + padding: 3px; + border: 1px solid #ccc; + font-family: Tahoma,Verdana,Arial,Sans-Serif; } -#main p { +.usercp_nav_item { + display: block; + padding: 1px 0 1px 23px; +} - padding: 10px; +.usercp_nav_pmfolder { + background: url(pmfolder.gif) no-repeat left center; +} +.usercp_nav_sub_pmfolder { + padding-left: 40px; + background: url(sub_pmfolder.gif) no-repeat left center; } -h3 { - font-size: 14px; - line-height: 14px; - font-weight: bold; - color: #5494af; - padding: 0 0 0 10px; - margin: 20px 0 10px; +.usercp_nav_home { + background: url(home.gif) no-repeat left center; } -h4 { - padding: 0 0 0 10px; - margin: 20px 0 10px; +.pagehead { + top: 0; + left: 0; + width: 100%; } -#main ul { - padding: 0 0 0 10px; - list-style-type: circle; - list-style-position: inside; +table { + width: 100%; } -#main table { - border-top: 1px solid #ddd; - width: 700px; +table th { + border-bottom: 1px solid rgba(0,0,0,0.12); + padding: 5px; + text-align: left; } -#main table tr th { - text-align: left; - background: #f6f6f6; - padding: 0px 20px; - height: 20px; - line-height: 20px; - border-bottom: 1px solid #ddd; +table tr:nth-child(odd) { + background-color: rgba(0,0,0,0.015); } -#main table tr td { - background: #f6f6f6; - padding: 0px 20px; - height: 29px; - line-height: 29px; - border-bottom: 1px solid #ddd; +p { + margin: 4px 0; + padding: 4px 3px; } -#main table tr.odd td { - background: #fbfbfb; +a { + text-decoration: none; + color: #000; + -webkit-transition: color .1s linear; + -moz-transition: color .1s linear; + transition: color .1s linear; } -#main table tr:hover td { background: #fdfcf6; } +a:hover { + color: #888; +} -#main table .action { - text-align: right; - padding: 0 20px 0 10px; +input[type="text"] { + background: #fff; + color: #000; + border: 1px solid #ccc; + padding: 2px; + line-height: 1.4; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + font-size: 13px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; } -#main table tr .action a { margin: 0 0 0 10px; text-decoration: none; color: #9b9b9b; } -#main table tr:hover .action .edit { color: #c5a059; } -#main table tr:hover .action .delete { color: #a02b2b; } -#main table tr:hover .action .view { color: #55a34a; } +input[type="text"]:hover { + background-color: #E5E4E2; +} -#main table tr:hover .action a:hover { text-decoration: underline; } +input[type="text"]:focus { + background-color: #E5E4E2; +} -fieldset { - border: 1px solid #ddd; - padding: 19px; - margin: 0 0 20px 0; - background: #fbfbfb; +hr { + border: none; + height: 1px; + background-color: rgba(0,0,0,0.12); } -form p { margin: 0 0 14px 0; float: left; width: 100%; } +h4 { + padding-bottom: 10px; + margin-bottom: 12px; + border-bottom: 1px solid rgba(0,0,0,0.12); +} -label { - display: block; - width: 100%; - margin: 0 0 7px 0; - line-height: 12px; +#ChatDiv { + margin-bottom: 10px; } -/* Footer ---------------------------------------- */ +#ChatMessage { + width: 92%; + margin-right: 5px; + box-sizing: border-box; + -moz-box-sizing: border-box; +} -#footer { - margin: 10px 0 30px 0; - font-size: 11px; - line-height: 11px; - color: #9B9B9B; - padding: 0 0 0 5px; +input[type="submit"] { + padding: 3px; + padding-left: 5px; + padding-right: 5px; + cursor: pointer; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + background: #f5f5f5; + border: 1px solid #ccc; } -#footer a { color: #9B9B9B; } +input[type="submit"]:hover { + background-color: #E5E4E2; +} -#footer a:hover { text-decoration: none; } +button:disabled,input:disabled { + padding: 3px; + padding-left: 5px; + padding-right: 5px; + cursor: pointer; + font-family: Tahoma,Verdana,Arial,Sans-Serif; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + border: none!important; + color: #fff!important; + background-color: #ccc!important; +} diff --git a/MCServer/webadmin/files/sub_pmfolder.gif b/MCServer/webadmin/files/sub_pmfolder.gif Binary files differnew file mode 100644 index 000000000..3d0d6e627 --- /dev/null +++ b/MCServer/webadmin/files/sub_pmfolder.gif diff --git a/MCServer/webadmin/files/tcat.png b/MCServer/webadmin/files/tcat.png Binary files differnew file mode 100644 index 000000000..eb64eb3d6 --- /dev/null +++ b/MCServer/webadmin/files/tcat.png diff --git a/MCServer/webadmin/files/thead.png b/MCServer/webadmin/files/thead.png Binary files differnew file mode 100644 index 000000000..81aa04bac --- /dev/null +++ b/MCServer/webadmin/files/thead.png diff --git a/MCServer/webadmin/login_template.html b/MCServer/webadmin/login_template.html index 913a85db0..7a8601065 100644 --- a/MCServer/webadmin/login_template.html +++ b/MCServer/webadmin/login_template.html @@ -1,25 +1,69 @@ +<!-- Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */ --> <html> <head> <title>MCServer WebAdmin - Login</title> - <meta charset="UTF-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link href="login.css" rel="stylesheet" type="text/css"> <link rel="icon" href="favicon.ico"> - <style type="text/css"> - header { - margin: 0 auto; - text-align: center; - vertical-align: middle; - } - </style> </head> - <body> - <header> - <img src="mc-logo.png" alt="MCServer Logo" class="logo"> - <h1>MCServer - WebAdmin</h1> - <form method="get" action="webadmin/"> - <input type="submit" value="Log in"> - </form> - </header> +<div class="contention"> + <div class="row1"> + <div class="wrapper"> + <img src="logo_login.png" alt="MCServer Logo" class="logo"> + </div> + </div> + <div id="panel"> + <div class="upper"> + <div class="wrapper"> + <div> + <form method="get" action="webadmin/" /> + <button type="submit" value="Log in" style="width:150px;height:25px;font-family:'Source Sans Pro',sans-serif;background:transparent;border:none!important;vertical-align:middle"> + <strong><img src="login.gif" style="vertical-align:bottom" /> WebAdmin Log in</strong> + </button> + </form> + </div> + </div> + </div> + </div> + <div class="row2 push10"> + <div class="wrapper padtopp"> + <table border="0" cellspacing="0" cellpadding="5" class="tborder" style="margin-bottom:5px"> + <tbody> + <tr> + <td class="thead rounded_top"> + <div style="float:left!important"><strong>MCServer WebAdmin</strong></div> + </td> + </tr> + <tr> + <td class="trow2 post_content"> + <div class="post_body"> + <iframe width="100%" height="100%" style="border:none;min-height:350px;max-height:450px" src="/guest.html"></iframe> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> +</div> +<div id="footer"> + <div class="upper"> + <div class="wrapper"> + <ul class="menu bottom_links"> + <li><a href="http://www.mc-server.org" target="_blank">MCServer</a></li> + <li><a href="http://forum.mc-server.org" target="_blank">Forums</a></li> + <li><a href="http://builds.cuberite.org" target="_blank">Buildserver</a></li> + <li><a href="http://mc-server.xoft.cz/LuaAPI" target="_blank">API Documentation</a></li> + <li><a href="http://book.mc-server.org/" target="_blank">User's Manual</a></li> + </ul> + </div> + </div> + <div class="lower"> + <div class="wrapper"> + <span id="copyright">Copyright © <a href="http://www.mc-server.org" target="_blank">MCServer Team</a> 2014.</span> + </div> + </div> +</div> </body> - </html> diff --git a/MCServer/webadmin/template.html b/MCServer/webadmin/template.html index 822f73857..b0864e35d 100644 --- a/MCServer/webadmin/template.html +++ b/MCServer/webadmin/template.html @@ -1,129 +1,140 @@ <!DOCTYPE html> <html> -<head> - <title>{TITLE} | {PLUGIN_NAME}</title> - <style type="text/css"> - body { - line-height: 1; - background: #B8B8B8; - } - - #maincontent { - padding: 0px 25px 10px 25px; - } - - #wrapper { - min-width: 850px; - width: 75%; - margin: 10px auto; - background-color: white; - border: 4px #888888 solid; - border-radius: 10px; - font-family: Calibri, Trebuchet MS; - } - - header { - text-align:center; - padding: 10px; 0px; - } - - span { - text-align: right; - float: right; - border-left: 2px #C8C8C8 solid; - border-bottom: 2px #C8C8C8 solid; - padding: 2px 10px; - } - - footer { - font-family: helvetica; - font-size: 10px; - text-align: center; - border-top: 1px #000 dotted; - padding: 1px 0px 1px 0px; - } - - table { - border-collapse: collapse; - border-spacing: 10; - } - - table { - border-top: 1px solid #ddd; - width: 700px; - } - - table tr th { - text-align: left; - background: #f6f6f6; - padding: 0px 20px; - height: 25px; - line-height: 25px; - border: 1px solid #ddd; - border-radius: 3px; - } - - table tr td { - background: #f6f6f6; - padding: 0px 20px; - height: 29px; - line-height: 29px; - border: 1px solid #ddd; - border-radius: 3px; - } - #main table tr.odd td { - background: #fbfbfb; - } - - table tr:hover td { background: #fdfcf6; } - table .action { - text-align: right; - padding: 0 20px 0 10px; - } - - table tr .action a { color: #9b9b9b; } - - #cssmenu{ height:10px; display:table; padding:0; margin: 0 auto; border:1px #707070 solid; border-radius:5px; } - #cssmenu > ul {list-style:inside none; padding:0; margin:0;} - #cssmenu > ul > li {list-style:inside none; padding:0; margin:0; float:left; display:block; position:relative;} - #cssmenu > ul > li > a{ outline:none; display:block; position:relative; color:#E8E8E8; padding:10px 10px; font:bold 13px/100% Arial, Helvetica, sans-serif; text-align:center; text-decoration:none; text-shadow:1px 1px 0 rgba(0,0,0, 0.4); } - #cssmenu > ul > li:first-child > a{border-radius:5px 0 0 5px;} - /* #cssmenu > ul > li > a:after{ content:''; position:absolute; border-right:1px solid #FFFFFF; top:-1px; bottom:-1px; right:-2px; z-index:99; } */ - #cssmenu ul li.has-sub:hover > a:after{top:0; bottom:0;} - #cssmenu > ul > li.has-sub > a:before{ content:''; position:absolute; top:18px; right:6px; border:5px solid transparent; border-top:5px solid #707070; } - #cssmenu > ul > li.has-sub:hover > a:before{top:19px;} - #cssmenu ul li.has-sub:hover > a{ background:#3f3f3f; border-color:#707070; padding-bottom:13px; padding-top:13px; top:-1px; z-index:999; } - #cssmenu ul li.has-sub:hover > ul, #cssmenu ul li.has-sub:hover > div{display:block;} - #cssmenu ul li.has-sub > a:hover{background:#3f3f3f; border-color:#3f3f3f;} - #cssmenu ul li > ul, #cssmenu ul li > div{ display:none; width:auto; position:absolute; top:38px; padding:10px 0; background:#3f3f3f; border-radius:0 0 5px 5px; z-index:999; } - #cssmenu ul li > ul{width:200px;} - #cssmenu ul li > ul li{display:block; list-style:inside none; padding:0; margin:0; position:relative;} - #cssmenu ul li > ul li a{ outline:none; display:block; position:relative; margin:0; padding:8px 20px; font:10pt Arial, Helvetica, sans-serif; color:#fff; text-decoration:none; text-shadow:1px 1px 0 rgba(0,0,0, 0.5); } - #cssmenu, #cssmenu > ul > li > ul > li a:hover{ background:#C8C8C8;} - #cssmenu > ul > li > a{border-right:1px solid #707070; color:#FFFFFF;} - #cssmenu > ul > li > a:after{border-color:#707070;} - #cssmenu > ul > li > a:hover{background:#B8B8B8;} - </style> - <meta name="msapplication-tooltip" content="MCServer WebAdministrator"/> - <meta name="msapplication-navbutton-color" content="#B8B8B8" /> - <link rel="shortcut icon" href="http://mc-server.org/favicon.ico" /> -</head> - -<body> - <div id="wrapper"> - <span><b>Login: {USERNAME}</b></span><br /> - <header> - <img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAkCAMAAAAXdeBDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuVQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7OzAAAAAAAAoqKiAAAAvLy8AAAAlZWVtbW1j4+Pra2tiYmJp6enAAAAhISEoaGhAAAAgICAm5ube3t7lZWVd3d3kZGRc3NzjIyMbGxsg4ODgICAeHh43NzcdXV1cnJyy8vLWVlZbGxswcHB09PTvLy8uLi4tLS0sLCwvLy8uLi4tbW1oaGhnp6era2tm5ubqqqq39/f29vblZWV09PT4ODgz8/P3NzckZGRxcXF0tLSwsLCzs7Oy8vLyMjIt7e3vLy85ubm7u7u3d3d5+fn2tra5OTk19fX1dXV3t7e29vb2dnZ1tbW0dHRv7+/8PDw7u7u6+vr8fHx5ubm4+Pj7Ozs4eHh3t7e5+fn5OTk2tra4uLi39/f1dXV3d3d29vb2dnZ19fX1dXV0tLS9fX18/Pzzs7O7u7u8/PzycnJ6urq6Ojo7+/v5ubm7Ozs4+Pj4eHh39/f5ubm5OTk4uLi4ODg2NjY3Nzc29vb19fX8vLy9/f39fX17e3t8/Pz6+vr8fHx7+/v5+fn7e3t5eXl6+vr6enp6Ojo4ODg39/f9PT0+Pj48fHx9vb27+/v9PT07e3t8/Pz7Ozs8fHx7+/v6Ojo7u7u5+fn7Ozs5eXl6urq5OTk6enp5+fn5ubm5OTk+Pj49/f39fX19PT0+fn58vLy8fHx9fX19PT08vLy8fHx6urq+Pj49vb29fX19PT08vLy8PDw+/v7+vr6+Pj49/f39vb29fX18/Pz/f39+/v7+vr6+fn5+Pj49/f3/f39/Pz8+vr6/v7+/f39a5KrdZmxf6G2iai8kq/BnLbHpr7NsMXSuszYxNPdxmZTynBeznpqztvj0YV11Y+B2OLp2ZmM3aOY4a2j4enu5Liv6MK66/D07MzG8NbR9ODd9fj59+vo+/X0ucu1kQAAANl0Uk5TAAECAwQFBgcICQoLDA0ODxAREhMUFBUWFhcXGBgYGRkaGhsbGxwcHB0dHh4fHyEhIiQkJSYnKCgpKSorLC0uLzAxMjIzMzc4Ojo6Ozs8Pj4/P0BBQ0VISUtLTExNTk5PUFFTV1dYWVpbXFxdXl5fYGBhYmJjZGVmZ2doaWprbGxtbW5ub3BxcXJzdHV2d3l6e3x9fX5+f4CAgYGCg4SIi4yNjY6Oj4+QkJGSkpOTlJSVlZaXmJqbnJ2dnp+foKGip6+wsbKztb6/wMHCw8TOz9DR0tPf4OHv8LXp8fEAAAi/SURBVHja3Zh/dBRXFcdhZ+a9eTPzZnaXmJam0FYUEQWLrVVbqdZaf6EWQW2txN/SWiAmxFqtIlWr9bdWqkbwF6WQYIq/+WFpwSZqTahhg6RhNptkl9nsbjeb2eyv+dv73g6wlcyewXMazvGek3Dm5jLv8+689733vTn/q81ldr5zzsWxuVWr55sbCAiiBCYKAeZ1nYIgigJ4Zh2Zj+0OXesTgQ987pOEZUVVVYXISIJQPi3mJETG0kXADggIL5CRWDMy57kCaDgdBMgK1de0gi2jGsESZJt5iXpjS8utGkHiLFMDIHrNgfJBFYs1i0Ei73iifIAggIEHrNDWnuGpFFg50vEKVYbcArNye0+lUCj13aUgYbahRbInbqbu1zAf2XXpR8bN1CZZYItA1jb0pcaiJrdYorxzIRYFYN7qZC2wTOVXMuR+dqGR2hU3Y4NLFSlwJtGIfmbKNFOt4BIkQndOj5rR8dMpsETMjCae+gASJbLKSSftUsWeSJbWz3aqgXBvPGomOnWWajfRoWOjAN2uIWBedOh0NJoYPvJgW1tb+47I1Jg5Vl6AsPrkZLLU+f5bdjjpzNOzDo1pdzw2Fi2vVlBVFgRMf5oyYXl8lmIk00MJc7S8e6mhU02jerC5JzFavgyRlztWbl9j2NC3lvJbpMDFgJ6Ojh/VZb4XA5KycmhkNAXQOpG1ncDfv9HQQNsQZsK3cNvTn5SQ0lKwCveEdYWQd25BrugxUQHjAl/fPKL9Q2t747F/x82pjSpXC0Gme+EJoNt1Vb2jHI1FVlMmawFWYiQgB6mWCIcOaVgCA2ZX3BEGQyI4vAsXWN1of9Bd8diJZ0dG+3QiwuSRsq4cHf8rgzao3jMWnX5Al88oMdNnAQRPlOlwMrcvrBMYk2WrWmyIqlGqqYRJPE+kwK2a0Jr8wo9nNPzRL/QvTpupH4HsAQ4DLX+ZQQeNN02b8W6DSLWVh5mA+EbcHaKkWhF5sdGWdfREIj0dyzSCBDAJY1nGCKo/r/9uguEB/uQZLQZ8Qe+JxwZffGx0ZGixgiSsbXzOTDz2RQYdDm1PmFNrNXTee+ZKMpO8fP+DhiYjAGLF5oYux86m01nb6bqBACr+4Id1/cZHH7pUxne+HkE63fp7522A5xn9IiHgF7ppM6DuokRWjD7Av+7zDHrevEgsFgkq0vndnVtcMvmhjkUKJFvEyqf7ckkrmU7Dr1zfXQTLXyoWv95ZydnblB8UKut5BYL/Rw4Uih9S6Qav6B9CnD/oSGPj0fFouVmn+sOwUH7W9DmmHg0Nw9H4Xp0IM1Z/KOOFjDVhR7ZqMpbVO5yMlS2eGhw8VYTJOC9RtOPp9Ak7adk/picnMv/UZL5jyO0ly+4INntGP+QfOhxeXY6O9c4L31QeGettaLyHQTeuKJsALQdm3PyI0Na+UtZKl3ZSjS7uzVr23z7e0Nj00t8Wk2nnZaoeSadtK1s6uJD+xLYKLSBOTJp6sklnxXLP6AOXin6XRyRoGLsS5nObm34HctccCrdz6GsYNJ0JmquFrOjNvcV0srQrFN5tW/bh5aHQvPm/KQHFVkULDsK3n/x7s0bURZDqPtAg+DxrSlau+5JOz2gVCX434nGod4uhpDzzielo/HFdD7bXzbSbbBHJmvEAbMjK5qZTyUz/8qCuhzsZxf0qUUODaSt94n06rB3aYVulZhVLMgXRcd5SL1oM+IamCtEeTpmn/wFyt1JV9ba6a9qlZtgKUE9kjn0vb+W/FdapsYtTaBgrDCP/3bAiQX4XD01ke6B8qisdkPf5364TDcy+oQkmRu/YyGmmITKhbXXVwy10DFtSgjsgjX/KWc41IeMshQj+wTT4dBxg3cx2iGHbvCuXdN58yb560XP8Q8sSUpunzOho/xICX73trE5P33yeTgOre0KDNYLp1Y5l/xkwrm0In6UICMSArTUYVmHGMLNlTjLbGw69chj+aWjorhftHxoECWrh43HoouEluAodNNZMzVQRWQty2wJJ5NRIexU0fAz6tU2dVQomyVUM+ExCtXGspvjnLOGh0N460RcELQQkcn15/AnAFxCHbvPqPUSE9xedKyBDHPpqBm1blXc/5lKwfkRSOIbBNwQ8vQEW8x+uexaWtqEb2z2jLxSaadjb/vJWLAUCLnRtlye4bQ7CYPK7Slb+ayrMhfUqt1Ss/PeLlv17RvFVqsisEcQqx2C7+FyqfwmJXqcp2ke9oi8YGl4tSkgSAM6Fph799KcU7SSkLEgJxoSGYYVW3v5MZqIAFN8I65qqvu6RLUQLcgx4r9ukO0n7X5lsr04w0fu9on1CI5VDY4F/fN5DAnRriq3u2pMLrTm5XKVBjcvvDoPTCO8uJSePzr+3YFlp5ztNDUEjuO6pXP4rtAaDp/rI5ETBKn5MRbDl2zyifUMrDFrFgdoeTuHQyrkz4hCcEcF29PMz4lXKlVAk8r3fXHtzey8rw+8JzTtsW5POH++9dkV7twM1ehtlH/w4K6duqteWLCgphiyyJeUd7cMAkDwK0AQ9D5psAuhN5NxpfMQ9jY/y07gsK6ucSSubL1UKWYttJ5UuBY5kruA4BWjf7IOXqxRaoLPJgK5Dh36j0Mo6EJjBEo9on9AifiQeG8BSLbSA7wbou7HHvYcsSUhZ9aQ9YYFN5CJbVRnJ6pLDxYzFLVM8dDkhykA6PSDDe91UQ39X7fV4i+gZ7ceA6tW/HviCVNumwAh4f3k/ljxvmAQBkSs7TpYKheLQnusVJIIMErqxr1TI5QqVvg0gZAjfNzBwH3Lfy0DJeod31ezBO9qXsfOPexqqnQlagGa8y1MJFqviB85bW1o+QiHNTHEENrn3tnZ1tb6RsmMBkyJUcznJ5PIyyRX8OtF+jEsGG/S/fPyIOdOtKZuf2+NhonAPBLqTI6qmKQTDLPhrmbjXjnPmuW60/wtqryt07/tp3oA8z8MdCHHXjBcC7mOd6Bfk7r3udC94aDf6/9T+AzWzIkAbVeu4AAAAAElFTkSuQmCC" /> - </header> - <nav id="cssmenu"> - <ul> - {MENU} - </ul> - </nav> - <div id="maincontent"> - {CONTENT} + <head> + <title>{TITLE} | {PLUGIN_NAME}</title> + <style type="text/css"> + body { + line-height: 1; + background: #B8B8B8; + } + + #maincontent { + padding: 0px 25px 10px 25px; + } + + #wrapper { + min-width: 850px; + width: 75%; + margin: 10px auto; + background-color: white; + border: 4px #888888 solid; + border-radius: 10px; + font-family: Calibri, Trebuchet MS; + } + + header { + text-align:center; + padding: 10px; 0px; + } + + span { + text-align: right; + float: right; + border-left: 2px #C8C8C8 solid; + border-bottom: 2px #C8C8C8 solid; + padding: 2px 10px; + } + + footer { + font-family: helvetica; + font-size: 10px; + text-align: center; + border-top: 1px #000 dotted; + padding: 1px 0px 1px 0px; + } + + table { + border-collapse: collapse; + border-spacing: 10; + } + + table { + border-top: 1px solid #ddd; + width: 700px; + } + + table tr th { + text-align: left; + background: #f6f6f6; + padding: 0px 20px; + height: 25px; + line-height: 25px; + border: 1px solid #ddd; + border-radius: 3px; + } + + table tr td { + background: #f6f6f6; + padding: 0px 20px; + height: 29px; + line-height: 29px; + border: 1px solid #ddd; + border-radius: 3px; + } + + #main table tr.odd td { + background: #fbfbfb; + } + + table tr:hover td { + background: #fdfcf6; + } + + table .action { + text-align: right; + padding: 0 20px 0 10px; + } + + table tr .action a { + color: #9b9b9b; + } + + #cssmenu{ height:10px; display:table; padding:0; margin: 0 auto; border:1px #707070 solid; border-radius:5px; } + #cssmenu > ul {list-style:inside none; padding:0; margin:0;} + #cssmenu > ul > li {list-style:inside none; padding:0; margin:0; float:left; display:block; position:relative;} + #cssmenu > ul > li > a{ outline:none; display:block; position:relative; color:#E8E8E8; padding:10px 10px; font:bold 13px/100% Arial, Helvetica, sans-serif; text-align:center; text-decoration:none; text-shadow:1px 1px 0 rgba(0,0,0, 0.4); } + #cssmenu > ul > li:first-child > a{border-radius:5px 0 0 5px;} + /* #cssmenu > ul > li > a:after{ content:''; position:absolute; border-right:1px solid #FFFFFF; top:-1px; bottom:-1px; right:-2px; z-index:99; } */ + #cssmenu ul li.has-sub:hover > a:after{top:0; bottom:0;} + #cssmenu > ul > li.has-sub > a:before{ content:''; position:absolute; top:18px; right:6px; border:5px solid transparent; border-top:5px solid #707070; } + #cssmenu > ul > li.has-sub:hover > a:before{top:19px;} + #cssmenu ul li.has-sub:hover > a{ background:#3f3f3f; border-color:#707070; padding-bottom:13px; padding-top:13px; top:-1px; z-index:999; } + #cssmenu ul li.has-sub:hover > ul, #cssmenu ul li.has-sub:hover > div{display:block;} + #cssmenu ul li.has-sub > a:hover{background:#3f3f3f; border-color:#3f3f3f;} + #cssmenu ul li > ul, #cssmenu ul li > div{ display:none; width:auto; position:absolute; top:38px; padding:10px 0; background:#3f3f3f; border-radius:0 0 5px 5px; z-index:999; } + #cssmenu ul li > ul{width:200px;} + #cssmenu ul li > ul li{display:block; list-style:inside none; padding:0; margin:0; position:relative;} + #cssmenu ul li > ul li a{ outline:none; display:block; position:relative; margin:0; padding:8px 20px; font:10pt Arial, Helvetica, sans-serif; color:#fff; text-decoration:none; text-shadow:1px 1px 0 rgba(0,0,0, 0.5); } + #cssmenu, #cssmenu > ul > li > ul > li a:hover{ background:#C8C8C8;} + #cssmenu > ul > li > a { border-right:1px solid #707070; color:#FFFFFF; } + #cssmenu > ul > li > a:after { border-color:#707070; } + #cssmenu > ul > li > a:hover { background:#B8B8B8; } + </style> + <meta name="msapplication-tooltip" content="MCServer WebAdministrator"/> + <meta name="msapplication-navbutton-color" content="#B8B8B8" /> + <link rel="shortcut icon" href="http://mc-server.org/favicon.ico" /> + </head> + <body> + <div id="wrapper"> + <span> + <b>Login: {USERNAME}</b> + </span> + <br /> + <header> + <img alt="" src="files/logo.png" /> + </header> + <nav id="cssmenu"> + <ul> + {MENU} + </ul> + </nav> + <div id="maincontent"> + {CONTENT} + </div> + <footer> + <p>MCServer is using {MEM}MB of memory, with {NUMCHUNKS} chunks loaded.</p> + <p>Web Design by <a href="https://github.com/WebFreak001"@WebFreak001</a></p> + </footer> </div> - <footer><p>MCServer is using {MEM}MB of memory, with {NUMCHUNKS} chunks loaded.</p><p>Web Design by Tiger</p></footer> - </div> -</head> + </body> </html> diff --git a/MCServer/webadmin/template.lua b/MCServer/webadmin/template.lua index a7480f83e..4d3934da8 100644 --- a/MCServer/webadmin/template.lua +++ b/MCServer/webadmin/template.lua @@ -33,7 +33,7 @@ function GetDefaultPage() local AllPlugins = PM:GetAllPlugins() for key,value in pairs(AllPlugins) do if( value ~= nil and value ~= false ) then - Content = Content .. "<li>" .. key .. " V." .. value:GetVersion() .. "</li>" + Content = Content .. "<li>" .. key .. " (version " .. value:GetVersion() .. ")</li>" end end @@ -70,25 +70,67 @@ function ShowPage(WebAdmin, TemplateRequest) PageContent, SubTitle = GetDefaultPage() end + local reqParamsClass = "" + + for key,value in pairs(TemplateRequest.Request.Params) do + reqParamsClass = reqParamsClass .. " param-" .. string.lower(string.gsub(key, "[^a-zA-Z0-9]+", "-") .. "-" .. string.gsub(value, "[^a-zA-Z0-9]+", "-")) + end + + if (string.gsub(reqParamsClass, "%s", "") == "") then + reqParamsClass = " no-param" + end + Output([[ -<!DOCTYPE html> +<!-- Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 --> +<html> <head> -<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -<link rel="icon" href="/favicon.ico"> -<title>]] .. Title .. [[</title> -<link rel="stylesheet" type="text/css" media="screen" href="/style.css"> + <title>]] .. Title .. [[</title> + <meta charset="UTF-8"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="/favicon.ico"> </head> - <body> - <div id="wrapper"> - <!-- h1 tag stays for the logo, you can use the a tag for linking the index page --> - <h1> - <a href="]] .. BaseURL .. [["><span>MCServer</span></a> - </h1> - <div id="containerHolder"> - <div id="container"> - <div id="sidebar"> - <ul class="sideNav"> +<div class="contention push25"> + <div class="pagehead"> + <div class="row1"> + <div class="wrapper"> + <img src="/logo_login.png" alt="MCServer Logo" class="logo"> + </div> + </div> + <div id="panel"> + <div class="upper"> + <div class="wrapper"> + <ul class="menu top_links"> + <li><a>Server Name: <strong>]] .. cRoot:Get():GetServer():GetServerID() .. [[</strong></a></li> + <li><a>Memory: <strong>]] .. MemoryUsageKiB / 1024 .. [[MB</strong></a></li> + <li><a>Chunks: <strong>]] .. NumChunks .. [[</strong></a></li> + </ul> + <div class="welcome"><strong>Welcome back, ]] .. TemplateRequest.Request.Username .. [[</strong> <a href=".././"><img src="/log_out.png" style="vertical-align:bottom;"> Log Out</a></div> + </div> + </div> + </div> + </div> + <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"> ]]) @@ -97,41 +139,62 @@ function ShowPage(WebAdmin, TemplateRequest) local PluginWebTitle = value:GetWebTitle() local TabNames = value:GetTabNames() if (GetTableSize(TabNames) > 0) then - Output("<li>"..PluginWebTitle.."</li>\n"); + Output("<div><a class='usercp_nav_item usercp_nav_pmfolder' style='text-decoration:none;'><b>"..PluginWebTitle.."</b></a></div>\n"); for webname,prettyname in pairs(TabNames) do - Output("<li><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n") + Output("<div><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "' class='usercp_nav_item usercp_nav_sub_pmfolder'>" .. prettyname .. "</a></div>\n") end + + Output("<br>\n"); end end Output([[ - </ul> - <!-- // .sideNav --> - </div> - <!-- // #sidebar --> - <!-- h2 stays for breadcrumbs --> - <h2>Welcome ]] .. TemplateRequest.Request.Username .. [[</h2> - <div id="main"> - <h3>]] .. SubTitle .. [[</h3> - ]] .. PageContent .. [[ - </div> - <!-- // #main --> - - <div class="clear"></div> - - </div> - <!-- // #container --> - </div> - <!-- // #containerHolder --> - - <p id="footer">MCServer is using: ]] .. MemoryUsageKiB / 1024 .. [[ MiB of memory; Current chunk count: ]] .. NumChunks .. [[ </p> + </td> + </tr> + </tbody> + </table> + </td> + <td valign="top" style='padding-left:25px;'> + <table border="0" cellspacing="0" cellpadding="5" class="tborder"> + <tbody> + <tr> + <td class="thead" colspan="2"><strong>]] .. SubTitle .. [[</strong></td> + </tr> + <tr> + <td class="trow2">]] .. PageContent .. [[</td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> + </div> + </div> +<div id="footer"> + <div class="upper"> + <div class="wrapper"> + <ul class="menu bottom_links"> + <li><a href="http://www.mc-server.org" target="_blank">MCServer</a></li> + <li><a href="http://forum.mc-server.org" target="_blank">Forums</a></li> + <li><a href="http://builds.cuberite.org" target="_blank">Buildserver</a></li> + <li><a href="http://mc-server.xoft.cz/LuaAPI" target="_blank">API Documentation</a></li> + <li><a href="http://book.mc-server.org/" target="_blank">User's Manual</a></li> + </ul> + </div> </div> - <!-- // #wrapper --> + <div class="lower"> + <div class="wrapper"> + <span id="copyright">Copyright © <a href="http://www.mc-server.org" target="_blank">MCServer Team</a> 2014.</span> + </div> + </div> +</div> +</div> </body> </html> - ]]) +]]) return table.concat(SiteContent) end diff --git a/MCServer/webadmin/template_orig.lua b/MCServer/webadmin/template_orig.lua new file mode 100644 index 000000000..a7480f83e --- /dev/null +++ b/MCServer/webadmin/template_orig.lua @@ -0,0 +1,137 @@ +-- Use a table for fast concatenation of strings +local SiteContent = {} +function Output(String) + table.insert(SiteContent, String) +end + + + + + +function GetTableSize(Table) + local Size = 0 + for key,value in pairs(Table) do + Size = Size + 1 + end + return Size +end + + + + + +function GetDefaultPage() + local PM = cRoot:Get():GetPluginManager() + + local SubTitle = "Current Game" + local Content = "" + + Content = Content .. "<h4>Server Name:</h4>" + Content = Content .. "<p>" .. cRoot:Get():GetServer():GetServerID() .. "</p>" + + Content = Content .. "<h4>Plugins:</h4><ul>" + local AllPlugins = PM:GetAllPlugins() + for key,value in pairs(AllPlugins) do + if( value ~= nil and value ~= false ) then + Content = Content .. "<li>" .. key .. " V." .. value:GetVersion() .. "</li>" + end + end + + Content = Content .. "</ul>" + Content = Content .. "<h4>Players:</h4><ul>" + + local AddPlayerToTable = function( Player ) + Content = Content .. "<li>" .. Player:GetName() .. "</li>" + end + cRoot:Get():ForEachPlayer( AddPlayerToTable ) + + Content = Content .. "</ul><br>"; + + return Content, SubTitle +end + + + + + +function ShowPage(WebAdmin, TemplateRequest) + SiteContent = {} + local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path) + local Title = "MCServer WebAdmin" + local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage() + local NumChunks = cRoot:Get():GetTotalChunkCount() + local PluginPage = WebAdmin:GetPage(TemplateRequest.Request) + local PageContent = PluginPage.Content + local SubTitle = PluginPage.PluginName + if (PluginPage.TabName ~= "") then + SubTitle = PluginPage.PluginName .. " - " .. PluginPage.TabName + end + if (PageContent == "") then + PageContent, SubTitle = GetDefaultPage() + end + + Output([[ +<!DOCTYPE html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<link rel="icon" href="/favicon.ico"> +<title>]] .. Title .. [[</title> +<link rel="stylesheet" type="text/css" media="screen" href="/style.css"> +</head> + +<body> + <div id="wrapper"> + <!-- h1 tag stays for the logo, you can use the a tag for linking the index page --> + <h1> + <a href="]] .. BaseURL .. [["><span>MCServer</span></a> + </h1> + <div id="containerHolder"> + <div id="container"> + <div id="sidebar"> + <ul class="sideNav"> + ]]) + + + local AllPlugins = WebAdmin:GetPlugins() + for key,value in pairs(AllPlugins) do + local PluginWebTitle = value:GetWebTitle() + local TabNames = value:GetTabNames() + if (GetTableSize(TabNames) > 0) then + Output("<li>"..PluginWebTitle.."</li>\n"); + + for webname,prettyname in pairs(TabNames) do + Output("<li><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n") + end + end + end + + + Output([[ + </ul> + <!-- // .sideNav --> + </div> + <!-- // #sidebar --> + <!-- h2 stays for breadcrumbs --> + <h2>Welcome ]] .. TemplateRequest.Request.Username .. [[</h2> + <div id="main"> + <h3>]] .. SubTitle .. [[</h3> + ]] .. PageContent .. [[ + </div> + <!-- // #main --> + + <div class="clear"></div> + + </div> + <!-- // #container --> + </div> + <!-- // #containerHolder --> + + <p id="footer">MCServer is using: ]] .. MemoryUsageKiB / 1024 .. [[ MiB of memory; Current chunk count: ]] .. NumChunks .. [[ </p> + </div> + <!-- // #wrapper --> +</body> +</html> + ]]) + + return table.concat(SiteContent) +end @@ -1,28 +1,34 @@ -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. -MCServer can run on PCs, Macs, and *nix. This includes android phones and tablets as well as Raspberry Pis. +MCServer can run on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis. -We currently support the protocol from Minecraft 1.2 all the way up to Minecraft 1.8. +We currently support Release 1.7 and 1.8 (not beta) Minecraft protocol versions. Installation ------------ -Normally, you will want to download a pre-compiled version of MCServer from one of the buildservers: +[![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer) - * [Windows and Linux](http://builds.mc-server.org) - * [Raspberry Pi](http://ci.bearbin.net) +For Linux there is an easy installation method, just run this in your terminal: -You simply need to download and extract these files before you can use the server. + curl -s https://raw.githubusercontent.com/mc-server/MCServer/master/easyinstall.sh | sh -If you're a more advanced user, you may want to compile the server yourself for more performance. See the [COMPILING.md](https://github.com/mc-server/MCServer/blob/master/COMPILING.md) file for more details. +For Windows, you just need to download a file and extract it: + + - [Windows 32 bit](http://builds.cuberite.org/job/MCServer%20Windows%20x86/lastSuccessfulBuild/artifact/Install/MCServer.zip) + - [Windows 64 bit](http://builds.cuberite.org/job/MCServer%20Windows%20x64/lastSuccessfulBuild/artifact/Install/MCServer.zip) + +For other operating systems you need to download and compile yourself. There is also an archive of binary builds on the buildserver: http://builds.cuberite.org + +Compiling the server yourself has other benefits: you may get better performance performance (1.5-3x as fast) and it supports more operating systems. See the [COMPILING.md](https://github.com/mc-server/MCServer/blob/master/COMPILING.md) file for more details. Contributing ------------ -MCServer is licensed under the Apache license V2, and we welcome anybody to fork and submit a Pull Request back with their changes, and if you want to join as a permanent member we can add you to the team. +MCServer is licensed under the Apache License V2, and we welcome anybody to fork and submit a Pull Request back with their changes, and if you want to join as a permanent member we can add you to the team. Check out the [CONTRIBUTING.md](https://github.com/mc-server/MCServer/blob/master/CONTRIBUTING.md) file for more details. @@ -33,7 +39,7 @@ For other stuff, including plugins and discussion, check the [forums](http://for Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) -Support Us on Gratipay: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team) +Support Us on Gratipay: [![Support via Gratipay](http://img.shields.io/gittip/cuberite_team.svg)](https://www.gratipay.com/cuberite_team) Travis CI: [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) diff --git a/SetFlags.cmake b/SetFlags.cmake index 1827a4b66..c0a021c25 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -59,12 +59,25 @@ macro(set_flags) set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") elseif(APPLE) - #on os x clang adds pthread for us but we need to add it for gcc - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + 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() + #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++") add_flags_lnk("-stdlib=libc++") else() @@ -77,8 +90,17 @@ macro(set_flags) add_flags_cxx("-pthread") endif() - # Make CLang use C++11, otherwise MSVC2008-supported extensions don't work ("override" keyword etc.): - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + 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") diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index c5916c1ca..eaf4fab02 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -1819,8 +1819,7 @@ bool cConnection::HandleServerKick(void) Reason.append(Split[4]); Reason.push_back(0); Reason.append(Split[5]); - AString ReasonBE16; - UTF8ToRawBEUTF16(Reason.data(), Reason.size(), ReasonBE16); + AString ReasonBE16 = UTF8ToRawBEUTF16(Reason.data(), Reason.size()); AString PacketStart("\xff"); PacketStart.push_back((ReasonBE16.size() / 2) / 256); PacketStart.push_back((ReasonBE16.size() / 2) % 256); diff --git a/Tools/QtBiomeVisualiser/BiomeView.cpp b/Tools/QtBiomeVisualiser/BiomeView.cpp index ce5a870cd..c77b39482 100644 --- a/Tools/QtBiomeVisualiser/BiomeView.cpp +++ b/Tools/QtBiomeVisualiser/BiomeView.cpp @@ -1,8 +1,8 @@ #include "Globals.h" #include "BiomeView.h" -#include "QtChunk.h" #include <QPainter> #include <QResizeEvent> +#include "Region.h" @@ -14,6 +14,116 @@ static const int DELTA_STEP = 120; // The normal per-notch wheel delta +/** Map for converting biome values to colors. Initialized from biomeColors[]. */ +static uchar biomeToColor[256 * 4]; + +/** Map for converting biome values to colors. Used to initialize biomeToColor[].*/ +static struct +{ + EMCSBiome m_Biome; + uchar m_Color[3]; +} biomeColors[] = +{ + { biOcean, { 0x00, 0x00, 0x70 }, }, + { biPlains, { 0x8d, 0xb3, 0x60 }, }, + { biDesert, { 0xfa, 0x94, 0x18 }, }, + { biExtremeHills, { 0x60, 0x60, 0x60 }, }, + { biForest, { 0x05, 0x66, 0x21 }, }, + { biTaiga, { 0x0b, 0x66, 0x59 }, }, + { biSwampland, { 0x2f, 0xff, 0xda }, }, + { biRiver, { 0x30, 0x30, 0xaf }, }, + { biHell, { 0x7f, 0x00, 0x00 }, }, + { biSky, { 0x00, 0x7f, 0xff }, }, + { biFrozenOcean, { 0xa0, 0xa0, 0xdf }, }, + { biFrozenRiver, { 0xa0, 0xa0, 0xff }, }, + { biIcePlains, { 0xff, 0xff, 0xff }, }, + { biIceMountains, { 0xa0, 0xa0, 0xa0 }, }, + { biMushroomIsland, { 0xff, 0x00, 0xff }, }, + { biMushroomShore, { 0xa0, 0x00, 0xff }, }, + { biBeach, { 0xfa, 0xde, 0x55 }, }, + { biDesertHills, { 0xd2, 0x5f, 0x12 }, }, + { biForestHills, { 0x22, 0x55, 0x1c }, }, + { biTaigaHills, { 0x16, 0x39, 0x33 }, }, + { biExtremeHillsEdge, { 0x7f, 0x8f, 0x7f }, }, + { biJungle, { 0x53, 0x7b, 0x09 }, }, + { biJungleHills, { 0x2c, 0x42, 0x05 }, }, + + { biJungleEdge, { 0x62, 0x8b, 0x17 }, }, + { biDeepOcean, { 0x00, 0x00, 0x30 }, }, + { biStoneBeach, { 0xa2, 0xa2, 0x84 }, }, + { biColdBeach, { 0xfa, 0xf0, 0xc0 }, }, + { biBirchForest, { 0x30, 0x74, 0x44 }, }, + { biBirchForestHills, { 0x1f, 0x5f, 0x32 }, }, + { biRoofedForest, { 0x40, 0x51, 0x1a }, }, + { biColdTaiga, { 0x31, 0x55, 0x4a }, }, + { biColdTaigaHills, { 0x59, 0x7d, 0x72 }, }, + { biMegaTaiga, { 0x59, 0x66, 0x51 }, }, + { biMegaTaigaHills, { 0x59, 0x66, 0x59 }, }, + { biExtremeHillsPlus, { 0x50, 0x70, 0x50 }, }, + { biSavanna, { 0xbd, 0xb2, 0x5f }, }, + { biSavannaPlateau, { 0xa7, 0x9d, 0x64 }, }, + { biMesa, { 0xd9, 0x45, 0x15 }, }, + { biMesaPlateauF, { 0xb0, 0x97, 0x65 }, }, + { biMesaPlateau, { 0xca, 0x8c, 0x65 }, }, + + // M variants: + { biSunflowerPlains, { 0xb5, 0xdb, 0x88 }, }, + { biDesertM, { 0xff, 0xbc, 0x40 }, }, + { biExtremeHillsM, { 0x88, 0x88, 0x88 }, }, + { biFlowerForest, { 0x2d, 0x8e, 0x49 }, }, + { biTaigaM, { 0x33, 0x8e, 0x81 }, }, + { biSwamplandM, { 0x07, 0xf9, 0xb2 }, }, + { biIcePlainsSpikes, { 0xb4, 0xdc, 0xdc }, }, + { biJungleM, { 0x7b, 0xa3, 0x31 }, }, + { biJungleEdgeM, { 0x62, 0x8b, 0x17 }, }, + { biBirchForestM, { 0x58, 0x9c, 0x6c }, }, + { biBirchForestHillsM, { 0x47, 0x87, 0x5a }, }, + { biRoofedForestM, { 0x68, 0x79, 0x42 }, }, + { biColdTaigaM, { 0x24, 0x3f, 0x36 }, }, + { biMegaSpruceTaiga, { 0x45, 0x4f, 0x3e }, }, + { biMegaSpruceTaigaHills, { 0x45, 0x4f, 0x4e }, }, + { biExtremeHillsPlusM, { 0x78, 0x98, 0x78 }, }, + { biSavannaM, { 0xe5, 0xda, 0x87 }, }, + { biSavannaPlateauM, { 0xa7, 0x9d, 0x74 }, }, + { biMesaBryce, { 0xff, 0x6d, 0x3d }, }, + { biMesaPlateauFM, { 0xd8, 0xbf, 0x8d }, }, + { biMesaPlateauM, { 0xf2, 0xb4, 0x8d }, }, +} ; + + + + + +static class BiomeColorsInitializer +{ +public: + BiomeColorsInitializer(void) + { + // Reset all colors to gray: + for (size_t i = 0; i < ARRAYCOUNT(biomeToColor); i++) + { + biomeToColor[i] = 0x7f; + } + + // Set known biomes to their colors: + for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++) + { + uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome]; + color[0] = biomeColors[i].m_Color[2]; + color[1] = biomeColors[i].m_Color[1]; + color[2] = biomeColors[i].m_Color[0]; + color[3] = 0xff; + } + } +} biomeColorInitializer; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// BiomeView: + BiomeView::BiomeView(QWidget * parent) : super(parent), m_X(0), @@ -40,10 +150,11 @@ BiomeView::BiomeView(QWidget * parent) : redraw(); // Add a chunk-update callback mechanism: - connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int))); + connect(&m_Cache, SIGNAL(regionAvailable(int, int)), this, SLOT(regionAvailable(int, int))); - // Allow keyboard interaction: + // Allow mouse and keyboard interaction: setFocusPolicy(Qt::StrongFocus); + setMouseTracking(true); } @@ -80,6 +191,27 @@ void BiomeView::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource) +void BiomeView::setPosition(int a_BlockX, int a_BlockZ) +{ + m_X = a_BlockX; + m_Z = a_BlockZ; + redraw(); +} + + + + + +void BiomeView::setZoomLevel(double a_ZoomLevel) +{ + m_Zoom = a_ZoomLevel; + redraw(); +} + + + + + void BiomeView::redraw() { if (!hasData()) @@ -121,9 +253,15 @@ void BiomeView::redraw() -void BiomeView::chunkAvailable(int a_ChunkX, int a_ChunkZ) +void BiomeView::regionAvailable(int a_RegionX, int a_RegionZ) { - drawChunk(a_ChunkX, a_ChunkZ); + for (int z = 0; z < 32; z++) + { + for (int x = 0; x < 32; x++) + { + drawChunk(a_RegionX * 32 + x, a_RegionZ * 32 + z); + } + } update(); } @@ -153,8 +291,11 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ) return; } - //fetch the chunk: - ChunkPtr chunk = m_Cache.fetch(a_ChunkX, a_ChunkZ); + // Fetch the region: + int regionX; + int regionZ; + Region::chunkToRegion(a_ChunkX, a_ChunkZ, regionX, regionZ); + RegionPtr region = m_Cache.fetch(regionX, regionZ); // Figure out where on the screen this chunk should be drawn: // first find the center chunk @@ -172,11 +313,10 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ) centerx += (a_ChunkX - centerchunkx) * chunksize; centery += (a_ChunkZ - centerchunkz) * chunksize; - int srcoffset = 0; uchar * bits = m_Image.bits(); int imgstride = m_Image.bytesPerLine(); - int skipx = 0,skipy = 0; + int skipx = 0, skipy = 0; int blockwidth = chunksize, blockheight = chunksize; // now if we're off the screen we need to crop if (centerx < 0) @@ -205,29 +345,52 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ) int imgoffset = centerx * 4 + centery * imgstride; // If the chunk is valid, use its data; otherwise use the empty placeholder: - const uchar * src = m_EmptyChunkImage; - if (chunk.get() != nullptr) + const short * src = m_EmptyChunkBiomes; + if (region.get() != nullptr) { - src = chunk->getImage(); + int relChunkX = a_ChunkX - regionX * 32; + int relChunkZ = a_ChunkZ - regionZ * 32; + Chunk & chunk = region->getRelChunk(relChunkX, relChunkZ); + if (chunk.isValid()) + { + src = chunk.getBiomes(); + } } - // Blit or scale-blit the image: + // Scale-blit the image: for (int z = skipy; z < blockheight; z++, imgoffset += imgstride) { - srcoffset = floor((double)z / m_Zoom) * 16 * 4; - if (m_Zoom == 1.0) - { - memcpy(bits + imgoffset, src + srcoffset + skipx * 4, (blockwidth - skipx) * 4); - } - else + size_t srcoffset = static_cast<size_t>(std::floor((double)z / m_Zoom)) * 16; + int imgxoffset = imgoffset; + for (int x = skipx; x < blockwidth; x++) { - int xofs = 0; - for (int x = skipx; x < blockwidth; x++, xofs +=4) + short biome = src[srcoffset + static_cast<size_t>(std::floor((double)x / m_Zoom))]; + const uchar * color; + if (biome < 0) { - memcpy(bits + imgoffset + xofs, src + srcoffset + (int)floor((double)x / m_Zoom) * 4, 4); + static const uchar emptyBiome1[] = { 0x44, 0x44, 0x44, 0xff }; + static const uchar emptyBiome2[] = { 0x88, 0x88, 0x88, 0xff }; + color = ((x & 8) ^ (z & 8)) ? emptyBiome1 : emptyBiome2; } - } - } + else + { + if (biome * 4 >= ARRAYCOUNT(biomeToColor)) + { + static const uchar errorImage[] = { 0xff, 0x00, 0x00, 0xff }; + color = errorImage; + } + else + { + color = biomeToColor + biome * 4; + } + } + bits[imgxoffset] = color[0]; + bits[imgxoffset + 1] = color[1]; + bits[imgxoffset + 2] = color[2]; + bits[imgxoffset + 3] = color[3]; + imgxoffset += 4; + } // for x + } // for z } @@ -275,6 +438,12 @@ void BiomeView::mousePressEvent(QMouseEvent * a_Event) void BiomeView::mouseMoveEvent(QMouseEvent * a_Event) { + // If there's no data displayed, bail out: + if (!hasData()) + { + return; + } + if (m_IsMouseDragging) { // The user is dragging the mouse, move the view around: @@ -286,7 +455,16 @@ void BiomeView::mouseMoveEvent(QMouseEvent * a_Event) return; } - // TODO: Update the status bar info for the biome currently pointed at + // Update the status bar info text: + int blockX = floor((a_Event->x() - width() / 2) / m_Zoom + m_X); + int blockZ = floor((a_Event->y() - height() / 2) / m_Zoom + m_Z); + int regionX, regionZ; + Region::blockToRegion(blockX, blockZ, regionX, regionZ); + int relX = blockX - regionX * 512; + int relZ = blockZ - regionZ * 512; + auto region = m_Cache.fetch(regionX, regionZ); + int biome = (region.get() != nullptr) ? region->getRelBiome(relX, relZ) : biInvalidBiome; + emit hoverChanged(blockX, blockZ, biome); } @@ -307,12 +485,12 @@ void BiomeView::wheelEvent(QWheelEvent * a_Event) m_MouseWheelDelta += a_Event->delta(); while (m_MouseWheelDelta >= DELTA_STEP) { - increaseZoom(); + emit wheelUp(); m_MouseWheelDelta -= DELTA_STEP; } while (m_MouseWheelDelta <= -DELTA_STEP) { - decreaseZoom(); + emit wheelDown(); m_MouseWheelDelta += DELTA_STEP; } } @@ -360,14 +538,14 @@ void BiomeView::keyPressEvent(QKeyEvent * a_Event) case Qt::Key_PageUp: case Qt::Key_Q: { - increaseZoom(); + emit increaseZoom(); break; } case Qt::Key_PageDown: case Qt::Key_E: { - decreaseZoom(); + emit decreaseZoom(); break; } } @@ -376,52 +554,3 @@ void BiomeView::keyPressEvent(QKeyEvent * a_Event) - -void BiomeView::decreaseZoom() -{ - if (m_Zoom > 1.001) - { - m_Zoom--; - if (m_Zoom < 1.0) - { - // Just crossed the 100%, fixate the 100% threshold: - m_Zoom = 1.0; - } - } - else if (m_Zoom > 0.01) - { - m_Zoom = m_Zoom / 2; - } - redraw(); -} - - - - - -void BiomeView::increaseZoom() -{ - if (m_Zoom > 0.99) - { - if (m_Zoom > 20.0) - { - // Zoom too large - return; - } - m_Zoom++; - } - else - { - m_Zoom = m_Zoom * 2; - if (m_Zoom > 1.0) - { - // Just crossed the 100%, fixate the 100% threshold: - m_Zoom = 1.0; - } - } - redraw(); -} - - - - diff --git a/Tools/QtBiomeVisualiser/BiomeView.h b/Tools/QtBiomeVisualiser/BiomeView.h index f0521571d..cd9c7ead9 100644 --- a/Tools/QtBiomeVisualiser/BiomeView.h +++ b/Tools/QtBiomeVisualiser/BiomeView.h @@ -2,7 +2,7 @@ #include <QWidget> #include <memory> -#include "ChunkCache.h" +#include "RegionCache.h" #include "ChunkSource.h" @@ -25,14 +25,34 @@ public: The entire view is then invalidated and regenerated. */ void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource); + /** Sets the position of the central pixel of the map to the specified point and redraws the view. */ + void setPosition(int a_BlockX, int a_BlockZ); + + /** Sets the zoom level to the specified value and redraws the view. */ + void setZoomLevel(double a_ZoomLevel); + signals: + /** Signalled when the user uses the wheel to scroll upwards. */ + void wheelUp(); + + /** Signalled when the user uses the wheel to scroll downwards. */ + void wheelDown(); + + /** Signalled when the user presses a key to increase zoom. */ + void increaseZoom(); + + /** Signalled when the user presses a key to decrease zoom. */ + void decreaseZoom(); + + /** Emitted when the user moves the mouse, to reflect the current block under the cursor. */ + void hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome); public slots: /** Redraw the entire widget area. */ void redraw(); - /** A specified chunk has become available, redraw it. */ - void chunkAvailable(int a_ChunkX, int a_ChunkZ); + /** A specified region has become available, redraw it. */ + void regionAvailable(int a_RegionX, int a_RegionZ); /** Reloads the current chunk source and redraws the entire workspace. */ void reload(); @@ -42,7 +62,7 @@ protected: double m_Zoom; /** Cache for the loaded chunk data. */ - ChunkCache m_Cache; + RegionCache m_Cache; /** The entire view's contents in an offscreen image. */ QImage m_Image; @@ -59,6 +79,9 @@ protected: /** Data used for rendering a chunk that hasn't been loaded yet */ uchar m_EmptyChunkImage[16 * 16 * 4]; + /** Data placeholder for chunks that aren't valid. */ + short m_EmptyChunkBiomes[16 * 16]; + /** Draws the specified chunk into m_Image */ void drawChunk(int a_ChunkX, int a_ChunkZ); @@ -86,12 +109,6 @@ protected: /** Called when the user presses a key. */ virtual void keyPressEvent(QKeyEvent * a_Event) override; - - /** Decreases the zoom level and queues a redraw. */ - void decreaseZoom(); - - /** Increases the zoom level and queues a redraw. */ - void increaseZoom(); }; diff --git a/Tools/QtBiomeVisualiser/ChunkCache.cpp b/Tools/QtBiomeVisualiser/ChunkCache.cpp deleted file mode 100644 index 05c267d30..000000000 --- a/Tools/QtBiomeVisualiser/ChunkCache.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "Globals.h" -#include "ChunkCache.h" -#include <QMutexLocker> -#include <QThreadPool> -#include "ChunkSource.h" -#include "ChunkLoader.h" - - - - - -ChunkCache::ChunkCache(QObject * parent) : - super(parent) -{ - m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache -} - - - - - -ChunkPtr ChunkCache::fetch(int a_ChunkX, int a_ChunkZ) -{ - // Retrieve from the cache: - quint32 hash = getChunkHash(a_ChunkX, a_ChunkZ); - ChunkPtr * res; - { - QMutexLocker lock(&m_Mtx); - res = m_Cache[hash]; - // If succesful and chunk loaded, return the retrieved value: - if ((res != nullptr) && (*res)->isValid()) - { - return *res; - } - } - - // If the chunk is in cache but not valid, it means it has been already queued for rendering, do nothing now: - if (res != nullptr) - { - return ChunkPtr(nullptr); - } - - // There's no such item in the cache, create it now: - res = new ChunkPtr(new Chunk); - if (res == nullptr) - { - return ChunkPtr(nullptr); - } - { - QMutexLocker lock(&m_Mtx); - m_Cache.insert(hash, res, sizeof(Chunk)); - } - - // Queue the chunk for rendering: - queueChunkRender(a_ChunkX, a_ChunkZ, *res); - - // Return failure, the chunk is not yet rendered: - return ChunkPtr(nullptr); -} - - - - - -void ChunkCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource) -{ - // Replace the chunk source: - m_ChunkSource = a_ChunkSource; - - // Clear the cache: - QMutexLocker lock(&m_Mtx); - m_Cache.clear(); -} - - - - - -void ChunkCache::reload() -{ - assert(m_ChunkSource.get() != nullptr); - - // Reload the chunk source: - m_ChunkSource->reload(); - - // Clear the cache: - QMutexLocker lock(&m_Mtx); - m_Cache.clear(); -} - - - - - -void ChunkCache::gotChunk(int a_ChunkX, int a_ChunkZ) -{ - emit chunkAvailable(a_ChunkX, a_ChunkZ); -} - - - - - -quint32 ChunkCache::getChunkHash(int a_ChunkX, int a_ChunkZ) -{ - // Simply join the two coords into a single int - // The coords will never be larger than 16-bits, so we can do this safely - return (((static_cast<quint32>(a_ChunkX) & 0xffff) << 16) | (static_cast<quint32>(a_ChunkZ) & 0xffff)); -} - - - - - -void ChunkCache::queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk) -{ - // Create a new loader task: - ChunkLoader * loader = new ChunkLoader(a_ChunkX, a_ChunkZ, a_Chunk, m_ChunkSource); - connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotChunk(int, int))); - - QThreadPool::globalInstance()->start(loader); -} - - - - diff --git a/Tools/QtBiomeVisualiser/ChunkLoader.cpp b/Tools/QtBiomeVisualiser/ChunkLoader.cpp deleted file mode 100644 index 3d0123b23..000000000 --- a/Tools/QtBiomeVisualiser/ChunkLoader.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "Globals.h" -#include "ChunkLoader.h" -#include "ChunkSource.h" - - - - - -ChunkLoader::ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource) : - m_ChunkX(a_ChunkX), - m_ChunkZ(a_ChunkZ), - m_Chunk(a_Chunk), - m_ChunkSource(a_ChunkSource) -{ -} - - - - - -void ChunkLoader::run() -{ - m_ChunkSource->getChunkBiomes(m_ChunkX, m_ChunkZ, m_Chunk); - emit loaded(m_ChunkX, m_ChunkZ); -} - - - - diff --git a/Tools/QtBiomeVisualiser/ChunkLoader.h b/Tools/QtBiomeVisualiser/ChunkLoader.h deleted file mode 100644 index 4d026a45e..000000000 --- a/Tools/QtBiomeVisualiser/ChunkLoader.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include <QObject> -#include <QRunnable> -#include <memory> - - - - -// fwd: -class Chunk; -typedef std::shared_ptr<Chunk> ChunkPtr; - -class ChunkSource; -typedef std::shared_ptr<ChunkSource> ChunkSourcePtr; - - - - - -class ChunkLoader : - public QObject, - public QRunnable -{ - Q_OBJECT - -public: - ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource); - virtual ~ChunkLoader() {} - -signals: - void loaded(int a_ChunkX, int a_ChunkZ); - -protected: - virtual void run() override; - -private: - int m_ChunkX, m_ChunkZ; - ChunkPtr m_Chunk; - ChunkSourcePtr m_ChunkSource; -}; - - - - diff --git a/Tools/QtBiomeVisualiser/ChunkSource.cpp b/Tools/QtBiomeVisualiser/ChunkSource.cpp index bebf89a0a..ea3346f04 100644 --- a/Tools/QtBiomeVisualiser/ChunkSource.cpp +++ b/Tools/QtBiomeVisualiser/ChunkSource.cpp @@ -4,177 +4,89 @@ #include "src/Generating/BioGen.h" #include "src/StringCompression.h" #include "src/WorldStorage/FastNBT.h" -#include "inifile/iniFile.h" +#include "src/IniFile.h" -/** Map for converting biome values to colors. Initialized from biomeColors[]. */ -static uchar biomeToColor[256 * 4]; +//////////////////////////////////////////////////////////////////////////////// +// BioGenSource: -/** Map for converting biome values to colors. Used to initialize biomeToColor[].*/ -static struct -{ - EMCSBiome m_Biome; - uchar m_Color[3]; -} biomeColors[] = -{ - { biOcean, { 0x00, 0x00, 0x70 }, }, - { biPlains, { 0x8d, 0xb3, 0x60 }, }, - { biDesert, { 0xfa, 0x94, 0x18 }, }, - { biExtremeHills, { 0x60, 0x60, 0x60 }, }, - { biForest, { 0x05, 0x66, 0x21 }, }, - { biTaiga, { 0x0b, 0x66, 0x59 }, }, - { biSwampland, { 0x2f, 0xff, 0xda }, }, - { biRiver, { 0x30, 0x30, 0xaf }, }, - { biHell, { 0x7f, 0x00, 0x00 }, }, - { biSky, { 0x00, 0x7f, 0xff }, }, - { biFrozenOcean, { 0xa0, 0xa0, 0xdf }, }, - { biFrozenRiver, { 0xa0, 0xa0, 0xff }, }, - { biIcePlains, { 0xff, 0xff, 0xff }, }, - { biIceMountains, { 0xa0, 0xa0, 0xa0 }, }, - { biMushroomIsland, { 0xff, 0x00, 0xff }, }, - { biMushroomShore, { 0xa0, 0x00, 0xff }, }, - { biBeach, { 0xfa, 0xde, 0x55 }, }, - { biDesertHills, { 0xd2, 0x5f, 0x12 }, }, - { biForestHills, { 0x22, 0x55, 0x1c }, }, - { biTaigaHills, { 0x16, 0x39, 0x33 }, }, - { biExtremeHillsEdge, { 0x7f, 0x8f, 0x7f }, }, - { biJungle, { 0x53, 0x7b, 0x09 }, }, - { biJungleHills, { 0x2c, 0x42, 0x05 }, }, - - { biJungleEdge, { 0x62, 0x8b, 0x17 }, }, - { biDeepOcean, { 0x00, 0x00, 0x30 }, }, - { biStoneBeach, { 0xa2, 0xa2, 0x84 }, }, - { biColdBeach, { 0xfa, 0xf0, 0xc0 }, }, - { biBirchForest, { 0x30, 0x74, 0x44 }, }, - { biBirchForestHills, { 0x1f, 0x5f, 0x32 }, }, - { biRoofedForest, { 0x40, 0x51, 0x1a }, }, - { biColdTaiga, { 0x31, 0x55, 0x4a }, }, - { biColdTaigaHills, { 0x59, 0x7d, 0x72 }, }, - { biMegaTaiga, { 0x59, 0x66, 0x51 }, }, - { biMegaTaigaHills, { 0x59, 0x66, 0x59 }, }, - { biExtremeHillsPlus, { 0x50, 0x70, 0x50 }, }, - { biSavanna, { 0xbd, 0xb2, 0x5f }, }, - { biSavannaPlateau, { 0xa7, 0x9d, 0x64 }, }, - { biMesa, { 0xd9, 0x45, 0x15 }, }, - { biMesaPlateauF, { 0xb0, 0x97, 0x65 }, }, - { biMesaPlateau, { 0xca, 0x8c, 0x65 }, }, - - // M variants: - { biSunflowerPlains, { 0xb5, 0xdb, 0x88 }, }, - { biDesertM, { 0xff, 0xbc, 0x40 }, }, - { biExtremeHillsM, { 0x88, 0x88, 0x88 }, }, - { biFlowerForest, { 0x2d, 0x8e, 0x49 }, }, - { biTaigaM, { 0x33, 0x8e, 0x81 }, }, - { biSwamplandM, { 0x07, 0xf9, 0xb2 }, }, - { biIcePlainsSpikes, { 0xb4, 0xdc, 0xdc }, }, - { biJungleM, { 0x7b, 0xa3, 0x31 }, }, - { biJungleEdgeM, { 0x62, 0x8b, 0x17 }, }, - { biBirchForestM, { 0x58, 0x9c, 0x6c }, }, - { biBirchForestHillsM, { 0x47, 0x87, 0x5a }, }, - { biRoofedForestM, { 0x68, 0x79, 0x42 }, }, - { biColdTaigaM, { 0x24, 0x3f, 0x36 }, }, - { biMegaSpruceTaiga, { 0x45, 0x4f, 0x3e }, }, - { biMegaSpruceTaigaHills, { 0x45, 0x4f, 0x4e }, }, - { biExtremeHillsPlusM, { 0x78, 0x98, 0x78 }, }, - { biSavannaM, { 0xe5, 0xda, 0x87 }, }, - { biSavannaPlateauM, { 0xa7, 0x9d, 0x74 }, }, - { biMesaBryce, { 0xff, 0x6d, 0x3d }, }, - { biMesaPlateauFM, { 0xd8, 0xbf, 0x8d }, }, - { biMesaPlateauM, { 0xf2, 0xb4, 0x8d }, }, -} ; - - - - - -static class BiomeColorsInitializer +BioGenSource::BioGenSource(cIniFilePtr a_IniFile) : + m_IniFile(a_IniFile), + m_Mtx(QMutex::Recursive) { -public: - BiomeColorsInitializer(void) - { - // Reset all colors to gray: - for (size_t i = 0; i < ARRAYCOUNT(biomeToColor); i++) - { - biomeToColor[i] = 0x7f; - } - - // Set known biomes to their colors: - for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++) - { - uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome]; - color[0] = biomeColors[i].m_Color[2]; - color[1] = biomeColors[i].m_Color[1]; - color[2] = biomeColors[i].m_Color[0]; - color[3] = 0xff; - } - } -} biomeColorInitializer; + reload(); +} -/** Converts biomes in an array into the chunk image data. */ -static void biomesToImage(cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image) +void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) { - // Make sure the two arrays are of the same size, compile-time. - // Note that a_Image is actually 4 items per pixel, so the array is 4 times bigger: - static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1] = {}; - static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1] = {}; - - // Convert the biomes into color: - for (size_t i = 0; i < ARRAYCOUNT(a_Biomes); i++) - { - a_Image[4 * i + 0] = biomeToColor[4 * a_Biomes[i] + 0]; - a_Image[4 * i + 1] = biomeToColor[4 * a_Biomes[i] + 1]; - a_Image[4 * i + 2] = biomeToColor[4 * a_Biomes[i] + 2]; - a_Image[4 * i + 3] = biomeToColor[4 * a_Biomes[i] + 3]; - } + cChunkDef::BiomeMap biomes; + int tag; + cBiomeGenPtr biomeGen = getBiomeGen(tag); + biomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes); + releaseBiomeGen(std::move(biomeGen), tag); + a_DestChunk.setBiomes(biomes); } -//////////////////////////////////////////////////////////////////////////////// -// BioGenSource: - -BioGenSource::BioGenSource(cIniFilePtr a_IniFile) : - m_IniFile(a_IniFile), - m_Mtx(QMutex::Recursive) +void BioGenSource::reload() { - reload(); + QMutexLocker lock(&m_Mtx); + m_CurrentTag += 1; + m_BiomeGens.clear(); } -void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) +cBiomeGenPtr BioGenSource::getBiomeGen(int & a_Tag) { - cChunkDef::BiomeMap biomes; + QMutexLocker lock(&m_Mtx); + a_Tag = m_CurrentTag; + if (m_BiomeGens.empty()) { - QMutexLocker lock(&m_Mtx); - m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes); + // Create a new biogen: + lock.unlock(); + int seed = m_IniFile->GetValueSetI("Seed", "Seed", 0); + bool unused; + cBiomeGenPtr res = cBiomeGen::CreateBiomeGen(*m_IniFile, seed, unused); + return res; + } + else + { + // Return an existing biogen: + cBiomeGenPtr res = m_BiomeGens.back(); + m_BiomeGens.pop_back(); + return res; } - Chunk::Image img; - biomesToImage(biomes, img); - a_DestChunk->setImage(img); } -void BioGenSource::reload() +void BioGenSource::releaseBiomeGen(cBiomeGenPtr && a_BiomeGen, int a_Tag) { - int seed = m_IniFile->GetValueSetI("Generator", "Seed", 0); - bool unused = false; QMutexLocker lock(&m_Mtx); - m_BiomeGen.reset(cBiomeGen::CreateBiomeGen(*m_IniFile, seed, unused)); + + // If the tag differs, the source has been reloaded and this biogen is old, dispose: + if (a_Tag != m_CurrentTag) + { + return; + } + + // The tag is the same, put the biogen back to list: + m_BiomeGens.push_back(std::move(a_BiomeGen)); } @@ -291,7 +203,7 @@ AnvilSource::AnvilSource(QString a_WorldRegionFolder) : -void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) +void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) { // Load the compressed data: AString compressedChunkData = getCompressedChunkData(a_ChunkX, a_ChunkZ); @@ -331,10 +243,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChun { biomeMap[i] = (EMCSBiome)GetBEInt(beBiomes + 4 * i); } - // Render the biomes: - Chunk::Image img; - biomesToImage(biomeMap, img); - a_DestChunk->setImage(img); + a_DestChunk.setBiomes(biomeMap); return; } @@ -350,10 +259,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChun { biomeMap[i] = EMCSBiome(vanillaBiomes[i]); } - // Render the biomes: - Chunk::Image img; - biomesToImage(biomeMap, img); - a_DestChunk->setImage(img); + a_DestChunk.setBiomes(biomeMap); } @@ -397,7 +303,7 @@ AnvilSource::AnvilFilePtr AnvilSource::getAnvilFile(int a_ChunkX, int a_ChunkZ) // Search the cache for the file: QMutexLocker lock(&m_Mtx); - for (auto itr = m_Files.cbegin(), end = m_Files.cend(); itr != end; ++itr) + for (auto itr = m_Files.begin(), end = m_Files.end(); itr != end; ++itr) { if (((*itr)->m_RegionX == RegionX) && ((*itr)->m_RegionZ == RegionZ)) { diff --git a/Tools/QtBiomeVisualiser/ChunkSource.h b/Tools/QtBiomeVisualiser/ChunkSource.h index 7bd1865ff..62f9b5626 100644 --- a/Tools/QtBiomeVisualiser/ChunkSource.h +++ b/Tools/QtBiomeVisualiser/ChunkSource.h @@ -10,7 +10,7 @@ // fwd: class cBiomeGen; -typedef std::shared_ptr<cBiomeGen> cBiomeGenPtr; +typedef SharedPtr<cBiomeGen> cBiomeGenPtr; class cIniFile; typedef std::shared_ptr<cIniFile> cIniFilePtr; @@ -26,7 +26,7 @@ public: /** Fills the a_DestChunk with the biomes for the specified coords. It is expected to be thread-safe and re-entrant. Usually QThread::idealThreadCount() threads are used. */ - virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) = 0; + virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) = 0; /** Forces a fresh reload of the source. Useful mainly for the generator, whose underlying definition file may have been changed. */ virtual void reload() = 0; @@ -45,7 +45,7 @@ public: BioGenSource(cIniFilePtr a_IniFile); // ChunkSource overrides: - virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override; + virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) override; virtual void reload(void) override; protected: @@ -53,10 +53,30 @@ protected: cIniFilePtr m_IniFile; /** The generator used for generating biomes. */ - std::unique_ptr<cBiomeGen> m_BiomeGen; + std::vector<cBiomeGenPtr> m_BiomeGens; - /** Guards m_BiomeGen against multithreaded access. */ + /** Guards m_BiomeGens against multithreaded access. */ QMutex m_Mtx; + + /** Keeps track of the current settings of the biomegens. + Incremented by one each time reload() is called. Provides the means of releasing old biomegens that were + in use while reload() was being processed and thus couldn't be changed back then. releaseBiomeGen() does + the job of filtering the biogens before reusing them. */ + int m_CurrentTag; + + + /** Retrieves one cBiomeGenPtr from m_BiomeGens. + If there's no biogen available there, creates a new one based on the ini file. + When done with it, the caller should call releaseBiomeGen() to put the biogen back to m_BiomeGens. + a_Tag receives the value of m_CurrentTag from when the lock was held; it should be passed to + releaseBiomeGen() together with the biogen. */ + cBiomeGenPtr getBiomeGen(int & a_Tag); + + /** Marks the specified biogen as available for reuse (puts it back into m_BiomeGens). + a_Tag is the value of m_CurrentTag from the time when the biogen was retrieved; if it is different from + current m_CurrentTagValue, the biogen will be disposed of (because reload() has been called in the + meantime). */ + void releaseBiomeGen(cBiomeGenPtr && a_BiomeGen, int a_Tag); }; @@ -70,7 +90,7 @@ public: AnvilSource(QString a_WorldRegionFolder); // ChunkSource overrides: - virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override; + virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) override; virtual void reload() override; protected: diff --git a/Tools/QtBiomeVisualiser/GeneratorSetup.cpp b/Tools/QtBiomeVisualiser/GeneratorSetup.cpp index f5412404c..8f97e1f37 100644 --- a/Tools/QtBiomeVisualiser/GeneratorSetup.cpp +++ b/Tools/QtBiomeVisualiser/GeneratorSetup.cpp @@ -3,7 +3,7 @@ #include <QLabel> #include <QLineEdit> #include "src/Generating/BioGen.h" -#include "inifile/iniFile.h" +#include "src/IniFile.h" @@ -14,6 +14,8 @@ static const QString s_GeneratorNames[] = QString("Checkerboard"), QString("Constant"), QString("DistortedVoronoi"), + QString("Grown"), + QString("GrownProt"), QString("MultiStepMap"), QString("TwoLevel"), QString("Voronoi"), @@ -31,6 +33,7 @@ GeneratorSetup::GeneratorSetup(const AString & a_IniFileName, QWidget * a_Parent m_eSeed = new QLineEdit(); m_eSeed->setValidator(new QIntValidator()); m_eSeed->setText("0"); + m_eSeed->setProperty("INI.SectionName", QVariant("Seed")); m_eSeed->setProperty("INI.ItemName", QVariant("Seed")); m_cbGenerator = new QComboBox(); m_cbGenerator->setMinimumWidth(120); @@ -53,17 +56,12 @@ GeneratorSetup::GeneratorSetup(const AString & a_IniFileName, QWidget * a_Parent setLayout(m_MainLayout); // Load the INI file, if specified, otherwise set defaults: - if (!a_IniFileName.empty() && m_IniFile->ReadFile(a_IniFileName)) - { - m_cbGenerator->setCurrentText(QString::fromStdString(m_IniFile->GetValue("Generator", "BiomeGen"))); - m_eSeed->setText(QString::number(m_IniFile->GetValueI("Generator", "Seed"))); - } - else + if (a_IniFileName.empty() || !m_IniFile->ReadFile(a_IniFileName)) { m_IniFile->SetValue("Generator", "Generator", "Composable"); m_IniFile->SetValue("Generator", "BiomeGen", m_cbGenerator->currentText().toStdString()); bool dummy; - delete cBiomeGen::CreateBiomeGen(*m_IniFile, 0, dummy); + cBiomeGen::CreateBiomeGen(*m_IniFile, 0, dummy); } updateFromIni(); @@ -95,7 +93,7 @@ void GeneratorSetup::generatorChanged(const QString & a_NewName) // Create a dummy biome gen from the INI file, this will create the defaults in the INI file: bool dummy; - delete cBiomeGen::CreateBiomeGen(*m_IniFile, m_Seed, dummy); + cBiomeGen::CreateBiomeGen(*m_IniFile, m_Seed, dummy); // Read all values from the INI file and put them into the form layout: updateFromIni(); @@ -110,8 +108,9 @@ void GeneratorSetup::generatorChanged(const QString & a_NewName) void GeneratorSetup::editChanged(const QString & a_NewValue) { - QString itemName = sender()->property("INI.ItemName").toString(); - m_IniFile->SetValue("Generator", itemName.toStdString(), a_NewValue.toStdString()); + QString sectionName = sender()->property("INI.SectionName").toString(); + QString itemName = sender()->property("INI.ItemName").toString(); + m_IniFile->SetValue(sectionName.toStdString(), itemName.toStdString(), a_NewValue.toStdString()); emit generatorUpdated(); } @@ -121,6 +120,7 @@ void GeneratorSetup::editChanged(const QString & a_NewValue) void GeneratorSetup::updateFromIni() { + m_eSeed->setText(QString::number(m_IniFile->GetValueI("Seed", "Seed", 0))); int keyID = m_IniFile->FindKey("Generator"); if (keyID <= -1) { @@ -141,6 +141,7 @@ void GeneratorSetup::updateFromIni() QLineEdit * edit = new QLineEdit(); edit->setText(QString::fromStdString(itemValue)); + edit->setProperty("INI.SectionName", QVariant("Generator")); edit->setProperty("INI.ItemName", QVariant(QString::fromStdString(itemName))); // Remove the generator name prefix from the item name, for clarity purposes: diff --git a/Tools/QtBiomeVisualiser/Globals.h b/Tools/QtBiomeVisualiser/Globals.h index 8d2e913b7..e2e9a9970 100644 --- a/Tools/QtBiomeVisualiser/Globals.h +++ b/Tools/QtBiomeVisualiser/Globals.h @@ -158,8 +158,17 @@ template class SizeChecker<UInt16, 2>; TypeName(const TypeName &); \ void operator =(const TypeName &) +// A macro that is used to mark unused local variables, to avoid pedantic warnings in gcc / clang / MSVC +// Note that in MSVC it requires the full type of X to be known +#define UNUSED_VAR(X) (void)(X) + // A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc -#define UNUSED(X) (void)(X) +// Written so that the full type of param needn't be known +#ifdef _MSC_VER + #define UNUSED(X) +#else + #define UNUSED UNUSED_VAR +#endif diff --git a/Tools/QtBiomeVisualiser/MainWindow.cpp b/Tools/QtBiomeVisualiser/MainWindow.cpp index eb45690c1..c6ea8656e 100644 --- a/Tools/QtBiomeVisualiser/MainWindow.cpp +++ b/Tools/QtBiomeVisualiser/MainWindow.cpp @@ -7,12 +7,23 @@ #include <QFileDialog> #include <QSettings> #include <QDirIterator> -#include "inifile/iniFile.h" +#include <QStatusBar> #include "ChunkSource.h" +#include "src/IniFile.h" #include "src/Generating/BioGen.h" #include "src/StringCompression.h" #include "src/WorldStorage/FastNBT.h" #include "GeneratorSetup.h" +#include "RegionLoader.h" + + + + + +const double MainWindow::m_ViewZooms[] = +{ + 0.0625, 0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 24, +}; @@ -21,11 +32,27 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent), m_GeneratorSetup(nullptr), - m_LineSeparator(nullptr) + m_LineSeparator(nullptr), + m_CurrentZoomLevel(2) { initMinecraftPath(); m_BiomeView = new BiomeView(); + connect(m_BiomeView, SIGNAL(increaseZoom()), this, SLOT(increaseZoom())); + connect(m_BiomeView, SIGNAL(decreaseZoom()), this, SLOT(decreaseZoom())); + connect(m_BiomeView, SIGNAL(wheelUp()), this, SLOT(increaseZoom())); + connect(m_BiomeView, SIGNAL(wheelDown()), this, SLOT(decreaseZoom())); + m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]); + + m_StatusBar = new QStatusBar(); + this->setStatusBar(m_StatusBar); + m_StatusBlockX = new QLabel(tr("X")); + m_StatusBlockZ = new QLabel(tr("Z")); + m_StatusBiome = new QLabel(tr("B")); + m_StatusBar->addPermanentWidget(m_StatusBlockX); + m_StatusBar->addPermanentWidget(m_StatusBlockZ); + m_StatusBar->addPermanentWidget(m_StatusBiome); + m_MainLayout = new QHBoxLayout(); m_MainLayout->addWidget(m_BiomeView, 1); m_MainLayout->setMenuBar(menuBar()); @@ -36,6 +63,8 @@ MainWindow::MainWindow(QWidget * parent) : createActions(); createMenus(); + + connect(m_BiomeView, SIGNAL(hoverChanged(int, int, int)), this, SLOT(hoverChanged(int, int, int))); } @@ -44,7 +73,7 @@ MainWindow::MainWindow(QWidget * parent) : MainWindow::~MainWindow() { - + RegionLoader::shutdown(); } @@ -129,6 +158,80 @@ void MainWindow::openVanillaWorld() +void MainWindow::centerView() +{ + m_BiomeView->setPosition(0, 0); +} + + + + + +void MainWindow::setViewZoom() +{ + // The zoom level is stored in the sender action's data, retrieve it: + QAction * action = qobject_cast<QAction *>(sender()); + if (action == nullptr) + { + return; + } + m_CurrentZoomLevel = action->data().toInt(); + double newZoom = m_ViewZooms[m_CurrentZoomLevel]; + m_BiomeView->setZoomLevel(newZoom); + action->setChecked(true); +} + + + + + +void MainWindow::increaseZoom() +{ + // If already at max zoom, bail out: + if (m_CurrentZoomLevel >= ARRAYCOUNT(m_ViewZooms) - 1) + { + return; + } + + // Increase the zoom level: + m_CurrentZoomLevel += 1; + m_actViewZoom[m_CurrentZoomLevel]->setChecked(true); + m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]); +} + + + + + +void MainWindow::decreaseZoom() +{ + // If already at min zoom, bail out: + if (m_CurrentZoomLevel == 0) + { + return; + } + + // Decrease the zoom level: + m_CurrentZoomLevel -= 1; + m_actViewZoom[m_CurrentZoomLevel]->setChecked(true); + m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]); +} + + + + + +void MainWindow::hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome) +{ + m_StatusBlockX->setText(tr("X: %1").arg(a_BlockX)); + m_StatusBlockZ->setText(tr("Z: %1").arg(a_BlockZ)); + m_StatusBiome->setText (tr("B: %1 (%2)").arg(BiomeToString(a_Biome).c_str()).arg(a_Biome)); +} + + + + + void MainWindow::initMinecraftPath() { #ifdef Q_OS_MAC @@ -147,6 +250,7 @@ void MainWindow::initMinecraftPath() void MainWindow::createActions() { + // Map menu: createWorldActions(); m_actNewGen = new QAction(tr("&New generator"), this); @@ -173,6 +277,22 @@ void MainWindow::createActions() m_actExit->setShortcut(tr("Alt+X")); m_actExit->setStatusTip(tr("Exit %1").arg(QApplication::instance()->applicationName())); connect(m_actExit, SIGNAL(triggered()), this, SLOT(close())); + + // View menu: + m_actViewCenter = new QAction(tr("&Reset to center"), this); + m_actViewCenter->setStatusTip(tr("Scrolls the view back to the map center")); + connect(m_actViewCenter, SIGNAL(triggered()), this, SLOT(centerView())); + + QActionGroup * zoomGroup = new QActionGroup(this); + for (int i = 0; i < ARRAYCOUNT(m_ViewZooms); i++) + { + m_actViewZoom[i] = new QAction(tr("&Zoom %1%").arg(std::floor(m_ViewZooms[i] * 100)), this); + m_actViewZoom[i]->setCheckable(true); + m_actViewZoom[i]->setData(QVariant(i)); + zoomGroup->addAction(m_actViewZoom[i]); + connect(m_actViewZoom[i], SIGNAL(triggered()), this, SLOT(setViewZoom())); + } + m_actViewZoom[m_CurrentZoomLevel]->setChecked(true); } @@ -220,11 +340,12 @@ void MainWindow::createWorldActions() void MainWindow::createMenus() { + // Map menu: QMenu * file = menuBar()->addMenu(tr("&Map")); file->addAction(m_actNewGen); file->addAction(m_actOpenGen); file->addSeparator(); - QMenu * worlds = file->addMenu(tr("Open existing")); + QMenu * worlds = file->addMenu(tr("Open &existing")); worlds->addActions(m_WorldActions); if (m_WorldActions.empty()) { @@ -235,6 +356,15 @@ void MainWindow::createMenus() file->addAction(m_actReload); file->addSeparator(); file->addAction(m_actExit); + + // View menu: + QMenu * view = menuBar()->addMenu(tr("&View")); + view->addAction(m_actViewCenter); + view->addSeparator(); + for (size_t i = 0; i < ARRAYCOUNT(m_actViewZoom); i++) + { + view->addAction(m_actViewZoom[i]); + } } diff --git a/Tools/QtBiomeVisualiser/MainWindow.h b/Tools/QtBiomeVisualiser/MainWindow.h index 6490a937f..27faae7a8 100644 --- a/Tools/QtBiomeVisualiser/MainWindow.h +++ b/Tools/QtBiomeVisualiser/MainWindow.h @@ -4,6 +4,7 @@ #include <QList> #include <QMainWindow> #include <QHBoxLayout> +#include <QLabel> #include "BiomeView.h" @@ -39,13 +40,33 @@ private slots: /** Opens a vanilla world that is specified by the calling action. */ void openVanillaWorld(); + /** Moves the view to the map's center. */ + void centerView(); + + /** Sets the zoom level specified in the triggering action. */ + void setViewZoom(); + + /** Sets a zoom level one step larger than current, if allowed. */ + void increaseZoom(); + + /** Sets a zoom level one step smaller than current, if allowed. */ + void decreaseZoom(); + + /** Updates the statusbar for the specified info about the current block under the cursor. */ + void hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome); + protected: + /** The zoom levels */ + static const double m_ViewZooms[10]; + // Actions: QAction * m_actNewGen; QAction * m_actOpenGen; QAction * m_actOpenWorld; QAction * m_actReload; QAction * m_actExit; + QAction * m_actViewCenter; + QAction * m_actViewZoom[ARRAYCOUNT(m_ViewZooms)]; /** List of actions that open the specific vanilla world. */ QList<QAction *> m_WorldActions; @@ -62,9 +83,19 @@ protected: /** The layout for the window. */ QHBoxLayout * m_MainLayout; + /** The status bar that displays the current hover information. */ + QStatusBar * m_StatusBar; + + QLabel * m_StatusBlockX; + QLabel * m_StatusBlockZ; + QLabel * m_StatusBiome; + /** The separator line between biome view and generator setup. */ QWidget * m_LineSeparator; + /** Index into m_ViewZooms[] for the current zoom level. */ + size_t m_CurrentZoomLevel; + /** Initializes the m_MinecraftPath based on the proper MC path */ void initMinecraftPath(); diff --git a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro index 9e5d1303c..9522491a8 100644 --- a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro +++ b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro @@ -12,76 +12,86 @@ TARGET = QtBiomeVisualiser TEMPLATE = app -SOURCES +=\ - MainWindow.cpp \ - BiomeView.cpp \ - ../../src/Generating/BioGen.cpp \ - ../../src/VoronoiMap.cpp \ - ../../src/Noise.cpp \ - ../../src/StringUtils.cpp \ - ../../src/LoggerListeners.cpp \ - ../../src/Logger.cpp \ - ../../lib/inifile/iniFile.cpp \ - ../../src/OSSupport/File.cpp \ - ../../src/OSSupport/CriticalSection.cpp \ - ../../src/OSSupport/IsThread.cpp \ - ../../src/BiomeDef.cpp \ - ChunkCache.cpp \ - ChunkSource.cpp \ - ChunkLoader.cpp \ - ../../src/StringCompression.cpp \ - ../../src/WorldStorage/FastNBT.cpp \ - ../../lib/zlib/adler32.c \ - ../../lib/zlib/compress.c \ - ../../lib/zlib/crc32.c \ - ../../lib/zlib/deflate.c \ - ../../lib/zlib/gzclose.c \ - ../../lib/zlib/gzlib.c \ - ../../lib/zlib/gzread.c \ - ../../lib/zlib/gzwrite.c \ - ../../lib/zlib/infback.c \ - ../../lib/zlib/inffast.c \ - ../../lib/zlib/inflate.c \ - ../../lib/zlib/inftrees.c \ - ../../lib/zlib/trees.c \ - ../../lib/zlib/uncompr.c \ - ../../lib/zlib/zutil.c \ - GeneratorSetup.cpp \ - QtBiomeVisualiser.cpp \ - QtChunk.cpp - -HEADERS += MainWindow.h \ - Globals.h \ - BiomeView.h \ - ../../src/Generating/BioGen.h \ - ../../src/VoronoiMap.h \ - ../../src/Noise.h \ - ../../src/StringUtils.h \ - ../../src/LoggerListeners.h \ - ../../src/Logger.h \ - ../../lib/inifile/iniFile.h \ - ../../src/OSSupport/File.h \ - ../../src/OSSupport/CriticalSection.h \ - ../../src/OSSupport/IsThread.h \ - ../../src/BiomeDef.h \ - ChunkCache.h \ - ChunkSource.h \ - ChunkLoader.h \ - ../../src/StringCompression.h \ - ../../src/WorldStorage/FastNBT.h \ - ../../lib/zlib/crc32.h \ - ../../lib/zlib/deflate.h \ - ../../lib/zlib/gzguts.h \ - ../../lib/zlib/inffast.h \ - ../../lib/zlib/inffixed.h \ - ../../lib/zlib/inflate.h \ - ../../lib/zlib/inftrees.h \ - ../../lib/zlib/trees.h \ - ../../lib/zlib/zconf.h \ - ../../lib/zlib/zlib.h \ - ../../lib/zlib/zutil.h \ - GeneratorSetup.h \ - QtChunk.h +SOURCES += \ + MainWindow.cpp \ + BiomeView.cpp \ + ../../src/Generating/BioGen.cpp \ + ../../src/VoronoiMap.cpp \ + ../../src/Noise.cpp \ + ../../src/StringUtils.cpp \ + ../../src/LoggerListeners.cpp \ + ../../src/Logger.cpp \ + ../../src/IniFile.cpp \ + ../../src/OSSupport/File.cpp \ + ../../src/OSSupport/CriticalSection.cpp \ + ../../src/OSSupport/IsThread.cpp \ + ../../src/BiomeDef.cpp \ + ../../src/StringCompression.cpp \ + ../../src/WorldStorage/FastNBT.cpp \ + ../../lib/zlib/adler32.c \ + ../../lib/zlib/compress.c \ + ../../lib/zlib/crc32.c \ + ../../lib/zlib/deflate.c \ + ../../lib/zlib/gzclose.c \ + ../../lib/zlib/gzlib.c \ + ../../lib/zlib/gzread.c \ + ../../lib/zlib/gzwrite.c \ + ../../lib/zlib/infback.c \ + ../../lib/zlib/inffast.c \ + ../../lib/zlib/inflate.c \ + ../../lib/zlib/inftrees.c \ + ../../lib/zlib/trees.c \ + ../../lib/zlib/uncompr.c \ + ../../lib/zlib/zutil.c \ + GeneratorSetup.cpp \ + QtBiomeVisualiser.cpp \ + QtChunk.cpp \ + RegionCache.cpp \ + Region.cpp \ + ChunkSource.cpp \ + RegionLoader.cpp + + + +HEADERS += \ + MainWindow.h \ + QtChunk.h \ + Globals.h \ + BiomeView.h \ + ../../src/Generating/BioGen.h \ + ../../src/Generating/IntGen.h \ + ../../src/Generating/ProtIntGen.h \ + ../../src/VoronoiMap.h \ + ../../src/Noise.h \ + ../../src/StringUtils.h \ + ../../src/LoggerListeners.h \ + ../../src/Logger.h \ + ../../src/IniFile.h \ + ../../src/OSSupport/File.h \ + ../../src/OSSupport/CriticalSection.h \ + ../../src/OSSupport/IsThread.h \ + ../../src/BiomeDef.h \ + ../../src/StringCompression.h \ + ../../src/WorldStorage/FastNBT.h \ + ../../lib/zlib/crc32.h \ + ../../lib/zlib/deflate.h \ + ../../lib/zlib/gzguts.h \ + ../../lib/zlib/inffast.h \ + ../../lib/zlib/inffixed.h \ + ../../lib/zlib/inflate.h \ + ../../lib/zlib/inftrees.h \ + ../../lib/zlib/trees.h \ + ../../lib/zlib/zconf.h \ + ../../lib/zlib/zlib.h \ + ../../lib/zlib/zutil.h \ + GeneratorSetup.h \ + QtChunk.h \ + RegionCache.h \ + Region.h \ + ChunkSource.h \ + RegionLoader.h + + INCLUDEPATH += $$_PRO_FILE_PWD_ \ $$_PRO_FILE_PWD_/../../lib \ diff --git a/Tools/QtBiomeVisualiser/QtChunk.cpp b/Tools/QtBiomeVisualiser/QtChunk.cpp index 80109b2f8..f201ef220 100644 --- a/Tools/QtBiomeVisualiser/QtChunk.cpp +++ b/Tools/QtBiomeVisualiser/QtChunk.cpp @@ -14,20 +14,26 @@ Chunk::Chunk() : -const uchar * Chunk::getImage(void) const +void Chunk::setBiomes(const cChunkDef::BiomeMap & a_Biomes) { - ASSERT(m_IsValid); - return m_Image; + for (size_t idx = 0; idx < ARRAYCOUNT(a_Biomes); ++idx) + { + m_Biomes[idx] = static_cast<short>(a_Biomes[idx]); + } + m_IsValid = true; } -void Chunk::setImage(const Image & a_Image) +EMCSBiome Chunk::getBiome(int a_RelX, int a_RelZ) { - memcpy(m_Image, a_Image, sizeof(a_Image)); - m_IsValid = true; + if (!m_IsValid) + { + return biInvalidBiome; + } + return static_cast<EMCSBiome>(m_Biomes[a_RelX + 16 * a_RelZ]); } diff --git a/Tools/QtBiomeVisualiser/QtChunk.h b/Tools/QtBiomeVisualiser/QtChunk.h index 03e7bd1b3..d806d18bb 100644 --- a/Tools/QtBiomeVisualiser/QtChunk.h +++ b/Tools/QtBiomeVisualiser/QtChunk.h @@ -18,18 +18,23 @@ public: /** Returns true iff the chunk data is valid - loaded or generated. */ bool isValid(void) const { return m_IsValid; } - /** Returns the image of the chunk's biomes. Assumes that the chunk is valid. */ - const uchar * getImage(void) const; + /** Sets the biomes to m_Biomes and renders them into m_Image. */ + void setBiomes(const cChunkDef::BiomeMap & a_Biomes); - /** Sets the image data for this chunk. */ - void setImage(const Image & a_Image); + /** Returns the biome at the specified relative coords, or biInvalidBiome if not valid. + Coords must be valid inside this chunk. */ + EMCSBiome getBiome(int a_RelX, int a_RelZ); + + /** Returns the raw biome data for this chunk. */ + const short * getBiomes(void) const { return m_Biomes; } protected: /** Flag that specifies if the chunk data is valid - loaded or generated. */ bool m_IsValid; - /** Cached rendered image of this chunk's biomes. Updated in render(). */ - Image m_Image; + /** Biomes comprising the chunk, in the X + 16 * Z ordering. + Typed as short to save on memory, converted automatically when needed. */ + short m_Biomes[16 * 16]; }; typedef std::shared_ptr<Chunk> ChunkPtr; diff --git a/Tools/QtBiomeVisualiser/Region.cpp b/Tools/QtBiomeVisualiser/Region.cpp new file mode 100644 index 000000000..d8a0a2f76 --- /dev/null +++ b/Tools/QtBiomeVisualiser/Region.cpp @@ -0,0 +1,72 @@ + +#include "Globals.h" +#include "Region.h" + + + + + +Region::Region() +{ +} + + + + + +Chunk & Region::getRelChunk(int a_RelChunkX, int a_RelChunkZ) +{ + ASSERT(a_RelChunkX >= 0); + ASSERT(a_RelChunkZ >= 0); + ASSERT(a_RelChunkX < 32); + ASSERT(a_RelChunkZ < 32); + + return m_Chunks[a_RelChunkX + a_RelChunkZ * 32]; +} + + + + + +int Region::getRelBiome(int a_RelBlockX, int a_RelBlockZ) +{ + ASSERT(a_RelBlockX >= 0); + ASSERT(a_RelBlockZ >= 0); + ASSERT(a_RelBlockX < 512); + ASSERT(a_RelBlockZ < 512); + + int chunkX = a_RelBlockX / 16; + int chunkZ = a_RelBlockZ / 16; + Chunk & chunk = m_Chunks[chunkX + 32 * chunkZ]; + if (chunk.isValid()) + { + return chunk.getBiome(a_RelBlockX - 16 * chunkX, a_RelBlockZ - 16 * chunkZ); + } + else + { + return biInvalidBiome; + } +} + + + + +void Region::blockToRegion(int a_BlockX, int a_BlockZ, int & a_RegionX, int & a_RegionZ) +{ + a_RegionX = static_cast<int>(std::floor(static_cast<float>(a_BlockX) / 512)); + a_RegionZ = static_cast<int>(std::floor(static_cast<float>(a_BlockZ) / 512)); +} + + + + + +void Region::chunkToRegion(int a_ChunkX, int a_ChunkZ, int & a_RegionX, int & a_RegionZ) +{ + a_RegionX = static_cast<int>(std::floor(static_cast<float>(a_ChunkX) / 32)); + a_RegionZ = static_cast<int>(std::floor(static_cast<float>(a_ChunkZ) / 32)); +} + + + + diff --git a/Tools/QtBiomeVisualiser/Region.h b/Tools/QtBiomeVisualiser/Region.h new file mode 100644 index 000000000..863c0ac02 --- /dev/null +++ b/Tools/QtBiomeVisualiser/Region.h @@ -0,0 +1,46 @@ +#pragma once + +#include "QtChunk.h" + + + + + +class Region +{ +public: + Region(); + + /** Retrieves the chunk with the specified relative coords. */ + Chunk & getRelChunk(int a_RelChunkX, int a_RelChunkZ); + + /** Returns true iff the chunk data for all chunks has been loaded. + This doesn't mean that all the chunks are valid, only that the entire region has been processed and should + be displayed. */ + bool isValid(void) const { return m_IsValid; } + + /** Returns the biome in the block coords relative to this region. + Returns biInvalidBiome if the underlying chunk is not valid. */ + int getRelBiome(int a_RelBlockX, int a_RelBlockZ); + + /** Converts block coordinates into region coordinates. */ + static void blockToRegion(int a_BlockX, int a_BlockZ, int & a_RegionX, int & a_RegionZ); + + /** Converts chunk coordinates into region coordinates. */ + static void chunkToRegion(int a_ChunkX, int a_ChunkZ, int & a_RegionX, int & a_RegionZ); + +protected: + friend class RegionLoader; + + + Chunk m_Chunks[32 * 32]; + + /** True iff the data for all the chunks has been loaded. + This doesn't mean that all the chunks are valid, only that the entire region has been processed and should + be displayed. */ + bool m_IsValid; +}; + + + + diff --git a/Tools/QtBiomeVisualiser/RegionCache.cpp b/Tools/QtBiomeVisualiser/RegionCache.cpp new file mode 100644 index 000000000..e46fd222a --- /dev/null +++ b/Tools/QtBiomeVisualiser/RegionCache.cpp @@ -0,0 +1,138 @@ +#include "Globals.h" +#include "RegionCache.h" +#include <QMutexLocker> +#include <QThreadPool> +#include "ChunkSource.h" +#include "RegionLoader.h" +#include "Region.h" + + + + + +RegionCache::RegionCache(QObject * parent) : + super(parent) +{ + m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache +} + + + + + +RegionPtr RegionCache::fetch(int a_RegionX, int a_RegionZ) +{ + // Retrieve from the cache: + quint32 hash = getRegionHash(a_RegionX, a_RegionZ); + RegionPtr * res; + { + QMutexLocker lock(&m_Mtx); + res = m_Cache[hash]; + // If succesful and region loaded, return the retrieved value: + if ((res != nullptr) && (*res)->isValid()) + { + return *res; + } + } + + // If the region is in cache but not valid, it means it has been already queued for rendering, do nothing now: + if (res != nullptr) + { + return RegionPtr(nullptr); + } + + // There's no such item in the cache, create it now: + try + { + res = new RegionPtr(new Region); + } + catch (const std::bad_alloc &) + { + /* Allocation failed (32-bit process hit the 2 GiB barrier?) + This may happen even with the cache set to 1 GiB, because it contains shared ptrs and so they may be + held by another place in the code even when they are removed from cache. + */ + return RegionPtr(nullptr); + } + if (res == nullptr) + { + return RegionPtr(nullptr); + } + { + QMutexLocker lock(&m_Mtx); + m_Cache.insert(hash, res, sizeof(Region)); + } + + // Queue the region for rendering: + queueRegionRender(a_RegionX, a_RegionZ, *res); + + // Return failure, the region is not yet rendered: + return RegionPtr(nullptr); +} + + + + + +void RegionCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource) +{ + // Replace the chunk source: + m_ChunkSource = a_ChunkSource; + + // Clear the cache: + QMutexLocker lock(&m_Mtx); + m_Cache.clear(); +} + + + + + +void RegionCache::reload() +{ + assert(m_ChunkSource.get() != nullptr); + + // Reload the chunk source: + m_ChunkSource->reload(); + + // Clear the cache: + QMutexLocker lock(&m_Mtx); + m_Cache.clear(); +} + + + + + +void RegionCache::gotRegion(int a_RegionX, int a_RegionZ) +{ + emit regionAvailable(a_RegionX, a_RegionZ); +} + + + + + +quint32 RegionCache::getRegionHash(int a_RegionX, int a_RegionZ) +{ + // Simply join the two coords into a single int + // The coords will never be larger than 16-bits, so we can do this safely + return (((static_cast<quint32>(a_RegionX) & 0xffff) << 16) | (static_cast<quint32>(a_RegionZ) & 0xffff)); +} + + + + + +void RegionCache::queueRegionRender(int a_RegionX, int a_RegionZ, RegionPtr & a_Region) +{ + // Create a new loader task: + RegionLoader * loader = new RegionLoader(a_RegionX, a_RegionZ, a_Region, m_ChunkSource); + connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotRegion(int, int))); + + QThreadPool::globalInstance()->start(loader); +} + + + + diff --git a/Tools/QtBiomeVisualiser/ChunkCache.h b/Tools/QtBiomeVisualiser/RegionCache.h index 8d198f02f..c343e4ba9 100644 --- a/Tools/QtBiomeVisualiser/ChunkCache.h +++ b/Tools/QtBiomeVisualiser/RegionCache.h @@ -9,8 +9,9 @@ -class Chunk; -typedef std::shared_ptr<Chunk> ChunkPtr; +// fwd: +class Region; +typedef std::shared_ptr<Region> RegionPtr; class ChunkSource; @@ -18,19 +19,19 @@ class ChunkSource; -/** Caches chunk data for reuse */ -class ChunkCache : +/** Caches regions' chunk data for reuse */ +class RegionCache : public QObject { typedef QObject super; Q_OBJECT public: - explicit ChunkCache(QObject * parent = NULL); + explicit RegionCache(QObject * parent = NULL); - /** Retrieves the specified chunk from the cache. - Only returns valid chunks; if the chunk is invalid, queues it for rendering and returns an empty ptr. */ - ChunkPtr fetch(int a_ChunkX, int a_ChunkZ); + /** Retrieves the specified region from the cache. + Only returns valid regions; if the region is invalid, queues it for rendering and returns an empty ptr. */ + RegionPtr fetch(int a_RegionX, int a_RegionZ); /** Replaces the chunk source used by the biome view to get the chunk biome data. The cache is then invalidated. */ @@ -43,16 +44,16 @@ public: void reload(); signals: - void chunkAvailable(int a_ChunkX, int a_ChunkZ); + void regionAvailable(int a_RegionX, int a_RegionZ); protected slots: - void gotChunk(int a_ChunkX, int a_ChunkZ); + void gotRegion(int a_RegionX, int a_RegionZ); protected: /** The cache of the chunks */ - QCache<quint32, ChunkPtr> m_Cache; + QCache<quint32, RegionPtr> m_Cache; - /** Locks te cache against multithreaded access */ + /** Locks the cache against multithreaded access */ QMutex m_Mtx; /** The source used to get the biome data. */ @@ -60,10 +61,10 @@ protected: /** Returns the hash used by the chunk in the cache */ - quint32 getChunkHash(int a_ChunkX, int a_ChunkZ); + quint32 getRegionHash(int a_RegionX, int a_RegionZ); - /** Queues the specified chunk for rendering by m_ChunkSource. */ - void queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk); + /** Queues the specified region for rendering by m_RegionSource. */ + void queueRegionRender(int a_RegionX, int a_RegionZ, RegionPtr & a_Region); }; diff --git a/Tools/QtBiomeVisualiser/RegionLoader.cpp b/Tools/QtBiomeVisualiser/RegionLoader.cpp new file mode 100644 index 000000000..2a318098b --- /dev/null +++ b/Tools/QtBiomeVisualiser/RegionLoader.cpp @@ -0,0 +1,49 @@ +#include "Globals.h" +#include "RegionLoader.h" +#include "ChunkSource.h" +#include "Region.h" + + + + + +volatile bool RegionLoader::m_IsShuttingDown = false; + + + + + +RegionLoader::RegionLoader(int a_RegionX, int a_RegionZ, RegionPtr a_Region, ChunkSourcePtr a_ChunkSource) : + m_RegionX(a_RegionX), + m_RegionZ(a_RegionZ), + m_Region(a_Region), + m_ChunkSource(a_ChunkSource) +{ +} + + + + + +void RegionLoader::run() +{ + // Load all the chunks in this region: + for (int z = 0; z < 32; z++) + { + for (int x = 0; x < 32; x++) + { + m_ChunkSource->getChunkBiomes(m_RegionX * 32 + x, m_RegionZ * 32 + z, m_Region->getRelChunk(x, z)); + if (m_IsShuttingDown) + { + return; + } + } + } + m_Region->m_IsValid = true; + + emit loaded(m_RegionX, m_RegionZ); +} + + + + diff --git a/Tools/QtBiomeVisualiser/RegionLoader.h b/Tools/QtBiomeVisualiser/RegionLoader.h new file mode 100644 index 000000000..6bbb4aa60 --- /dev/null +++ b/Tools/QtBiomeVisualiser/RegionLoader.h @@ -0,0 +1,56 @@ +#pragma once + +#include <QObject> +#include <QRunnable> +#include <memory> + + + + +// fwd: +class Region; +typedef std::shared_ptr<Region> RegionPtr; + +class ChunkSource; +typedef std::shared_ptr<ChunkSource> ChunkSourcePtr; + + + + + +class RegionLoader : + public QObject, + public QRunnable +{ + Q_OBJECT + +public: + RegionLoader(int a_RegionX, int a_RegionZ, RegionPtr a_Region, ChunkSourcePtr a_ChunkSource); + virtual ~RegionLoader() {} + + /** Signals to all loaders that the app is shutting down and the loading should be aborted. */ + static void shutdown() { m_IsShuttingDown = true; } + +signals: + void loaded(int a_RegionX, int a_RegionZ); + +protected: + virtual void run() override; + +private: + /** Coords of the region to be loaded. */ + int m_RegionX, m_RegionZ; + + /** The region to be loaded. */ + RegionPtr m_Region; + + /** The chunk source to be used for individual chunks within the region. */ + ChunkSourcePtr m_ChunkSource; + + /** Flag that is set upon app exit to terminate the queued loaders faster. */ + static volatile bool m_IsShuttingDown; +}; + + + + diff --git a/app.yml b/app.yml new file mode 100644 index 000000000..44edf0852 --- /dev/null +++ b/app.yml @@ -0,0 +1,11 @@ +name: MCServer +image: ubuntu-14-04-x64 +config: + #cloud-config + packages: + - curl + - screen + runcmd: + - mkdir /minecraft + - cd /minecraft && curl -s https://raw.githubusercontent.com/mc-server/MCServer/master/easyinstall.sh | sh + - cd /minecraft/MCServer && screen -S mcserver -d -m ./MCServer diff --git a/easyinstall.sh b/easyinstall.sh new file mode 100755 index 000000000..77ffb2290 --- /dev/null +++ b/easyinstall.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +PLATFORM=$(uname -m) + +echo "Identifying platform: $PLATFORM" +case $PLATFORM in + "i686") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20x86/lastSuccessfulBuild/artifact/MCServer.tar" ;; + "x86_64") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20x64/lastSuccessfulBuild/artifact/MCServer.tar" ;; + # Assume that all arm devices are a raspi for now. + "arm*") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20armhf/lastSuccessfulBuild/artifact/MCServer.tar" +esac + +echo "Downloading precompiled binaries." +curl -s $DOWNLOADURL | tar -xzf - +echo "Done." + +echo "MCServer is now installed, run using 'cd MCServer; ./MCServer'." diff --git a/lib/inifile/CMakeLists.txt b/lib/inifile/CMakeLists.txt deleted file mode 100644 index 321d501d7..000000000 --- a/lib/inifile/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required (VERSION 2.6) -project (iniFile) - -include_directories ("${PROJECT_SOURCE_DIR}/../../src/") - -file(GLOB SOURCE - "*.h" - "*.cpp" -) - -add_library(iniFile ${SOURCE}) diff --git a/lib/polarssl b/lib/polarssl -Subproject 1ed82759c68f92c4acc7e3f33b850cf9f01c8ab +Subproject d6a15321ae51762098e49a976d26efa2493c94f diff --git a/src/AllocationPool.h b/src/AllocationPool.h index 61431a548..7c358cc84 100644 --- a/src/AllocationPool.h +++ b/src/AllocationPool.h @@ -45,7 +45,7 @@ class cListAllocationPool : public cAllocationPool<T> for (size_t i = 0; i < NumElementsInReserve; i++) { void * space = malloc(sizeof(T)); - if (space == NULL) + if (space == nullptr) { m_Callbacks->OnStartUsingReserve(); break; @@ -68,7 +68,7 @@ class cListAllocationPool : public cAllocationPool<T> if (m_FreeList.size() <= NumElementsInReserve) { void * space = malloc(sizeof(T)); - if (space != NULL) + if (space != nullptr) { return new(space) T; } @@ -90,7 +90,7 @@ class cListAllocationPool : public cAllocationPool<T> } virtual void Free(T * a_ptr) override { - if (a_ptr == NULL) + if (a_ptr == nullptr) { return; } diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 37e6aecd2..7b78578ee 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -15,7 +15,7 @@ $cfile "../Vector3.h" $cfile "../ChunkDef.h" $cfile "../BiomeDef.h" -$cfile "../../lib/inifile/iniFile.h" +$cfile "../IniFile.h" $cfile "../OSSupport/File.h" @@ -27,20 +27,33 @@ $cfile "WebPlugin.h" $cfile "LuaWindow.h" $cfile "../BlockID.h" +$cfile "../Mobs/MonsterTypes.h" $cfile "../BlockInfo.h" $cfile "../StringUtils.h" $cfile "../Defines.h" $cfile "../ChatColor.h" $cfile "../ClientHandle.h" +$cfile "../Entities/ArrowEntity.h" $cfile "../Entities/Entity.h" +$cfile "../Entities/EntityEffect.h" +$cfile "../Entities/ExpBottleEntity.h" +$cfile "../Entities/FireChargeEntity.h" +$cfile "../Entities/FireworkEntity.h" $cfile "../Entities/Floater.h" +$cfile "../Entities/GhastFireballEntity.h" +$cfile "../Entities/HangingEntity.h" +$cfile "../Entities/ItemFrame.h" $cfile "../Entities/Pawn.h" $cfile "../Entities/Player.h" $cfile "../Entities/Painting.h" $cfile "../Entities/Pickup.h" $cfile "../Entities/ProjectileEntity.h" +$cfile "../Entities/SplashPotionEntity.h" +$cfile "../Entities/ThrownEggEntity.h" +$cfile "../Entities/ThrownEnderPearlEntity.h" +$cfile "../Entities/ThrownSnowballEntity.h" $cfile "../Entities/TNTEntity.h" -$cfile "../Entities/EntityEffect.h" +$cfile "../Entities/WitherSkullEntity.h" $cfile "../Server.h" $cfile "../World.h" $cfile "../Inventory.h" diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 930ee9771..d47579cd6 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -5,134 +5,133 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") include_directories (".") SET (SRCS - Bindings.cpp - DeprecatedBindings.cpp - LuaChunkStay.cpp - LuaState.cpp - LuaWindow.cpp - ManualBindings.cpp - ManualBindings_RankManager.cpp - Plugin.cpp - PluginLua.cpp - PluginManager.cpp - WebPlugin.cpp + Bindings.cpp + DeprecatedBindings.cpp + LuaChunkStay.cpp + LuaState.cpp + LuaWindow.cpp + ManualBindings.cpp + ManualBindings_RankManager.cpp + Plugin.cpp + PluginLua.cpp + PluginManager.cpp + WebPlugin.cpp ) SET (HDRS - Bindings.h - DeprecatedBindings.h - LuaChunkStay.h - LuaFunctions.h - LuaState.h - LuaWindow.h - ManualBindings.h - Plugin.h - PluginLua.h - PluginManager.h - WebPlugin.h - tolua++.h + Bindings.h + DeprecatedBindings.h + LuaChunkStay.h + LuaFunctions.h + LuaState.h + LuaWindow.h + ManualBindings.h + Plugin.h + PluginLua.h + PluginManager.h + WebPlugin.h + tolua++.h ) # List all the files that are generated as part of the Bindings build process set (BINDING_OUTPUTS - ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.h - ${CMAKE_CURRENT_SOURCE_DIR}/LuaState_Call.inc + ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.h ) set(BINDING_DEPENDENCIES - tolua - ../Bindings/virtual_method_hooks.lua - ../Bindings/AllToLua.pkg - ../Bindings/gen_LuaState_Call.lua - ../Bindings/LuaFunctions.h - ../Bindings/LuaWindow.h - ../Bindings/Plugin.h - ../Bindings/PluginLua.h - ../Bindings/PluginManager.h - ../Bindings/WebPlugin.h - ../BiomeDef.h - ../BlockArea.h + tolua + ../Bindings/virtual_method_hooks.lua + ../Bindings/AllToLua.pkg + ../Bindings/LuaFunctions.h + ../Bindings/LuaWindow.h + ../Bindings/Plugin.h + ../Bindings/PluginLua.h + ../Bindings/PluginManager.h + ../Bindings/WebPlugin.h + ../BiomeDef.h + ../BlockArea.h ../BlockEntities/BeaconEntity.h - ../BlockEntities/BlockEntity.h - ../BlockEntities/BlockEntityWithItems.h - ../BlockEntities/ChestEntity.h - ../BlockEntities/DispenserEntity.h - ../BlockEntities/DropSpenserEntity.h - ../BlockEntities/DropperEntity.h - ../BlockEntities/FurnaceEntity.h - ../BlockEntities/HopperEntity.h - ../BlockEntities/JukeboxEntity.h - ../BlockEntities/NoteEntity.h - ../BlockEntities/SignEntity.h - ../BlockEntities/MobHeadEntity.h - ../BlockEntities/FlowerPotEntity.h - ../BlockID.h - ../BoundingBox.h - ../ChatColor.h - ../ChunkDef.h - ../ClientHandle.h - ../CraftingRecipes.h - ../Cuboid.h - ../Defines.h - ../Enchantments.h - ../Entities/EntityEffect.h - ../Entities/Entity.h - ../Entities/Floater.h - ../Entities/Pawn.h - ../Entities/Painting.h - ../Entities/Pickup.h - ../Entities/Player.h - ../Entities/ProjectileEntity.h - ../Entities/ArrowEntity.h - ../Entities/ThrownEggEntity.h - ../Entities/ThrownEnderPearlEntity.h - ../Entities/ExpBottleEntity.h - ../Entities/ThrownSnowballEntity.h - ../Entities/FireChargeEntity.h - ../Entities/FireworkEntity.h - ../Entities/GhastFireballEntity.h - ../Entities/TNTEntity.h - ../Entities/ExpOrb.h - ../Entities/HangingEntity.h - ../Entities/ItemFrame.h - ../Generating/ChunkDesc.h - ../Inventory.h - ../Item.h - ../ItemGrid.h - ../Mobs/Monster.h - ../OSSupport/File.h - ../Root.h - ../Server.h - ../StringUtils.h - ../Tracer.h - ../UI/Window.h - ../Vector3.h - ../WebAdmin.h - ../World.h + ../BlockEntities/BlockEntity.h + ../BlockEntities/BlockEntityWithItems.h + ../BlockEntities/ChestEntity.h + ../BlockEntities/DispenserEntity.h + ../BlockEntities/DropSpenserEntity.h + ../BlockEntities/DropperEntity.h + ../BlockEntities/FurnaceEntity.h + ../BlockEntities/HopperEntity.h + ../BlockEntities/JukeboxEntity.h + ../BlockEntities/NoteEntity.h + ../BlockEntities/SignEntity.h + ../BlockEntities/MobHeadEntity.h + ../BlockEntities/FlowerPotEntity.h + ../BlockID.h + ../BoundingBox.h + ../ChatColor.h + ../ChunkDef.h + ../ClientHandle.h + ../CraftingRecipes.h + ../Cuboid.h + ../Defines.h + ../Enchantments.h + ../Entities/ArrowEntity.h + ../Entities/Entity.h + ../Entities/EntityEffect.h + ../Entities/ExpBottleEntity.h + ../Entities/FireChargeEntity.h + ../Entities/FireworkEntity.h + ../Entities/Floater.h + ../Entities/GhastFireballEntity.h + ../Entities/HangingEntity.h + ../Entities/ItemFrame.h + ../Entities/Pawn.h + ../Entities/Player.h + ../Entities/Painting.h + ../Entities/Pickup.h + ../Entities/ProjectileEntity.h + ../Entities/SplashPotionEntity.h + ../Entities/ThrownEggEntity.h + ../Entities/ThrownEnderPearlEntity.h + ../Entities/ThrownSnowballEntity.h + ../Entities/TNTEntity.h + ../Entities/WitherSkullEntity.h + ../Generating/ChunkDesc.h + ../Inventory.h + ../Item.h + ../ItemGrid.h + ../Mobs/Monster.h + ../OSSupport/File.h + ../Root.h + ../Server.h + ../StringUtils.h + ../Tracer.h + ../UI/Window.h + ../Vector3.h + ../WebAdmin.h + ../World.h ) if (NOT MSVC) - ADD_CUSTOM_COMMAND( - # add any new generated bindings here - OUTPUT ${BINDING_OUTPUTS} + ADD_CUSTOM_COMMAND( + # add any new generated bindings here + OUTPUT ${BINDING_OUTPUTS} - # Regenerate bindings: - COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + # Regenerate bindings: + COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - # add any new generation dependencies here - DEPENDS ${BINDING_DEPENDENCIES} - ) + # add any new generation dependencies here + DEPENDS ${BINDING_DEPENDENCIES} + ) endif () + set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.cpp PROPERTIES GENERATED TRUE) set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.h PROPERTIES GENERATED TRUE) -set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/LuaState_Call.inc PROPERTIES GENERATED TRUE) set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.cpp PROPERTIES COMPILE_FLAGS -Wno-error) if(NOT MSVC) - add_library(Bindings ${SRCS} ${HDRS}) + add_library(Bindings ${SRCS} ${HDRS}) - target_link_libraries(Bindings lua sqlite tolualib polarssl) + target_link_libraries(Bindings lua sqlite tolualib polarssl) endif() diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp index 02aa15be4..345ab2a07 100644 --- a/src/Bindings/DeprecatedBindings.cpp +++ b/src/Bindings/DeprecatedBindings.cpp @@ -7,6 +7,9 @@ #include "../BlockInfo.h" +#include "../World.h" +#include "../Entities/Player.h" +#include "LuaState.h" @@ -29,7 +32,7 @@ static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushnumber(tolua_S, (lua_Number)cBlockInfo::GetLightValue((BLOCKTYPE)BlockType)); return 1; @@ -55,7 +58,7 @@ static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushnumber(tolua_S, (lua_Number)cBlockInfo::GetSpreadLightFalloff((BLOCKTYPE)BlockType)); return 1; @@ -81,7 +84,7 @@ static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent((BLOCKTYPE)BlockType)); return 1; @@ -107,7 +110,7 @@ static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushboolean(tolua_S, cBlockInfo::IsOneHitDig((BLOCKTYPE)BlockType)); return 1; @@ -133,7 +136,7 @@ static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushboolean(tolua_S, cBlockInfo::IsPistonBreakable((BLOCKTYPE)BlockType)); return 1; @@ -159,7 +162,7 @@ static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushboolean(tolua_S, cBlockInfo::IsSnowable((BLOCKTYPE)BlockType)); return 1; @@ -185,7 +188,7 @@ static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushboolean(tolua_S, (bool)cBlockInfo::IsSolid((BLOCKTYPE)BlockType)); return 1; @@ -211,7 +214,7 @@ static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S) BlockType = (int)tolua_tonumber(tolua_S, 2, 0); if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_error(tolua_S, "array indexing out of range.", NULL); + tolua_error(tolua_S, "array indexing out of range.", nullptr); } tolua_pushboolean(tolua_S, (bool)cBlockInfo::FullyOccupiesVoxel((BLOCKTYPE)BlockType)); return 1; @@ -222,18 +225,80 @@ static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S) +/** 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, NULL); - - tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, NULL); - tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, NULL); - tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, NULL); - tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, NULL); - tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, NULL); - tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, NULL); - tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, NULL); - tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, NULL); + tolua_beginmodule(tolua_S, nullptr); + + tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, nullptr); + tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, nullptr); + tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, nullptr); + tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, nullptr); + tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, nullptr); + tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, nullptr); + 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_beginmodule(tolua_S, "cWorld"); + tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); + tolua_endmodule(tolua_S); tolua_endmodule(tolua_S); } diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp index a3d3a8090..e50ffb75b 100644 --- a/src/Bindings/LuaChunkStay.cpp +++ b/src/Bindings/LuaChunkStay.cpp @@ -13,7 +13,7 @@ cLuaChunkStay::cLuaChunkStay(cPluginLua & a_Plugin) : m_Plugin(a_Plugin), - m_LuaState(NULL) + m_LuaState(nullptr) { } @@ -130,8 +130,11 @@ void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPo void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ) { - cPluginLua::cOperation Op(m_Plugin); - Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ); + if (m_OnChunkAvailable.IsValid()) + { + cPluginLua::cOperation Op(m_Plugin); + Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ); + } } @@ -140,6 +143,7 @@ void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ) bool cLuaChunkStay::OnAllChunksAvailable(void) { + if (m_OnAllChunksAvailable.IsValid()) { // Call the callback: cPluginLua::cOperation Op(m_Plugin); diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index ba2f3c5e0..2f5d173fd 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -16,6 +16,8 @@ extern "C" #include "Bindings.h" #include "ManualBindings.h" #include "DeprecatedBindings.h" +#include "../Entities/Entity.h" +#include "../BlockEntities/BlockEntity.h" // fwd: SQLite/lsqlite3.c extern "C" @@ -44,7 +46,7 @@ const cLuaState::cRet cLuaState::Return = {}; // cLuaState: cLuaState::cLuaState(const AString & a_SubsystemName) : - m_LuaState(NULL), + m_LuaState(nullptr), m_IsOwned(false), m_SubsystemName(a_SubsystemName), m_NumCurrentFunctionArgs(-1) @@ -88,7 +90,7 @@ cLuaState::~cLuaState() void cLuaState::Create(void) { - if (m_LuaState != NULL) + if (m_LuaState != nullptr) { LOGWARNING("%s: Trying to create an already-existing LuaState, ignoring.", __FUNCTION__); return; @@ -117,7 +119,7 @@ void cLuaState::RegisterAPILibs(void) void cLuaState::Close(void) { - if (m_LuaState == NULL) + if (m_LuaState == nullptr) { LOGWARNING("%s: Trying to close an invalid LuaState, ignoring.", __FUNCTION__); return; @@ -132,7 +134,7 @@ void cLuaState::Close(void) return; } lua_close(m_LuaState); - m_LuaState = NULL; + m_LuaState = nullptr; m_IsOwned = false; } @@ -142,7 +144,7 @@ void cLuaState::Close(void) void cLuaState::Attach(lua_State * a_State) { - if (m_LuaState != NULL) + if (m_LuaState != nullptr) { LOGINFO("%s: Already contains a LuaState (0x%p), will be closed / detached.", __FUNCTION__, m_LuaState); if (m_IsOwned) @@ -164,7 +166,7 @@ void cLuaState::Attach(lua_State * a_State) void cLuaState::Detach(void) { - if (m_LuaState == NULL) + if (m_LuaState == nullptr) { return; } @@ -177,7 +179,7 @@ void cLuaState::Detach(void) Close(); return; } - m_LuaState = NULL; + m_LuaState = nullptr; } @@ -520,7 +522,7 @@ void cLuaState::Push(cBlockEntity * a_BlockEntity) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_BlockEntity, "cBlockEntity"); + tolua_pushusertype(m_LuaState, a_BlockEntity, (a_BlockEntity == nullptr) ? "cBlockEntity" : a_BlockEntity->GetClass()); m_NumCurrentFunctionArgs += 1; } @@ -556,7 +558,61 @@ void cLuaState::Push(cEntity * a_Entity) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_Entity, "cEntity"); + if (a_Entity == nullptr) + { + lua_pushnil(m_LuaState); + } + else + { + switch (a_Entity->GetEntityType()) + { + case cEntity::etMonster: + { + // Don't push specific mob types, as those are not exported in the API: + tolua_pushusertype(m_LuaState, a_Entity, "cMonster"); + break; + } + case cEntity::etPlayer: + { + tolua_pushusertype(m_LuaState, a_Entity, "cPlayer"); + break; + } + case cEntity::etPickup: + { + tolua_pushusertype(m_LuaState, a_Entity, "cPickup"); + break; + } + case cEntity::etTNT: + { + tolua_pushusertype(m_LuaState, a_Entity, "cTNTEntity"); + break; + } + case cEntity::etProjectile: + { + tolua_pushusertype(m_LuaState, a_Entity, a_Entity->GetClass()); + break; + } + case cEntity::etFloater: + { + tolua_pushusertype(m_LuaState, a_Entity, "cFloater"); + break; + } + + case cEntity::etEntity: + case cEntity::etEnderCrystal: + case cEntity::etFallingBlock: + case cEntity::etMinecart: + case cEntity::etBoat: + case cEntity::etExpOrb: + case cEntity::etItemFrame: + case cEntity::etPainting: + { + // Push the generic entity class type: + tolua_pushusertype(m_LuaState, a_Entity, "cEntity"); + } + } // switch (EntityType) + } + m_NumCurrentFunctionArgs += 1; } @@ -813,7 +869,7 @@ void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) { size_t len = 0; const char * data = lua_tolstring(m_LuaState, a_StackPos, &len); - if (data != NULL) + if (data != nullptr) { a_Value.assign(data, len); } @@ -861,6 +917,11 @@ void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) { + if (lua_isnil(m_LuaState, a_StackPos)) + { + a_ReturnedVal = nullptr; + return; + } tolua_Error err; if (tolua_isusertype(m_LuaState, a_StackPos, "cBoundingBox", false, &err)) { @@ -874,6 +935,11 @@ void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) { + if (lua_isnil(m_LuaState, a_StackPos)) + { + a_ReturnedVal = nullptr; + return; + } tolua_Error err; if (tolua_isusertype(m_LuaState, a_StackPos, "cWorld", false, &err)) { @@ -936,7 +1002,7 @@ bool cLuaState::CheckParamUserTable(int a_StartParam, const char * a_UserTable, lua_Debug entry; VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); - AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -969,7 +1035,7 @@ bool cLuaState::CheckParamUserType(int a_StartParam, const char * a_UserType, in lua_Debug entry; VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); - AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -1002,7 +1068,7 @@ bool cLuaState::CheckParamTable(int a_StartParam, int a_EndParam) lua_Debug entry; VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); - AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -1035,7 +1101,7 @@ bool cLuaState::CheckParamNumber(int a_StartParam, int a_EndParam) lua_Debug entry; VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); - AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -1068,7 +1134,7 @@ bool cLuaState::CheckParamString(int a_StartParam, int a_EndParam) lua_Debug entry; VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); - AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -1101,7 +1167,7 @@ bool cLuaState::CheckParamFunction(int a_StartParam, int a_EndParam) VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); luaL_error(m_LuaState, "Error in function '%s' parameter #%d. Function expected, got %s", - (entry.name != NULL) ? entry.name : "?", i, GetTypeText(i).c_str() + (entry.name != nullptr) ? entry.name : "?", i, GetTypeText(i).c_str() ); return false; } // for i - Param @@ -1134,7 +1200,7 @@ bool cLuaState::CheckParamFunctionOrNil(int a_StartParam, int a_EndParam) VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); luaL_error(m_LuaState, "Error in function '%s' parameter #%d. Function expected, got %s", - (entry.name != NULL) ? entry.name : "?", i, GetTypeText(i).c_str() + (entry.name != nullptr) ? entry.name : "?", i, GetTypeText(i).c_str() ); return false; } // for i - Param @@ -1158,7 +1224,7 @@ bool cLuaState::CheckParamEnd(int a_Param) lua_Debug entry; VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); - AString ErrMsg = Printf("#ferror in function '%s': Too many arguments.", (entry.name != NULL) ? entry.name : "?"); + AString ErrMsg = Printf("#ferror in function '%s': Too many arguments.", (entry.name != nullptr) ? entry.name : "?"); tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } @@ -1337,7 +1403,7 @@ int cLuaState::CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_Sr case LUA_TUSERDATA: { // Get the class name: - const char * type = NULL; + const char * type = nullptr; if (lua_getmetatable(a_SrcLuaState, i) == 0) { LOGWARNING("%s: Unknown class in pos %d, cannot copy.", __FUNCTION__, i); @@ -1349,7 +1415,7 @@ int cLuaState::CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_Sr lua_pop(a_SrcLuaState, 1); // Stack -1 // Copy the value: - void * ud = tolua_touserdata(a_SrcLuaState, i, NULL); + void * ud = tolua_touserdata(a_SrcLuaState, i, nullptr); tolua_pushusertype(m_LuaState, ud, type); break; } @@ -1375,7 +1441,7 @@ void cLuaState::ToString(int a_StackPos, AString & a_String) { size_t len; const char * s = lua_tolstring(m_LuaState, a_StackPos, &len); - if (s != NULL) + if (s != nullptr) { a_String.assign(s, len); } @@ -1396,10 +1462,8 @@ void cLuaState::LogStack(const char * a_Header) void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header) { - UNUSED(a_Header); // The param seems unused when compiling for release, so the compiler warns - // Format string consisting only of %s is used to appease the compiler - LOGD("%s", (a_Header != NULL) ? a_Header : "Lua C API Stack contents:"); + LOG("%s", (a_Header != nullptr) ? a_Header : "Lua C API Stack contents:"); for (int i = lua_gettop(a_LuaState); i > 0; i--) { AString Value; @@ -1436,7 +1500,7 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) // cLuaState::cRef: cLuaState::cRef::cRef(void) : - m_LuaState(NULL), + m_LuaState(nullptr), m_Ref(LUA_REFNIL) { } @@ -1446,7 +1510,7 @@ cLuaState::cRef::cRef(void) : cLuaState::cRef::cRef(cLuaState & a_LuaState, int a_StackPos) : - m_LuaState(NULL), + m_LuaState(nullptr), m_Ref(LUA_REFNIL) { RefStack(a_LuaState, a_StackPos); @@ -1458,7 +1522,7 @@ cLuaState::cRef::cRef(cLuaState & a_LuaState, int a_StackPos) : cLuaState::cRef::~cRef() { - if (m_LuaState != NULL) + if (m_LuaState != nullptr) { UnRef(); } @@ -1471,7 +1535,7 @@ cLuaState::cRef::~cRef() void cLuaState::cRef::RefStack(cLuaState & a_LuaState, int a_StackPos) { ASSERT(a_LuaState.IsValid()); - if (m_LuaState != NULL) + if (m_LuaState != nullptr) { UnRef(); } @@ -1492,7 +1556,7 @@ void cLuaState::cRef::UnRef(void) { luaL_unref(*m_LuaState, LUA_REGISTRYINDEX, m_Ref); } - m_LuaState = NULL; + m_LuaState = nullptr; m_Ref = LUA_REFNIL; } diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 094a200e0..c13e36188 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -164,7 +164,7 @@ public: void Detach(void); /** Returns true if the m_LuaState is valid */ - bool IsValid(void) const { return (m_LuaState != NULL); } + bool IsValid(void) const { return (m_LuaState != nullptr); } /** Adds the specified path to package.<a_PathVariable> */ void AddPackagePath(const AString & a_PathVariable, const AString & a_Path); @@ -240,10 +240,28 @@ public: /** Retrieve value at a_StackPos, if it is a valid cWorld class. If not, a_Value is unchanged */ void GetStackValue(int a_StackPos, pWorld & a_Value); + /** Call the specified Lua function. + Returns true if call succeeded, false if there was an error. + A special param of cRet & signifies the end of param list and the start of return values. + Example call: Call(Fn, Param1, Param2, Param3, cLuaState::Return, Ret1, Ret2) */ + template <typename FnT, typename... Args> + bool Call(const FnT & a_Function, Args &&... args) + { + if (!PushFunction(a_Function)) + { + // Pushing the function failed + return false; + } + return PushCallPop(args...); + } - // Include the cLuaState::Call() overload implementation that is generated by the gen_LuaState_Call.lua script: - #include "LuaState_Call.inc" - + /** Retrieves a list of values from the Lua stack, starting at the specified index. */ + template <typename T, typename... Args> + inline void GetStackValues(int a_StartStackPos, T & a_Ret, Args &&... args) + { + GetStackValue(a_StartStackPos, a_Ret); + GetStackValues(a_StartStackPos + 1, args...); + } /** Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions */ bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1); @@ -304,12 +322,13 @@ public: void ToString(int a_StackPos, AString & a_String); /** Logs all the elements' types on the API stack, with an optional header for the listing. */ - void LogStack(const char * a_Header); + void LogStack(const char * a_Header = nullptr); /** Logs all the elements' types on the API stack, with an optional header for the listing. */ - static void LogStack(lua_State * a_LuaState, const char * a_Header = NULL); + static void LogStack(lua_State * a_LuaState, const char * a_Header = nullptr); protected: + lua_State * m_LuaState; /** If true, the state is owned by this object and will be auto-Closed. False => attached state */ @@ -327,6 +346,63 @@ protected: int m_NumCurrentFunctionArgs; + /** Variadic template terminator: Counting zero args returns zero. */ + int CountArgs(void) + { + return 0; + } + + /** Variadic template: Counting args means add one to the count of the rest. */ + template <typename T, typename... Args> + int CountArgs(T, Args... args) + { + return 1 + CountArgs(args...); + } + + /** Variadic template terminator: If there's nothing more to push / pop, just call the function. + Note that there are no return values either, because those are prefixed by a cRet value, so the arg list is never empty. */ + bool PushCallPop(void) + { + return CallFunction(0); + } + + /** Variadic template recursor: More params to push. Push them and recurse. */ + template <typename T, typename... Args> + inline bool PushCallPop(T a_Param, Args &&... args) + { + Push(a_Param); + return PushCallPop(args...); + } + + /** Variadic template terminator: If there's nothing more to push, but return values to collect, call the function and collect the returns. */ + template <typename... Args> + bool PushCallPop(cLuaState::cRet, Args &&... args) + { + // Calculate the number of return values (number of args left): + int NumReturns = CountArgs(args...); + + // Call the function: + if (!CallFunction(NumReturns)) + { + return false; + } + + // Collect the return values: + GetStackValues(-NumReturns, args...); + lua_pop(m_LuaState, NumReturns); + + // All successful: + return true; + } + + /** Variadic template terminator: If there are no more values to get, bail out. + This function is not available in the public API, because it's an error to request no values directly; only internal functions can do that. + If you get a compile error saying this function is not accessible, check your calling code, you aren't reading any stack values. */ + void GetStackValues(int a_StartingStackPos) + { + // Do nothing + } + /** Pushes the function of the specified name onto the stack. Returns true if successful. Logs a warning on failure (incl. m_SubsystemName) */ diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp index c4d03b86b..35730878d 100644 --- a/src/Bindings/LuaWindow.cpp +++ b/src/Bindings/LuaWindow.cpp @@ -18,7 +18,7 @@ cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) : super(a_WindowType, a_Title), m_Contents(a_SlotsX, a_SlotsY), - m_Plugin(NULL), + m_Plugin(nullptr), m_LuaRef(LUA_REFNIL), m_OnClosingFnRef(LUA_REFNIL), m_OnSlotChangedFnRef(LUA_REFNIL) @@ -70,7 +70,7 @@ cLuaWindow::~cLuaWindow() void cLuaWindow::SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef) { // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object - ASSERT((m_Plugin == NULL) || (m_Plugin == a_Plugin)); + ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin)); ASSERT(m_LuaRef == LUA_REFNIL); m_Plugin = a_Plugin; m_LuaRef = a_LuaRef; @@ -82,7 +82,7 @@ void cLuaWindow::SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef) bool cLuaWindow::IsLuaReferenced(void) const { - return ((m_Plugin != NULL) && (m_LuaRef != LUA_REFNIL)); + return ((m_Plugin != nullptr) && (m_LuaRef != LUA_REFNIL)); } @@ -92,7 +92,7 @@ bool cLuaWindow::IsLuaReferenced(void) const void cLuaWindow::SetOnClosing(cPluginLua * a_Plugin, int a_FnRef) { // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object - ASSERT((m_Plugin == NULL) || (m_Plugin == a_Plugin)); + ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin)); // If there already was a function, unreference it first if (m_OnClosingFnRef != LUA_REFNIL) @@ -112,7 +112,7 @@ void cLuaWindow::SetOnClosing(cPluginLua * a_Plugin, int a_FnRef) void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef) { // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object - ASSERT((m_Plugin == NULL) || (m_Plugin == a_Plugin)); + ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin)); // If there already was a function, unreference it first if (m_OnSlotChangedFnRef != LUA_REFNIL) @@ -134,7 +134,7 @@ bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) // First notify the plugin through the registered callback: if (m_OnClosingFnRef != LUA_REFNIL) { - ASSERT(m_Plugin != NULL); + ASSERT(m_Plugin != nullptr); if (m_Plugin->CallbackWindowClosing(m_OnClosingFnRef, *this, a_Player, a_CanRefuse)) { // The callback disagrees (the higher levels check the CanRefuse flag compliance) @@ -153,7 +153,7 @@ void cLuaWindow::Destroy(void) { super::Destroy(); - if ((m_LuaRef != LUA_REFNIL) && (m_Plugin != NULL)) + if ((m_LuaRef != LUA_REFNIL) && (m_Plugin != nullptr)) { // The object is referenced by Lua, un-reference it m_Plugin->Unreference(m_LuaRef); diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index d8134f159..750f7c65a 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -145,13 +145,13 @@ static AString GetLogMessage(lua_State * tolua_S) tolua_Error err; if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) { - return ((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->ExtractText(); + return ((cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr))->ExtractText(); } else { size_t len = 0; const char * str = lua_tolstring(tolua_S, 1, &len); - if (str != NULL) + if (str != nullptr) { return AString(str, len); } @@ -170,7 +170,7 @@ static int tolua_LOG(lua_State * tolua_S) tolua_Error err; if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) { - LogLevel = cCompositeChat::MessageTypeToLogLevel(((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->GetMessageType()); + LogLevel = cCompositeChat::MessageTypeToLogLevel(((cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr))->GetMessageType()); } // Log the message: @@ -264,7 +264,7 @@ static cPluginLua * GetLuaPlugin(lua_State * L) { LOGWARNING("%s: cannot get plugin instance, what have you done to my Lua state?", __FUNCTION__); lua_pop(L, 1); - return NULL; + return nullptr; } cPluginLua * Plugin = (cPluginLua *)lua_topointer(L, -1); lua_pop(L, 1); @@ -312,10 +312,10 @@ static int tolua_DoWith(lua_State* tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs); } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL); + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, nullptr); const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); - if ((ItemName == NULL) || (ItemName[0] == 0)) + if ((ItemName == nullptr) || (ItemName[0] == 0)) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a non-empty string for parameter #1", NumArgs); } @@ -406,7 +406,7 @@ static int tolua_DoWithID(lua_State* tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs); } - Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, NULL); + Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, nullptr); int ItemID = (int)tolua_tonumber(tolua_S, 2, 0); if (!lua_isfunction(tolua_S, 3)) @@ -496,7 +496,7 @@ static int tolua_DoWithXYZ(lua_State* tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 4 or 5 arguments, got %i", NumArgs); } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL); + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, nullptr); if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3) || !lua_isnumber(tolua_S, 4)) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); @@ -591,7 +591,7 @@ static int tolua_ForEachInChunk(lua_State * tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 3 or 4 arguments, got %i", NumArgs); } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, NULL); + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, nullptr); if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3)) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1 and #2"); @@ -694,11 +694,15 @@ static int tolua_ForEachInBox(lua_State * tolua_S) } // Get the params: - Ty1 * Self = NULL; - cBoundingBox * Box = NULL; + Ty1 * Self = nullptr; + cBoundingBox * Box = nullptr; L.GetStackValues(1, Self, Box); - ASSERT(Self != NULL); // We have verified the type at the top, so we should get valid objects here - ASSERT(Box != NULL); + if ((Self == nullptr) || (Box == nullptr)) + { + LOGWARNING("Invalid world (%p) or boundingbox (%p)", Self, Box); + L.LogStackTrace(); + return 0; + } // Create a reference for the function: cLuaState::cRef FnRef(L, 3); @@ -756,8 +760,8 @@ static int tolua_ForEach(lua_State * tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 1 or 2 arguments, got %i", NumArgs); } - Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } @@ -853,14 +857,14 @@ static int tolua_cWorld_GetBlockInfo(lua_State * tolua_S) else #endif { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL); + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); #ifndef TOLUA_RELEASE - if (self == NULL) + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'GetBlockInfo'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'GetBlockInfo'", nullptr); } #endif { @@ -908,14 +912,14 @@ static int tolua_cWorld_GetBlockTypeMeta(lua_State * tolua_S) else #endif { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL); + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); #ifndef TOLUA_RELEASE - if (self == NULL) + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'GetBlockTypeMeta'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'GetBlockTypeMeta'", nullptr); } #endif { @@ -960,14 +964,14 @@ static int tolua_cWorld_GetSignLines(lua_State * tolua_S) else #endif { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL); + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); #ifndef TOLUA_RELEASE - if (self == NULL) + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'GetSignLines'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'GetSignLines'", nullptr); } #endif { @@ -1018,7 +1022,7 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S) else #endif { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL); + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); @@ -1026,15 +1030,15 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S) const AString Line2 = tolua_tocppstring(tolua_S, 6, 0); const AString Line3 = tolua_tocppstring(tolua_S, 7, 0); const AString Line4 = tolua_tocppstring(tolua_S, 8, 0); - cPlayer * Player = (cPlayer *)tolua_tousertype (tolua_S, 9, NULL); + cPlayer * Player = (cPlayer *)tolua_tousertype (tolua_S, 9, nullptr); #ifndef TOLUA_RELEASE - if (self == NULL) + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'SetSignLines' / 'UpdateSign'", NULL); + 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); } } @@ -1042,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 } @@ -1067,13 +1071,13 @@ static int tolua_cWorld_TryGetHeight(lua_State * tolua_S) else #endif { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, NULL); + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); int BlockZ = (int) tolua_tonumber (tolua_S, 3, 0); #ifndef TOLUA_RELEASE - if (self == NULL) + if (self == nullptr) { - tolua_error(tolua_S, "Invalid 'self' in function 'TryGetHeight'", NULL); + tolua_error(tolua_S, "Invalid 'self' in function 'TryGetHeight'", nullptr); } #endif { @@ -1132,15 +1136,15 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) // Retrieve the cPlugin from the LuaState: cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == NULL) + if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() return 0; } // Retrieve the args: - cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } @@ -1156,7 +1160,7 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - self->QueueTask(new cLuaWorldTask(*Plugin, FnRef)); + self->QueueTask(make_unique<cLuaWorldTask>(*Plugin, FnRef)); return 0; } @@ -1196,7 +1200,7 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) // Retrieve the cPlugin from the LuaState: cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == NULL) + if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() return 0; @@ -1212,8 +1216,8 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) { return 0; } - cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); - if (World == NULL) + cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); + if (World == nullptr) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } @@ -1237,7 +1241,7 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) { - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, NULL); + cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); const cPluginManager::PluginMap & AllPlugins = self->GetAllPlugins(); @@ -1248,7 +1252,7 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) { const cPlugin* Plugin = iter->second; tolua_pushstring(tolua_S, iter->first.c_str()); - if (Plugin != NULL) + if (Plugin != nullptr) { tolua_pushusertype(tolua_S, (void *)Plugin, "const cPlugin"); } @@ -1270,7 +1274,7 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) static int tolua_cPluginManager_GetCurrentPlugin(lua_State * S) { cPluginLua * Plugin = GetLuaPlugin(S); - if (Plugin == NULL) + if (Plugin == nullptr) { // An error message has already been printed in GetLuaPlugin() return 0; @@ -1301,7 +1305,7 @@ static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager, // Retrieve the cPlugin from the LuaState: cPluginLua * Plugin = GetLuaPlugin(S); - if (Plugin == NULL) + if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() return 0; @@ -1340,8 +1344,8 @@ static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager, // The arg types have already been checked // Retrieve and check the cPlugin parameter - cPluginLua * Plugin = (cPluginLua *)tolua_tousertype(S, a_ParamIdx, NULL); - if (Plugin == NULL) + cPluginLua * Plugin = (cPluginLua *)tolua_tousertype(S, a_ParamIdx, nullptr); + if (Plugin == nullptr) { LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, expected a valid cPlugin object. Hook not added"); S.LogStackTrace(); @@ -1366,7 +1370,7 @@ static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager, // Get the standard name for the callback function: const char * FnName = cPluginLua::GetHookFnName(HookType); - if (FnName == NULL) + if (FnName == nullptr) { LOGWARNING("cPluginManager.AddHook(): Unknown hook type (%d). Hook not added.", HookType); S.LogStackTrace(); @@ -1413,8 +1417,8 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) if (tolua_isusertype(S, 1, "cPluginManager", 0, &err)) { // Style 2 or 3, retrieve the PlgMgr instance - PlgMgr = (cPluginManager *)tolua_tousertype(S, 1, NULL); - if (PlgMgr == NULL) + PlgMgr = (cPluginManager *)tolua_tousertype(S, 1, nullptr); + if (PlgMgr == nullptr) { LOGWARNING("Malformed plugin, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction). Fixing the call for you."); S.LogStackTrace(); @@ -1461,8 +1465,8 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) return 0; } - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { LOGWARN("Error in function call 'ForEachCommand': Not called on an object instance"); return 0; @@ -1538,8 +1542,8 @@ static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S) return 0; } - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { LOGWARN("Error in function call 'ForEachConsoleCommand': Not called on an object instance"); return 0; @@ -1613,7 +1617,7 @@ static int tolua_cPluginManager_BindCommand(lua_State * L) cPluginManager.BindCommand(Command, Permission, Function, HelpString) -- without the "self" param */ cPluginLua * Plugin = GetLuaPlugin(L); - if (Plugin == NULL) + if (Plugin == nullptr) { return 0; } @@ -1683,7 +1687,7 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L) // Get the plugin identification out of LuaState: cPluginLua * Plugin = GetLuaPlugin(L); - if (Plugin == NULL) + if (Plugin == nullptr) { return 0; } @@ -1771,7 +1775,7 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S) // If requesting calling the current plugin, refuse: cPluginLua * ThisPlugin = GetLuaPlugin(L); - if (ThisPlugin == NULL) + if (ThisPlugin == nullptr) { return 0; } @@ -1839,14 +1843,14 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) } cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == NULL) + if (Plugin == nullptr) { return 0; } // Read the params: - cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); - if (World == NULL) + cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); + if (World == nullptr) { LOGWARNING("World:ChunkStay(): invalid world parameter"); L.LogStackTrace(); @@ -1858,7 +1862,7 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) if (!ChunkStay->AddChunks(2)) { delete ChunkStay; - ChunkStay = NULL; + ChunkStay = nullptr; return 0; } @@ -1885,8 +1889,8 @@ static int tolua_cPlayer_GetPermissions(lua_State * tolua_S) } // Get the params: - cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); return 0; @@ -1907,15 +1911,15 @@ static int tolua_cPlayer_OpenWindow(lua_State * tolua_S) // Retrieve the plugin instance from the Lua state cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == NULL) + if (Plugin == nullptr) { return 0; } // Get the parameters: - cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); - cWindow * wnd = (cWindow *)tolua_tousertype(tolua_S, 2, NULL); - if ((self == NULL) || (wnd == NULL)) + cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, nullptr); + cWindow * wnd = (cWindow *)tolua_tousertype(tolua_S, 2, nullptr); + if ((self == nullptr) || (wnd == nullptr)) { LOGWARNING("%s: invalid self (%p) or wnd (%p)", __FUNCTION__, self, wnd); return 0; @@ -1957,26 +1961,20 @@ static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S) // Check the params: cLuaState L(tolua_S); if ( - !L.CheckParamUserType(1, "cPlayer") || - !L.CheckParamString (2, 3) || - !L.CheckParamEnd (4) + !L.CheckParamUserTable(1, "cPlayer") || + !L.CheckParamString (2, 3) || + !L.CheckParamEnd (4) ) { return 0; } // Get the params: - cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) - { - LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); - return 0; - } AString Permission, Template; L.GetStackValues(2, Permission, Template); // Push the result of the match: - L.Push(self->PermissionMatches(StringSplit(Permission, "."), StringSplit(Template, "."))); + L.Push(cPlayer::PermissionMatches(StringSplit(Permission, "."), StringSplit(Template, "."))); return 1; } @@ -1994,15 +1992,15 @@ static int tolua_SetObjectCallback(lua_State * tolua_S) // Retrieve the plugin instance from the Lua state cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == NULL) + if (Plugin == nullptr) { // Warning message has already been printed by GetLuaPlugin(), bail out silently return 0; } // Get the parameters - self and the function reference: - OBJTYPE * self = (OBJTYPE *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + OBJTYPE * self = (OBJTYPE *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); return 0; @@ -2025,7 +2023,7 @@ static int tolua_SetObjectCallback(lua_State * tolua_S) static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S) { - cPluginLua * self = (cPluginLua *)tolua_tousertype(tolua_S, 1, NULL); + cPluginLua * self = (cPluginLua *)tolua_tousertype(tolua_S, 1, nullptr); tolua_Error tolua_err; tolua_err.array = 0; @@ -2069,7 +2067,7 @@ static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S) static int tolua_cPluginLua_AddTab(lua_State* tolua_S) { - cPluginLua * self = (cPluginLua *) tolua_tousertype(tolua_S, 1, NULL); + cPluginLua * self = (cPluginLua *) tolua_tousertype(tolua_S, 1, nullptr); LOGWARN("WARNING: Using deprecated function AddTab()! Use AddWebTab() instead. (plugin \"%s\" in folder \"%s\")", self->GetName().c_str(), self->GetDirectory().c_str() ); @@ -2089,7 +2087,7 @@ static int tolua_cPlugin_Call(lua_State * tolua_S) L.LogStackTrace(); // Retrieve the params: plugin and the function name to call - cPluginLua * TargetPlugin = (cPluginLua *) tolua_tousertype(tolua_S, 1, NULL); + cPluginLua * TargetPlugin = (cPluginLua *) tolua_tousertype(tolua_S, 1, nullptr); AString FunctionName = tolua_tostring(tolua_S, 2, ""); // Call the function: @@ -2144,7 +2142,7 @@ static int tolua_push_StringStringMap(lua_State* tolua_S, std::map< std::string, static int tolua_get_HTTPRequest_Params(lua_State* tolua_S) { - HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, NULL); + HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, nullptr); return tolua_push_StringStringMap(tolua_S, self->Params); } @@ -2154,7 +2152,7 @@ static int tolua_get_HTTPRequest_Params(lua_State* tolua_S) static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S) { - HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, NULL); + HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, nullptr); return tolua_push_StringStringMap(tolua_S, self->PostParams); } @@ -2164,7 +2162,7 @@ static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S) static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S) { - HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, NULL); + HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, nullptr); std::map< std::string, HTTPFormData >& FormData = self->FormData; lua_newtable(tolua_S); @@ -2187,7 +2185,7 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S) static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S) { - cWebAdmin * self = (cWebAdmin *)tolua_tousertype(tolua_S, 1, NULL); + cWebAdmin * self = (cWebAdmin *)tolua_tousertype(tolua_S, 1, nullptr); const cWebAdmin::PluginList & AllPlugins = self->GetPlugins(); @@ -2268,7 +2266,7 @@ static int tolua_AllToLua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S) static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) { - cWebPlugin* self = (cWebPlugin*) tolua_tousertype(tolua_S, 1, NULL); + cWebPlugin* self = (cWebPlugin*) tolua_tousertype(tolua_S, 1, nullptr); const cWebPlugin::TabNameList & TabNames = self->GetTabNames(); @@ -2304,8 +2302,8 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L) { return 0; } - cClientHandle * Client = (cClientHandle *)tolua_tousertype(L, 1, NULL); - if (Client == NULL) + cClientHandle * Client = (cClientHandle *)tolua_tousertype(L, 1, nullptr); + if (Client == nullptr) { LOGWARNING("ClientHandle is nil in cClientHandle:SendPluginMessage()"); S.LogStackTrace(); @@ -2550,11 +2548,11 @@ static int Lua_ItemGrid_GetSlotCoords(lua_State * L) } { - const cItemGrid * self = (const cItemGrid *)tolua_tousertype(L, 1, NULL); + const cItemGrid * self = (const cItemGrid *)tolua_tousertype(L, 1, nullptr); int SlotNum = (int)tolua_tonumber(L, 2, 0); - if (self == NULL) + if (self == nullptr) { - tolua_error(L, "invalid 'self' in function 'cItemGrid:GetSlotCoords'", NULL); + tolua_error(L, "invalid 'self' in function 'cItemGrid:GetSlotCoords'", nullptr); return 0; } int X, Y; @@ -2691,7 +2689,7 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) } // Trace: - cWorld * World = (cWorld *)tolua_tousertype(L, idx, NULL); + cWorld * World = (cWorld *)tolua_tousertype(L, idx, nullptr); cLuaBlockTracerCallbacks Callbacks(L, idx + 1); double StartX = tolua_tonumber(L, idx + 2, 0); double StartY = tolua_tonumber(L, idx + 3, 0); @@ -2721,8 +2719,8 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) } // Check the input param: - cItem * Input = (cItem *)tolua_tousertype(L, 2, NULL); - if (Input == NULL) + cItem * Input = (cItem *)tolua_tousertype(L, 2, nullptr); + if (Input == nullptr) { LOGWARNING("cRoot:GetFurnaceRecipe: the Input parameter is nil or missing."); return 0; @@ -2731,7 +2729,7 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) // Get the recipe for the input cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe(); const cFurnaceRecipe::cRecipe * Recipe = FR->GetRecipeFrom(*Input); - if (Recipe == NULL) + if (Recipe == nullptr) { // There is no such furnace recipe for this input, return no value return 0; @@ -2762,10 +2760,10 @@ static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S) { return 0; } - cHopperEntity * self = (cHopperEntity *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cHopperEntity * self = (cHopperEntity *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cHopperEntity::GetOutputBlockPos()'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cHopperEntity::GetOutputBlockPos()'", nullptr); return 0; } @@ -2802,10 +2800,10 @@ static int tolua_cBlockArea_GetBlockTypeMeta(lua_State * tolua_S) return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", nullptr); return 0; } int BlockX = (int)tolua_tonumber(tolua_S, 2, 0); @@ -2836,10 +2834,10 @@ static int tolua_cBlockArea_GetOrigin(lua_State * tolua_S) return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetOrigin'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetOrigin'", nullptr); return 0; } @@ -2868,10 +2866,10 @@ static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * tolua_S) return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", nullptr); return 0; } int BlockX = (int)tolua_tonumber(tolua_S, 2, 0); @@ -2902,10 +2900,10 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S) return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", nullptr); return 0; } @@ -2933,10 +2931,10 @@ static int tolua_cBlockArea_GetCoordRange(lua_State * tolua_S) return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", nullptr); return 0; } @@ -2964,10 +2962,10 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S) { return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", nullptr); return 0; } @@ -2994,10 +2992,10 @@ static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S) { return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", nullptr); return 0; } @@ -3025,10 +3023,10 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S) { return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", nullptr); return 0; } AString Filename = tolua_tostring(tolua_S, 2, 0); @@ -3053,10 +3051,10 @@ static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S) { return 0; } - cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", nullptr); return 0; } @@ -3087,10 +3085,10 @@ static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", nullptr); return 0; } @@ -3124,10 +3122,10 @@ static int tolua_cCompositeChat_AddSuggestCommandPart(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", nullptr); return 0; } @@ -3161,10 +3159,10 @@ static int tolua_cCompositeChat_AddTextPart(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", nullptr); return 0; } @@ -3197,10 +3195,10 @@ static int tolua_cCompositeChat_AddUrlPart(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", nullptr); return 0; } @@ -3234,10 +3232,10 @@ static int tolua_cCompositeChat_ParseText(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", nullptr); return 0; } @@ -3269,10 +3267,10 @@ static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", nullptr); return 0; } @@ -3301,10 +3299,10 @@ static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S) { return 0; } - cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL); - if (self == NULL) + cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", NULL); + tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", nullptr); return 0; } @@ -3322,7 +3320,7 @@ static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S) void ManualBindings::Bind(lua_State * tolua_S) { - tolua_beginmodule(tolua_S, NULL); + tolua_beginmodule(tolua_S, nullptr); tolua_function(tolua_S, "Clamp", tolua_Clamp); tolua_function(tolua_S, "StringSplit", tolua_StringSplit); tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim); @@ -3370,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); @@ -3391,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>); @@ -3405,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"); @@ -3449,7 +3448,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "AddWebTab", tolua_cPluginLua_AddWebTab); tolua_endmodule(tolua_S); - tolua_cclass(tolua_S, "HTTPRequest", "HTTPRequest", "", NULL); + tolua_cclass(tolua_S, "HTTPRequest", "HTTPRequest", "", nullptr); tolua_beginmodule(tolua_S, "HTTPRequest"); // tolua_variable(tolua_S, "Method", tolua_get_HTTPRequest_Method, tolua_set_HTTPRequest_Method); // tolua_variable(tolua_S, "Path", tolua_get_HTTPRequest_Path, tolua_set_HTTPRequest_Path); diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index 2e93ad264..fa1b88b6a 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -34,7 +34,7 @@ static int tolua_cRankManager_AddGroup(lua_State * L) S.GetStackValue(2, GroupName); // Add the group: - cRoot::Get()->GetRankManager().AddGroup(GroupName); + cRoot::Get()->GetRankManager()->AddGroup(GroupName); return 0; } @@ -63,7 +63,7 @@ static int tolua_cRankManager_AddGroupToRank(lua_State * L) S.GetStackValues(2, GroupName, RankName); // Add the group to the rank: - S.Push(cRoot::Get()->GetRankManager().AddGroupToRank(GroupName, RankName)); + S.Push(cRoot::Get()->GetRankManager()->AddGroupToRank(GroupName, RankName)); return 1; } @@ -92,7 +92,7 @@ static int tolua_cRankManager_AddPermissionToGroup(lua_State * L) S.GetStackValues(2, Permission, GroupName); // Add the group to the rank: - S.Push(cRoot::Get()->GetRankManager().AddPermissionToGroup(Permission, GroupName)); + S.Push(cRoot::Get()->GetRankManager()->AddPermissionToGroup(Permission, GroupName)); return 1; } @@ -121,7 +121,7 @@ static int tolua_cRankManager_AddRank(lua_State * L) S.GetStackValues(2, RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); // Add the rank: - cRoot::Get()->GetRankManager().AddRank(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + cRoot::Get()->GetRankManager()->AddRank(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); return 0; } @@ -129,6 +129,27 @@ static int tolua_cRankManager_AddRank(lua_State * L) +/** Binds cRankManager::ClearPlayerRanks */ +static int tolua_cRankManager_ClearPlayerRanks(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Remove all players: + cRoot::Get()->GetRankManager()->ClearPlayerRanks(); + return 1; +} + + + + + /** Binds cRankManager::GetAllGroups */ static int tolua_cRankManager_GetAllGroups(lua_State * L) { @@ -145,7 +166,7 @@ static int tolua_cRankManager_GetAllGroups(lua_State * L) } // Get the groups: - AStringVector Groups = cRoot::Get()->GetRankManager().GetAllGroups(); + AStringVector Groups = cRoot::Get()->GetRankManager()->GetAllGroups(); // Push the results: S.Push(Groups); @@ -172,7 +193,7 @@ static int tolua_cRankManager_GetAllPermissions(lua_State * L) } // Get the permissions: - AStringVector Permissions = cRoot::Get()->GetRankManager().GetAllPermissions(); + AStringVector Permissions = cRoot::Get()->GetRankManager()->GetAllPermissions(); // Push the results: S.Push(Permissions); @@ -183,6 +204,33 @@ static int tolua_cRankManager_GetAllPermissions(lua_State * L) +/** Binds cRankManager::GetAllPlayerUUIDs */ +static int tolua_cRankManager_GetAllPlayerUUIDs(lua_State * L) +{ + // Function signature: + // cRankManager:GetAllPlayerUUIDs() -> arraytable of Player UUID's + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Get the player uuid's: + AStringVector Players = cRoot::Get()->GetRankManager()->GetAllPlayerUUIDs(); + + // Push the results: + S.Push(Players); + return 1; +} + + + + + /** Binds cRankManager::GetAllRanks */ static int tolua_cRankManager_GetAllRanks(lua_State * L) { @@ -199,7 +247,7 @@ static int tolua_cRankManager_GetAllRanks(lua_State * L) } // Get the ranks: - AStringVector Ranks = cRoot::Get()->GetRankManager().GetAllRanks(); + AStringVector Ranks = cRoot::Get()->GetRankManager()->GetAllRanks(); // Push the results: S.Push(Ranks); @@ -226,7 +274,7 @@ static int tolua_cRankManager_GetDefaultRank(lua_State * L) } // Return the rank name: - S.Push(cRoot::Get()->GetRankManager().GetDefaultRank()); + S.Push(cRoot::Get()->GetRankManager()->GetDefaultRank()); return 1; } @@ -255,7 +303,7 @@ static int tolua_cRankManager_GetGroupPermissions(lua_State * L) S.GetStackValue(2, GroupName); // Get the permissions: - AStringVector Permissions = cRoot::Get()->GetRankManager().GetGroupPermissions(GroupName); + AStringVector Permissions = cRoot::Get()->GetRankManager()->GetGroupPermissions(GroupName); // Push the results: S.Push(Permissions); @@ -287,7 +335,7 @@ static int tolua_cRankManager_GetPlayerGroups(lua_State * L) S.GetStackValue(2, PlayerUUID); // Get the groups: - AStringVector Groups = cRoot::Get()->GetRankManager().GetPlayerGroups(PlayerUUID); + AStringVector Groups = cRoot::Get()->GetRankManager()->GetPlayerGroups(PlayerUUID); // Push the results: S.Push(Groups); @@ -320,7 +368,7 @@ static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L) // Get the permissions: AString MsgPrefix, MsgSuffix, MsgNameColorCode; - if (!cRoot::Get()->GetRankManager().GetPlayerMsgVisuals(PlayerUUID, MsgPrefix, MsgSuffix, MsgNameColorCode)) + if (!cRoot::Get()->GetRankManager()->GetPlayerMsgVisuals(PlayerUUID, MsgPrefix, MsgSuffix, MsgNameColorCode)) { return 0; } @@ -357,7 +405,7 @@ static int tolua_cRankManager_GetPlayerPermissions(lua_State * L) S.GetStackValue(2, PlayerUUID); // Get the permissions: - AStringVector Permissions = cRoot::Get()->GetRankManager().GetPlayerPermissions(PlayerUUID); + AStringVector Permissions = cRoot::Get()->GetRankManager()->GetPlayerPermissions(PlayerUUID); // Push the results: S.Push(Permissions); @@ -389,7 +437,7 @@ static int tolua_cRankManager_GetPlayerRankName(lua_State * L) S.GetStackValue(2, PlayerUUID); // Get the rank name: - AString RankName = cRoot::Get()->GetRankManager().GetPlayerRankName(PlayerUUID); + AString RankName = cRoot::Get()->GetRankManager()->GetPlayerRankName(PlayerUUID); // Push the result: S.Push(RankName); @@ -400,6 +448,38 @@ static int tolua_cRankManager_GetPlayerRankName(lua_State * L) +/** Binds cRankManager::GetPlayerName */ +static int tolua_cRankManager_GetPlayerName(lua_State * L) +{ + // Function signature: + // cRankManager:GetPlayerName(PlayerUUID) -> string + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the player name: + AString PlayerName = cRoot::Get()->GetRankManager()->GetPlayerName(PlayerUUID); + + // Push the result: + S.Push(PlayerName); + return 1; +} + + + + + /** Binds cRankManager::GetRankGroups */ static int tolua_cRankManager_GetRankGroups(lua_State * L) { @@ -421,7 +501,7 @@ static int tolua_cRankManager_GetRankGroups(lua_State * L) S.GetStackValue(2, RankName); // Get the groups: - AStringVector Groups = cRoot::Get()->GetRankManager().GetRankGroups(RankName); + AStringVector Groups = cRoot::Get()->GetRankManager()->GetRankGroups(RankName); // Push the results: S.Push(Groups); @@ -453,7 +533,7 @@ static int tolua_cRankManager_GetRankPermissions(lua_State * L) S.GetStackValue(2, RankName); // Get the permissions: - AStringVector Permissions = cRoot::Get()->GetRankManager().GetRankPermissions(RankName); + AStringVector Permissions = cRoot::Get()->GetRankManager()->GetRankPermissions(RankName); // Push the results: S.Push(Permissions); @@ -486,7 +566,7 @@ static int tolua_cRankManager_GetRankVisuals(lua_State * L) // Get the visuals: AString MsgPrefix, MsgSuffix, MsgNameColorCode; - if (!cRoot::Get()->GetRankManager().GetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode)) + if (!cRoot::Get()->GetRankManager()->GetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode)) { // No such rank, return nothing: return 0; @@ -524,7 +604,7 @@ static int tolua_cRankManager_GroupExists(lua_State * L) S.GetStackValue(2, GroupName); // Get the response: - bool res = cRoot::Get()->GetRankManager().GroupExists(GroupName); + bool res = cRoot::Get()->GetRankManager()->GroupExists(GroupName); // Push the result: S.Push(res); @@ -556,7 +636,7 @@ static int tolua_cRankManager_IsGroupInRank(lua_State * L) S.GetStackValues(2, GroupName, RankName); // Get the response: - bool res = cRoot::Get()->GetRankManager().IsGroupInRank(GroupName, RankName); + bool res = cRoot::Get()->GetRankManager()->IsGroupInRank(GroupName, RankName); // Push the result: S.Push(res); @@ -588,7 +668,7 @@ static int tolua_cRankManager_IsPermissionInGroup(lua_State * L) S.GetStackValues(2, Permission, GroupName); // Get the response: - bool res = cRoot::Get()->GetRankManager().IsPermissionInGroup(Permission, GroupName); + bool res = cRoot::Get()->GetRankManager()->IsPermissionInGroup(Permission, GroupName); // Push the result: S.Push(res); @@ -620,7 +700,7 @@ static int tolua_cRankManager_IsPlayerRankSet(lua_State * L) S.GetStackValue(2, PlayerUUID); // Get the response: - bool res = cRoot::Get()->GetRankManager().IsPlayerRankSet(PlayerUUID); + bool res = cRoot::Get()->GetRankManager()->IsPlayerRankSet(PlayerUUID); // Push the result: S.Push(res); @@ -652,7 +732,7 @@ static int tolua_cRankManager_RankExists(lua_State * L) S.GetStackValue(2, RankName); // Get the response: - bool res = cRoot::Get()->GetRankManager().RankExists(RankName); + bool res = cRoot::Get()->GetRankManager()->RankExists(RankName); // Push the result: S.Push(res); @@ -684,7 +764,7 @@ static int tolua_cRankManager_RemoveGroup(lua_State * L) S.GetStackValue(2, GroupName); // Remove the group: - cRoot::Get()->GetRankManager().RemoveGroup(GroupName); + cRoot::Get()->GetRankManager()->RemoveGroup(GroupName); return 0; } @@ -713,7 +793,7 @@ static int tolua_cRankManager_RemoveGroupFromRank(lua_State * L) S.GetStackValues(2, GroupName, RankName); // Remove the group: - cRoot::Get()->GetRankManager().RemoveGroupFromRank(GroupName, RankName); + cRoot::Get()->GetRankManager()->RemoveGroupFromRank(GroupName, RankName); return 0; } @@ -742,7 +822,7 @@ static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) S.GetStackValues(2, Permission, GroupName); // Remove the group: - cRoot::Get()->GetRankManager().RemovePermissionFromGroup(Permission, GroupName); + cRoot::Get()->GetRankManager()->RemovePermissionFromGroup(Permission, GroupName); return 0; } @@ -771,7 +851,7 @@ static int tolua_cRankManager_RemovePlayerRank(lua_State * L) S.GetStackValue(2, PlayerUUID); // Remove the player's rank: - cRoot::Get()->GetRankManager().RemovePlayerRank(PlayerUUID); + cRoot::Get()->GetRankManager()->RemovePlayerRank(PlayerUUID); return 0; } @@ -801,7 +881,7 @@ static int tolua_cRankManager_RemoveRank(lua_State * L) S.GetStackValues(2, RankName, ReplacementRankName); // Remove the rank: - cRoot::Get()->GetRankManager().RemoveRank(RankName, ReplacementRankName); + cRoot::Get()->GetRankManager()->RemoveRank(RankName, ReplacementRankName); return 0; } @@ -830,7 +910,7 @@ static int tolua_cRankManager_RenameGroup(lua_State * L) S.GetStackValues(2, OldName, NewName); // Remove the group: - bool res = cRoot::Get()->GetRankManager().RenameGroup(OldName, NewName); + bool res = cRoot::Get()->GetRankManager()->RenameGroup(OldName, NewName); // Push the result: S.Push(res); @@ -862,7 +942,7 @@ static int tolua_cRankManager_RenameRank(lua_State * L) S.GetStackValues(2, OldName, NewName); // Remove the rank: - bool res = cRoot::Get()->GetRankManager().RenameRank(OldName, NewName); + bool res = cRoot::Get()->GetRankManager()->RenameRank(OldName, NewName); // Push the result: S.Push(res); @@ -894,8 +974,8 @@ static int tolua_cRankManager_SetDefaultRank(lua_State * L) S.GetStackValue(2, RankName); // Set the rank, return the result: - S.Push(cRoot::Get()->GetRankManager().SetDefaultRank(RankName)); - return 0; + S.Push(cRoot::Get()->GetRankManager()->SetDefaultRank(RankName)); + return 1; } @@ -923,7 +1003,7 @@ static int tolua_cRankManager_SetPlayerRank(lua_State * L) S.GetStackValues(2, PlayerUUID, PlayerName, RankName); // Set the rank: - cRoot::Get()->GetRankManager().SetPlayerRank(PlayerUUID, PlayerName, RankName); + cRoot::Get()->GetRankManager()->SetPlayerRank(PlayerUUID, PlayerName, RankName); return 0; } @@ -952,7 +1032,7 @@ static int tolua_cRankManager_SetRankVisuals(lua_State * L) S.GetStackValues(2, RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); // Set the visuals: - cRoot::Get()->GetRankManager().SetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + cRoot::Get()->GetRankManager()->SetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); return 0; } @@ -964,7 +1044,7 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) { // Create the cRankManager class in the API: tolua_usertype(tolua_S, "cRankManager"); - tolua_cclass(tolua_S, "cRankManager", "cRankManager", "", NULL); + tolua_cclass(tolua_S, "cRankManager", "cRankManager", "", nullptr); // Fill in the functions (alpha-sorted): tolua_beginmodule(tolua_S, "cRankManager"); @@ -972,8 +1052,10 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "AddGroupToRank", tolua_cRankManager_AddGroupToRank); tolua_function(tolua_S, "AddPermissionToGroup", tolua_cRankManager_AddPermissionToGroup); tolua_function(tolua_S, "AddRank", tolua_cRankManager_AddRank); + tolua_function(tolua_S, "ClearPlayerRanks", tolua_cRankManager_ClearPlayerRanks); tolua_function(tolua_S, "GetAllGroups", tolua_cRankManager_GetAllGroups); tolua_function(tolua_S, "GetAllPermissions", tolua_cRankManager_GetAllPermissions); + tolua_function(tolua_S, "GetAllPlayerUUIDs", tolua_cRankManager_GetAllPlayerUUIDs); tolua_function(tolua_S, "GetAllRanks", tolua_cRankManager_GetAllRanks); tolua_function(tolua_S, "GetDefaultRank", tolua_cRankManager_GetDefaultRank); tolua_function(tolua_S, "GetGroupPermissions", tolua_cRankManager_GetGroupPermissions); @@ -981,6 +1063,7 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "GetPlayerMsgVisuals", tolua_cRankManager_GetPlayerMsgVisuals); tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerPermissions); tolua_function(tolua_S, "GetPlayerRankName", tolua_cRankManager_GetPlayerRankName); + tolua_function(tolua_S, "GetPlayerName", tolua_cRankManager_GetPlayerName); tolua_function(tolua_S, "GetRankGroups", tolua_cRankManager_GetRankGroups); tolua_function(tolua_S, "GetRankPermissions", tolua_cRankManager_GetRankPermissions); tolua_function(tolua_S, "GetRankVisuals", tolua_cRankManager_GetRankVisuals); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index fb22dd33e..8cc9ff0cd 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -45,26 +45,26 @@ public: virtual void Tick(float a_Dt) = 0; /** Calls the specified hook with the params given. Returns the bool that the hook callback returns.*/ - virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0; - virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; - virtual bool OnChat (cPlayer * a_Player, AString & a_Message) = 0; - virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0; - virtual bool OnChunkGenerated (cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) = 0; - virtual bool OnChunkGenerating (cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) = 0; - 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 (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; + virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0; + virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; + virtual bool OnChat (cPlayer & a_Player, AString & a_Message) = 0; + virtual bool OnChunkAvailable (cWorld & a_World, int a_ChunkX, int a_ChunkZ) = 0; + virtual bool OnChunkGenerated (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) = 0; + virtual bool OnChunkGenerating (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) = 0; + 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 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; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; - virtual bool OnHandshake (cClientHandle * a_Client, const AString & a_Username) = 0; + virtual bool OnHandshake (cClientHandle & a_Client, const AString & a_Username) = 0; virtual bool OnHopperPullingItem (cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum) = 0; virtual bool OnHopperPushingItem (cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum) = 0; virtual bool OnKilling (cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI) = 0; - virtual bool OnLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) = 0; + virtual bool OnLogin (cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username) = 0; virtual bool OnPlayerAnimation (cPlayer & a_Player, int a_Animation) = 0; virtual bool OnPlayerBreakingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; @@ -89,8 +89,8 @@ public: virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) = 0; virtual bool OnPluginsLoaded (void) = 0; - virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; - virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; + virtual bool OnPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0; + virtual bool OnPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) = 0; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0; virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; @@ -99,8 +99,8 @@ public: virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawningMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo) = 0; - virtual bool OnUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) = 0; - virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) = 0; + virtual bool OnUpdatedSign (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) = 0; + virtual bool OnUpdatingSign (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) = 0; virtual bool OnWeatherChanged (cWorld & a_World) = 0; virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) = 0; virtual bool OnWorldStarted (cWorld & a_World) = 0; @@ -110,7 +110,7 @@ public: Command permissions have already been checked. Returns true if command handled successfully */ - virtual bool HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) = 0; + virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) = 0; /** Handles the console command split into a_Split. Returns true if command handled successfully. Output is to be sent to the a_Output callback. diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 2629eb641..391d8bcbe 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -202,14 +202,14 @@ void cPluginLua::Tick(float a_Dt) -bool cPluginLua::OnBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) +bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source, cLuaState::Return, res); if (res) { return true; @@ -222,14 +222,14 @@ bool cPluginLua::OnBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int -bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) +bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res); if (res) { return true; @@ -242,14 +242,14 @@ bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_Bl -bool cPluginLua::OnChat(cPlayer * a_Player, AString & a_Message) +bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Message, cLuaState::Return, res, a_Message); + m_LuaState.Call((int)(**itr), &a_Player, a_Message, cLuaState::Return, res, a_Message); if (res) { return true; @@ -262,14 +262,14 @@ bool cPluginLua::OnChat(cPlayer * a_Player, AString & a_Message) -bool cPluginLua::OnChunkAvailable(cWorld * a_World, int a_ChunkX, int a_ChunkZ) +bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); if (res) { return true; @@ -282,14 +282,14 @@ bool cPluginLua::OnChunkAvailable(cWorld * a_World, int a_ChunkX, int a_ChunkZ) -bool cPluginLua::OnChunkGenerated(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) +bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); if (res) { return true; @@ -302,14 +302,14 @@ bool cPluginLua::OnChunkGenerated(cWorld * a_World, int a_ChunkX, int a_ChunkZ, -bool cPluginLua::OnChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) +bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); if (res) { return true; @@ -322,14 +322,14 @@ bool cPluginLua::OnChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, -bool cPluginLua::OnChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_ChunkZ) +bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); if (res) { return true; @@ -342,14 +342,14 @@ bool cPluginLua::OnChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_ChunkZ) -bool cPluginLua::OnChunkUnloading(cWorld * a_World, int a_ChunkX, int a_ChunkZ) +bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); if (res) { return true; @@ -362,14 +362,14 @@ bool cPluginLua::OnChunkUnloading(cWorld * a_World, int a_ChunkX, int a_ChunkZ) -bool cPluginLua::OnCollectingPickup(cPlayer * a_Player, cPickup * a_Pickup) +bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Pickup, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, &a_Pickup, cLuaState::Return, res); if (res) { return true; @@ -382,14 +382,14 @@ bool cPluginLua::OnCollectingPickup(cPlayer * a_Player, cPickup * a_Pickup) -bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const 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; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), (cPlayer *)a_Player, a_Grid, a_Recipe, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, &a_Grid, &a_Recipe, cLuaState::Return, res); if (res) { return true; @@ -471,12 +471,12 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can { switch (a_Source) { - case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break; - case esMonster: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cMonster *)a_SourceData, cLuaState::Return, res); break; - case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; - case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; - case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break; + case esMonster: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cMonster *)a_SourceData, cLuaState::Return, res); break; + case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; + case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; + case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; case esWitherSkullBlack: case esWitherSkullBlue: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; case esWitherBirth: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; @@ -536,14 +536,14 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & -bool cPluginLua::OnHandshake(cClientHandle * a_Client, const AString & a_Username) +bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Client, a_Username, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Client, a_Username, cLuaState::Return, res); if (res) { return true; @@ -617,14 +617,14 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf -bool cPluginLua::OnLogin(cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) +bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res); if (res) { return true; @@ -784,7 +784,7 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward) cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), &a_Player, a_Reward, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, &a_Reward, cLuaState::Return, res); if (res) { return true; @@ -1115,14 +1115,14 @@ bool cPluginLua::OnPluginsLoaded(void) -bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) +bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Grid, a_Recipe, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, &a_Grid, &a_Recipe, cLuaState::Return, res); if (res) { return true; @@ -1135,14 +1135,14 @@ bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * -bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) +bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Grid, a_Recipe, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, &a_Grid, &a_Recipe, cLuaState::Return, res); if (res) { return true; @@ -1316,7 +1316,7 @@ bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) bool cPluginLua::OnUpdatedSign( - cWorld * a_World, + cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player @@ -1327,7 +1327,7 @@ bool cPluginLua::OnUpdatedSign( cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res); if (res) { return true; @@ -1341,7 +1341,7 @@ bool cPluginLua::OnUpdatedSign( bool cPluginLua::OnUpdatingSign( - cWorld * a_World, + cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player @@ -1352,7 +1352,7 @@ bool cPluginLua::OnUpdatingSign( cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4); + m_LuaState.Call((int)(**itr), &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4); if (res) { return true; @@ -1435,7 +1435,7 @@ bool cPluginLua::OnWorldTick(cWorld & a_World, float a_Dt, int a_LastTickDuratio -bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) +bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) { ASSERT(!a_Split.empty()); CommandMap::iterator cmd = m_Commands.find(a_Split[0]); @@ -1447,7 +1447,7 @@ bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Player cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(cmd->second, a_Split, a_Player, cLuaState::Return, res); + m_LuaState.Call(cmd->second, a_Split, &a_Player, cLuaState::Return, res); return res; } @@ -1487,7 +1487,7 @@ void cPluginLua::ClearCommands(void) cCSLock Lock(m_CriticalSection); // Unreference the bound functions so that Lua can GC them - if (m_LuaState != NULL) + if (m_LuaState != nullptr) { for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) { @@ -1506,7 +1506,7 @@ void cPluginLua::ClearConsoleCommands(void) cCSLock Lock(m_CriticalSection); // Unreference the bound functions so that Lua can GC them - if (m_LuaState != NULL) + if (m_LuaState != nullptr) { for (CommandMap::iterator itr = m_ConsoleCommands.begin(), end = m_ConsoleCommands.end(); itr != end; ++itr) { @@ -1523,7 +1523,7 @@ void cPluginLua::ClearConsoleCommands(void) bool cPluginLua::CanAddOldStyleHook(int a_HookType) { const char * FnName = GetHookFnName(a_HookType); - if (FnName == NULL) + if (FnName == nullptr) { // Unknown hook ID LOGWARNING("Plugin %s wants to add an unknown hook ID (%d). The plugin need not work properly.", @@ -1614,7 +1614,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType) } // switch (a_Hook) LOGWARNING("Requested name of an unknown hook type function: %d (max is %d)", a_HookType, cPluginManager::HOOK_MAX); ASSERT(!"Unknown hook requested!"); - return NULL; + return nullptr; } @@ -1627,12 +1627,12 @@ bool cPluginLua::AddHookRef(int a_HookType, int a_FnRefIdx) // Check if the function reference is valid: cLuaState::cRef * Ref = new cLuaState::cRef(m_LuaState, a_FnRefIdx); - if ((Ref == NULL) || !Ref->IsValid()) + if ((Ref == nullptr) || !Ref->IsValid()) { LOGWARNING("Plugin %s tried to add a hook %d with bad handler function.", GetName().c_str(), a_HookType); m_LuaState.LogStackTrace(); delete Ref; - Ref = NULL; + Ref = nullptr; return false; } @@ -1700,7 +1700,7 @@ AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request) } } - if (Tab != NULL) + if (Tab != nullptr) { AString Contents = Printf("WARNING: WebPlugin tab '%s' did not return a string!", Tab->Title.c_str()); if (!m_LuaState.Call(Tab->UserData, a_Request, cLuaState::Return, Contents)) diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index eda65b76c..6bb134efc 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -69,26 +69,26 @@ public: virtual void Tick(float a_Dt) override; - virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override; - virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override; - virtual bool OnChat (cPlayer * a_Player, AString & a_Message) override; - virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override; - virtual bool OnChunkGenerated (cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) override; - virtual bool OnChunkGenerating (cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) override; - 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 (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; + virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override; + virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override; + virtual bool OnChat (cPlayer & a_Player, AString & a_Message) override; + virtual bool OnChunkAvailable (cWorld & a_World, int a_ChunkX, int a_ChunkZ) override; + virtual bool OnChunkGenerated (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) override; + virtual bool OnChunkGenerating (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) override; + 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 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; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; - virtual bool OnHandshake (cClientHandle * a_Client, const AString & a_Username) override; + virtual bool OnHandshake (cClientHandle & a_Client, const AString & a_Username) override; virtual bool OnHopperPullingItem (cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum) override; virtual bool OnHopperPushingItem (cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum) override; virtual bool OnKilling (cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI) override; - virtual bool OnLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) override; + virtual bool OnLogin (cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username) override; virtual bool OnPlayerAnimation (cPlayer & a_Player, int a_Animation) override; virtual bool OnPlayerBreakingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; @@ -113,8 +113,8 @@ public: virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) override; virtual bool OnPluginsLoaded (void) override; - virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; - virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; + virtual bool OnPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override; + virtual bool OnPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) override; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override; virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; @@ -123,14 +123,14 @@ public: virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawningMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo) override; - virtual bool OnUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) override; - virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) override; + virtual bool OnUpdatedSign (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) override; + virtual bool OnUpdatingSign (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) override; virtual bool OnWeatherChanged (cWorld & a_World) override; virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) override; virtual bool OnWorldStarted (cWorld & a_World) override; virtual bool OnWorldTick (cWorld & a_World, float a_Dt, int a_LastTickDurationMSec) override; - virtual bool HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) override; + virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) override; virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index e0faa838a..f63578885 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -9,7 +9,7 @@ #include "../Server.h" #include "../CommandOutput.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "../Entities/Player.h" #define FIND_HOOK(a_HookName) HookMap::iterator Plugins = m_Hooks.find(a_HookName); @@ -66,7 +66,7 @@ void cPluginManager::FindPlugins(void) // First get a clean list of only the currently running plugins, we don't want to mess those up for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) { - if (itr->second == NULL) + if (itr->second == nullptr) { PluginMap::iterator thiz = itr; ++thiz; @@ -89,7 +89,7 @@ void cPluginManager::FindPlugins(void) // Add plugin name/directory to the list if (m_Plugins.find(*itr) == m_Plugins.end()) { - m_Plugins[*itr] = NULL; + m_Plugins[*itr] = nullptr; } } } @@ -151,7 +151,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) // Remove invalid plugins from the PluginMap. for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) { - if (itr->second == NULL) + if (itr->second == nullptr) { PluginMap::iterator thiz = itr; ++thiz; @@ -225,7 +225,7 @@ void cPluginManager::Tick(float a_Dt) -bool cPluginManager::CallHookBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) +bool cPluginManager::CallHookBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) { FIND_HOOK(HOOK_BLOCK_SPREAD); VERIFY_HOOK; @@ -245,7 +245,7 @@ bool cPluginManager::CallHookBlockSpread(cWorld * a_World, int a_BlockX, int a_B bool cPluginManager::CallHookBlockToPickups( - cWorld * a_World, cEntity * a_Digger, + cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups ) @@ -267,7 +267,7 @@ bool cPluginManager::CallHookBlockToPickups( -bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) +bool cPluginManager::CallHookChat(cPlayer & a_Player, AString & a_Message) { // Check if the message contains a command, execute it: switch (HandleCommand(a_Player, a_Message, true)) @@ -288,14 +288,14 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) case crError: { // An error in the plugin has prevented the command from executing. Report the error to the player: - a_Player->SendMessageFailure(Printf("Something went wrong while executing command \"%s\"", a_Message.c_str())); + a_Player.SendMessageFailure(Printf("Something went wrong while executing command \"%s\"", a_Message.c_str())); return true; } case crNoPermission: { // The player is not allowed to execute this command - a_Player->SendMessageFailure(Printf("Forbidden command; insufficient privileges: \"%s\"", a_Message.c_str())); + a_Player.SendMessageFailure(Printf("Forbidden command; insufficient privileges: \"%s\"", a_Message.c_str())); return true; } @@ -311,8 +311,8 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) { AStringVector Split(StringSplit(a_Message, " ")); ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long - a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", a_Message.c_str())); - LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str()); + a_Player.SendMessageInfo(Printf("Unknown command: \"%s\"", a_Message.c_str())); + LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player.GetName().c_str(), a_Message.c_str()); return true; // Cancel sending } @@ -334,7 +334,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) -bool cPluginManager::CallHookChunkAvailable(cWorld * a_World, int a_ChunkX, int a_ChunkZ) +bool cPluginManager::CallHookChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { FIND_HOOK(HOOK_CHUNK_AVAILABLE); VERIFY_HOOK; @@ -353,7 +353,7 @@ bool cPluginManager::CallHookChunkAvailable(cWorld * a_World, int a_ChunkX, int -bool cPluginManager::CallHookChunkGenerated(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) +bool cPluginManager::CallHookChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { FIND_HOOK(HOOK_CHUNK_GENERATED); VERIFY_HOOK; @@ -372,7 +372,7 @@ bool cPluginManager::CallHookChunkGenerated(cWorld * a_World, int a_ChunkX, int -bool cPluginManager::CallHookChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) +bool cPluginManager::CallHookChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { FIND_HOOK(HOOK_CHUNK_GENERATING); VERIFY_HOOK; @@ -391,7 +391,7 @@ bool cPluginManager::CallHookChunkGenerating(cWorld * a_World, int a_ChunkX, int -bool cPluginManager::CallHookChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_ChunkZ) +bool cPluginManager::CallHookChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { FIND_HOOK(HOOK_CHUNK_UNLOADED); VERIFY_HOOK; @@ -410,7 +410,7 @@ bool cPluginManager::CallHookChunkUnloaded(cWorld * a_World, int a_ChunkX, int a -bool cPluginManager::CallHookChunkUnloading(cWorld * a_World, int a_ChunkX, int a_ChunkZ) +bool cPluginManager::CallHookChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { FIND_HOOK(HOOK_CHUNK_UNLOADING); VERIFY_HOOK; @@ -429,14 +429,14 @@ bool cPluginManager::CallHookChunkUnloading(cWorld * a_World, int a_ChunkX, int -bool cPluginManager::CallHookCollectingPickup(cPlayer * a_Player, cPickup & a_Pickup) +bool cPluginManager::CallHookCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup) { FIND_HOOK(HOOK_COLLECTING_PICKUP); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnCollectingPickup(a_Player, &a_Pickup)) + if ((*itr)->OnCollectingPickup(a_Player, a_Pickup)) { return true; } @@ -448,7 +448,7 @@ bool cPluginManager::CallHookCollectingPickup(cPlayer * a_Player, cPickup & a_Pi -bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const 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; @@ -562,7 +562,7 @@ bool cPluginManager::CallHookExploding(cWorld & a_World, double & a_ExplosionSiz -bool cPluginManager::CallHookHandshake(cClientHandle * a_ClientHandle, const AString & a_Username) +bool cPluginManager::CallHookHandshake(cClientHandle & a_ClientHandle, const AString & a_Username) { FIND_HOOK(HOOK_HANDSHAKE); VERIFY_HOOK; @@ -638,7 +638,7 @@ bool cPluginManager::CallHookKilling(cEntity & a_Victim, cEntity * a_Killer, Tak -bool cPluginManager::CallHookLogin(cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) +bool cPluginManager::CallHookLogin(cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username) { FIND_HOOK(HOOK_LOGIN); VERIFY_HOOK; @@ -1111,7 +1111,7 @@ bool cPluginManager::CallHookPluginsLoaded(void) -bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) +bool cPluginManager::CallHookPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { FIND_HOOK(HOOK_POST_CRAFTING); VERIFY_HOOK; @@ -1130,7 +1130,7 @@ bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraft -bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) +bool cPluginManager::CallHookPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { FIND_HOOK(HOOK_PRE_CRAFTING); VERIFY_HOOK; @@ -1299,7 +1299,7 @@ bool cPluginManager::CallHookTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a -bool cPluginManager::CallHookUpdatingSign(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) +bool cPluginManager::CallHookUpdatingSign(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) { FIND_HOOK(HOOK_UPDATING_SIGN); VERIFY_HOOK; @@ -1318,7 +1318,7 @@ bool cPluginManager::CallHookUpdatingSign(cWorld * a_World, int a_BlockX, int a_ -bool cPluginManager::CallHookUpdatedSign(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) +bool cPluginManager::CallHookUpdatedSign(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) { FIND_HOOK(HOOK_UPDATED_SIGN); VERIFY_HOOK; @@ -1413,10 +1413,8 @@ bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt, int a_LastT -cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) +cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) { - ASSERT(a_Player != NULL); - AStringVector Split(StringSplit(a_Command, " ")); if (Split.empty()) { @@ -1431,23 +1429,23 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer * a_Player, } // Ask plugins first if a command is okay to execute the command: - if (CallHookExecuteCommand(a_Player, Split)) + if (CallHookExecuteCommand(&a_Player, Split)) { - LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str()); + LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player.GetName().c_str(), Split[0].c_str()); return crBlocked; } if ( a_ShouldCheckPermissions && !cmd->second.m_Permission.empty() && - !a_Player->HasPermission(cmd->second.m_Permission) + !a_Player.HasPermission(cmd->second.m_Permission) ) { - LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player->GetName().c_str(), Split[0].c_str()); + LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player.GetName().c_str(), Split[0].c_str()); return crNoPermission; } - ASSERT(cmd->second.m_Plugin != NULL); + ASSERT(cmd->second.m_Plugin != nullptr); if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player)) { @@ -1465,7 +1463,7 @@ cPlugin * cPluginManager::GetPlugin( const AString & a_Plugin) const { for (PluginMap::const_iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr) { - if (itr->second == NULL) continue; + if (itr->second == nullptr) continue; if (itr->second->GetName().compare(a_Plugin) == 0) { return itr->second; @@ -1515,7 +1513,7 @@ bool cPluginManager::DisablePlugin(const AString & a_PluginName) if (itr->first.compare(a_PluginName) == 0) // _X 2013_02_01: wtf? Isn't this supposed to be what find() does? { m_DisablePluginList.push_back(itr->second); - itr->second = NULL; // Get rid of this thing right away + itr->second = nullptr; // Get rid of this thing right away return true; } return false; @@ -1560,12 +1558,12 @@ void cPluginManager::RemovePlugin(cPlugin * a_Plugin) RemovePluginCommands(a_Plugin); RemovePluginConsoleCommands(a_Plugin); RemoveHooks(a_Plugin); - if (a_Plugin != NULL) + if (a_Plugin != nullptr) { a_Plugin->OnDisable(); } delete a_Plugin; - a_Plugin = NULL; + a_Plugin = nullptr; } @@ -1574,7 +1572,7 @@ void cPluginManager::RemovePlugin(cPlugin * a_Plugin) void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin) { - if (a_Plugin != NULL) + if (a_Plugin != nullptr) { a_Plugin->ClearCommands(); } @@ -1652,7 +1650,7 @@ AString cPluginManager::GetCommandPermission(const AString & a_Command) -cPluginManager::CommandResult cPluginManager::ExecuteCommand(cPlayer * a_Player, const AString & a_Command) +cPluginManager::CommandResult cPluginManager::ExecuteCommand(cPlayer & a_Player, const AString & a_Command) { return HandleCommand(a_Player, a_Command, true); } @@ -1661,7 +1659,7 @@ cPluginManager::CommandResult cPluginManager::ExecuteCommand(cPlayer * a_Player, -cPluginManager::CommandResult cPluginManager::ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command) +cPluginManager::CommandResult cPluginManager::ForceExecuteCommand(cPlayer & a_Player, const AString & a_Command) { return HandleCommand(a_Player, a_Command, false); } @@ -1672,7 +1670,7 @@ cPluginManager::CommandResult cPluginManager::ForceExecuteCommand(cPlayer * a_Pl void cPluginManager::RemovePluginConsoleCommands(cPlugin * a_Plugin) { - if (a_Plugin != NULL) + if (a_Plugin != nullptr) { a_Plugin->ClearConsoleCommands(); } @@ -1701,7 +1699,7 @@ bool cPluginManager::BindConsoleCommand(const AString & a_Command, cPlugin * a_P CommandMap::iterator cmd = m_ConsoleCommands.find(a_Command); if (cmd != m_ConsoleCommands.end()) { - if (cmd->second.m_Plugin == NULL) + if (cmd->second.m_Plugin == nullptr) { LOGWARNING("Console command \"%s\" is already bound internally by MCServer, cannot bind in plugin \"%s\".", a_Command.c_str(), a_Plugin->GetName().c_str()); } @@ -1761,14 +1759,14 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma return false; } - if (cmd->second.m_Plugin == NULL) + if (cmd->second.m_Plugin == nullptr) { // This is a built-in command return false; } // Ask plugins first if a command is okay to execute the console command: - if (CallHookExecuteCommand(NULL, a_Split)) + if (CallHookExecuteCommand(nullptr, a_Split)) { a_Output.Out("Command \"%s\" was stopped by the HOOK_EXECUTE_COMMAND hook", a_Split[0].c_str()); return false; @@ -1790,7 +1788,7 @@ void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & // Command name doesn't match continue; } - if ((a_Player != NULL) && !a_Player->HasPermission(itr->second.m_Permission)) + if ((a_Player != nullptr) && !a_Player->HasPermission(itr->second.m_Permission)) { // Player doesn't have permission for the command continue; @@ -1816,7 +1814,7 @@ bool cPluginManager::DoWithPlugin(const AString & a_PluginName, cPluginCallback { // TODO: Implement locking for plugins PluginMap::iterator itr = m_Plugins.find(a_PluginName); - if ((itr == m_Plugins.end()) || (itr->second == NULL)) + if ((itr == m_Plugins.end()) || (itr->second == nullptr)) { return false; } @@ -1830,6 +1828,7 @@ bool cPluginManager::DoWithPlugin(const AString & a_PluginName, cPluginCallback bool cPluginManager::AddPlugin(cPlugin * a_Plugin) { m_Plugins[a_Plugin->GetDirectory()] = a_Plugin; + if (a_Plugin->Initialize()) { // Initialization OK @@ -1849,7 +1848,7 @@ void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) { if (!a_Plugin) { - LOGWARN("Called cPluginManager::AddHook() with a_Plugin == NULL"); + LOGWARN("Called cPluginManager::AddHook() with a_Plugin == nullptr"); return; } PluginList & Plugins = m_Hooks[a_Hook]; diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index fff3bc323..bc8c1f5e6 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -178,26 +178,26 @@ public: size_t GetNumPlugins() const; // tolua_export // Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort - bool CallHookBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source); - bool CallHookBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups); - bool CallHookChat (cPlayer * a_Player, AString & a_Message); - bool CallHookChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ); - bool CallHookChunkGenerated (cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc); - bool CallHookChunkGenerating (cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc); - 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 (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); + bool CallHookBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source); + bool CallHookBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups); + bool CallHookChat (cPlayer & a_Player, AString & a_Message); + bool CallHookChunkAvailable (cWorld & a_World, int a_ChunkX, int a_ChunkZ); + bool CallHookChunkGenerated (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc); + bool CallHookChunkGenerating (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc); + 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 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 == NULL, it is a console cmd + bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == nullptr, it is a console cmd bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); - bool CallHookHandshake (cClientHandle * a_ClientHandle, const AString & a_Username); + bool CallHookHandshake (cClientHandle & a_ClientHandle, const AString & a_Username); bool CallHookHopperPullingItem (cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum); bool CallHookHopperPushingItem (cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum); bool CallHookKilling (cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI); - bool CallHookLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username); + bool CallHookLogin (cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username); bool CallHookPlayerAnimation (cPlayer & a_Player, int a_Animation); bool CallHookPlayerBreakingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); @@ -222,8 +222,8 @@ public: bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); bool CallHookPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message); bool CallHookPluginsLoaded (void); - bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); - bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); + bool CallHookPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe); + bool CallHookPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe); bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos); bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity); bool CallHookServerPing (cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); @@ -232,8 +232,8 @@ public: bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawningMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TDI); - bool CallHookUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player); - bool CallHookUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player); + bool CallHookUpdatedSign (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player); + bool CallHookUpdatingSign (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player); bool CallHookWeatherChanged (cWorld & a_World); bool CallHookWeatherChanging (cWorld & a_World, eWeather & a_NewWeather); bool CallHookWorldStarted (cWorld & a_World); @@ -264,10 +264,10 @@ public: AString GetCommandPermission(const AString & a_Command); // tolua_export /** Executes the command, as if it was requested by a_Player. Checks permissions first. Returns crExecuted if executed. */ - CommandResult ExecuteCommand(cPlayer * a_Player, const AString & a_Command); // tolua_export + CommandResult ExecuteCommand(cPlayer & a_Player, const AString & a_Command); // tolua_export /** Executes the command, as if it was requested by a_Player. Permisssions are not checked. Returns crExecuted if executed. */ - CommandResult ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command); // tolua_export + CommandResult ForceExecuteCommand(cPlayer & a_Player, const AString & a_Command); // tolua_export /** Removes all console command bindings that the specified plugin has made */ void RemovePluginConsoleCommands(cPlugin * a_Plugin); @@ -285,7 +285,7 @@ public: bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output); /** Appends all commands beginning with a_Text (case-insensitive) into a_Results. - If a_Player is not NULL, only commands for which the player has permissions are added. + If a_Player is not nullptr, only commands for which the player has permissions are added. */ void TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player); @@ -341,7 +341,7 @@ private: bool AddPlugin(cPlugin * a_Plugin); /** Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns crExecuted if the command is executed. */ - cPluginManager::CommandResult HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions); + CommandResult HandleCommand(cPlayer & a_Player, const AString & a_Command, bool a_ShouldCheckPermissions); } ; // tolua_export diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp index eca1c74e6..5759b20e7 100644 --- a/src/Bindings/WebPlugin.cpp +++ b/src/Bindings/WebPlugin.cpp @@ -12,7 +12,7 @@ cWebPlugin::cWebPlugin() { cWebAdmin * WebAdmin = cRoot::Get()->GetWebAdmin(); - if (WebAdmin != NULL) + if (WebAdmin != nullptr) { WebAdmin->AddPlugin(this); } @@ -25,7 +25,7 @@ cWebPlugin::cWebPlugin() cWebPlugin::~cWebPlugin() { cWebAdmin * WebAdmin = cRoot::Get()->GetWebAdmin(); - if (WebAdmin != NULL) + if (WebAdmin != nullptr) { WebAdmin->RemovePlugin(this); } @@ -65,7 +65,7 @@ std::pair< AString, AString > cWebPlugin::GetTabNameForRequest(const HTTPRequest if (Split.size() > 1) { - sWebPluginTab * Tab = NULL; + sWebPluginTab * Tab = nullptr; if (Split.size() > 2) // If we got the tab name, show that page { for (TabList::iterator itr = GetTabs().begin(); itr != GetTabs().end(); ++itr) @@ -85,7 +85,7 @@ std::pair< AString, AString > cWebPlugin::GetTabNameForRequest(const HTTPRequest } } - if (Tab != NULL) + if (Tab != nullptr) { Names.first = Tab->Title; Names.second = Tab->SafeTitle; diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua deleted file mode 100644 index 7f62573c7..000000000 --- a/src/Bindings/gen_LuaState_Call.lua +++ /dev/null @@ -1,224 +0,0 @@ - --- gen_LuaState_Call.lua - --- Generates the cLuaState::Call() function templates that are included from LuaState.h - ---[[ -The cLuaState::Call() family of functions provides a template-based system for calling any Lua function -either by name or by reference with almost any number of parameters and return values. This is done by -providing a number of overloads of the same name with variable number of template-type parameters. To -separate the arguments from the return values, a special type of cLuaState::cRet is used. ---]] - - - - -print("Generating LuaState_Call.inc . . .") - - - - --- List of combinations (# params, # returns) to generate: -local Combinations = -{ - -- no return values: - {0, 0}, - {1, 0}, - {2, 0}, - {3, 0}, - {4, 0}, - - -- 1 return value: - {0, 1}, - {1, 1}, - {2, 1}, - {3, 1}, - {4, 1}, - {5, 1}, - {6, 1}, - {7, 1}, - {8, 1}, - {9, 1}, - {10, 1}, - - -- 2 return values: - {0, 2}, - {1, 2}, - {2, 2}, - {3, 2}, - {4, 2}, - {5, 2}, - {6, 2}, - {7, 2}, - {8, 2}, - {9, 2}, - - -- Special combinations: - {5, 5}, - {7, 3}, - {8, 3}, - {9, 5}, -} - - - - ---- Writes a single overloaded function definition for the specified number of params and returns into f ---[[ -The format for the generated function is this: -/** Call the specified 3-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template <typename FnT, typename ParamT1, typename ParamT2, typename ParamT3, typename RetT1, typename RetT2> -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} -Note especially the negative numbers in GetStackValue() calls. ---]] -local function WriteOverload(f, a_NumParams, a_NumReturns) - -- Write the function doxy-comments: - f:write("/** Call the specified ", a_NumParams, "-param ", a_NumReturns, "-return Lua function:\n") - f:write("Returns true if call succeeded, false if there was an error. */\n") - - -- Write the template <...> line: - f:write("template <typename FnT") - for i = 1, a_NumParams do - f:write(", typename ParamT", i) - end - if (a_NumReturns > 0) then - for i = 1, a_NumReturns do - f:write(", typename RetT", i) - end - end - f:write(">\n") - - -- Write the function signature: - f:write("bool Call(") - f:write("const FnT & a_Function") - for i = 1, a_NumParams do - f:write(", ParamT", i, " a_Param", i) - end - if (a_NumReturns > 0) then - f:write(", const cLuaState::cRet & a_RetMark") - for i = 1, a_NumReturns do - f:write(", RetT", i, " & a_Ret", i) - end - end - f:write(")\n") - - -- Common code: - f:write("{\n") - if (a_NumReturns > 0) then - f:write("\tUNUSED(a_RetMark);\n") - end - f:write("\tif (!PushFunction(a_Function))\n") - f:write("\t{\n") - f:write("\t\treturn false;\n") - f:write("\t}\n") - - -- Push the params: - for i = 1, a_NumParams do - f:write("\tPush(a_Param", i, ");\n") - end - - -- Call the function: - f:write("\tif (!CallFunction(", a_NumReturns, "))\n") - f:write("\t{\n") - f:write("\t\treturn false;\n") - f:write("\t}\n") - - -- Get the return values: - for i = 1, a_NumReturns do - f:write("\tGetStackValue(", -1 - a_NumReturns + i, ", a_Ret", i, ");\n") - end - - -- Pop the returns off the stack, if needed: - if (a_NumReturns > 0) then - f:write("\tlua_pop(m_LuaState, ", a_NumReturns, ");\n") - end - - -- Everything ok: - f:write("\treturn true;\n") - f:write("}\n") - - -- Separate from the next function: - f:write("\n\n\n\n\n") -end - - - - - -local f = assert(io.open("LuaState_Call.inc", "w")) - --- Write file header: -f:write([[ -// LuaState_Call.inc - -// This file is auto-generated by gen_LuaState_Call.lua -// Make changes to the generator instead of to this file! - -// This file contains the various overloads for the cLuaState::Call() function -// Each overload handles a different number of parameters / return values -]]) -f:write("\n\n\n\n\n") - --- Write out a template function for each overload: -for _, combination in ipairs(Combinations) do - WriteOverload(f, combination[1], combination[2]) -end - --- Generate the cLuaState::GetStackValues() multi-param templates: -for i = 2, 6 do - f:write("/** Reads ", i, " consecutive values off the stack */\ntemplate <\n") - - -- Write the template function header: - local txt = {} - for idx = 1, i do - table.insert(txt, "\ttypename ArgT" .. idx) - end - f:write(table.concat(txt, ",\n")) - - -- Write the argument declarations: - txt = {} - f:write("\n>\nvoid GetStackValues(\n\tint a_BeginPos,\n") - for idx = 1, i do - table.insert(txt, "\tArgT" .. idx .. " & Arg" .. idx) - end - f:write(table.concat(txt, ",\n")) - - -- Write the function body: - f:write("\n)\n{\n") - for idx = 1, i do - f:write("\tGetStackValue(a_BeginPos + ", idx - 1, ", Arg", idx, ");\n") - end - f:write("}\n\n\n\n\n\n") -end - --- Close the generated file -f:close() - - - - - -print("LuaState_Call.inc generated.") - - - - diff --git a/src/Bindings/virtual_method_hooks.lua b/src/Bindings/virtual_method_hooks.lua index 8ad30bf78..a52728ff8 100644 --- a/src/Bindings/virtual_method_hooks.lua +++ b/src/Bindings/virtual_method_hooks.lua @@ -7,16 +7,6 @@ local default_private_access = false --- Code generators used by the build --- Note that these are not exactly needed for the bindings, but rather we --- misuse tolua's Lua engine to process files for us -dofile("gen_LuaState_Call.lua") - - - - - - local access = {public = 0, protected = 1, private = 2} function preparse_hook(p) diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp index 02f8c2232..188e06173 100644 --- a/src/BiomeDef.cpp +++ b/src/BiomeDef.cpp @@ -160,3 +160,65 @@ bool IsBiomeNoDownfall(EMCSBiome a_Biome) } } } + + + + + +bool IsBiomeVeryCold(EMCSBiome a_Biome) +{ + switch (a_Biome) + { + case biFrozenOcean: + case biFrozenRiver: + case biIcePlains: + case biIceMountains: + case biColdBeach: + case biColdTaiga: + case biColdTaigaHills: + case biIcePlainsSpikes: + case biColdTaigaM: + { + return true; + } + default: + { + return false; + } + } +} + + + + +bool IsBiomeCold(EMCSBiome a_Biome) +{ + switch (a_Biome) + { + case biExtremeHills: + case biTaiga: + case biTaigaHills: + case biExtremeHillsEdge: + case biStoneBeach: + case biMegaTaiga: + case biMegaTaigaHills: + case biExtremeHillsPlus: + case biExtremeHillsM: + case biTaigaM: + case biColdTaigaM: + case biMegaSpruceTaiga: + case biMegaSpruceTaigaHills: + case biExtremeHillsPlusM: + { + return true; + } + default: + { + return false; + } + } +} + + + + diff --git a/src/BiomeDef.h b/src/BiomeDef.h index f929596e9..84751cfd7 100644 --- a/src/BiomeDef.h +++ b/src/BiomeDef.h @@ -113,5 +113,20 @@ extern AString BiomeToString(int a_Biome); /** Returns true if the biome has no downfall - deserts and savannas */ extern bool IsBiomeNoDownfall(EMCSBiome a_Biome); +/** Returns true if the biome is an ocean biome. */ +inline bool IsBiomeOcean(int a_Biome) +{ + return ((a_Biome == biOcean) || (a_Biome == biDeepOcean)); +} + +/** Returns true if the biome is very cold +(has snow on ground everywhere, turns top water to ice, has snowfall instead of rain everywhere). +Doesn't report mildly cold biomes (where it snows above certain elevation), use IsBiomeCold() for those. */ +extern bool IsBiomeVeryCold(EMCSBiome a_Biome); + +/** Returns true if the biome is cold +(has snow and snowfall at higher elevations but not at regular heights). +Doesn't report Very Cold biomes, use IsBiomeVeryCold() for those. */ +extern bool IsBiomeCold(EMCSBiome a_Biome); // tolua_end diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index ba55528b8..4c3da0535 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -273,10 +273,10 @@ void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE // cBlockArea: cBlockArea::cBlockArea(void) : - m_BlockTypes(NULL), - m_BlockMetas(NULL), - m_BlockLight(NULL), - m_BlockSkyLight(NULL) + m_BlockTypes(nullptr), + m_BlockMetas(nullptr), + m_BlockLight(nullptr), + m_BlockSkyLight(nullptr) { } @@ -295,10 +295,10 @@ cBlockArea::~cBlockArea() void cBlockArea::Clear(void) { - delete[] m_BlockTypes; m_BlockTypes = NULL; - delete[] m_BlockMetas; m_BlockMetas = NULL; - delete[] m_BlockLight; m_BlockLight = NULL; - delete[] m_BlockSkyLight; m_BlockSkyLight = NULL; + delete[] m_BlockTypes; m_BlockTypes = nullptr; + delete[] m_BlockMetas; m_BlockMetas = nullptr; + delete[] m_BlockLight; m_BlockLight = nullptr; + delete[] m_BlockSkyLight; m_BlockSkyLight = nullptr; m_Origin.Set(0, 0, 0); m_Size.Set(0, 0, 0); } @@ -711,7 +711,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas(); NIBBLETYPE * DstMetas = m_BlockMetas; - bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL)); + bool IsDummyMetas = ((SrcMetas == nullptr) || (DstMetas == nullptr)); if (IsDummyMetas) { @@ -1013,8 +1013,8 @@ void cBlockArea::RotateCCW(void) } // for x std::swap(m_BlockTypes, NewTypes); std::swap(m_BlockMetas, NewMetas); - delete[] NewTypes; NewTypes = NULL; - delete[] NewMetas; NewMetas = NULL; + delete[] NewTypes; NewTypes = nullptr; + delete[] NewMetas; NewMetas = nullptr; std::swap(m_Size.x, m_Size.z); } @@ -1058,8 +1058,8 @@ void cBlockArea::RotateCW(void) } // for x std::swap(m_BlockTypes, NewTypes); std::swap(m_BlockMetas, NewMetas); - delete[] NewTypes; NewTypes = NULL; - delete[] NewMetas; NewMetas = NULL; + delete[] NewTypes; NewTypes = nullptr; + delete[] NewMetas; NewMetas = nullptr; std::swap(m_Size.x, m_Size.z); } @@ -1206,7 +1206,7 @@ void cBlockArea::RotateCCWNoMeta(void) } // for z } // for x std::swap(m_BlockTypes, NewTypes); - delete[] NewTypes; NewTypes = NULL; + delete[] NewTypes; NewTypes = nullptr; } if (HasBlockMetas()) { @@ -1224,7 +1224,7 @@ void cBlockArea::RotateCCWNoMeta(void) } // for z } // for x std::swap(m_BlockMetas, NewMetas); - delete[] NewMetas; NewMetas = NULL; + delete[] NewMetas; NewMetas = nullptr; } std::swap(m_Size.x, m_Size.z); } @@ -1251,7 +1251,7 @@ void cBlockArea::RotateCWNoMeta(void) } // for x } // for z std::swap(m_BlockTypes, NewTypes); - delete[] NewTypes; NewTypes = NULL; + delete[] NewTypes; NewTypes = nullptr; } if (HasBlockMetas()) { @@ -1269,7 +1269,7 @@ void cBlockArea::RotateCWNoMeta(void) } // for x } // for z std::swap(m_BlockMetas, NewMetas); - delete[] NewMetas; NewMetas = NULL; + delete[] NewMetas; NewMetas = nullptr; } std::swap(m_Size.x, m_Size.z); } @@ -1391,7 +1391,7 @@ void cBlockArea::MirrorYZNoMeta(void) void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType) { - if (m_BlockTypes == NULL) + if (m_BlockTypes == nullptr) { LOGWARNING("cBlockArea: BlockTypes have not been read!"); return; @@ -1468,7 +1468,7 @@ void cBlockArea::SetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBB BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const { - if (m_BlockTypes == NULL) + if (m_BlockTypes == nullptr) { LOGWARNING("cBlockArea: BlockTypes have not been read!"); return E_BLOCK_AIR; @@ -1555,7 +1555,7 @@ void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOC void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { int idx = MakeIndex(a_RelX, a_RelY, a_RelZ); - if (m_BlockTypes == NULL) + if (m_BlockTypes == nullptr) { LOGWARNING("%s: BlockTypes not available but requested to be written to.", __FUNCTION__); } @@ -1563,7 +1563,7 @@ void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, B { m_BlockTypes[idx] = a_BlockType; } - if (m_BlockMetas == NULL) + if (m_BlockMetas == nullptr) { LOGWARNING("%s: BlockMetas not available but requested to be written to.", __FUNCTION__); } @@ -1589,7 +1589,7 @@ void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOC void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const { int idx = MakeIndex(a_RelX, a_RelY, a_RelZ); - if (m_BlockTypes == NULL) + if (m_BlockTypes == nullptr) { LOGWARNING("cBlockArea: BlockTypes have not been read!"); a_BlockType = E_BLOCK_AIR; @@ -1599,7 +1599,7 @@ void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTY a_BlockType = m_BlockTypes[idx]; } - if (m_BlockMetas == NULL) + if (m_BlockMetas == nullptr) { LOGWARNING("cBlockArea: BlockMetas have not been read!"); a_BlockMeta = 0; @@ -1617,19 +1617,19 @@ void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTY int cBlockArea::GetDataTypes(void) const { int res = 0; - if (m_BlockTypes != NULL) + if (m_BlockTypes != nullptr) { res |= baTypes; } - if (m_BlockMetas != NULL) + if (m_BlockMetas != nullptr) { res |= baMetas; } - if (m_BlockLight != NULL) + if (m_BlockLight != nullptr) { res |= baLight; } - if (m_BlockSkyLight != NULL) + if (m_BlockSkyLight != nullptr) { res |= baSkyLight; } @@ -1642,12 +1642,12 @@ int cBlockArea::GetDataTypes(void) const bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes) { - ASSERT(m_BlockTypes == NULL); // Has been cleared + ASSERT(m_BlockTypes == nullptr); // Has been cleared if (a_DataTypes & baTypes) { m_BlockTypes = new BLOCKTYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockTypes == NULL) + if (m_BlockTypes == nullptr) { return false; } @@ -1655,36 +1655,36 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes) if (a_DataTypes & baMetas) { m_BlockMetas = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockMetas == NULL) + if (m_BlockMetas == nullptr) { delete[] m_BlockTypes; - m_BlockTypes = NULL; + m_BlockTypes = nullptr; return false; } } if (a_DataTypes & baLight) { m_BlockLight = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockLight == NULL) + if (m_BlockLight == nullptr) { delete[] m_BlockMetas; - m_BlockMetas = NULL; + m_BlockMetas = nullptr; delete[] m_BlockTypes; - m_BlockTypes = NULL; + m_BlockTypes = nullptr; return false; } } if (a_DataTypes & baSkyLight) { m_BlockSkyLight = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockSkyLight == NULL) + if (m_BlockSkyLight == nullptr) { delete[] m_BlockLight; - m_BlockLight = NULL; + m_BlockLight = nullptr; delete[] m_BlockMetas; - m_BlockMetas = NULL; + m_BlockMetas = nullptr; delete[] m_BlockTypes; - m_BlockTypes = NULL; + m_BlockTypes = nullptr; return false; } } @@ -1714,7 +1714,7 @@ int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array) { - if (a_Array == NULL) + if (a_Array == nullptr) { LOGWARNING("cBlockArea: datatype has not been read!"); return; @@ -1737,7 +1737,7 @@ void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE * a_Array) const { - if (a_Array == NULL) + if (a_Array == nullptr) { LOGWARNING("cBlockArea: datatype has not been read!"); return 16; @@ -1896,7 +1896,7 @@ void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer) } // Copy the blocktypes: - if (m_Area.m_BlockTypes != NULL) + if (m_Area.m_BlockTypes != nullptr) { for (int y = 0; y < SizeY; y++) { @@ -1917,7 +1917,7 @@ void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer) } // Copy the block metas: - if (m_Area.m_BlockMetas != NULL) + if (m_Area.m_BlockMetas != nullptr) { for (int y = 0; y < SizeY; y++) { @@ -1938,7 +1938,7 @@ void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer) } // Copy the blocklight: - if (m_Area.m_BlockLight != NULL) + if (m_Area.m_BlockLight != nullptr) { for (int y = 0; y < SizeY; y++) { @@ -1959,7 +1959,7 @@ void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer) } // Copy the skylight: - if (m_Area.m_BlockSkyLight != NULL) + if (m_Area.m_BlockSkyLight != nullptr) { for (int y = 0; y < SizeY; y++) { diff --git a/src/BlockArea.h b/src/BlockArea.h index 86f7c4f2d..348e960dd 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -282,10 +282,10 @@ public: /** Returns the datatypes that are stored in the object (bitmask of baXXX values) */ int GetDataTypes(void) const; - bool HasBlockTypes (void) const { return (m_BlockTypes != NULL); } - bool HasBlockMetas (void) const { return (m_BlockMetas != NULL); } - bool HasBlockLights (void) const { return (m_BlockLight != NULL); } - bool HasBlockSkyLights(void) const { return (m_BlockSkyLight != NULL); } + bool HasBlockTypes (void) const { return (m_BlockTypes != nullptr); } + bool HasBlockMetas (void) const { return (m_BlockMetas != nullptr); } + bool HasBlockLights (void) const { return (m_BlockLight != nullptr); } + bool HasBlockSkyLights(void) const { return (m_BlockSkyLight != nullptr); } // tolua_end diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index dcf659f47..85819446c 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -97,7 +97,7 @@ bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect) m_PrimaryEffect = a_Effect; // Send window update: - if (GetWindow() != NULL) + if (GetWindow() != nullptr) { GetWindow()->SetProperty(1, m_PrimaryEffect); } @@ -119,7 +119,7 @@ bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect) m_SecondaryEffect = a_Effect; // Send window update: - if (GetWindow() != NULL) + if (GetWindow() != nullptr) { GetWindow()->SetProperty(2, m_SecondaryEffect); } @@ -184,7 +184,7 @@ void cBeaconEntity::UpdateBeacon(void) if (m_BeaconLevel != OldBeaconLevel) { // Send window update: - if (GetWindow() != NULL) + if (GetWindow() != nullptr) { GetWindow()->SetProperty(0, m_BeaconLevel); } @@ -283,13 +283,13 @@ bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) void cBeaconEntity::UsedBy(cPlayer * a_Player) { cWindow * Window = GetWindow(); - if (Window == NULL) + if (Window == nullptr) { OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this)); Window = GetWindow(); } - if (Window != NULL) + if (Window != nullptr) { // if (a_Player->GetWindow() != Window) // -> Because mojang doesn't send a 'close window' packet when you click the cancel button in the beacon inventory ... @@ -303,68 +303,6 @@ void cBeaconEntity::UsedBy(cPlayer * a_Player) -bool cBeaconEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - Json::Value AllSlots = a_Value.get("Slots", 0); - int SlotIdx = 0; - for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) - { - cItem Item; - Item.FromJson(*itr); - SetSlot(SlotIdx, Item); - SlotIdx++; - } - - m_BeaconLevel = (char)a_Value.get("Level", 0).asInt(); - int PrimaryEffect = a_Value.get("PrimaryEffect", 0).asInt(); - int SecondaryEffect = a_Value.get("SecondaryEffect", 0).asInt(); - - if ((PrimaryEffect >= 0) && (PrimaryEffect <= (int)cEntityEffect::effSaturation)) - { - m_PrimaryEffect = (cEntityEffect::eType)PrimaryEffect; - } - - if ((SecondaryEffect >= 0) && (SecondaryEffect <= (int)cEntityEffect::effSaturation)) - { - m_SecondaryEffect = (cEntityEffect::eType)SecondaryEffect; - } - - return true; -} - - - - - -void cBeaconEntity::SaveToJson(Json::Value& a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - Json::Value AllSlots; - int NumSlots = m_Contents.GetNumSlots(); - for (int i = 0; i < NumSlots; i++) - { - Json::Value Slot; - m_Contents.GetSlot(i).GetJson(Slot); - AllSlots.append(Slot); - } - a_Value["Slots"] = AllSlots; - - a_Value["Level"] = m_BeaconLevel; - a_Value["PrimaryEffect"] = (int)m_PrimaryEffect; - a_Value["SecondaryEffect"] = (int)m_SecondaryEffect; -} - - - - - void cBeaconEntity::SendTo(cClientHandle & a_Client) { a_Client.SendUpdateBlockEntity(*this); diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 0d7150aef..d1db3a68f 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -32,11 +32,11 @@ class cBeaconEntity : public: // tolua_end + BLOCKENTITY_PROTODEF(cBeaconEntity); + cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - bool LoadFromJson(const Json::Value & a_Value); // cBlockEntity overrides: - virtual void SaveToJson(Json::Value& a_Value) override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual void UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index a969f493e..346970cd2 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -50,7 +50,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() ); ASSERT(!"Requesting creation of an unknown block entity"); - return NULL; + return nullptr; } diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index 11f185ce6..c778e97bc 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -5,6 +5,28 @@ +/** Place this macro in the declaration of each cBlockEntity descendant. */ +#define BLOCKENTITY_PROTODEF(classname) \ + virtual bool IsA(const char * a_ClassName) const override \ + { \ + return ((strcmp(a_ClassName, #classname) == 0) || super::IsA(a_ClassName)); \ + } \ + virtual const char * GetClass(void) const override \ + { \ + return #classname; \ + } \ + static const char * GetClassStatic(void) \ + { \ + return #classname; \ + } \ + virtual const char * GetParentClass(void) const override \ + { \ + return super::GetClass(); \ + } + + + + namespace Json { @@ -48,13 +70,22 @@ public: /// Creates a new block entity for the specified block type /// If a_World is valid, then the entity is created bound to that world - /// Returns NULL for unknown block types - static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World = NULL); + /// Returns nullptr for unknown block types + static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World = nullptr); static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates { return "cBlockEntity"; } + + /** Returns true if the object is the specified class, or its descendant. */ + virtual bool IsA(const char * a_ClassName) const { return (strcmp(a_ClassName, "cBlockEntity") == 0); } + + /** Returns the name of the tompost class (the most descendant). Used for Lua bindings to push the correct object type. */ + virtual const char * GetClass(void) const { return GetClassStatic(); } + + /** Returns the name of the parent class, or empty string if no parent class. */ + virtual const char * GetParentClass(void) const { return ""; } // tolua_begin @@ -74,8 +105,6 @@ public: int GetRelZ(void) const { return m_RelZ; } // tolua_end - - virtual void SaveToJson (Json::Value & a_Value) = 0; /// Called when a player uses this entity; should open the UI window virtual void UsedBy( cPlayer * a_Player) = 0; diff --git a/src/BlockEntities/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h index e511ee8cb..8c7d4749b 100644 --- a/src/BlockEntities/BlockEntityWithItems.h +++ b/src/BlockEntities/BlockEntityWithItems.h @@ -20,18 +20,17 @@ // tolua_begin class cBlockEntityWithItems : - public cBlockEntity - // tolua_end - // tolua doesn't seem to support multiple inheritance? - , public cItemGrid::cListener - , public cBlockEntityWindowOwner - // tolua_begin + public cBlockEntity, + public cItemGrid::cListener, + public cBlockEntityWindowOwner { typedef cBlockEntity super; - + public: // tolua_end + BLOCKENTITY_PROTODEF(cBlockEntityWithItems); + cBlockEntityWithItems( BLOCKTYPE a_BlockType, // Type of the block that the entity represents int a_BlockX, int a_BlockY, int a_BlockZ, // Position of the block entity @@ -39,6 +38,7 @@ public: cWorld * a_World // Optional world to assign to the entity ) : super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World), + cBlockEntityWindowOwner(this), m_Contents(a_ItemGridWidth, a_ItemGridHeight) { m_Contents.AddListener(*this); @@ -47,7 +47,7 @@ public: virtual void Destroy(void) override { // Drop the contents as pickups: - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); cItems Pickups; m_Contents.CopyToItems(Pickups); m_Contents.Clear(); @@ -78,9 +78,9 @@ protected: { UNUSED(a_SlotNum); ASSERT(a_Grid == &m_Contents); - if (m_World != NULL) + if (m_World != nullptr) { - if (GetWindow() != NULL) + if (GetWindow() != nullptr) { GetWindow()->BroadcastWholeWindow(); } diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 5447c7c49..0cd9c66e0 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -14,7 +14,6 @@ cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_ super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), m_NumActivePlayers(0) { - cBlockEntityWindowOwner::SetBlockEntity(this); } @@ -24,7 +23,7 @@ cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_ cChestEntity::~cChestEntity() { cWindow * Window = GetWindow(); - if (Window != NULL) + if (Window != nullptr) { Window->OwnerDestroyed(); } @@ -34,48 +33,6 @@ cChestEntity::~cChestEntity() -bool cChestEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - Json::Value AllSlots = a_Value.get("Slots", 0); - int SlotIdx = 0; - for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) - { - cItem Item; - Item.FromJson(*itr); - SetSlot(SlotIdx, Item); - SlotIdx++; - } - return true; -} - - - - - -void cChestEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - Json::Value AllSlots; - for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--) - { - Json::Value Slot; - m_Contents.GetSlot(i).GetJson(Slot); - AllSlots.append(Slot); - } - a_Value["Slots"] = AllSlots; -} - - - - - void cChestEntity::SendTo(cClientHandle & a_Client) { // The chest entity doesn't need anything sent to the client when it's created / gets in the viewdistance @@ -92,14 +49,14 @@ void cChestEntity::UsedBy(cPlayer * a_Player) { // If the window is not created, open it anew: cWindow * Window = GetWindow(); - if (Window == NULL) + if (Window == nullptr) { OpenNewWindow(); Window = GetWindow(); } // Open the window for the player: - if (Window != NULL) + if (Window != nullptr) { if (a_Player->GetWindow() != Window) { diff --git a/src/BlockEntities/ChestEntity.h b/src/BlockEntities/ChestEntity.h index fa36e08be..09fffb923 100644 --- a/src/BlockEntities/ChestEntity.h +++ b/src/BlockEntities/ChestEntity.h @@ -33,17 +33,14 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cChestEntity); + /** Constructor used for normal operation */ cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type); virtual ~cChestEntity(); - static const char * GetClassStatic(void) { return "cChestEntity"; } - - bool LoadFromJson(const Json::Value & a_Value); - // cBlockEntity overrides: - virtual void SaveToJson(Json::Value & a_Value) override; virtual void SendTo(cClientHandle & a_Client) override; virtual void UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 318874a9b..b7f938ffd 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -152,41 +152,9 @@ void cCommandBlockEntity::SendTo(cClientHandle & a_Client) -bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - m_Command = a_Value.get("Command", "").asString(); - m_LastOutput = a_Value.get("LastOutput", "").asString(); - m_Result = (NIBBLETYPE)a_Value.get("SuccessCount", 0).asInt(); - - return true; -} - - - - - -void cCommandBlockEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - a_Value["Command"] = m_Command; - a_Value["LastOutput"] = m_LastOutput; - a_Value["SuccessCount"] = m_Result; -} - - - - - void cCommandBlockEntity::Execute() { - ASSERT(m_World != NULL); // Execute should not be called before the command block is attached to a world + ASSERT(m_World != nullptr); // Execute should not be called before the command block is attached to a world if (!m_World->AreCommandBlocksEnabled()) { diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h index 22cd44322..217390293 100644 --- a/src/BlockEntities/CommandBlockEntity.h +++ b/src/BlockEntities/CommandBlockEntity.h @@ -36,12 +36,11 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cCommandBlockEntity); + /// Creates a new empty command block entity cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); - bool LoadFromJson( const Json::Value& a_Value); - virtual void SaveToJson(Json::Value& a_Value) override; - virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual void SendTo(cClientHandle & a_Client) override; virtual void UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 4794375cf..42a0476b6 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -14,7 +14,6 @@ cDispenserEntity::cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(E_BLOCK_DISPENSER, a_BlockX, a_BlockY, a_BlockZ, a_World) { - SetBlockEntity(this); // cBlockEntityWindowOwner } @@ -29,7 +28,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); AddDropSpenserDir(DispX, DispY, DispZ, Meta); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); - if (DispChunk == NULL) + if (DispChunk == nullptr) { // Would dispense into / interact with a non-loaded chunk, ignore the tick return; @@ -106,7 +105,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - if (m_World->SpawnMob(MobX, DispY, MobZ, (eMonsterType)m_Contents.GetSlot(a_SlotNum).m_ItemDamage) >= 0) + if (m_World->SpawnMob(MobX, DispY, MobZ, static_cast<eMonsterType>(m_Contents.GetSlot(a_SlotNum).m_ItemDamage)) >= 0) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -191,7 +190,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) void cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector) { - m_World->CreateProjectile((double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, a_Kind, NULL, NULL, &a_ShootVector); + m_World->CreateProjectile(static_cast<double>(a_BlockX + 0.5), static_cast<double>(a_BlockY + 0.5), static_cast<double>(a_BlockZ + 0.5), a_Kind, nullptr, nullptr, &a_ShootVector); } @@ -276,6 +275,3 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum m_Contents.AddItem(EmptyBucket); return true; } - - - diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index b33d08342..5ba87b716 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -17,11 +17,11 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cDispenserEntity); + /** Constructor used for normal operation */ cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - static const char * GetClassStatic(void) { return "cDispenserEntity"; } - // tolua_begin /** Spawns a projectile of the given kind in front of the dispenser with the specified speed. */ diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp index 260c71641..3f98836e7 100644 --- a/src/BlockEntities/DropSpenserEntity.cpp +++ b/src/BlockEntities/DropSpenserEntity.cpp @@ -18,7 +18,6 @@ cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int m_ShouldDropSpense(false), m_IsPowered(false) { - SetBlockEntity(this); // cBlockEntityWindowOwner } @@ -29,7 +28,7 @@ cDropSpenserEntity::~cDropSpenserEntity() { // Tell window its owner is destroyed cWindow * Window = GetWindow(); - if (Window != NULL) + if (Window != nullptr) { Window->OwnerDestroyed(); } @@ -143,54 +142,6 @@ bool cDropSpenserEntity::Tick(float a_Dt, cChunk & a_Chunk) -bool cDropSpenserEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - Json::Value AllSlots = a_Value.get("Slots", 0); - int SlotIdx = 0; - for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) - { - cItem Contents; - Contents.FromJson(*itr); - m_Contents.SetSlot(SlotIdx, Contents); - SlotIdx++; - if (SlotIdx >= m_Contents.GetNumSlots()) - { - return true; - } - } - - return true; -} - - - - - -void cDropSpenserEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - Json::Value AllSlots; - int NumSlots = m_Contents.GetNumSlots(); - for (int i = 0; i < NumSlots; i++) - { - Json::Value Slot; - m_Contents.GetSlot(i).GetJson(Slot); - AllSlots.append(Slot); - } - a_Value["Slots"] = AllSlots; -} - - - - - void cDropSpenserEntity::SendTo(cClientHandle & a_Client) { // Nothing needs to be sent @@ -204,13 +155,13 @@ void cDropSpenserEntity::SendTo(cClientHandle & a_Client) void cDropSpenserEntity::UsedBy(cPlayer * a_Player) { cWindow * Window = GetWindow(); - if (Window == NULL) + if (Window == nullptr) { OpenWindow(new cDropSpenserWindow(m_PosX, m_PosY, m_PosZ, this)); Window = GetWindow(); } - if (Window != NULL) + if (Window != nullptr) { if (a_Player->GetWindow() != Window) { diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h index c70cd0531..f77a28c28 100644 --- a/src/BlockEntities/DropSpenserEntity.h +++ b/src/BlockEntities/DropSpenserEntity.h @@ -45,15 +45,12 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cDropSpenserEntity); + cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); virtual ~cDropSpenserEntity(); - static const char * GetClassStatic(void) { return "cDropSpenserEntity"; } - - bool LoadFromJson(const Json::Value & a_Value); - // cBlockEntity overrides: - virtual void SaveToJson(Json::Value & a_Value) override; virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual void SendTo(cClientHandle & a_Client) override; virtual void UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/DropperEntity.cpp b/src/BlockEntities/DropperEntity.cpp index 5cbf6d56e..38d1aa988 100644 --- a/src/BlockEntities/DropperEntity.cpp +++ b/src/BlockEntities/DropperEntity.cpp @@ -13,7 +13,6 @@ cDropperEntity::cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(E_BLOCK_DROPPER, a_BlockX, a_BlockY, a_BlockZ, a_World) { - SetBlockEntity(this); // cBlockEntityWindowOwner } diff --git a/src/BlockEntities/DropperEntity.h b/src/BlockEntities/DropperEntity.h index 8e07bc6f8..91adf660f 100644 --- a/src/BlockEntities/DropperEntity.h +++ b/src/BlockEntities/DropperEntity.h @@ -25,11 +25,11 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cDropperEntity); + /// Constructor used for normal operation cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - static const char * GetClassStatic(void) { return "cDropperEntity"; } - protected: // cDropSpenserEntity overrides: virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override; diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp index b870f9e50..e18490a1e 100644 --- a/src/BlockEntities/EnderChestEntity.cpp +++ b/src/BlockEntities/EnderChestEntity.cpp @@ -11,7 +11,8 @@ cEnderChestEntity::cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : - super(E_BLOCK_ENDER_CHEST, a_BlockX, a_BlockY, a_BlockZ, a_World) + super(E_BLOCK_ENDER_CHEST, a_BlockX, a_BlockY, a_BlockZ, a_World), + cBlockEntityWindowOwner(this) { } @@ -22,7 +23,7 @@ cEnderChestEntity::cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c cEnderChestEntity::~cEnderChestEntity() { cWindow * Window = GetWindow(); - if (Window != NULL) + if (Window != nullptr) { Window->OwnerDestroyed(); } @@ -36,14 +37,14 @@ void cEnderChestEntity::UsedBy(cPlayer * a_Player) { // If the window is not created, open it anew: cWindow * Window = GetWindow(); - if (Window == NULL) + if (Window == nullptr) { OpenNewWindow(); Window = GetWindow(); } // Open the window for the player: - if (Window != NULL) + if (Window != nullptr) { if (a_Player->GetWindow() != Window) { diff --git a/src/BlockEntities/EnderChestEntity.h b/src/BlockEntities/EnderChestEntity.h index 311af8d76..17abd880a 100644 --- a/src/BlockEntities/EnderChestEntity.h +++ b/src/BlockEntities/EnderChestEntity.h @@ -18,14 +18,13 @@ class cEnderChestEntity : public: // tolua_end + BLOCKENTITY_PROTODEF(cEnderChestEntity); + cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); virtual ~cEnderChestEntity(); - static const char * GetClassStatic(void) { return "cEnderChestEntity"; } - // cBlockEntity overrides: virtual void UsedBy(cPlayer * a_Player) override; - virtual void SaveToJson(Json::Value & a_Value) override { UNUSED(a_Value); } virtual void SendTo(cClientHandle & a_Client) override { UNUSED(a_Client); } static void LoadFromJson(const Json::Value & a_Value, cItemGrid & a_Grid); diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp index d2bc59d34..64b7edd02 100644 --- a/src/BlockEntities/FlowerPotEntity.cpp +++ b/src/BlockEntities/FlowerPotEntity.cpp @@ -28,7 +28,7 @@ void cFlowerPotEntity::UsedBy(cPlayer * a_Player) { return; } - + cItem SelectedItem = a_Player->GetInventory().GetEquippedItem(); if (IsFlower(SelectedItem.m_ItemType, SelectedItem.m_ItemDamage)) { @@ -59,11 +59,11 @@ void cFlowerPotEntity::Destroy(void) // Drop the contents as pickups: if (!m_Item.IsEmpty()) { - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); cItems Pickups; Pickups.Add(m_Item); m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5); - + m_Item.Empty(); } } @@ -72,37 +72,6 @@ void cFlowerPotEntity::Destroy(void) -bool cFlowerPotEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - m_Item = cItem(); - m_Item.FromJson(a_Value.get("Item", 0)); - - return true; -} - - - - - -void cFlowerPotEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - Json::Value Item; - m_Item.GetJson(Item); - a_Value["Item"] = Item; -} - - - - - bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData) { switch (m_ItemType) @@ -119,7 +88,7 @@ bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData) } case E_BLOCK_TALL_GRASS: { - return (m_ItemData == (short) 2); + return (m_ItemData == static_cast<short>(2)); } default: { @@ -127,7 +96,3 @@ bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData) } } } - - - - diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h index b86f9c840..fc886c51f 100644 --- a/src/BlockEntities/FlowerPotEntity.h +++ b/src/BlockEntities/FlowerPotEntity.h @@ -36,11 +36,10 @@ public: // tolua_end - /** Creates a new flowerpot entity at the specified block coords. a_World may be NULL */ + 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); - - bool LoadFromJson( const Json::Value& a_Value); - virtual void SaveToJson(Json::Value& a_Value) override; virtual void Destroy(void) override; @@ -62,8 +61,6 @@ public: static bool IsFlower(short m_ItemType, short m_ItemData); - static const char * GetClassStatic(void) { return "cFlowerPotEntity"; } - private: cItem m_Item; diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index d7b2fd910..d2ec2bd1e 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -5,6 +5,7 @@ #include "../UI/Window.h" #include "../Entities/Player.h" #include "../Root.h" +#include "../Chunk.h" @@ -13,8 +14,9 @@ enum { - PROGRESSBAR_SMELTING = 0, - PROGRESSBAR_FUEL = 1, + PROGRESSBAR_FUEL = 0, + PROGRESSBAR_SMELTING = 2, + PROGRESSBAR_SMELTING_CONFIRM = 3, } ; @@ -22,19 +24,16 @@ enum cFurnaceEntity::cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World) : - super(E_BLOCK_FURNACE, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), - m_BlockType(a_BlockType), + super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), m_BlockMeta(a_BlockMeta), - m_CurrentRecipe(NULL), - m_IsCooking((a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_LIT_FURNACE)), + m_CurrentRecipe(nullptr), + m_IsDestroyed(false), + m_IsCooking(a_BlockType == E_BLOCK_LIT_FURNACE), m_NeedCookTime(0), m_TimeCooked(0), m_FuelBurnTime(0), - m_TimeBurned(0), - m_LastProgressFuel(0), - m_LastProgressCook(0) + m_TimeBurned(0) { - cBlockEntityWindowOwner::SetBlockEntity(this); m_Contents.AddListener(*this); } @@ -46,7 +45,7 @@ cFurnaceEntity::~cFurnaceEntity() { // Tell window its owner is destroyed cWindow * Window = GetWindow(); - if (Window != NULL) + if (Window != nullptr) { Window->OwnerDestroyed(); } @@ -58,27 +57,28 @@ cFurnaceEntity::~cFurnaceEntity() void cFurnaceEntity::UsedBy(cPlayer * a_Player) { - if (GetWindow() == NULL) + cWindow * Window = GetWindow(); + if (Window == nullptr) { OpenWindow(new cFurnaceWindow(m_PosX, m_PosY, m_PosZ, this)); + Window = GetWindow(); } - cWindow * Window = GetWindow(); - if (Window != NULL) + + if (Window != nullptr) { if (a_Player->GetWindow() != Window) { a_Player->OpenWindow(Window); - BroadcastProgress(PROGRESSBAR_FUEL, (short)m_LastProgressFuel); - BroadcastProgress(PROGRESSBAR_SMELTING, (short)m_LastProgressCook); } } + + UpdateProgressBars(true); } -/// Restarts cooking. Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active. Returns true if cooking. bool cFurnaceEntity::ContinueCooking(void) { UpdateInput(); @@ -93,14 +93,16 @@ bool cFurnaceEntity::ContinueCooking(void) bool cFurnaceEntity::Tick(float a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); - UNUSED(a_Chunk); + if (m_FuelBurnTime <= 0) { - // No fuel is burning, reset progressbars and bail out - if ((m_LastProgressCook > 0) || (m_LastProgressFuel > 0)) - { - UpdateProgressBars(); - } + // If a furnace is out of fuel, the progress bar reverses at twice the speed of cooking. + m_TimeCooked = std::max((m_TimeCooked - 2), 0); + + // Reset progressbars, block type, and bail out + m_BlockType = E_BLOCK_FURNACE; + a_Chunk.FastSetBlock(GetRelX(), m_PosY, GetRelZ(), E_BLOCK_FURNACE, m_BlockMeta); + UpdateProgressBars(); return false; } @@ -113,43 +115,15 @@ bool cFurnaceEntity::Tick(float a_Dt, cChunk & a_Chunk) FinishOne(); } } - + m_TimeBurned++; if (m_TimeBurned >= m_FuelBurnTime) { // The current fuel has been exhausted, use another one, if possible BurnNewFuel(); } - - UpdateProgressBars(); - - return true; -} - - - - - -bool cFurnaceEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - Json::Value AllSlots = a_Value.get("Slots", 0); - int SlotIdx = 0; - for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) - { - cItem Item; - Item.FromJson(*itr); - SetSlot(SlotIdx, Item); - SlotIdx++; - } - m_NeedCookTime = (int)(a_Value.get("CookTime", 0).asDouble() / 50); - m_TimeCooked = (int)(a_Value.get("TimeCooked", 0).asDouble() / 50); - m_FuelBurnTime = (int)(a_Value.get("BurnTime", 0).asDouble() / 50); - m_TimeBurned = (int)(a_Value.get("TimeBurned", 0).asDouble() / 50); + UpdateProgressBars(); return true; } @@ -158,32 +132,6 @@ bool cFurnaceEntity::LoadFromJson(const Json::Value & a_Value) -void cFurnaceEntity::SaveToJson( Json::Value& a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - Json::Value AllSlots; - int NumSlots = m_Contents.GetNumSlots(); - for (int i = 0; i < NumSlots; i++) - { - Json::Value Slot; - m_Contents.GetSlot(i).GetJson(Slot); - AllSlots.append(Slot); - } - a_Value["Slots"] = AllSlots; - - a_Value["CookTime"] = m_NeedCookTime * 50; - a_Value["TimeCooked"] = m_TimeCooked * 50; - a_Value["BurnTime"] = m_FuelBurnTime * 50; - a_Value["TimeBurned"] = m_TimeBurned * 50; -} - - - - - void cFurnaceEntity::SendTo(cClientHandle & a_Client) { // Nothing needs to be sent @@ -194,12 +142,12 @@ void cFurnaceEntity::SendTo(cClientHandle & a_Client) -void cFurnaceEntity::BroadcastProgress(int a_ProgressbarID, short a_Value) +void cFurnaceEntity::BroadcastProgress(short a_ProgressbarID, short a_Value) { cWindow * Window = GetWindow(); - if (Window != NULL) + if (Window != nullptr) { - Window->BroadcastProgress(a_ProgressbarID, a_Value); + Window->SetProperty(a_ProgressbarID, a_Value); } } @@ -207,7 +155,6 @@ void cFurnaceEntity::BroadcastProgress(int a_ProgressbarID, short a_Value) -/// One item finished cooking void cFurnaceEntity::FinishOne() { m_TimeCooked = 0; @@ -221,8 +168,6 @@ void cFurnaceEntity::FinishOne() m_Contents.ChangeSlotCount(fsOutput, m_CurrentRecipe->Out->m_ItemCount); } m_Contents.ChangeSlotCount(fsInput, -m_CurrentRecipe->In->m_ItemCount); - - UpdateIsCooking(); } @@ -236,12 +181,11 @@ void cFurnaceEntity::BurnNewFuel(void) if (NewTime == 0) { // The item in the fuel slot is not suitable - m_FuelBurnTime = 0; - m_TimeBurned = 0; + SetBurnTimes(0, 0); SetIsCooking(false); return; } - + // Is the input and output ready for cooking? if (!CanCookInputToOutput()) { @@ -249,8 +193,7 @@ void cFurnaceEntity::BurnNewFuel(void) } // Burn one new fuel: - m_FuelBurnTime = NewTime; - m_TimeBurned = 0; + SetBurnTimes(NewTime, 0); SetIsCooking(true); if (m_Contents.GetSlot(fsFuel).m_ItemType == E_ITEM_LAVA_BUCKET) { @@ -269,33 +212,19 @@ void cFurnaceEntity::BurnNewFuel(void) void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) { super::OnSlotChanged(a_ItemGrid, a_SlotNum); - - if (m_World == NULL) + + if (m_IsDestroyed) { - // The furnace isn't initialized yet, do no processing return; } - + ASSERT(a_ItemGrid == &m_Contents); switch (a_SlotNum) { - case fsInput: - { - UpdateInput(); - break; - } - - case fsFuel: - { - UpdateFuel(); - break; - } - - case fsOutput: - { - UpdateOutput(); - break; - } + case fsInput: UpdateInput(); break; + case fsFuel: UpdateFuel(); break; + case fsOutput: UpdateOutput(); break; + default: ASSERT(!"Invalid furnace slot update!"); break; } } @@ -304,7 +233,6 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) -/// Updates the current recipe, based on the current input void cFurnaceEntity::UpdateInput(void) { if (!m_Contents.GetSlot(fsInput).IsEqual(m_LastInput)) @@ -313,20 +241,20 @@ void cFurnaceEntity::UpdateInput(void) m_TimeCooked = 0; } m_LastInput = m_Contents.GetSlot(fsInput); - + cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe(); m_CurrentRecipe = FR->GetRecipeFrom(m_Contents.GetSlot(fsInput)); if (!CanCookInputToOutput()) { - // This input cannot be cooked - m_NeedCookTime = 0; + // This input cannot be cooked, reset cook counter immediately + SetCookTimes(0, 0); SetIsCooking(false); } else { m_NeedCookTime = m_CurrentRecipe->CookTime; SetIsCooking(true); - + // Start burning new fuel if there's no flame now: if (GetFuelBurnTimeLeft() <= 0) { @@ -339,7 +267,6 @@ void cFurnaceEntity::UpdateInput(void) -/// Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropriate void cFurnaceEntity::UpdateFuel(void) { if (m_FuelBurnTime > m_TimeBurned) @@ -347,7 +274,7 @@ void cFurnaceEntity::UpdateFuel(void) // The current fuel is still burning, don't modify anything: return; } - + // The current fuel is spent, try to burn some more: BurnNewFuel(); } @@ -356,18 +283,16 @@ void cFurnaceEntity::UpdateFuel(void) -/// Called when the output slot changes; starts burning if space became available void cFurnaceEntity::UpdateOutput(void) { if (!CanCookInputToOutput()) { // Cannot cook anymore: - m_TimeCooked = 0; - m_NeedCookTime = 0; + SetCookTimes(0, 0); SetIsCooking(false); return; } - + // No need to burn new fuel, the Tick() function will take care of that // Can cook, start cooking if not already underway: @@ -379,38 +304,14 @@ void cFurnaceEntity::UpdateOutput(void) -/// Updates the m_IsCooking, based on the input slot, output slot and m_FuelBurnTime / m_TimeBurned -void cFurnaceEntity::UpdateIsCooking(void) -{ - if ( - !CanCookInputToOutput() || // Cannot cook this - (m_FuelBurnTime <= 0) || // No fuel - (m_TimeBurned >= m_FuelBurnTime) // Fuel burnt out - ) - { - // Reset everything - SetIsCooking(false); - m_TimeCooked = 0; - m_NeedCookTime = 0; - return; - } - - SetIsCooking(true); -} - - - - - -/// Returns true if the input can be cooked into output and the item counts allow for another cooking operation bool cFurnaceEntity::CanCookInputToOutput(void) const { - if (m_CurrentRecipe == NULL) + if (m_CurrentRecipe == nullptr) { // This input cannot be cooked return false; } - + const cItem & Slot = m_Contents.GetSlot(fsOutput); if (Slot.IsEmpty()) { @@ -423,13 +324,13 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const // The output slot is blocked with something that cannot be stacked with the recipe's output return false; } - + if (Slot.IsFullStack()) { // Cannot add any more items to the output slot return false; } - + return true; } @@ -437,25 +338,20 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const -/// Broadcasts progressbar updates, if needed -void cFurnaceEntity::UpdateProgressBars(void) +void cFurnaceEntity::UpdateProgressBars(bool a_ForceUpdate) { // In order to preserve bandwidth, an update is sent only every 10th tick - // That's why the comparisons use the division by eight - - int CurFuel = (m_FuelBurnTime > 0) ? (200 - 200 * m_TimeBurned / m_FuelBurnTime) : 0; - if ((CurFuel / 8) != (m_LastProgressFuel / 8)) + if (!a_ForceUpdate && (m_World->GetWorldAge() % 10 != 0)) { - BroadcastProgress(PROGRESSBAR_FUEL, (short)CurFuel); - m_LastProgressFuel = CurFuel; + return; } + + int CurFuel = (m_FuelBurnTime > 0) ? 200 - (200 * m_TimeBurned / m_FuelBurnTime) : 0; + BroadcastProgress(PROGRESSBAR_FUEL, static_cast<short>(CurFuel)); int CurCook = (m_NeedCookTime > 0) ? (200 * m_TimeCooked / m_NeedCookTime) : 0; - if ((CurCook / 8) != (m_LastProgressCook / 8)) - { - BroadcastProgress(PROGRESSBAR_SMELTING, (short)CurCook); - m_LastProgressCook = CurCook; - } + BroadcastProgress(PROGRESSBAR_SMELTING_CONFIRM, 200); // Post 1.8, Mojang requires a random packet with an ID of three and value of 200. Wat. Wat. Wat. + BroadcastProgress(PROGRESSBAR_SMELTING, static_cast<short>(CurCook)); } @@ -468,13 +364,12 @@ void cFurnaceEntity::SetIsCooking(bool a_IsCooking) { return; } - m_IsCooking = a_IsCooking; - - // Light or extinguish the furnace: - m_World->FastSetBlock(m_PosX, m_PosY, m_PosZ, m_IsCooking ? E_BLOCK_LIT_FURNACE : E_BLOCK_FURNACE, m_BlockMeta); -} - - - + // Only light the furnace as it is extinguished only when the fuel runs out, not when cooking stops - handled in this::Tick() + if (m_IsCooking) + { + m_BlockType = E_BLOCK_LIT_FURNACE; + m_World->FastSetBlock(m_PosX, m_PosY, m_PosZ, E_BLOCK_LIT_FURNACE, m_BlockMeta); + } +} diff --git a/src/BlockEntities/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h index 7ac25cf52..71c2fe127 100644 --- a/src/BlockEntities/FurnaceEntity.h +++ b/src/BlockEntities/FurnaceEntity.h @@ -38,117 +38,128 @@ public: // tolua_end - /// Constructor used for normal operation + 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); virtual ~cFurnaceEntity(); - static const char * GetClassStatic() { return "cFurnaceEntity"; } - - bool LoadFromJson(const Json::Value & a_Value); - // cBlockEntity overrides: - virtual void SaveToJson(Json::Value & a_Value) override; virtual void SendTo(cClientHandle & a_Client) override; virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual void UsedBy(cPlayer * a_Player) override; + virtual void Destroy() override + { + m_IsDestroyed = true; + super::Destroy(); + } - /// Restarts cooking. Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active. Returns true if cooking. + /** Restarts cooking + Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active + Returns true if cooking */ bool ContinueCooking(void); - - void ResetCookTimer(); // tolua_begin - /// Returns the item in the input slot + /** Returns the item in the input slot */ const cItem & GetInputSlot(void) const { return GetSlot(fsInput); } - /// Returns the item in the fuel slot + /** Returns the item in the fuel slot */ const cItem & GetFuelSlot(void) const { return GetSlot(fsFuel); } - /// Returns the item in the output slot + /** Returns the item in the output slot */ const cItem & GetOutputSlot(void) const { return GetSlot(fsOutput); } - /// Sets the item in the input slot + /** Sets the item in the input slot */ void SetInputSlot(const cItem & a_Item) { SetSlot(fsInput, a_Item); } - /// Sets the item in the fuel slot + /** Sets the item in the fuel slot */ void SetFuelSlot(const cItem & a_Item) { SetSlot(fsFuel, a_Item); } - /// Sets the item in the output slot + /** Sets the item in the output slot */ void SetOutputSlot(const cItem & a_Item) { SetSlot(fsOutput, a_Item); } - /// Returns the time that the current item has been cooking, in ticks - int GetTimeCooked(void) const {return m_TimeCooked; } + /** Returns the time that the current item has been cooking, in ticks */ + int GetTimeCooked(void) const { return m_TimeCooked; } - /// Returns the time until the current item finishes cooking, in ticks + /** Returns the time until the current item finishes cooking, in ticks */ int GetCookTimeLeft(void) const { return m_NeedCookTime - m_TimeCooked; } - /// Returns the time until the current fuel is depleted, in ticks - int GetFuelBurnTimeLeft(void) const {return m_FuelBurnTime - m_TimeBurned; } + /** Returns the time until the current fuel is depleted, in ticks */ + int GetFuelBurnTimeLeft(void) const { return m_FuelBurnTime - m_TimeBurned; } - /// Returns true if there's time left before the current fuel is depleted + /** Returns true if there's time left before the current fuel is depleted */ bool HasFuelTimeLeft(void) const { return (GetFuelBurnTimeLeft() > 0); } // tolua_end - void SetBurnTimes(int a_FuelBurnTime, int a_TimeBurned) {m_FuelBurnTime = a_FuelBurnTime; m_TimeBurned = a_TimeBurned; } - void SetCookTimes(int a_NeedCookTime, int a_TimeCooked) {m_NeedCookTime = a_NeedCookTime; m_TimeCooked = a_TimeCooked; } + void SetBurnTimes(int a_FuelBurnTime, int a_TimeBurned) + { + m_FuelBurnTime = a_FuelBurnTime; + m_TimeBurned = a_TimeBurned; + } + + void SetCookTimes(int a_NeedCookTime, int a_TimeCooked) + { + m_NeedCookTime = a_NeedCookTime; + m_TimeCooked = a_TimeCooked; + } protected: - - /// Block type of the block currently represented by this entity (changes when furnace lights up) - BLOCKTYPE m_BlockType; - /// Block meta of the block currently represented by this entity + /** Block meta of the block currently represented by this entity */ NIBBLETYPE m_BlockMeta; - /// The recipe for the current input slot + /** The recipe for the current input slot */ const cFurnaceRecipe::cRecipe * m_CurrentRecipe; - /// The item that is being smelted + /** The item that is being smelted */ cItem m_LastInput; + + /** Set to true when the furnace entity has been destroyed to prevent the block being set again */ + bool m_IsDestroyed; - bool m_IsCooking; ///< Set to true if the furnace is cooking an item - - // All timers are in ticks - int m_NeedCookTime; ///< Amount of time needed to fully cook current item - int m_TimeCooked; ///< Amount of time that the current item has been cooking - int m_FuelBurnTime; ///< Amount of time that the current fuel can burn (in total); zero if no fuel burning - int m_TimeBurned; ///< Amount of time that the current fuel has been burning - - int m_LastProgressFuel; ///< Last value sent as the progress for the fuel - int m_LastProgressCook; ///< Last value sent as the progress for the cooking + /** Set to true if the furnace is cooking an item */ + bool m_IsCooking; + /** Amount of ticks needed to fully cook current item */ + int m_NeedCookTime; + + /** Amount of ticks that the current item has been cooking */ + int m_TimeCooked; + + /** Amount of ticks that the current fuel can burn (in total); zero if no fuel burning */ + int m_FuelBurnTime; + + /** Amount of ticks that the current fuel has been burning */ + int m_TimeBurned; - /// Sends the specified progressbar value to all clients of the window - void BroadcastProgress(int a_ProgressbarID, short a_Value); + /** Sends the specified progressbar value to all clients of the window */ + void BroadcastProgress(short a_ProgressbarID, short a_Value); - /// One item finished cooking + /** One item finished cooking */ void FinishOne(); - /// Starts burning a new fuel, if possible + /** Starts burning a new fuel, if possible */ void BurnNewFuel(void); - /// Updates the recipe, based on the current input + /** Updates the recipe, based on the current input */ void UpdateInput(void); - /// Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropriate + /** Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropriate */ void UpdateFuel(void); - /// Called when the output slot changes + /** Called when the output slot changes */ void UpdateOutput(void); - /// Updates the m_IsCooking, based on the input slot, output slot and m_FuelBurnTime / m_TimeBurned - void UpdateIsCooking(void); - - /// Returns true if the input can be cooked into output and the item counts allow for another cooking operation + /** Returns true if the input can be cooked into output and the item counts allow for another cooking operation */ bool CanCookInputToOutput(void) const; - /// Broadcasts progressbar updates, if needed - void UpdateProgressBars(void); + /** Broadcasts progressbar updates, if needed */ + void UpdateProgressBars(bool a_ForceUpdate = false); - /// Sets the m_IsCooking variable, updates the furnace block type based on the value + /** Sets the m_IsCooking variable, updates the furnace block type based on the value */ void SetIsCooking(bool a_IsCooking); // cItemGrid::cListener overrides: diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index 444378c92..fe3fb85c4 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -58,7 +58,7 @@ bool cHopperEntity::Tick(float a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge(); - + bool res = false; res = MoveItemsIn (a_Chunk, CurrentTick) || res; res = MovePickupsIn(a_Chunk, CurrentTick) || res; @@ -70,22 +70,11 @@ bool cHopperEntity::Tick(float a_Dt, cChunk & a_Chunk) -void cHopperEntity::SaveToJson(Json::Value & a_Value) -{ - UNUSED(a_Value); - // TODO - LOGWARNING("%s: Not implemented yet", __FUNCTION__); -} - - - - - void cHopperEntity::SendTo(cClientHandle & a_Client) { // The hopper entity doesn't need anything sent to the client when it's created / gets in the viewdistance // All the actual handling is in the cWindow UI code that gets called when the hopper is rclked - + UNUSED(a_Client); } @@ -97,14 +86,14 @@ void cHopperEntity::UsedBy(cPlayer * a_Player) { // If the window is not created, open it anew: cWindow * Window = GetWindow(); - if (Window == NULL) + if (Window == nullptr) { OpenNewWindow(); Window = GetWindow(); } - + // Open the window for the player: - if (Window != NULL) + if (Window != nullptr) { if (a_Player->GetWindow() != Window) { @@ -149,7 +138,7 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick) // Too early after the previous transfer return false; } - + // Try moving an item in: bool res = false; switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ)) @@ -172,17 +161,17 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick) case E_BLOCK_DROPPER: case E_BLOCK_HOPPER: { - res = MoveItemsFromGrid(*(cBlockEntityWithItems *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)); + res = MoveItemsFromGrid(*static_cast<cBlockEntityWithItems *>(a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ))); break; } } - + // If the item has been moved, reset the last tick: if (res) { m_LastMoveItemsInTick = a_CurrentTick; } - + return res; } @@ -208,7 +197,7 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick) virtual bool Item(cEntity * a_Entity) override { - ASSERT(a_Entity != NULL); + ASSERT(a_Entity != nullptr); if (!a_Entity->IsPickup() || a_Entity->IsDestroyed()) { @@ -216,12 +205,12 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick) } Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_Pos.x + 0.5f, (float)m_Pos.y + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards + Vector3f BlockPos(m_Pos.x + 0.5f, static_cast<float>(m_Pos.y) + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards double Distance = (EntityPos - BlockPos).Length(); if (Distance < 0.5) { - if (TrySuckPickupIn((cPickup *)a_Entity)) + if (TrySuckPickupIn(static_cast<cPickup *>(a_Entity))) { return false; } @@ -249,9 +238,9 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick) m_bFoundPickupsAbove = true; int PreviousCount = m_Contents.GetSlot(i).m_ItemCount; - + Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added - + if (Item.IsEmpty()) { a_Pickup->Destroy(); // Kill pickup if all items were added @@ -291,7 +280,7 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) // Too early after the previous transfer return false; } - + // Get the coords of the block where to output items: int OutX, OutY, OutZ; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); @@ -305,17 +294,17 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) // Cannot output below the zero-th block level return false; } - + // Convert coords to relative: int OutRelX = OutX - a_Chunk.GetPosX() * cChunkDef::Width; int OutRelZ = OutZ - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(OutRelX, OutRelZ); - if (DestChunk == NULL) + if (DestChunk == nullptr) { // The destination chunk has been unloaded, don't tick return false; } - + // Call proper moving function, based on the blocktype present at the coords: bool res = false; switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ)) @@ -338,8 +327,8 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) case E_BLOCK_DROPPER: case E_BLOCK_HOPPER: { - cBlockEntityWithItems * BlockEntity = (cBlockEntityWithItems *)DestChunk->GetBlockEntity(OutX, OutY, OutZ); - if (BlockEntity == NULL) + cBlockEntityWithItems * BlockEntity = static_cast<cBlockEntityWithItems *>(DestChunk->GetBlockEntity(OutX, OutY, OutZ)); + if (BlockEntity == nullptr) { LOGWARNING("%s: A block entity was not found where expected at {%d, %d, %d}", __FUNCTION__, OutX, OutY, OutZ); return false; @@ -348,13 +337,13 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) break; } } - + // If the item has been moved, reset the last tick: if (res) { m_LastMoveItemsOutTick = a_CurrentTick; } - + return res; } @@ -365,8 +354,8 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) /// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed. bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) { - cChestEntity * MainChest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ); - if (MainChest == NULL) + cChestEntity * MainChest = static_cast<cChestEntity *>(a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)); + if (MainChest == nullptr) { LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ); return false; @@ -376,7 +365,7 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) // Moved the item from the chest directly above the hopper return true; } - + // Check if the chest is a double-chest (chest directly above was empty), if so, try to move from there: static const struct { @@ -394,7 +383,7 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) int x = m_RelX + Coords[i].x; int z = m_RelZ + Coords[i].z; cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z); - if (Neighbor == NULL) + if (Neighbor == nullptr) { continue; } @@ -406,8 +395,8 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) continue; } - cChestEntity * SideChest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z); - if (SideChest == NULL) + cChestEntity * SideChest = static_cast<cChestEntity *>(Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z)); + if (SideChest == nullptr) { LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z); } @@ -420,7 +409,7 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) } return false; } - + // The chest was single and nothing could be moved return false; } @@ -432,13 +421,13 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) /// Moves items from a furnace above the hopper into this hopper. Returns true if contents have changed. bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk) { - cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ); - if (Furnace == NULL) + cFurnaceEntity * Furnace = static_cast<cFurnaceEntity *>(a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)); + if (Furnace == nullptr) { LOGWARNING("%s: A furnace entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ); return false; } - + // Try move from the output slot: if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsOutput, true)) { @@ -446,7 +435,7 @@ bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk) Furnace->SetOutputSlot(NewOutput.AddCount(-1)); return true; } - + // No output moved, check if we can move an empty bucket out of the fuel slot: if (Furnace->GetFuelSlot().m_ItemType == E_ITEM_BUCKET) { @@ -456,7 +445,7 @@ bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk) return true; } } - + // Nothing can be moved return false; } @@ -469,7 +458,7 @@ bool cHopperEntity::MoveItemsFromGrid(cBlockEntityWithItems & a_Entity) { cItemGrid & Grid = a_Entity.GetContents(); int NumSlots = Grid.GetNumSlots(); - + // First try adding items of types already in the hopper: for (int i = 0; i < NumSlots; i++) { @@ -530,7 +519,7 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl // Plugin disagrees with the move continue; } - + m_Contents.ChangeSlotCount(i, 1); return true; } @@ -546,8 +535,8 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ) { // Try the chest directly connected to the hopper: - cChestEntity * ConnectedChest = (cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); - if (ConnectedChest == NULL) + cChestEntity * ConnectedChest = static_cast<cChestEntity *>(a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)); + if (ConnectedChest == nullptr) { LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, a_BlockX, a_BlockY, a_BlockZ); return false; @@ -577,7 +566,7 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block int x = RelX + Coords[i].x; int z = RelZ + Coords[i].z; cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z); - if (Neighbor == NULL) + if (Neighbor == nullptr) { continue; } @@ -589,8 +578,8 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block continue; } - cChestEntity * Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z); - if (Chest == NULL) + cChestEntity * Chest = static_cast<cChestEntity *>(Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z)); + if (Chest == nullptr) { LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d} (%d, %d)", __FUNCTION__, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z, x, z); continue; @@ -601,7 +590,7 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block } return false; } - + // The chest was single and nothing could be moved return false; } @@ -613,7 +602,7 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block /// Moves items to the furnace at the specified coords. Returns true if contents have changed bool cHopperEntity::MoveItemsToFurnace(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_HopperMeta) { - cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); + cFurnaceEntity * Furnace = static_cast<cFurnaceEntity *>(a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)); if (a_HopperMeta == E_META_HOPPER_FACING_YM) { // Feed the input slot of the furnace @@ -695,7 +684,3 @@ bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstS return false; } } - - - - diff --git a/src/BlockEntities/HopperEntity.h b/src/BlockEntities/HopperEntity.h index 8e856fcda..7070bbad3 100644 --- a/src/BlockEntities/HopperEntity.h +++ b/src/BlockEntities/HopperEntity.h @@ -31,6 +31,8 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cHopperEntity); + /// Constructor used for normal operation cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); @@ -40,8 +42,6 @@ public: */ bool GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, int & a_OutputY, int & a_OutputZ); - static const char * GetClassStatic(void) { return "cHopperEntity"; } - protected: Int64 m_LastMoveItemsInTick; @@ -49,7 +49,6 @@ protected: // cBlockEntity overrides: virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; - virtual void SaveToJson(Json::Value & a_Value) override; virtual void SendTo(cClientHandle & a_Client) override; virtual void UsedBy(cPlayer * a_Player) override; diff --git a/src/BlockEntities/JukeboxEntity.cpp b/src/BlockEntities/JukeboxEntity.cpp index 1131b99b0..473526855 100644 --- a/src/BlockEntities/JukeboxEntity.cpp +++ b/src/BlockEntities/JukeboxEntity.cpp @@ -79,7 +79,7 @@ bool cJukeboxEntity::EjectRecord(void) } cItems Drops; - Drops.push_back(cItem(m_Record, 1, 0)); + Drops.push_back(cItem(static_cast<short>(m_Record), 1, 0)); m_Record = 0; m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 8); m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, 0); @@ -113,35 +113,3 @@ void cJukeboxEntity::SetRecord(int a_Record) { m_Record = a_Record; } - - - - - -bool cJukeboxEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - m_Record = a_Value.get("Record", 0).asInt(); - - return true; -} - - - - - -void cJukeboxEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - a_Value["Record"] = m_Record; -} - - - - diff --git a/src/BlockEntities/JukeboxEntity.h b/src/BlockEntities/JukeboxEntity.h index a6fdf3c7e..7a69d6499 100644 --- a/src/BlockEntities/JukeboxEntity.h +++ b/src/BlockEntities/JukeboxEntity.h @@ -26,12 +26,11 @@ public: // tolua_end + BLOCKENTITY_PROTODEF(cJukeboxEntity); + cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); virtual ~cJukeboxEntity(); - bool LoadFromJson(const Json::Value & a_Value); - virtual void SaveToJson(Json::Value & a_Value) override; - // tolua_begin int GetRecord(void); @@ -54,8 +53,6 @@ public: // tolua_end - static const char * GetClassStatic(void) { return "cJukeboxEntity"; } - virtual void UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle &) override {} diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp index 9a1a40abe..67e13ffb2 100644 --- a/src/BlockEntities/MobHeadEntity.cpp +++ b/src/BlockEntities/MobHeadEntity.cpp @@ -77,35 +77,3 @@ void cMobHeadEntity::SendTo(cClientHandle & a_Client) - -bool cMobHeadEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - m_Type = static_cast<eMobHeadType>(a_Value.get("Type", 0).asInt()); - m_Rotation = static_cast<eMobHeadRotation>(a_Value.get("Rotation", 0).asInt()); - m_Owner = a_Value.get("Owner", "").asString(); - - return true; -} - - - - - -void cMobHeadEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - a_Value["Type"] = m_Type; - a_Value["Rotation"] = m_Rotation; - a_Value["Owner"] = m_Owner; -} - - - - diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h index 45fa0d951..7132ef558 100644 --- a/src/BlockEntities/MobHeadEntity.h +++ b/src/BlockEntities/MobHeadEntity.h @@ -34,12 +34,11 @@ public: // tolua_end - /** Creates a new mob head entity at the specified block coords. a_World may be NULL */ + 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); - bool LoadFromJson( const Json::Value& a_Value); - virtual void SaveToJson(Json::Value& a_Value) override; - // tolua_begin /** Set the Type */ @@ -65,8 +64,6 @@ public: virtual void UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle & a_Client) override; - static const char * GetClassStatic(void) { return "cMobHeadEntity"; } - private: eMobHeadType m_Type; diff --git a/src/BlockEntities/NoteEntity.cpp b/src/BlockEntities/NoteEntity.cpp index ecbedbcb1..a9af13c55 100644 --- a/src/BlockEntities/NoteEntity.cpp +++ b/src/BlockEntities/NoteEntity.cpp @@ -124,32 +124,3 @@ void cNoteEntity::IncrementPitch(void) - -bool cNoteEntity::LoadFromJson(const Json::Value & a_Value) -{ - - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - m_Pitch = (char)a_Value.get("p", 0).asInt(); - - return true; -} - - - - - -void cNoteEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - a_Value["p"] = m_Pitch; -} - - - - diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index f538de060..fc5f27d07 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -40,13 +40,12 @@ public: // tolua_end - /// Creates a new note entity. a_World may be NULL + 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); virtual ~cNoteEntity() {} - bool LoadFromJson(const Json::Value & a_Value); - virtual void SaveToJson(Json::Value & a_Value) override; - // tolua_begin char GetPitch(void); @@ -67,8 +66,6 @@ public: } } - static const char * GetClassStatic(void) { return "cNoteEntity"; } - private: char m_Pitch; } ; // tolua_export diff --git a/src/BlockEntities/SignEntity.cpp b/src/BlockEntities/SignEntity.cpp index 423d254d2..9a2695b3f 100644 --- a/src/BlockEntities/SignEntity.cpp +++ b/src/BlockEntities/SignEntity.cpp @@ -22,7 +22,6 @@ cSignEntity::cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorl -// It don't do anything when 'used' void cSignEntity::UsedBy(cPlayer * a_Player) { UNUSED(a_Player); @@ -46,7 +45,7 @@ void cSignEntity::SetLines(const AString & a_Line1, const AString & a_Line2, con void cSignEntity::SetLine(int a_Index, const AString & a_Line) { - if ((a_Index < 0) || (a_Index >= (int)ARRAYCOUNT(m_Line))) + if ((a_Index < 0) || (a_Index >= static_cast<int>(ARRAYCOUNT(m_Line)))) { LOGWARNING("%s: setting a non-existent line %d (value \"%s\"", __FUNCTION__, a_Index, a_Line.c_str()); return; @@ -60,7 +59,7 @@ void cSignEntity::SetLine(int a_Index, const AString & a_Line) AString cSignEntity::GetLine(int a_Index) const { - if ((a_Index < 0) || (a_Index >= (int)ARRAYCOUNT(m_Line))) + if ((a_Index < 0) || (a_Index >= static_cast<int>(ARRAYCOUNT(m_Line)))) { LOGWARNING("%s: requesting a non-existent line %d", __FUNCTION__, a_Index); return ""; @@ -76,41 +75,3 @@ void cSignEntity::SendTo(cClientHandle & a_Client) { a_Client.SendUpdateSign(m_PosX, m_PosY, m_PosZ, m_Line[0], m_Line[1], m_Line[2], m_Line[3]); } - - - - - -bool cSignEntity::LoadFromJson(const Json::Value & a_Value) -{ - m_PosX = a_Value.get("x", 0).asInt(); - m_PosY = a_Value.get("y", 0).asInt(); - m_PosZ = a_Value.get("z", 0).asInt(); - - m_Line[0] = a_Value.get("Line1", "").asString(); - m_Line[1] = a_Value.get("Line2", "").asString(); - m_Line[2] = a_Value.get("Line3", "").asString(); - m_Line[3] = a_Value.get("Line4", "").asString(); - - return true; -} - - - - - -void cSignEntity::SaveToJson(Json::Value & a_Value) -{ - a_Value["x"] = m_PosX; - a_Value["y"] = m_PosY; - a_Value["z"] = m_PosZ; - - a_Value["Line1"] = m_Line[0]; - a_Value["Line2"] = m_Line[1]; - a_Value["Line3"] = m_Line[2]; - a_Value["Line4"] = m_Line[3]; -} - - - - diff --git a/src/BlockEntities/SignEntity.h b/src/BlockEntities/SignEntity.h index 33af100a4..52baa486d 100644 --- a/src/BlockEntities/SignEntity.h +++ b/src/BlockEntities/SignEntity.h @@ -34,12 +34,11 @@ public: // tolua_end - /// Creates a new empty sign entity at the specified block coords and block type (wall or standing). a_World may be NULL + 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); - bool LoadFromJson( const Json::Value& a_Value); - virtual void SaveToJson(Json::Value& a_Value) override; - // tolua_begin /// Sets all the sign's lines @@ -56,8 +55,6 @@ public: virtual void UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle & a_Client) override; - static const char * GetClassStatic(void) { return "cSignEntity"; } - private: AString m_Line[4]; diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 9026d81f2..c98e0cad1 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -4,7 +4,7 @@ #include "Globals.h" #include "BlockID.h" -#include "inifile/iniFile.h" +#include "IniFile.h" #include "Item.h" #include "Mobs/Monster.h" @@ -217,7 +217,12 @@ BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString) bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item) { - return gsBlockIDMap.ResolveItem(TrimString(a_ItemTypeString), a_Item); + AString ItemName = TrimString(a_ItemTypeString); + if (ItemName.substr(0, 10) == "minecraft:") + { + ItemName = ItemName.substr(10); + } + return gsBlockIDMap.ResolveItem(ItemName, a_Item); } @@ -253,57 +258,6 @@ AString ItemToFullString(const cItem & a_Item) -int StringToMobType(const AString & a_MobString) -{ - static struct - { - int m_MobType; - const char * m_String; - } MobMap [] = - { - {mtCreeper, "Creeper"}, - {mtSkeleton, "Skeleton"}, - {mtSpider, "Spider"}, - {mtGiant, "Giant"}, - {mtZombie, "Zombie"}, - {mtSlime, "Slime"}, - {mtGhast, "Ghast"}, - {mtZombiePigman, "ZombiePigman"}, - {mtEnderman, "Enderman"}, - {mtCaveSpider, "CaveSpider"}, - {mtSilverfish, "SilverFish"}, - {mtBlaze, "Blaze"}, - {mtMagmaCube, "MagmaCube"}, - {mtEnderDragon, "EnderDragon"}, - {mtWither, "Wither"}, - {mtBat, "Bat"}, - {mtWitch, "Witch"}, - {mtPig, "Pig"}, - {mtSheep, "Sheep"}, - {mtCow, "Cow"}, - {mtChicken, "Chicken"}, - {mtSquid, "Squid"}, - {mtWolf, "Wolf"}, - {mtMooshroom, "Mooshroom"}, - {mtSnowGolem, "SnowGolem"}, - {mtOcelot, "Ocelot"}, - {mtIronGolem, "IronGolem"}, - {mtVillager, "Villager"}, - }; - for (size_t i = 0; i < ARRAYCOUNT(MobMap); i++) - { - if (NoCaseCompare(MobMap[i].m_String, a_MobString) == 0) - { - return MobMap[i].m_MobType; - } - } // for i - MobMap[] - return -1; -} - - - - - eDimension StringToDimension(const AString & a_DimensionString) { // First try decoding as a number diff --git a/src/BlockID.h b/src/BlockID.h index 45e71d85d..24de2dc8a 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -1,7 +1,13 @@ #pragma once +// The following hackery is to allow typed C++ enum for C++ code, yet have ToLua process the values. +// ToLua doesn't understand typed enums, so we use preprocessor to hide it from ToLua. + +enum ENUM_BLOCK_ID : BLOCKTYPE +#if 0 +enum ENUM_BLOCK_ID // tolua_export +#endif // tolua_begin -enum ENUM_BLOCK_ID { E_BLOCK_AIR = 0, E_BLOCK_STONE = 1, @@ -186,6 +192,9 @@ enum ENUM_BLOCK_ID E_BLOCK_BLOCK_OF_COAL = 173, E_BLOCK_PACKED_ICE = 174, E_BLOCK_BIG_FLOWER = 175, + E_BLOCK_STANDING_BANNER = 176, + E_BLOCK_WALL_BANNER = 177, + E_BLOCK_INVERTED_DAYLIGHT_SENSOR = 178, E_BLOCK_RED_SANDSTONE = 179, E_BLOCK_RED_SANDSTONE_STAIRS = 180, E_BLOCK_DOUBLE_NEW_STONE_SLAB= 181, @@ -218,6 +227,10 @@ enum ENUM_BLOCK_ID }; // tolua_end + + + + // tolua_begin enum ENUM_ITEM_ID { @@ -442,7 +455,22 @@ enum //////////////////////////////////////////////////////////////////////////////// // Block metas: - // E_BLOCK_BIG_FLOWER metas + // E_BLOCK_ANVIL metas + E_BLOCK_ANVIL_Z = 0, + E_BLOCK_ANVIL_X = 1, + E_BLOCK_ANVIL_NO_DAMAGE = 0, + E_BLOCK_ANVIL_LOW_DAMAGE = 4, + E_BLOCK_ANVIL_HIGH_DAMAGE = 8, + + // E_BLOCK_BED metas: + E_BLOCK_BED_ZP = 0, + E_BLOCK_BED_XM = 1, + E_BLOCK_BED_ZM = 2, + E_BLOCK_BED_XP = 3, + E_BLOCK_BED_OCCUPIED = 4, + E_BLOCK_BED_BED_HEAD = 8, + + // E_BLOCK_BIG_FLOWER metas: E_META_BIG_FLOWER_SUNFLOWER = 0, E_META_BIG_FLOWER_LILAC = 1, E_META_BIG_FLOWER_DOUBLE_TALL_GRASS = 2, @@ -450,6 +478,20 @@ enum E_META_BIG_FLOWER_ROSE_BUSH = 4, E_META_BIG_FLOWER_PEONY = 5, + // E_BLOCK_BREWING_STAND metas + E_META_BREWING_STAND_FILLED_SLOT_XP = 1, + E_META_BREWING_STAND_FILLED_SLOT_XM_ZP = 2, + E_META_BREWING_STAND_FILLED_SLOT_XM_ZM = 4, + + // E_BLOCK_BUTTON metas + E_BLOCK_BUTTON_YM = 0, + E_BLOCK_BUTTON_XP = 1, + E_BLOCK_BUTTON_XM = 2, + E_BLOCK_BUTTON_ZP = 3, + E_BLOCK_BUTTON_ZM = 4, + E_BLOCK_BUTTON_YP = 5, + E_BLOCK_BUTTON_PRESSED = 8, + // E_BLOCK_CARPET metas: E_META_CARPET_WHITE = 0, E_META_CARPET_ORANGE = 1, @@ -477,6 +519,7 @@ enum // E_BLOCK_DIRT metas: E_META_DIRT_NORMAL = 0, E_META_DIRT_GRASSLESS = 1, + E_META_DIRT_COARSE = 1, E_META_DIRT_PODZOL = 2, // E_BLOCK_DISPENSER / E_BLOCK_DROPPER metas: @@ -488,16 +531,19 @@ enum E_META_DROPSPENSER_FACING_XP = 5, // E_BLOCK_DOUBLE_STONE_SLAB metas: - E_META_DOUBLE_STONE_SLAB_STONE = 0, - E_META_DOUBLE_STONE_SLAB_SANDSTONE = 1, - E_META_DOUBLE_STONE_SLAB_WOODEN = 2, - E_META_DOUBLE_STONE_SLAB_COBBLESTONE = 3, - E_META_DOUBLE_STONE_SLAB_BRICK = 4, - E_META_DOUBLE_STONE_SLAB_STONE_BRICK = 5, - E_META_DOUBLE_STONE_SLAB_NETHER_BRICK = 6, - E_META_DOUBLE_STONE_SLAB_STONE_SECRET = 7, - - // E_BLOCK_FLOWER metas + E_META_DOUBLE_STONE_SLAB_STONE = 0, + E_META_DOUBLE_STONE_SLAB_SANDSTON = 1, + E_META_DOUBLE_STONE_SLAB_WOODEN = 2, + E_META_DOUBLE_STONE_SLAB_COBBLESTONE = 3, + E_META_DOUBLE_STONE_SLAB_BRICK = 4, + E_META_DOUBLE_STONE_SLAB_STONE_BRICK = 5, + E_META_DOUBLE_STONE_SLAB_NETHER_BRICK = 6, + E_META_DOUBLE_STONE_SLAB_QUARTZ = 7, + E_META_DOUBLE_STONE_SLAB_SMOOTH_STONE = 8, + E_META_DOUBLE_STONE_SLAB_SMOOTH_SANDSTONE = 9, + E_META_DOUBLE_STONE_SLAB_TILE_QUARTZ = 10, + + // E_BLOCK_FLOWER metas: E_META_FLOWER_POPPY = 0, E_META_FLOWER_BLUE_ORCHID = 1, E_META_FLOWER_ALLIUM = 2, @@ -507,9 +553,9 @@ enum E_META_FLOWER_PINK_TULIP = 7, E_META_FLOWER_OXEYE_DAISY = 8, - // E_BLOCK_JUKEBOX metas - E_META_JUKEBOX_OFF = 0, - E_META_JUKEBOX_ON = 1, + // E_BLOCK_JUKEBOX metas: + E_META_JUKEBOX_OFF = 0, + E_META_JUKEBOX_ON = 1, // E_BLOCK_HOPPER metas: E_META_HOPPER_FACING_YM = 0, @@ -520,10 +566,26 @@ enum E_META_HOPPER_FACING_XP = 5, // E_BLOCK_LEAVES metas: - E_META_LEAVES_APPLE = 0, - E_META_LEAVES_CONIFER = 1, - E_META_LEAVES_BIRCH = 2, - E_META_LEAVES_JUNGLE = 3, + E_META_LEAVES_APPLE = 0, + E_META_LEAVES_CONIFER = 1, + E_META_LEAVES_BIRCH = 2, + E_META_LEAVES_JUNGLE = 3, + E_META_LEAVES_APPLE_NO_DECAY = 4, + E_META_LEAVES_CONIFER_NO_DECAY = 5, + E_META_LEAVES_BIRCH_NO_DECAY = 6, + E_META_LEAVES_JUNGLE_NO_DECAY = 7, + E_META_LEAVES_APPLE_CHECK_DECAY = 8, + E_META_LEAVES_CONIFER_CHECK_DECAY = 9, + E_META_LEAVES_BIRCH_CHECK_DECAY = 10, + E_META_LEAVES_JUNGLE_CHECK_DECAY = 11, + + // E_BLOCK_LEAVES meta cont. (Block ID 161): + E_META_NEWLEAVES_ACACIA = 0, + E_META_NEWLEAVES_DARK_OAK = 1, + E_META_NEWLEAVES_ACACIA_NO_DECAY = 4, + E_META_NEWLEAVES_DARK_OAK_NO_DECAY = 5, + E_META_NEWLEAVES_ACACIA_CHECK_DECAY = 8, + E_META_NEWLEAVES_DARK_OAK_CHECK_DECAY = 9, // E_BLOCK_LOG metas: E_META_LOG_APPLE = 0, @@ -531,40 +593,62 @@ enum E_META_LOG_BIRCH = 2, E_META_LOG_JUNGLE = 3, - // E_BLOCK_NEW_LEAVES metas + // E_BLOCK_NEW_LEAVES metas: E_META_NEW_LEAVES_ACACIA_WOOD = 0, E_META_NEW_LEAVES_DARK_OAK_WOOD = 1, - // E_BLOCK_NEW_LOG metas - E_META_NEW_LOG_ACACIA_WOOD = 0, - E_META_NEW_LOG_DARK_OAK_WOOD = 1, + // E_BLOCK_NEW_LOG metas: + E_META_NEW_LOG_ACACIA_WOOD = 0, + E_META_NEW_LOG_DARK_OAK_WOOD = 1, + // E_BLOCK_PISTON metas: + E_META_PISTON_DOWN = 0, + E_META_PISTON_U = 1, + E_META_PISTON_ZM = 2, + E_META_PISTON_ZP = 3, + E_META_PISTON_XM = 4, + E_META_PISTON_XP = 5, + E_META_PISTON_HEAD_STICKY = 8, + E_META_PISTON_EXTENDED = 8, + // E_BLOCK_PLANKS metas: - E_META_PLANKS_APPLE = 0, - E_META_PLANKS_CONIFER = 1, - E_META_PLANKS_BIRCH = 2, - E_META_PLANKS_JUNGLE = 3, + E_META_PLANKS_APPLE = 0, + E_META_PLANKS_CONIFER = 1, + E_META_PLANKS_BIRCH = 2, + E_META_PLANKS_JUNGLE = 3, + E_META_PLANKS_ACACIA = 4, + E_META_PLANKS_DARK_OAK = 5, // E_BLOCK_(XXX_WEIGHTED)_PRESSURE_PLATE metas: - E_META_PRESSURE_PLATE_RAISED = 0, + E_META_PRESSURE_PLATE_RAISED = 0, E_META_PRESSURE_PLATE_DEPRESSED = 1, + // E_BLOCK_PRISMARINE_BLOCK metas: + E_META_PRISMARINE_BLOCK_ROUGH = 0, + E_META_PRISMARINE_BLOCK_BRICKS = 1, + E_META_PRISMARINE_BLOCK_DARK = 2, + // E_BLOCK_QUARTZ_BLOCK metas: - E_META_QUARTZ_NORMAL = 0, + E_META_QUARTZ_NORMAL = 0, E_META_QUARTZ_CHISELLED = 1, - E_META_QUARTZ_PILLAR = 2, + E_META_QUARTZ_PILLAR = 2, // E_BLOCK_RAIL metas - E_META_RAIL_ZM_ZP = 0, - E_META_RAIL_XM_XP = 1, - E_META_RAIL_ASCEND_XP = 2, - E_META_RAIL_ASCEND_XM = 3, - E_META_RAIL_ASCEND_ZM = 4, - E_META_RAIL_ASCEND_ZP = 5, - E_META_RAIL_CURVED_ZP_XP = 6, - E_META_RAIL_CURVED_ZP_XM = 7, - E_META_RAIL_CURVED_ZM_XM = 8, - E_META_RAIL_CURVED_ZM_XP = 9, + E_META_RAIL_ZM_ZP = 0, + E_META_RAIL_XM_XP = 1, + E_META_RAIL_ASCEND_XP = 2, + E_META_RAIL_ASCEND_XM = 3, + E_META_RAIL_ASCEND_ZM = 4, + E_META_RAIL_ASCEND_ZP = 5, + E_META_RAIL_CURVED_ZP_XP = 6, + E_META_RAIL_CURVED_ZP_XM = 7, + E_META_RAIL_CURVED_ZM_XM = 8, + E_META_RAIL_CURVED_ZM_XP = 9, + + // E_BLOCK_RED_SANDSTONE metas: + E_META_RED_SANDSTONE_NORMAL = 0, + E_META_RED_SANDSTONE_ORNAMENT = 1, + E_META_RED_SANDSTONE_SMOOTH = 2, // E_BLOCK_SAND metas: E_META_SAND_NORMAL = 0, @@ -598,7 +682,7 @@ enum E_META_SNOW_LAYER_SEVEN = 6, E_META_SNOW_LAYER_EIGHT = 7, - // E_BLOCK_STAINED_CLAY metas + // E_BLOCK_STAINED_CLAY metas: E_META_STAINED_CLAY_WHITE = 0, E_META_STAINED_CLAY_ORANGE = 1, E_META_STAINED_CLAY_MAGENTA = 2, @@ -616,7 +700,7 @@ enum E_META_STAINED_CLAY_RED = 14, E_META_STAINED_CLAY_BLACK = 15, - // E_BLOCK_STAINED_GLASS metas + // E_BLOCK_STAINED_GLASS metas: E_META_STAINED_GLASS_WHITE = 0, E_META_STAINED_GLASS_ORANGE = 1, E_META_STAINED_GLASS_MAGENTA = 2, @@ -634,7 +718,7 @@ enum E_META_STAINED_GLASS_RED = 14, E_META_STAINED_GLASS_BLACK = 15, - // E_BLOCK_STAINED_GLASS_PANE metas + // E_BLOCK_STAINED_GLASS_PANE metas: E_META_STAINED_GLASS_PANE_WHITE = 0, E_META_STAINED_GLASS_PANE_ORANGE = 1, E_META_STAINED_GLASS_PANE_MAGENTA = 2, @@ -652,6 +736,22 @@ enum E_META_STAINED_GLASS_PANE_RED = 14, E_META_STAINED_GLASS_PANE_BLACK = 15, + // E_BLOCK_STAIRS metas: + E_BLOCK_STAIRS_XP = 0, + E_BLOCK_STAIRS_XM = 1, + E_BLOCK_STAIRS_ZP = 2, + E_BLOCK_STAIRS_ZM = 3, + E_BLOCK_STAIRS_UPSIDE_DOWN = 4, + + // E_BLOCK_STONE metas: + E_META_STONE_STONE = 0, + E_META_STONE_GRANITE = 1, + E_META_STONE_POLISHED_GRANITE = 2, + E_META_STONE_DIORITE = 3, + E_META_STONE_POLISHED_DIORITE = 4, + E_META_STONE_ANDESITE = 5, + E_META_STONE_POLISHED_ANDESITE = 6, + // E_BLOCK_STONE_SLAB metas: E_META_STONE_SLAB_STONE = 0, E_META_STONE_SLAB_SANDSTONE = 1, @@ -660,18 +760,19 @@ enum E_META_STONE_SLAB_BRICK = 4, E_META_STONE_SLAB_STONE_BRICK = 5, E_META_STONE_SLAB_NETHER_BRICK = 6, - E_META_STONE_SLAB_STONE_SECRET = 7, + E_META_STONE_SLAB_QUARTZ = 7, // E_BLOCK_STONE_BRICKS metas: - E_META_STONE_BRICK_NORMAL = 0, - E_META_STONE_BRICK_MOSSY = 1, - E_META_STONE_BRICK_CRACKED = 2, - E_META_STONE_BRICK_ORNAMENT = 3, + E_META_STONE_BRICK_NORMAL = 0, + E_META_STONE_BRICK_MOSSY = 1, + E_META_STONE_BRICK_CRACKED = 2, + E_META_STONE_BRICK_ORNAMENT = 3, // E_BLOCK_TALL_GRASS metas: E_META_TALL_GRASS_DEAD_SHRUB = 0, E_META_TALL_GRASS_GRASS = 1, E_META_TALL_GRASS_FERN = 2, + E_META_TALL_GRASS_BIOME = 3, // E_BLOCK_TORCH, E_BLOCK_REDSTONE_TORCH_OFF, E_BLOCK_REDSTONE_TORCH_ON metas: E_META_TORCH_EAST = 1, // east face of the block, pointing east @@ -679,26 +780,55 @@ enum E_META_TORCH_SOUTH = 3, E_META_TORCH_NORTH = 4, E_META_TORCH_FLOOR = 5, - E_META_TORCH_XM = 1, // Torch attached to the XM side of its block - E_META_TORCH_XP = 2, // Torch attached to the XP side of its block - E_META_TORCH_ZM = 3, // Torch attached to the ZM side of its block - E_META_TORCH_ZP = 4, // Torch attached to the ZP side of its block - + E_META_TORCH_XM = 1, // Torch attached to the XM side of its block + E_META_TORCH_XP = 2, // Torch attached to the XP side of its block + E_META_TORCH_ZM = 3, // Torch attached to the ZM side of its block + E_META_TORCH_ZP = 4, // Torch attached to the ZP side of its block + + // E_META_LOG metas: + E_META_LOG_OAK_UP_DOWN = 0, + E_META_LOG_SPRUCE_UP_DOWN = 1, + E_META_LOG_BIRCH_UP_DOWN = 2, + E_META_LOG_JUNGLE_UP_DOWN = 3, + E_META_LOG_OAK_X = 4, + E_META_LOG_SPRUCE_X = 5, + E_META_LOG_BIRCH_X = 6, + E_META_LOG_JUNGLE_X = 7, + E_META_LOG_OAK_Z = 8, + E_META_LOG_SPRUCE_Z = 9, + E_META_LOG_BIRCH_Z = 10, + E_META_LOG_JUNGLE_Z = 11, + E_META_LOG_OAK_BARK_ONLY = 12, + E_META_LOG_SPRUCE_BARK_ONLY = 13, + E_META_LOG_BIRCH_BARK_ONLY = 14, + E_META_LOG_JUNGLE_BARK_ONLY = 15, + + // E_META_LOG metas cont. (Block ID 162): + E_META_NEWLOG_ACACIA_UP_DOWN = 0, + E_META_NEWLOG_DARK_OAK_UP_DOWN = 1, + E_META_NEWLOG_ACACIA_X = 4, + E_META_NEWLOG_DARK_OAK_X = 5, + E_META_NEWLOG_ACACIA_Z = 8, + E_META_NEWLOG_DARK_OAK_Z = 9, + E_META_NEWLOG_ACACIA_BARK_ONLY = 12, + E_META_NEWLOG_DARK_OAK_BARK_ONLY = 13, + // E_BLOCK_WOODEN_DOUBLE_SLAB metas: - E_META_WOODEN_DOUBLE_SLAB_APPLE = 0, - E_META_WOODEN_DOUBLE_SLAB_CONIFER = 1, - E_META_WOODEN_DOUBLE_SLAB_BIRCH = 2, - E_META_WOODEN_DOUBLE_SLAB_JUNGLE = 3, - E_META_WOODEN_DOUBLE_SLAB_ACACIA = 4, - E_META_WOODEN_DOUBLE_SLAB_DARK_OAK = 5, + E_META_WOODEN_DOUBLE_SLAB_APPLE = 0, + E_META_WOODEN_DOUBLE_SLAB_CONIFER = 1, + E_META_WOODEN_DOUBLE_SLAB_BIRCH = 2, + E_META_WOODEN_DOUBLE_SLAB_JUNGLE = 3, + E_META_WOODEN_DOUBLE_SLAB_ACACIA = 4, + E_META_WOODEN_DOUBLE_SLAB_DARK_OAK = 5, // E_BLOCK_WOODEN_SLAB metas: - E_META_WOODEN_SLAB_APPLE = 0, - E_META_WOODEN_SLAB_CONIFER = 1, - E_META_WOODEN_SLAB_BIRCH = 2, - E_META_WOODEN_SLAB_JUNGLE = 3, - E_META_WOODEN_SLAB_ACACIA = 4, - E_META_WOODEN_SLAB_DARK_OAK = 5, + E_META_WOODEN_SLAB_APPLE = 0, + E_META_WOODEN_SLAB_CONIFER = 1, + E_META_WOODEN_SLAB_BIRCH = 2, + E_META_WOODEN_SLAB_JUNGLE = 3, + E_META_WOODEN_SLAB_ACACIA = 4, + E_META_WOODEN_SLAB_DARK_OAK = 5, + E_META_WOODEN_SLAB_UPSIDE_DOWN = 8, // E_BLOCK_WOOL metas: E_META_WOOL_WHITE = 0, @@ -721,6 +851,24 @@ enum //////////////////////////////////////////////////////////////////////////////// // Item metas: + // E_ITEM_BANNER metas: + E_META_BANNER_BLACK = 0, + E_META_BANNER_RED = 1, + E_META_BANNER_GREEN = 2, + E_META_BANNER_BROWN = 3, + E_META_BANNER_BLUE = 4, + E_META_BANNER_PURPLE = 5, + E_META_BANNER_CYAN = 6, + E_META_BANNER_LIGHTGRAY = 7, + E_META_BANNER_GRAY = 8, + E_META_BANNER_PINK = 9, + E_META_BANNER_LIGHTGREEN = 10, + E_META_BANNER_YELLOW = 11, + E_META_BANNER_LIGHTBLUE = 12, + E_META_BANNER_MAGENTA = 13, + E_META_BANNER_ORANGE = 14, + E_META_BANNER_WHITE = 15, + // E_ITEM_COAL metas: E_META_COAL_NORMAL = 0, E_META_COAL_CHARCOAL = 1, @@ -747,6 +895,13 @@ enum E_META_GOLDEN_APPLE_NORMAL = 0, E_META_GOLDEN_APPLE_ENCHANTED = 1, + // E_ITEM_HEAD metas: + E_META_HEAD_SKELETON = 0, + E_META_HEAD_WITHER = 1, + E_META_HEAD_ZOMBIE = 2, + E_META_HEAD_PLAYER = 3, + E_META_HEAD_CREEPER = 4, + // E_ITEM_RAW_FISH metas: E_META_RAW_FISH_FISH = 0, E_META_RAW_FISH_SALMON = 1, @@ -756,8 +911,6 @@ enum // E_ITEM_COOKED_FISH metas: E_META_COOKED_FISH_FISH = 0, E_META_COOKED_FISH_SALMON = 1, - E_META_COOKED_FISH_CLOWNFISH = 2, - E_META_COOKED_FISH_PUFFERFISH = 3, // E_ITEM_MINECART_TRACKS metas: E_META_TRACKS_X = 1, @@ -957,9 +1110,6 @@ extern AString ItemTypeToString(short a_ItemType); /// Translates a full item into a fully-specified string (including meta and count). If the ItemType is not recognized, the ItemType number is output into the string. extern AString ItemToFullString(const cItem & a_Item); -/// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT) -extern int StringToMobType(const AString & a_MobString); - /// Translates a dimension string to dimension enum. Takes either a number or a dimension alias (built-in). Returns dimOverworld on failure extern eDimension StringToDimension(const AString & a_DimensionString); diff --git a/src/BlockInServerPluginInterface.h b/src/BlockInServerPluginInterface.h index e82435364..70c9944a8 100644 --- a/src/BlockInServerPluginInterface.h +++ b/src/BlockInServerPluginInterface.h @@ -6,14 +6,30 @@ #include "Root.h" #include "Bindings/PluginManager.h" -class cBlockInServerPluginInterface : public cBlockPluginInterface + + + + +class cBlockInServerPluginInterface : + public cBlockPluginInterface { public: cBlockInServerPluginInterface(cWorld & a_World) : m_World(a_World) {} + + virtual bool CallHookBlockSpread(int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) + { + return cPluginManager::Get()->CallHookBlockSpread(m_World, a_BlockX, a_BlockY, a_BlockZ, a_Source); + } + virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override { - return cRoot::Get()->GetPluginManager()->CallHookBlockToPickups(&m_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups); + return cPluginManager::Get()->CallHookBlockToPickups(m_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups); } + private: cWorld & m_World; }; + + + + diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index fb9b746b3..bcab21e77 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -9,7 +9,7 @@ cBlockInfo::~cBlockInfo() { delete m_Handler; - m_Handler = NULL; + m_Handler = nullptr; } @@ -17,7 +17,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) { for (unsigned int i = 0; i < 256; ++i) { - if (a_Info[i].m_Handler == NULL) + if (a_Info[i].m_Handler == nullptr) { a_Info[i].m_Handler = cBlockHandler::CreateBlockHandler((BLOCKTYPE) i); } @@ -99,6 +99,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_HOPPER ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_ICE ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_INVERTED_DAYLIGHT_SENSOR ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_IRON_TRAPDOOR ].m_SpreadLightFalloff = 1; @@ -137,6 +138,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_SPRUCE_FENCE_GATE ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_STAINED_GLASS ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_STANDING_BANNER ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_STICKY_PISTON ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_STONE_BUTTON ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_SpreadLightFalloff = 1; @@ -149,6 +151,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_TRIPWIRE ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_WALL_BANNER ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_WALLSIGN ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_WOODEN_BUTTON ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_WOODEN_DOOR ].m_SpreadLightFalloff = 1; @@ -256,6 +259,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_Transparent = true; a_Info[E_BLOCK_STATIONARY_LAVA ].m_Transparent = true; a_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true; + a_Info[E_BLOCK_STANDING_BANNER ].m_Transparent = true; a_Info[E_BLOCK_STICKY_PISTON ].m_Transparent = true; a_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true; a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true; @@ -268,6 +272,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_TRIPWIRE ].m_Transparent = true; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true; a_Info[E_BLOCK_VINES ].m_Transparent = true; + a_Info[E_BLOCK_WALL_BANNER ].m_Transparent = true; a_Info[E_BLOCK_WALLSIGN ].m_Transparent = true; a_Info[E_BLOCK_WATER ].m_Transparent = true; a_Info[E_BLOCK_WOODEN_BUTTON ].m_Transparent = true; @@ -329,6 +334,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true; a_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true; a_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true; + a_Info[E_BLOCK_IRON_TRAPDOOR ].m_PistonBreakable = true; a_Info[E_BLOCK_JACK_O_LANTERN ].m_PistonBreakable = true; a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true; a_Info[E_BLOCK_LILY_PAD ].m_PistonBreakable = true; @@ -474,12 +480,14 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_SNOW ].m_IsSolid = false; a_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSolid = false; a_Info[E_BLOCK_STATIONARY_WATER ].m_IsSolid = false; + a_Info[E_BLOCK_STANDING_BANNER ].m_IsSolid = false; a_Info[E_BLOCK_STONE_BUTTON ].m_IsSolid = false; a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_IsSolid = false; a_Info[E_BLOCK_TALL_GRASS ].m_IsSolid = false; a_Info[E_BLOCK_TORCH ].m_IsSolid = false; a_Info[E_BLOCK_TRIPWIRE ].m_IsSolid = false; a_Info[E_BLOCK_VINES ].m_IsSolid = false; + a_Info[E_BLOCK_WALL_BANNER ].m_IsSolid = false; a_Info[E_BLOCK_WALLSIGN ].m_IsSolid = false; a_Info[E_BLOCK_WATER ].m_IsSolid = false; a_Info[E_BLOCK_WOODEN_BUTTON ].m_IsSolid = false; @@ -527,6 +535,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_LAPIS_ORE ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_LOG ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_MELON ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_MOB_SPAWNER ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_MYCELIUM ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_NETHERRACK ].m_FullyOccupiesVoxel = true; @@ -734,7 +743,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_NEW_LOG ].m_PlaceSound = "dig.wood"; a_Info[E_BLOCK_ACACIA_WOOD_STAIRS ].m_PlaceSound = "dig.wood"; a_Info[E_BLOCK_DARK_OAK_WOOD_STAIRS ].m_PlaceSound = "dig.wood"; - a_Info[E_BLOCK_SLIME_BLOCK ].m_PlaceSound = "dig.slime"; // I hope it is named slime, it's definetly a new sound type though... + a_Info[E_BLOCK_SLIME_BLOCK ].m_PlaceSound = "mob.slime.big"; a_Info[E_BLOCK_BARRIER ].m_PlaceSound = "dig.stone"; a_Info[E_BLOCK_IRON_TRAPDOOR ].m_PlaceSound = "dig.metal"; a_Info[E_BLOCK_PRISMARINE_BLOCK ].m_PlaceSound = "dig.stone"; @@ -745,6 +754,8 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_BLOCK_OF_COAL ].m_PlaceSound = "dig.stone"; a_Info[E_BLOCK_PACKED_ICE ].m_PlaceSound = "dig.stone"; a_Info[E_BLOCK_BIG_FLOWER ].m_PlaceSound = "dig.grass"; + a_Info[E_BLOCK_STANDING_BANNER ].m_PlaceSound = "dig.wood"; + a_Info[E_BLOCK_WALL_BANNER ].m_PlaceSound = "dig.wood"; a_Info[E_BLOCK_RED_SANDSTONE ].m_PlaceSound = "dig.stone"; a_Info[E_BLOCK_RED_SANDSTONE_STAIRS ].m_PlaceSound = "dig.stone"; a_Info[E_BLOCK_NEW_STONE_SLAB ].m_PlaceSound = "dig.stone"; diff --git a/src/BlockInfo.h b/src/BlockInfo.h index 1e4cf2ca0..4709f2357 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -102,7 +102,7 @@ protected: , m_FullyOccupiesVoxel(false) , m_CanBeTerraformed(false) , m_PlaceSound("") - , m_Handler(NULL) + , m_Handler(nullptr) {} /** Cleans up the stored values */ diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index 5b687c710..09df16893 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -17,15 +17,25 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Don't drop anything - } - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SAND); + if (a_RelY <= 0) + { + return false; + } + + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); + switch (BelowBlock) + { + case E_BLOCK_CLAY: + case E_BLOCK_HARDENED_CLAY: + case E_BLOCK_STAINED_CLAY: + case E_BLOCK_SAND: + { + return true; + } + default: return false; + } } } ; diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index 60d81db72..aae6719e2 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -21,7 +21,15 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0)); + if (a_BlockMeta == E_META_DIRT_COARSE) + { + // Drop the coarse block (dirt, meta 1) + a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE); + } + else + { + a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL); + } } @@ -64,7 +72,7 @@ public: int BlockY = a_RelY + OfsY; int BlockZ = a_RelZ + OfsZ; cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(BlockX, BlockZ); - if (Chunk == NULL) + if (Chunk == nullptr) { // Unloaded chunk continue; @@ -81,7 +89,7 @@ public: Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta); if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta)) { - if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(Chunk->GetWorld(), Chunk->GetPosX() * cChunkDef::Width + BlockX, BlockY, Chunk->GetPosZ() * cChunkDef::Width + BlockZ, ssGrassSpread)) + if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), Chunk->GetPosX() * cChunkDef::Width + BlockX, BlockY, Chunk->GetPosZ() * cChunkDef::Width + BlockZ, ssGrassSpread)) { Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0); } diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index b2f9e4dcd..92ad8da12 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -55,7 +55,49 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - a_Pickups.push_back(cItem((m_BlockType == E_BLOCK_WOODEN_DOOR) ? E_ITEM_WOODEN_DOOR : E_ITEM_IRON_DOOR, 1, 0)); + switch (m_BlockType) + { + case E_BLOCK_WOODEN_DOOR: + { + a_Pickups.Add(E_ITEM_WOODEN_DOOR); + break; + } + case E_BLOCK_ACACIA_DOOR: + { + a_Pickups.Add(E_ITEM_ACACIA_DOOR); + break; + } + case E_BLOCK_BIRCH_DOOR: + { + a_Pickups.Add(E_ITEM_BIRCH_DOOR); + break; + } + case E_BLOCK_DARK_OAK_DOOR: + { + a_Pickups.Add(E_ITEM_DARK_OAK_DOOR); + break; + } + case E_BLOCK_JUNGLE_DOOR: + { + a_Pickups.Add(E_ITEM_JUNGLE_DOOR); + break; + } + case E_BLOCK_SPRUCE_DOOR: + { + a_Pickups.Add(E_ITEM_SPRUCE_DOOR); + break; + } + case E_BLOCK_IRON_DOOR: + { + a_Pickups.Add(E_ITEM_IRON_DOOR); + break; + } + default: + { + ASSERT(!"Unhandled door type!"); + break; + } + } } @@ -131,7 +173,23 @@ public: /** Returns true if the specified blocktype is any kind of door */ inline static bool IsDoor(BLOCKTYPE a_Block) { - return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR); + switch (a_Block) + { + case E_BLOCK_ACACIA_DOOR: + case E_BLOCK_BIRCH_DOOR: + case E_BLOCK_DARK_OAK_DOOR: + case E_BLOCK_IRON_DOOR: + case E_BLOCK_JUNGLE_DOOR: + case E_BLOCK_SPRUCE_DOOR: + case E_BLOCK_WOODEN_DOOR: + { + return true; + } + default: + { + return false; + } + } } diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index 3041dd46c..b5c1323bd 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -19,7 +19,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - a_Pickups.Add(E_BLOCK_FENCE_GATE, 1, 0); // Reset meta to zero + a_Pickups.Add(m_BlockType, 1, 0); // Reset meta to zero } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 7bfff0545..60f13a747 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -4,6 +4,7 @@ #include "../Item.h" #include "../World.h" #include "../Chunk.h" +#include "BlockPluginInterface.h" #include "BlockAnvil.h" #include "BlockBed.h" #include "BlockBigFlower.h" @@ -36,7 +37,6 @@ #include "BlockGlass.h" #include "BlockGlowstone.h" #include "BlockGravel.h" -#include "BlockHayBale.h" #include "BlockMobHead.h" #include "BlockHopper.h" #include "BlockIce.h" @@ -83,7 +83,6 @@ #include "BlockWorkbench.h" -#include "BlockPluginInterface.h" @@ -100,9 +99,9 @@ public: for (BLOCKTYPE Type = 0; Type < E_BLOCK_MAX_TYPE_ID; Type++) { cBlockHandler * Handler = cBlockInfo::GetHandler(Type); - if (Handler == NULL) + if (Handler == nullptr) { - printf("NULL handler for block type %d!\n", Type); + printf("nullptr handler for block type %d!\n", Type); continue; } AString BlockName = ItemTypeToString(Type); @@ -231,7 +230,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_GLASS_PANE: return new cBlockGlassHandler (a_BlockType); case E_BLOCK_GRASS: return new cBlockDirtHandler (a_BlockType); case E_BLOCK_GRAVEL: return new cBlockGravelHandler (a_BlockType); - case E_BLOCK_HAY_BALE: return new cBlockHayBaleHandler (a_BlockType); + case E_BLOCK_HAY_BALE: return new cBlockSidewaysHandler (a_BlockType); case E_BLOCK_HEAD: return new cBlockMobHeadHandler (a_BlockType); case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(a_BlockType); case E_BLOCK_HOPPER: return new cBlockHopperHandler (a_BlockType); @@ -294,6 +293,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_SIGN_POST: return new cBlockSignPostHandler (a_BlockType); case E_BLOCK_SNOW: return new cBlockSnowHandler (a_BlockType); case E_BLOCK_SPRUCE_DOOR: return new cBlockDoorHandler (a_BlockType); + case E_BLOCK_SPRUCE_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_SPRUCE_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_STAINED_GLASS: return new cBlockGlassHandler (a_BlockType); case E_BLOCK_STAINED_GLASS_PANE: return new cBlockGlassHandler (a_BlockType); @@ -441,7 +441,7 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac if (a_CanDrop) { - if ((a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)) + if ((a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)) { switch (m_BlockType) { @@ -562,7 +562,7 @@ void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterf { int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, NULL, BlockX, a_RelY, BlockZ); + DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); } a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 83de836cb..f2298afb5 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -78,7 +78,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta); /** Handles the dropping, but not destruction, of a block based on what ConvertTo(Verbatim)Pickups() returns, including the spawning of pickups and alertion of plugins - @param a_Digger The entity causing the drop; it may be NULL + @param a_Digger The entity causing the drop; it may be nullptr @param a_CanDrop Informs the handler whether the block should be dropped at all. One example when this is false is when stone is destroyed by hand @param a_DropVerbatim Calls ConvertToVerbatimPickups() instead of its counterpart, meaning the block itself is dropped by default (due to a speical tool or enchantment) */ diff --git a/src/Blocks/BlockHayBale.h b/src/Blocks/BlockHayBale.h deleted file mode 100644 index 8150b10d3..000000000 --- a/src/Blocks/BlockHayBale.h +++ /dev/null @@ -1,22 +0,0 @@ - -#pragma once - -#include "BlockSideways.h" - - - - - -class cBlockHayBaleHandler : - public cBlockSidewaysHandler -{ -public: - cBlockHayBaleHandler(BLOCKTYPE a_BlockType) - : cBlockSidewaysHandler(a_BlockType) - { - } -} ; - - - - diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index add571675..bd9a7414e 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -109,7 +109,7 @@ public: } // Decay the leaves: - DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, NULL, BlockX, a_RelY, BlockZ); + DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); a_ChunkInterface.DigBlock(a_WorldInterface, BlockX, a_RelY, BlockZ); } } ; diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 3b63b396c..f5bedea6c 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -1,9 +1,9 @@ #pragma once #include "BlockHandler.h" +#include "../Chunk.h" #include "MetaRotator.h" - - +#include "BlockSlab.h" class cBlockLeverHandler : @@ -93,13 +93,35 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - NIBBLETYPE Meta; - a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta); + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + + eBlockFace Face = BlockMetaDataToBlockFace(Meta); + + AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); + + if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height -1)) + { + return false; + } + + BLOCKTYPE BlockIsOn; + a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockIsOn, Meta); - AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); - BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); - return (a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn); + if (cBlockInfo::FullyOccupiesVoxel(BlockIsOn)) + { + return true; + } + else if (cBlockSlabHandler::IsAnySlabType(BlockIsOn)) + { + // Check if the slab is turned up side down + if (((Meta & 0x08) == 0x08) && (Face == BLOCK_FACE_TOP)) + { + return true; + } + } + + return false; } diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 34d11f675..8d245cabe 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -139,7 +139,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, { cChunkInterface ChunkInterface(a_World->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*a_World); - Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, NULL, a_BlockX, a_BlockY, a_BlockZ); + Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, nullptr, a_BlockX, a_BlockY, a_BlockZ); } } diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index 3a3fc7224..f868f4d8e 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -100,6 +100,7 @@ private: case E_BLOCK_BREWING_STAND: case E_BLOCK_CHEST: case E_BLOCK_COMMAND_BLOCK: + case E_BLOCK_DAYLIGHT_SENSOR: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENCHANTMENT_TABLE: @@ -108,6 +109,7 @@ private: // Notice the lack of an E_BLOCK_ENDER_CHEST here; its because ender chests can totally be pushed/pulled in MCS :) case E_BLOCK_FURNACE: case E_BLOCK_LIT_FURNACE: + case E_BLOCK_INVERTED_DAYLIGHT_SENSOR: case E_BLOCK_HOPPER: case E_BLOCK_JUKEBOX: case E_BLOCK_MOB_SPAWNER: @@ -115,7 +117,9 @@ private: case E_BLOCK_NOTE_BLOCK: case E_BLOCK_OBSIDIAN: case E_BLOCK_PISTON_EXTENSION: + case E_BLOCK_STANDING_BANNER: case E_BLOCK_TRAPPED_CHEST: + case E_BLOCK_WALL_BANNER: { return false; } diff --git a/src/Blocks/BlockPluginInterface.h b/src/Blocks/BlockPluginInterface.h index 3a36c40b1..b769bcf3e 100644 --- a/src/Blocks/BlockPluginInterface.h +++ b/src/Blocks/BlockPluginInterface.h @@ -1,7 +1,11 @@ #pragma once -/** This interface is used to decouple block handlers from the cPluginManager dependancy through cWorld. + + + + +/** This interface is used to decouple block handlers from the cPluginManager dependency through cWorld. The block handlers call this interface, which is then implemented by the specific classes that the caller provides. */ @@ -10,5 +14,10 @@ class cBlockPluginInterface public: virtual ~cBlockPluginInterface() {} + virtual bool CallHookBlockSpread(int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0; virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; }; + + + + diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h index 37d61ed73..2785eb479 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -3,6 +3,7 @@ #include "BlockHandler.h" #include "../World.h" +#include "BlockSlab.h" @@ -16,11 +17,33 @@ public: : cBlockHandler(a_BlockType) { } - + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))); + if (a_RelY <= 0) + { + return false; + } + + BLOCKTYPE BelowBlock; + NIBBLETYPE BelowBlockMeta; + a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta); + + if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) + { + return true; + } + else if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) + { + // Check if the slab is turned up side down + if ((BelowBlockMeta & 0x08) == 0x08) + { + return true; + } + } + return false; } diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 1eb67f714..e8262dc40 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -5,6 +5,7 @@ #include "Chunk.h" #include "MetaRotator.h" #include "ChunkInterface.h" +#include "BlockSlab.h" @@ -44,6 +45,7 @@ public: } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to zero @@ -59,7 +61,28 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))); + if (a_RelY <= 0) + { + return false; + } + + BLOCKTYPE BelowBlock; + NIBBLETYPE BelowBlockMeta; + a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta); + + if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) + { + return true; + } + else if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) + { + // Check if the slab is turned up side down + if ((BelowBlockMeta & 0x08) == 0x08) + { + return true; + } + } + return false; } diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index 40e15c253..d97501651 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -35,7 +35,7 @@ public: } BLOCKTYPE Type = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); - return ((Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type)); + return ((Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type)); } diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index ffe2414f7..d762154df 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -13,6 +13,7 @@ #include "../Items/ItemHandler.h" #include "Root.h" #include "ChunkInterface.h" +#include "../Entities/Player.h" diff --git a/src/Blocks/BlockStone.h b/src/Blocks/BlockStone.h index cd5230f49..69cc8301b 100644 --- a/src/Blocks/BlockStone.h +++ b/src/Blocks/BlockStone.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" - +#include "BlockID.h" @@ -18,9 +18,14 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0)); + if (a_BlockMeta == E_META_STONE_STONE) + { + a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0)); + return; + } + a_Pickups.push_back(cItem(E_BLOCK_STONE, 1, a_BlockMeta)); } -} ; +}; diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index f520414a7..8e821b899 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "ChunkInterface.h" @@ -10,6 +11,7 @@ class cBlockTallGrassHandler : public cBlockHandler { + typedef cBlockHandler super; public: cBlockTallGrassHandler(BLOCKTYPE a_BlockType) : cBlockHandler(a_BlockType) @@ -26,32 +28,58 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Drop seeds, sometimes - MTRand r1; - if (r1.randInt(10) == 5) + cFastRandom Random; + if (Random.NextInt(8) == 0) { a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0)); } } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - - if ((!a_Player->IsGameModeCreative()) && (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SHEARS)) + if (a_CanDrop && (a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS)) { - cItems Pickups; - Pickups.Add(E_BLOCK_TALL_GRASS, 1, Meta); - a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ); - - a_Player->UseEquippedItem(); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + cItems Drops; + Drops.Add(m_BlockType, 1, Meta); + + // Allow plugins to modify the pickups: + a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops); + + // Spawn the pickups: + if (!Drops.empty()) + { + MTRand r1; + + // Mid-block position first + double MicroX, MicroY, MicroZ; + MicroX = a_BlockX + 0.5; + MicroY = a_BlockY + 0.5; + MicroZ = a_BlockZ + 0.5; + + // Add random offset second + MicroX += r1.rand(1) - 0.5; + MicroZ += r1.rand(1) - 0.5; + + a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ); + } + return; } + + super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop); } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); + if (a_RelY <= 0) + { + return false; + } + + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); + return IsBlockTypeOfDirt(BelowBlock); } } ; diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index fa46b37a8..e77bbd1b8 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -24,32 +24,23 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - // Find proper placement of torch + BLOCKTYPE Block; + NIBBLETYPE Meta; + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block + a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta); - if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM)) + if (!CanBePlacedOn(Block, Meta, a_BlockFace)) // Try to preserve original direction { - a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Top or bottom faces clicked, find a suitable face + // Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face + + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block + a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Set a_BlockFace to a valid direction which will be converted later to a metadata if (a_BlockFace == BLOCK_FACE_NONE) { - // Client wouldn't have sent anything anyway, but whatever + // No attachable face found - don't place the torch return false; } } - else - { - // Not top or bottom faces, try to preserve whatever face was clicked - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block - if (!CanBePlacedOn(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ), a_BlockFace)) - { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block - // Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face - a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - if (a_BlockFace == BLOCK_FACE_NONE) - { - return false; - } - } - } a_BlockType = m_BlockType; a_BlockMeta = DirectionToMetaData(a_BlockFace); @@ -97,42 +88,57 @@ public: } - static bool CanBePlacedOn(BLOCKTYPE a_BlockType, eBlockFace a_BlockFace) + static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace) { - if (!cBlockInfo::FullyOccupiesVoxel(a_BlockType)) - { - return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle - } - else + switch (a_BlockType) { - return true; + case E_BLOCK_END_PORTAL_FRAME: + case E_BLOCK_SOULSAND: + { + // Exceptional vanilla behaviour + return true; + } + case E_BLOCK_GLASS: + case E_BLOCK_STAINED_GLASS: + case E_BLOCK_FENCE: + case E_BLOCK_NETHER_BRICK_FENCE: + case E_BLOCK_COBBLESTONE_WALL: + { + // Torches can only be placed on top of these blocks + return (a_BlockFace == BLOCK_FACE_YP); + } + case E_BLOCK_STONE_SLAB: + case E_BLOCK_WOODEN_SLAB: + { + // Toches can be placed on the top of these slabs only if the occupy the top half of the voxel + return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08)); + } + default: + { + if (cBlockInfo::FullyOccupiesVoxel(a_BlockType)) + { + // Torches can be placed on all sides of full blocks except the bottom + return (a_BlockFace != BLOCK_FACE_YM); + } + return false; + } } } - /// Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure + /** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */ static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all directions { eBlockFace Face = static_cast<eBlockFace>(i); AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, true); - BLOCKTYPE BlockInQuestion = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ); - - // If on a block that can only hold a torch if torch is standing on it, return that face - if ( - ((BlockInQuestion == E_BLOCK_GLASS) || - (BlockInQuestion == E_BLOCK_FENCE) || - (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) || - (BlockInQuestion == E_BLOCK_COBBLESTONE_WALL)) && - (Face == BLOCK_FACE_TOP) - ) - { - return Face; - } - else if (cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) && (i != BLOCK_FACE_BOTTOM)) + BLOCKTYPE BlockInQuestion; + NIBBLETYPE BlockInQuestionMeta; + a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockInQuestion, BlockInQuestionMeta); + + if (CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face)) { - // Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face return Face; } else @@ -148,34 +154,16 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { eBlockFace Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); - AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); + BLOCKTYPE BlockInQuestion; - a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockInQuestion); - - if ( - (BlockInQuestion == E_BLOCK_GLASS) || - (BlockInQuestion == E_BLOCK_STAINED_GLASS) || - (BlockInQuestion == E_BLOCK_FENCE) || - (BlockInQuestion == E_BLOCK_SOULSAND) || - (BlockInQuestion == E_BLOCK_MOB_SPAWNER) || - (BlockInQuestion == E_BLOCK_END_PORTAL_FRAME) || // Actual vanilla behaviour - (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) || - (BlockInQuestion == E_BLOCK_COBBLESTONE_WALL) - ) - { - // Torches can be placed on tops of glass and fences, despite them being 'untorcheable' - // No need to check for upright orientation, it was done when the torch was placed - return true; - } - else if (!cBlockInfo::FullyOccupiesVoxel(BlockInQuestion)) + NIBBLETYPE BlockInQuestionMeta; + if (!a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockInQuestion, BlockInQuestionMeta)) { return false; } - else - { - return true; - } + + return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face); } diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 41256ae55..8c96de0f1 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -29,6 +29,12 @@ 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 { + if (m_BlockType == E_BLOCK_IRON_TRAPDOOR) + { + // Iron doors can only be toggled by redstone, not by right-clicking + return; + } + // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x04); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 06d84f2d4..00d7a69b8 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -23,10 +23,6 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - UNUSED(a_Player); - UNUSED(a_CursorX); - UNUSED(a_CursorY); - UNUSED(a_CursorZ); // TODO: Disallow placement where the vine doesn't attach to something properly BLOCKTYPE BlockType = 0; NIBBLETYPE BlockMeta; @@ -80,7 +76,21 @@ public: /// Returns true if the specified block type is good for vines to attach to static bool IsBlockAttachable(BLOCKTYPE a_BlockType) { - return ((a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType)); + switch (a_BlockType) + { + case E_BLOCK_GLASS: + case E_BLOCK_STAINED_GLASS: + case E_BLOCK_CHEST: + case E_BLOCK_TRAPPED_CHEST: + { + // You can't attach a vine to this solid blocks. + return false; + } + default: + { + return cBlockInfo::IsSolid(a_BlockType); + } + } } @@ -138,7 +148,7 @@ public: { int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, NULL, BlockX, a_RelY, BlockZ); + DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); } a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); return; @@ -166,23 +176,31 @@ public: return false; } + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) { UNUSED(a_ChunkInterface); UNUSED(a_WorldInterface); - UNUSED(a_BlockPluginInterface); + // Vine cannot grow down if at the bottom: + if (a_RelY < 1) + { + return; + } + + // Grow one block down, if possible: BLOCKTYPE Block; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block); if (Block == E_BLOCK_AIR) { - if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread)) + if (!a_BlockPluginInterface.CallHookBlockSpread(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread)) { a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); } } } + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override { return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right diff --git a/src/Blocks/BroadcastInterface.h b/src/Blocks/BroadcastInterface.h index cf332b153..bf464627d 100644 --- a/src/Blocks/BroadcastInterface.h +++ b/src/Blocks/BroadcastInterface.h @@ -7,6 +7,6 @@ public: virtual ~cBroadcastInterface() {} virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) = 0; - virtual void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0; - virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0; + virtual void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr) = 0; + virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = nullptr) = 0; }; diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 9f971a8bd..eed949aab 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -45,7 +45,6 @@ SET (HDRS BlockGlowstone.h BlockGravel.h BlockHandler.h - BlockHayBale.h BlockHopper.h BlockIce.h BlockLadder.h diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp index e22a1410e..817640e98 100644 --- a/src/Blocks/ChunkInterface.cpp +++ b/src/Blocks/ChunkInterface.cpp @@ -4,7 +4,7 @@ #include "ChunkInterface.h" #include "ChunkMap.h" #include "BlockHandler.h" -#include "WorldInterface.h" +#include "WorldInterface.h" diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 70fdc008c..012105ca1 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -165,7 +165,7 @@ cByteBuffer::~cByteBuffer() { CheckValid(); delete[] m_Buffer; - m_Buffer = NULL; + m_Buffer = nullptr; } @@ -627,23 +627,6 @@ bool cByteBuffer::WriteBool(bool a_Value) -bool cByteBuffer::WriteBEUTF16String16(const AString & a_Value) -{ - CHECK_THREAD; - CheckValid(); - PUTBYTES(2); - AString UTF16BE; - UTF8ToRawBEUTF16(a_Value.data(), a_Value.size(), UTF16BE); - WriteBEShort((short)(UTF16BE.size() / 2)); - PUTBYTES(UTF16BE.size()); - WriteBuf(UTF16BE.data(), UTF16BE.size()); - return true; -} - - - - - bool cByteBuffer::WriteVarInt(UInt32 a_Value) { CHECK_THREAD; diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 74dc378d4..70de419f0 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -88,7 +88,6 @@ public: bool WriteBEFloat (float a_Value); bool WriteBEDouble (double a_Value); bool WriteBool (bool a_Value); - bool WriteBEUTF16String16(const AString & a_Value); // string length as BE short, then string as UTF-16BE bool WriteVarInt (UInt32 a_Value); bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 bool WriteLEInt (int a_Value); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d0e2cede..096fa824d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,7 @@ SET (SRCS FastRandom.cpp FurnaceRecipe.cpp Globals.cpp + IniFile.cpp Inventory.cpp Item.cpp ItemGrid.cpp @@ -98,6 +99,7 @@ SET (HDRS ForEachChunkProvider.h FurnaceRecipe.h Globals.h + IniFile.h Inventory.h Item.h ItemGrid.h @@ -320,4 +322,4 @@ endif () if (WIN32) target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib) endif() -target_link_libraries(${EXECUTABLE} luaexpat iniFile jsoncpp polarssl zlib sqlite lua SQLiteCpp) +target_link_libraries(${EXECUTABLE} luaexpat jsoncpp polarssl zlib sqlite lua SQLiteCpp) diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index b244b1fbc..76ae8c325 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -41,6 +41,7 @@ local g_ShouldProcessExt = --- The list of files not to be processed: local g_IgnoredFiles = { + "Bindings/Bindings.h", "Bindings/Bindings.cpp", "LeakFinder.cpp", "LeakFinder.h", diff --git a/src/Chunk.cpp b/src/Chunk.cpp index ddec950ea..45004fa22 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -93,22 +93,22 @@ cChunk::cChunk( m_NeighborZP(a_NeighborZP), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), - m_RedstoneSimulatorData(NULL), + m_RedstoneSimulatorData(a_World->GetRedstoneSimulator()->CreateChunkData()), m_AlwaysTicked(0) { - if (a_NeighborXM != NULL) + if (a_NeighborXM != nullptr) { a_NeighborXM->m_NeighborXP = this; } - if (a_NeighborXP != NULL) + if (a_NeighborXP != nullptr) { a_NeighborXP->m_NeighborXM = this; } - if (a_NeighborZM != NULL) + if (a_NeighborZM != nullptr) { a_NeighborZM->m_NeighborZP = this; } - if (a_NeighborZP != NULL) + if (a_NeighborZP != nullptr) { a_NeighborZP->m_NeighborZM = this; } @@ -120,7 +120,7 @@ cChunk::cChunk( cChunk::~cChunk() { - cPluginManager::Get()->CallHookChunkUnloaded(m_World, m_PosX, m_PosZ); + cPluginManager::Get()->CallHookChunkUnloaded(*m_World, m_PosX, m_PosZ); // LOGINFO("### delete cChunk() (%i, %i) from %p, thread 0x%x ###", m_PosX, m_PosZ, this, GetCurrentThreadId()); @@ -142,28 +142,28 @@ cChunk::~cChunk() } } - if (m_NeighborXM != NULL) + if (m_NeighborXM != nullptr) { - m_NeighborXM->m_NeighborXP = NULL; + m_NeighborXM->m_NeighborXP = nullptr; } - if (m_NeighborXP != NULL) + if (m_NeighborXP != nullptr) { - m_NeighborXP->m_NeighborXM = NULL; + m_NeighborXP->m_NeighborXM = nullptr; } - if (m_NeighborZM != NULL) + if (m_NeighborZM != nullptr) { - m_NeighborZM->m_NeighborZP = NULL; + m_NeighborZM->m_NeighborZP = nullptr; } - if (m_NeighborZP != NULL) + if (m_NeighborZP != nullptr) { - m_NeighborZP->m_NeighborZM = NULL; + m_NeighborZP->m_NeighborZM = nullptr; } delete m_WaterSimulatorData; - m_WaterSimulatorData = NULL; + m_WaterSimulatorData = nullptr; delete m_LavaSimulatorData; - m_LavaSimulatorData = NULL; + m_LavaSimulatorData = nullptr; delete m_RedstoneSimulatorData; - m_RedstoneSimulatorData = NULL; + m_RedstoneSimulatorData = nullptr; } @@ -334,7 +334,7 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData) { BLOCKTYPE EntityBlockType = (*itr)->GetBlockType(); BLOCKTYPE WorldBlockType = GetBlock((*itr)->GetRelX(), (*itr)->GetPosY(), (*itr)->GetRelZ()); - ASSERT(EntityBlockType == WorldBlockType); + ASSERT(WorldBlockType == EntityBlockType); } // for itr - m_BlockEntities #endif // _DEBUG @@ -582,7 +582,7 @@ void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) } cEntity * newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); - if (newMob == NULL) + if (newMob == nullptr) { continue; } @@ -640,7 +640,7 @@ void cChunk::Tick(float a_Dt) { // Remove all entities that are travelling to another world MarkDirty(); - (*itr)->SetWorldTravellingFrom(NULL); + (*itr)->SetWorldTravellingFrom(nullptr); itr = m_Entities.erase(itr); } else if ( @@ -669,7 +669,7 @@ void cChunk::Tick(float a_Dt) void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) { cBlockHandler * Handler = BlockHandler(GetBlock(a_RelX, a_RelY, a_RelZ)); - ASSERT(Handler != NULL); // Happenned on server restart, FS #243 + ASSERT(Handler != nullptr); // Happenned on server restart, FS #243 cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, a_RelX, a_RelY, a_RelZ); @@ -682,10 +682,10 @@ void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) { cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); - if (Neighbor == NULL) + if (Neighbor == nullptr) { Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); - if (Neighbor == NULL) + if (Neighbor == nullptr) { // TODO: What to do with this? LOGWARNING("%s: Failed to move entity, destination chunk unreachable. Entity lost", __FUNCTION__); @@ -848,7 +848,7 @@ void cChunk::TickBlocks(void) } cBlockHandler * Handler = BlockHandler(GetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ)); - ASSERT(Handler != NULL); // Happenned on server restart, FS #243 + ASSERT(Handler != nullptr); // Happenned on server restart, FS #243 Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ); } // for i - tickblocks } @@ -1128,7 +1128,7 @@ bool cChunk::UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1149,7 +1149,7 @@ bool cChunk::UnboundedRelGetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKT return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1170,7 +1170,7 @@ bool cChunk::UnboundedRelGetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLE return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1191,7 +1191,7 @@ bool cChunk::UnboundedRelGetBlockBlockLight(int a_RelX, int a_RelY, int a_RelZ, return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1212,7 +1212,7 @@ bool cChunk::UnboundedRelGetBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NI return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1233,7 +1233,7 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1255,7 +1255,7 @@ bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1276,7 +1276,7 @@ bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKT return false; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { // The chunk is not available, bail out return false; @@ -1297,7 +1297,7 @@ void cChunk::UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) return; } cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->QueueTickBlock(a_RelX, a_RelY, a_RelZ); } @@ -1454,12 +1454,12 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, // If there was a block entity, remove it: Vector3i WorldPos = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); cBlockEntity * BlockEntity = GetBlockEntity(WorldPos); - if (BlockEntity != NULL) + if (BlockEntity != nullptr) { BlockEntity->Destroy(); RemoveBlockEntity(BlockEntity); delete BlockEntity; - BlockEntity = NULL; + BlockEntity = nullptr; } // If the new block is a block entity, create the entity object: @@ -1622,7 +1622,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client) { - if (a_Client == NULL) + if (a_Client == nullptr) { // Queue the block for all clients in the chunk (will be sent in Tick()) m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ))); @@ -1676,7 +1676,7 @@ cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) } } // for itr - m_BlockEntities[] - return NULL; + return nullptr; } @@ -1711,7 +1711,7 @@ void cChunk::SetAlwaysTicked(bool a_AlwaysTicked) void cChunk::UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z) { cBlockEntity * be = GetBlockEntity(a_X, a_Y, a_Z); - if (be != NULL) + if (be != nullptr) { be->UsedBy(a_Player); } @@ -1745,7 +1745,7 @@ void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_Max // Re-send the chunk to all clients: for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { - m_World->ForceSendChunkTo(m_PosX, m_PosZ, (*itr)); + m_World->ForceSendChunkTo(m_PosX, m_PosZ, cChunkSender::E_CHUNK_PRIORITY_MEDIUM, (*itr)); } // for itr - m_LoadedByClient[] } @@ -1753,11 +1753,11 @@ void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_Max -void cChunk::CollectPickupsByPlayer(cPlayer * a_Player) +void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) { - double PosX = a_Player->GetPosX(); - double PosY = a_Player->GetPosY(); - double PosZ = a_Player->GetPosZ(); + double PosX = a_Player.GetPosX(); + double PosY = a_Player.GetPosY(); + double PosZ = a_Player.GetPosZ(); for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { @@ -2617,7 +2617,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const -void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) +void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const { a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ); a_BlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -2667,10 +2667,10 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) bool ReturnThis = true; if (a_RelX < 0) { - if (m_NeighborXM != NULL) + if (m_NeighborXM != nullptr) { cChunk * Candidate = m_NeighborXM->GetRelNeighborChunk(a_RelX + cChunkDef::Width, a_RelZ); - if (Candidate != NULL) + if (Candidate != nullptr) { return Candidate; } @@ -2680,10 +2680,10 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) } else if (a_RelX >= cChunkDef::Width) { - if (m_NeighborXP != NULL) + if (m_NeighborXP != nullptr) { cChunk * Candidate = m_NeighborXP->GetRelNeighborChunk(a_RelX - cChunkDef::Width, a_RelZ); - if (Candidate != NULL) + if (Candidate != nullptr) { return Candidate; } @@ -2694,24 +2694,24 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) if (a_RelZ < 0) { - if (m_NeighborZM != NULL) + if (m_NeighborZM != nullptr) { return m_NeighborZM->GetRelNeighborChunk(a_RelX, a_RelZ + cChunkDef::Width); // For requests crossing both X and Z, the X-first way has been already tried } - return NULL; + return nullptr; } else if (a_RelZ >= cChunkDef::Width) { - if (m_NeighborZP != NULL) + if (m_NeighborZP != nullptr) { return m_NeighborZP->GetRelNeighborChunk(a_RelX, a_RelZ - cChunkDef::Width); // For requests crossing both X and Z, the X-first way has been already tried } - return NULL; + return nullptr; } - return (ReturnThis ? this : NULL); + return (ReturnThis ? this : nullptr); } @@ -2734,27 +2734,27 @@ cChunk * cChunk::GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) con // Request for a different chunk, calculate chunk offset: int RelX = a_RelX; // Make a local copy of the coords (faster access) int RelZ = a_RelZ; - while ((RelX >= Width) && (ToReturn != NULL)) + while ((RelX >= Width) && (ToReturn != nullptr)) { RelX -= Width; ToReturn = ToReturn->m_NeighborXP; } - while ((RelX < 0) && (ToReturn != NULL)) + while ((RelX < 0) && (ToReturn != nullptr)) { RelX += Width; ToReturn = ToReturn->m_NeighborXM; } - while ((RelZ >= Width) && (ToReturn != NULL)) + while ((RelZ >= Width) && (ToReturn != nullptr)) { RelZ -= Width; ToReturn = ToReturn->m_NeighborZP; } - while ((RelZ < 0) && (ToReturn != NULL)) + while ((RelZ < 0) && (ToReturn != nullptr)) { RelZ += Width; ToReturn = ToReturn->m_NeighborZM; } - if (ToReturn != NULL) + if (ToReturn != nullptr) { a_RelX = RelX; a_RelZ = RelZ; @@ -2824,7 +2824,7 @@ void cChunk::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cons { // We can operate on entity pointers, we're inside the ChunkMap's CS lock which guards the list cBlockEntity * Entity = GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); - if (Entity == NULL) + if (Entity == nullptr) { return; } @@ -3161,7 +3161,7 @@ void cChunk::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Block void cChunk::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client) { cBlockEntity * Entity = GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); - if (Entity == NULL) + if (Entity == nullptr) { return; } diff --git a/src/Chunk.h b/src/Chunk.h index b525fbb82..6f4ac5cac 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -33,7 +33,7 @@ class cChunkMap; class cBeaconEntity; class cBoundingBox; class cChestEntity; -class cCHunkDataCallback; +class cChunkDataCallback; class cCommandBlockEntity; class cDispenserEntity; class cFurnaceEntity; @@ -186,17 +186,17 @@ public: void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const; BLOCKTYPE GetBlock(const Vector3i & a_RelCoords) const { return GetBlock(a_RelCoords.x, a_RelCoords.y, a_RelCoords.z); } - void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); + void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); /** Returns the chunk into which the specified block belongs, by walking the neighbors. - Will return self if appropriate. Returns NULL if not reachable through neighbors. + Will return self if appropriate. Returns nullptr if not reachable through neighbors. */ cChunk * GetNeighborChunk(int a_BlockX, int a_BlockZ); /** Returns the chunk into which the relatively-specified block belongs, by walking the neighbors. - Will return self if appropriate. Returns NULL if not reachable through neighbors. + Will return self if appropriate. Returns nullptr if not reachable through neighbors. */ cChunk * GetRelNeighborChunk(int a_RelX, int a_RelZ); @@ -218,7 +218,7 @@ public: Sends the chunk to all relevant clients. */ void SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_MaxRelZ, EMCSBiome a_Biome); - void CollectPickupsByPlayer(cPlayer * a_Player); + void CollectPickupsByPlayer(cPlayer & a_Player); /** Sets the sign text. Returns true if successful. Also sends update packets to all clients in the chunk */ bool SetSignLines(int a_RelX, int a_RelY, int a_RelZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); @@ -316,28 +316,28 @@ public: // Broadcast various packets to all clients of this chunk: // (Please keep these alpha-sorted) void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); - void BroadcastChunkData (cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL); - void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = NULL); - void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); - void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); - void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); - void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); + void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr); + void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr); + void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastChunkData (cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr); + void BroadcastCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = nullptr); + void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = nullptr); + void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = nullptr); + void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr); + void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = nullptr); + void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ); void SendBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); @@ -421,6 +421,7 @@ public: cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; } cRedstoneSimulatorChunkData * GetRedstoneSimulatorData(void) { return m_RedstoneSimulatorData; } + void SetRedstoneSimulatorData(cRedstoneSimulatorChunkData * a_Data) { m_RedstoneSimulatorData = a_Data; } bool IsRedstoneDirty(void) const { return m_IsRedstoneDirty; } void SetIsRedstoneDirty(bool a_Flag) { m_IsRedstoneDirty = a_Flag; } diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp index 03b0224a6..57b27c5e0 100644 --- a/src/ChunkData.cpp +++ b/src/ChunkData.cpp @@ -36,7 +36,7 @@ cChunkData::cChunkData(cAllocationPool<cChunkData::sChunkSection> & a_Pool) : { for (size_t i = 0; i < NumSections; i++) { - m_Sections[i] = NULL; + m_Sections[i] = nullptr; } } @@ -56,7 +56,7 @@ cChunkData::~cChunkData() for (size_t i = 0; i < NumSections; i++) { Free(m_Sections[i]); - m_Sections[i] = NULL; + m_Sections[i] = nullptr; } } @@ -96,7 +96,7 @@ cChunkData::~cChunkData() for (size_t i = 0; i < NumSections; i++) { Free(m_Sections[i]); - m_Sections[i] = NULL; + m_Sections[i] = nullptr; } } @@ -120,7 +120,7 @@ cChunkData::~cChunkData() for (size_t i = 0; i < NumSections; i++) { m_Sections[i] = other.m_Sections[i]; - other.m_Sections[i] = NULL; + other.m_Sections[i] = nullptr; } } @@ -137,7 +137,7 @@ cChunkData::~cChunkData() { Free(m_Sections[i]); m_Sections[i] = other.m_Sections[i]; - other.m_Sections[i] = NULL; + other.m_Sections[i] = nullptr; } } return *this; @@ -154,7 +154,7 @@ BLOCKTYPE cChunkData::GetBlock(int a_X, int a_Y, int a_Z) const ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height)); ASSERT((a_Z >= 0) && (a_Z < cChunkDef::Width)); int Section = a_Y / SectionHeight; - if (m_Sections[Section] != NULL) + if (m_Sections[Section] != nullptr) { int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * SectionHeight), a_Z); return m_Sections[Section]->m_BlockTypes[Index]; @@ -182,14 +182,14 @@ void cChunkData::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block) } int Section = a_RelY / SectionHeight; - if (m_Sections[Section] == NULL) + if (m_Sections[Section] == nullptr) { if (a_Block == 0x00) { return; } m_Sections[Section] = Allocate(); - if (m_Sections[Section] == NULL) + if (m_Sections[Section] == nullptr) { ASSERT(!"Failed to allocate a new section in Chunkbuffer"); return; @@ -212,7 +212,7 @@ NIBBLETYPE cChunkData::GetMeta(int a_RelX, int a_RelY, int a_RelZ) const (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) { int Section = a_RelY / SectionHeight; - if (m_Sections[Section] != NULL) + if (m_Sections[Section] != nullptr) { int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); return (m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4)) & 0x0f; @@ -243,14 +243,14 @@ bool cChunkData::SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble } int Section = a_RelY / SectionHeight; - if (m_Sections[Section] == NULL) + if (m_Sections[Section] == nullptr) { if ((a_Nibble & 0xf) == 0x00) { return false; } m_Sections[Section] = Allocate(); - if (m_Sections[Section] == NULL) + if (m_Sections[Section] == nullptr) { ASSERT(!"Failed to allocate a new section in Chunkbuffer"); return false; @@ -279,7 +279,7 @@ NIBBLETYPE cChunkData::GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const ) { int Section = a_RelY / SectionHeight; - if (m_Sections[Section] != NULL) + if (m_Sections[Section] != nullptr) { int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f; @@ -302,7 +302,7 @@ NIBBLETYPE cChunkData::GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) { int Section = a_RelY / SectionHeight; - if (m_Sections[Section] != NULL) + if (m_Sections[Section] != nullptr) { int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); return (m_Sections[Section]->m_BlockSkyLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f; @@ -325,7 +325,7 @@ cChunkData cChunkData::Copy(void) const cChunkData copy(m_Pool); for (size_t i = 0; i < NumSections; i++) { - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { copy.m_Sections[i] = copy.Allocate(); *copy.m_Sections[i] = *m_Sections[i]; @@ -354,7 +354,7 @@ void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Lengt { size_t ToCopy = std::min(+SectionBlockCount - StartPos, a_Length); a_Length -= ToCopy; - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { BLOCKTYPE * blockbuffer = m_Sections[i]->m_BlockTypes; memcpy(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], blockbuffer + StartPos, sizeof(BLOCKTYPE) * ToCopy); @@ -375,7 +375,7 @@ void cChunkData::CopyMetas(NIBBLETYPE * a_Dest) const { for (size_t i = 0; i < NumSections; i++) { - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockMetas, sizeof(m_Sections[i]->m_BlockMetas)); } @@ -394,7 +394,7 @@ void cChunkData::CopyBlockLight(NIBBLETYPE * a_Dest) const { for (size_t i = 0; i < NumSections; i++) { - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockLight, sizeof(m_Sections[i]->m_BlockLight)); } @@ -413,7 +413,7 @@ void cChunkData::CopySkyLight(NIBBLETYPE * a_Dest) const { for (size_t i = 0; i < NumSections; i++) { - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockSkyLight, sizeof(m_Sections[i]->m_BlockSkyLight)); } @@ -430,12 +430,12 @@ void cChunkData::CopySkyLight(NIBBLETYPE * a_Dest) const void cChunkData::SetBlockTypes(const BLOCKTYPE * a_Src) { - ASSERT(a_Src != NULL); + ASSERT(a_Src != nullptr); for (size_t i = 0; i < NumSections; i++) { // If the section is already allocated, copy the data into it: - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes)); continue; @@ -462,12 +462,12 @@ void cChunkData::SetBlockTypes(const BLOCKTYPE * a_Src) void cChunkData::SetMetas(const NIBBLETYPE * a_Src) { - ASSERT(a_Src != NULL); + ASSERT(a_Src != nullptr); for (size_t i = 0; i < NumSections; i++) { // If the section is already allocated, copy the data into it: - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas)); continue; @@ -495,7 +495,7 @@ void cChunkData::SetMetas(const NIBBLETYPE * a_Src) void cChunkData::SetBlockLight(const NIBBLETYPE * a_Src) { - if (a_Src == NULL) + if (a_Src == nullptr) { return; } @@ -503,7 +503,7 @@ void cChunkData::SetBlockLight(const NIBBLETYPE * a_Src) for (size_t i = 0; i < NumSections; i++) { // If the section is already allocated, copy the data into it: - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight)); continue; @@ -530,7 +530,7 @@ void cChunkData::SetBlockLight(const NIBBLETYPE * a_Src) void cChunkData::SetSkyLight(const NIBBLETYPE * a_Src) { - if (a_Src == NULL) + if (a_Src == nullptr) { return; } @@ -538,7 +538,7 @@ void cChunkData::SetSkyLight(const NIBBLETYPE * a_Src) for (size_t i = 0; i < NumSections; i++) { // If the section is already allocated, copy the data into it: - if (m_Sections[i] != NULL) + if (m_Sections[i] != nullptr) { memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight)); continue; diff --git a/src/ChunkData.h b/src/ChunkData.h index fe8b068a2..2ab629b29 100644 --- a/src/ChunkData.h +++ b/src/ChunkData.h @@ -88,12 +88,12 @@ public: /** Copies the blocklight data from the specified flat array into the internal representation. Allocates sectios that are needed for the operation. - Allows a_Src to be NULL, in which case it doesn't do anything. */ + Allows a_Src to be nullptr, in which case it doesn't do anything. */ void SetBlockLight(const NIBBLETYPE * a_Src); /** Copies the skylight data from the specified flat array into the internal representation. Allocates sectios that are needed for the operation. - Allows a_Src to be NULL, in which case it doesn't do anything. */ + Allows a_Src to be nullptr, in which case it doesn't do anything. */ void SetSkyLight(const NIBBLETYPE * a_Src); struct sChunkSection @@ -118,7 +118,7 @@ private: sChunkSection * Allocate(void); /** Frees the specified section, previously allocated using Allocate(). - Note that a_Section may be NULL. */ + Note that a_Section may be nullptr. */ void Free(sChunkSection * a_Section); /** Sets the data in the specified section to their default values. */ diff --git a/src/ChunkDef.h b/src/ChunkDef.h index f4ed66c4b..260aace58 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -66,7 +66,7 @@ public: /// The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the highest non-air block in the column typedef HEIGHTTYPE HeightMap[Width * Width]; - + /** The type used for any biomemap operations and storage inside MCServer, using MCServer biomes (need not correspond to client representation!) idx = x + Width * z // Need to verify this with the protocol spec, currently unknown! @@ -95,8 +95,8 @@ public: a_X = a_X - a_ChunkX * Width; a_Z = a_Z - a_ChunkZ * Width; } - - + + /// Converts absolute block coords to chunk coords: inline static void BlockToChunk(int a_X, int a_Z, int & a_ChunkX, int & a_ChunkZ) { @@ -165,15 +165,15 @@ public: ASSERT((a_Z >= 0) && (a_Z < Width)); a_BlockTypes[MakeIndexNoCheck(a_X, a_Y, a_Z)] = a_Type; } - - + + inline static void SetBlock(BLOCKTYPE * a_BlockTypes, int a_Index, BLOCKTYPE a_Type) { ASSERT((a_Index >= 0) && (a_Index <= NumBlocks)); a_BlockTypes[a_Index] = a_Type; } - - + + inline static BLOCKTYPE GetBlock(const BLOCKTYPE * a_BlockTypes, int a_X, int a_Y, int a_Z) { ASSERT((a_X >= 0) && (a_X < Width)); @@ -181,39 +181,39 @@ public: ASSERT((a_Z >= 0) && (a_Z < Width)); return a_BlockTypes[MakeIndexNoCheck(a_X, a_Y, a_Z)]; } - - + + inline static BLOCKTYPE GetBlock(const BLOCKTYPE * a_BlockTypes, int a_Idx) { ASSERT((a_Idx >= 0) && (a_Idx < NumBlocks)); return a_BlockTypes[a_Idx]; } - - + + inline static int GetHeight(const HeightMap & a_HeightMap, int a_X, int a_Z) { ASSERT((a_X >= 0) && (a_X < Width)); ASSERT((a_Z >= 0) && (a_Z < Width)); return a_HeightMap[a_X + Width * a_Z]; } - - + + inline static void SetHeight(HeightMap & a_HeightMap, int a_X, int a_Z, unsigned char a_Height) { ASSERT((a_X >= 0) && (a_X < Width)); ASSERT((a_Z >= 0) && (a_Z < Width)); a_HeightMap[a_X + Width * a_Z] = a_Height; } - - + + inline static EMCSBiome GetBiome(const BiomeMap & a_BiomeMap, int a_X, int a_Z) { ASSERT((a_X >= 0) && (a_X < Width)); ASSERT((a_Z >= 0) && (a_Z < Width)); return a_BiomeMap[a_X + Width * a_Z]; } - - + + inline static void SetBiome(BiomeMap & a_BiomeMap, int a_X, int a_Z, EMCSBiome a_Biome) { ASSERT((a_X >= 0) && (a_X < Width)); @@ -226,11 +226,11 @@ public: { if ((a_BlockIdx > -1) && (a_BlockIdx < NumBlocks)) { - if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + if (static_cast<size_t>(a_BlockIdx / 2) >= a_Buffer.size()) { return (a_IsSkyLightNibble ? 0xff : 0); } - return (a_Buffer[(size_t)(a_BlockIdx / 2)] >> ((a_BlockIdx & 1) * 4)) & 0x0f; + return (a_Buffer[static_cast<size_t>(a_BlockIdx / 2)] >> ((a_BlockIdx & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): index out of chunk range!"); return 0; @@ -241,7 +241,7 @@ public: { if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) { - size_t Index = (size_t)MakeIndexNoCheck(x, y, z); + size_t Index = static_cast<size_t>(MakeIndexNoCheck(x, y, z)); if ((Index / 2) >= a_Buffer.size()) { return (a_IsSkyLightNibble ? 0xff : 0); @@ -258,7 +258,7 @@ public: if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) { int Index = MakeIndexNoCheck(x, y, z); - return (a_Buffer[(size_t)(Index / 2)] >> ((Index & 1) * 4)) & 0x0f; + return (a_Buffer[static_cast<size_t>(Index / 2)] >> ((Index & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); return 0; @@ -272,11 +272,11 @@ public: ASSERT(!"cChunkDef::SetNibble(): index out of range!"); return; } - if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + if (static_cast<size_t>(a_BlockIdx / 2) >= a_Buffer.size()) { - a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1)); + a_Buffer.resize(static_cast<size_t>((a_BlockIdx / 2) + 1)); } - a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, (size_t)a_BlockIdx, a_Nibble); + a_Buffer[static_cast<size_t>(a_BlockIdx / 2)] = PackNibble(a_Buffer, static_cast<size_t>(a_BlockIdx), a_Nibble); } @@ -292,7 +292,7 @@ public: return; } - size_t Index = (size_t)MakeIndexNoCheck(x, y, z); + size_t Index = static_cast<size_t>(MakeIndexNoCheck(x, y, z)); if ((Index / 2) >= a_Buffer.size()) { a_Buffer.resize(((Index / 2) + 1)); @@ -336,7 +336,7 @@ public: /// Called for clients that are in Chunk1 and not in Chunk2, virtual void Removed(cClientHandle * a_Client) = 0; - + /// Called for clients that are in Chunk2 and not in Chunk1. virtual void Added(cClientHandle * a_Client) = 0; } ; @@ -373,9 +373,9 @@ class cChunkCoords public: int m_ChunkX; int m_ChunkZ; - + cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} - + bool operator == (const cChunkCoords & a_Other) const { return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); @@ -432,12 +432,12 @@ public: int y; int z; X Data; - + cCoordWithData(int a_X, int a_Y, int a_Z) : x(a_X), y(a_Y), z(a_Z), Data() { } - + cCoordWithData(int a_X, int a_Y, int a_Z, const X & a_Data) : x(a_X), y(a_Y), z(a_Z), Data(a_Data) { @@ -478,7 +478,3 @@ public: typedef cCoordWithDoubleData <BLOCKTYPE, bool> cCoordWithBlockAndBool; typedef std::vector<cCoordWithBlockAndBool> cCoordWithBlockAndBoolVector; - - - - diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 38a7d9bd4..8a8f17a1b 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -88,10 +88,10 @@ cChunkMap::cChunkLayer * cChunkMap::GetLayer(int a_LayerX, int a_LayerZ) // Not found, create new: cChunkLayer * Layer = new cChunkLayer(a_LayerX, a_LayerZ, this, *m_Pool); - if (Layer == NULL) + if (Layer == nullptr) { LOGERROR("cChunkMap: Cannot create new layer, server out of memory?"); - return NULL; + return nullptr; } m_Layers.push_back(Layer); return Layer; @@ -125,7 +125,7 @@ cChunkMap::cChunkLayer * cChunkMap::FindLayer(int a_LayerX, int a_LayerZ) } // for itr - m_Layers[] // Not found - return NULL; + return nullptr; } @@ -148,16 +148,16 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us cChunkLayer * Layer = GetLayerForChunk(a_ChunkX, a_ChunkZ); - if (Layer == NULL) + if (Layer == nullptr) { // An error must have occurred, since layers are automatically created if they don't exist - return NULL; + return nullptr; } cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { - return NULL; + return nullptr; } if (!Chunk->IsValid() && !Chunk->IsQueued()) { @@ -177,16 +177,16 @@ cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us cChunkLayer * Layer = GetLayerForChunk(a_ChunkX, a_ChunkZ); - if (Layer == NULL) + if (Layer == nullptr) { // An error must have occurred, since layers are automatically created if they don't exist - return NULL; + return nullptr; } cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { - return NULL; + return nullptr; } if (!Chunk->IsValid() && !Chunk->IsQueued()) { @@ -206,10 +206,10 @@ cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkZ) ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); - if (Layer == NULL) + if (Layer == nullptr) { // An error must have occurred, since layers are automatically created if they don't exist - return NULL; + return nullptr; } return Layer->GetChunk(a_ChunkX, a_ChunkZ); @@ -227,7 +227,7 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -249,7 +249,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -270,7 +270,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -289,7 +289,7 @@ bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -308,7 +308,7 @@ bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLO int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -326,9 +326,9 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) ASSERT(m_CSLayers.IsLockedByCurrentThread()); cChunkLayer * Layer = FindLayerForChunk(a_ChunkX, a_ChunkZ); - if (Layer == NULL) + if (Layer == nullptr) { - return NULL; + return nullptr; } return Layer->FindChunk(a_ChunkX, a_ChunkZ); } @@ -341,7 +341,7 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -361,7 +361,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c z = a_BlockZ; cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -380,7 +380,7 @@ void cChunkMap::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a cChunkDef::BlockToChunk(a_blockX, a_blockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -398,7 +398,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -413,7 +413,7 @@ void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSeriali { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -429,7 +429,7 @@ void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -445,7 +445,7 @@ void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHa { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -461,7 +461,7 @@ void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -477,7 +477,7 @@ void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotN { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -493,7 +493,7 @@ void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientH { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -509,7 +509,7 @@ void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandl { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -525,7 +525,7 @@ void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientH { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -541,7 +541,7 @@ void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, ch { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -557,7 +557,7 @@ void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -573,7 +573,7 @@ void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, c { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -589,7 +589,7 @@ void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientH { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -605,7 +605,7 @@ void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animat { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -624,7 +624,7 @@ void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_ cChunkDef::BlockToChunk((int) a_SrcX, (int) a_SrcZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -641,7 +641,7 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -660,7 +660,7 @@ void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, do cChunkDef::BlockToChunk((int)std::floor(a_X), (int)std::floor(a_Z), ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -679,7 +679,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S cChunkDef::BlockToChunk(a_SrcX, a_SrcZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -695,7 +695,7 @@ void cChunkMap::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -713,7 +713,7 @@ void cChunkMap::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, c int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -732,7 +732,7 @@ void cChunkMap::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bl cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -750,7 +750,7 @@ void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClien int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -768,7 +768,7 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -783,7 +783,7 @@ bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callb { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -800,7 +800,7 @@ void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -822,6 +822,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M int MinChunkX, MinChunkZ, MaxChunkX, MaxChunkZ; cChunkDef::BlockToChunk(a_MinBlockX, a_MinBlockZ, MinChunkX, MinChunkZ); cChunkDef::BlockToChunk(a_MaxBlockX, a_MaxBlockZ, MaxChunkX, MaxChunkZ); + cCSLock Lock(m_CSLayers); for (int z = MinChunkZ; z <= MaxChunkZ; z++) { int MinZ = std::max(a_MinBlockZ, z * cChunkDef::Width); @@ -829,7 +830,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M for (int x = MinChunkX; x <= MaxChunkX; x++) { cChunkPtr Chunk = GetChunkNoGen(x, z); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { continue; } @@ -857,7 +858,7 @@ void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -872,7 +873,7 @@ void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDi { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -891,7 +892,7 @@ void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -906,7 +907,7 @@ void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -924,7 +925,7 @@ void cChunkMap::SetChunkData(cSetChunkData & a_SetChunkData) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -954,7 +955,7 @@ void cChunkMap::SetChunkData(cSetChunkData & a_SetChunkData) } // Notify plugins of the chunk becoming available - cPluginManager::Get()->CallHookChunkAvailable(m_World, ChunkX, ChunkZ); + cPluginManager::Get()->CallHookChunkAvailable(*m_World, ChunkX, ChunkZ); } @@ -969,7 +970,7 @@ void cChunkMap::ChunkLighted( { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -985,7 +986,7 @@ bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_ { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -1001,7 +1002,7 @@ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blo { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -1017,7 +1018,7 @@ bool cChunkMap::IsChunkQueued(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - return (Chunk != NULL) && Chunk->IsQueued(); + return (Chunk != nullptr) && Chunk->IsQueued(); } @@ -1028,7 +1029,7 @@ bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - return (Chunk != NULL) && Chunk->IsValid(); + return (Chunk != nullptr) && Chunk->IsValid(); } @@ -1039,7 +1040,7 @@ bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - return (Chunk != NULL) && Chunk->HasAnyClients(); + return (Chunk != nullptr) && Chunk->HasAnyClients(); } @@ -1054,7 +1055,7 @@ int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return 0; } @@ -1081,7 +1082,7 @@ bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -1104,7 +1105,7 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList) int ChunkZ = a_BlockList.front().ChunkZ; cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) { @@ -1145,11 +1146,11 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList) -void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player) +void cChunkMap::CollectPickupsByPlayer(cPlayer & a_Player) { - int BlockX = (int)(a_Player->GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway - int BlockY = (int)(a_Player->GetPosY()); - int BlockZ = (int)(a_Player->GetPosZ()); + int BlockX = (int)(a_Player.GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway + int BlockY = (int)(a_Player.GetPosY()); + int BlockZ = (int)(a_Player.GetPosZ()); int ChunkX = 0, ChunkZ = 0; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); int OtherChunkX = ChunkX + ((BlockX > 8) ? 1 : -1); @@ -1193,7 +1194,7 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { return Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); } @@ -1222,7 +1223,7 @@ NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { return Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); } @@ -1240,7 +1241,7 @@ NIBBLETYPE cChunkMap::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { return Chunk->GetSkyLight(a_BlockX, a_BlockY, a_BlockZ); } @@ -1258,7 +1259,7 @@ NIBBLETYPE cChunkMap::GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_Block cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { return Chunk->GetBlockLight(a_BlockX, a_BlockY, a_BlockZ); } @@ -1277,7 +1278,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); } @@ -1300,7 +1301,7 @@ void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_B cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients); m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk); @@ -1319,7 +1320,7 @@ void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYP cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->QueueSetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType); } @@ -1336,7 +1337,7 @@ bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->GetBlockTypeMeta(X, Y, Z, a_BlockType, a_BlockMeta); return true; @@ -1355,7 +1356,7 @@ bool cChunkMap::GetBlockInfo(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->GetBlockInfo(X, Y, Z, a_BlockType, a_Meta, a_SkyLight, a_BlockLight); return true; @@ -1373,7 +1374,7 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { continue; } @@ -1394,7 +1395,7 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks) for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { continue; } @@ -1429,7 +1430,7 @@ EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { return Chunk->GetBiomeAt(X, Z); } @@ -1450,7 +1451,7 @@ bool cChunkMap::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->SetBiomeAt(X, Z, a_Biome); return true; @@ -1483,7 +1484,7 @@ bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMC int MinRelZ = (z == MinChunkZ) ? MinZ : 0; int MaxRelZ = (z == MaxChunkZ) ? MaxZ : cChunkDef::Width - 1; cChunkPtr Chunk = GetChunkNoLoad(x, z); - if ((Chunk != NULL) && Chunk->IsValid()) + if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->SetAreaBiome(MinRelX, MaxRelX, MinRelZ, MaxRelZ, a_Biome); } @@ -1507,7 +1508,7 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { if (!a_ContinueOnFailure) { @@ -1535,7 +1536,7 @@ bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z) { cCSLock Lock(m_CSLayers); cChunkPtr DestChunk = GetChunk( ChunkX, ChunkZ); - if ((DestChunk == NULL) || !DestChunk->IsValid()) + if ((DestChunk == nullptr) || !DestChunk->IsValid()) { return false; } @@ -1558,7 +1559,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != NULL) && (Chunk->IsValid())) + if ((Chunk != nullptr) && (Chunk->IsValid())) { Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle()); } @@ -1572,12 +1573,12 @@ void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, { cCSLock Lock(m_CSLayers); cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, a_ChunkZ1); - if (Chunk1 == NULL) + if (Chunk1 == nullptr) { return; } cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, a_ChunkZ2); - if (Chunk2 == NULL) + if (Chunk2 == nullptr) { return; } @@ -1639,7 +1640,7 @@ bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Cli { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return false; } @@ -1654,7 +1655,7 @@ void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_ { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -1684,7 +1685,7 @@ void cChunkMap::AddEntity(cEntity * a_Entity) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if ( - (Chunk == NULL) || // Chunk not present at all + (Chunk == nullptr) || // Chunk not present at all (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) ) { @@ -1705,7 +1706,7 @@ void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if ( - (Chunk == NULL) || // Chunk not present at all + (Chunk == nullptr) || // Chunk not present at all (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) ) { @@ -1747,7 +1748,7 @@ void cChunkMap::RemoveEntity(cEntity * a_Entity) cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -1779,7 +1780,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -1805,7 +1806,7 @@ bool cChunkMap::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & for (int x = MinChunkX; x <= MaxChunkX; x++) { cChunkPtr Chunk = GetChunkNoGen(x, z); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { continue; } @@ -1888,6 +1889,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ case E_BLOCK_OBSIDIAN: case E_BLOCK_BEACON: case E_BLOCK_BEDROCK: + case E_BLOCK_BARRIER: case E_BLOCK_WATER: case E_BLOCK_LAVA: { @@ -1979,7 +1981,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } // Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit - a_Entity->TakeDamage(dtExplosion, NULL, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0); + a_Entity->TakeDamage(dtExplosion, nullptr, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0); } // Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt() @@ -2037,7 +2039,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2052,7 +2054,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2067,7 +2069,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2082,7 +2084,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2097,7 +2099,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2112,7 +2114,7 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallba { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2130,7 +2132,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2148,7 +2150,7 @@ bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeacon cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2166,7 +2168,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2184,7 +2186,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2202,7 +2204,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2220,7 +2222,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2238,7 +2240,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2255,7 +2257,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2272,7 +2274,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2290,7 +2292,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2308,7 +2310,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2326,7 +2328,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2351,7 +2353,7 @@ void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { return; } @@ -2368,7 +2370,7 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } @@ -2383,7 +2385,7 @@ void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { // Not present return; @@ -2399,7 +2401,7 @@ bool cChunkMap::IsChunkLighted(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { // Not present return false; @@ -2420,7 +2422,7 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh for (int x = a_MinChunkX; x <= a_MaxChunkX; x++) { cChunkPtr Chunk = GetChunkNoLoad(x, z); - if ((Chunk == NULL) || (!Chunk->IsValid())) + if ((Chunk == nullptr) || (!Chunk->IsValid())) { // Not present / not valid Result = false; @@ -2462,7 +2464,7 @@ bool cChunkMap::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBl for (int x = MinChunkX; x <= MaxChunkX; x++) { cChunkPtr Chunk = GetChunkNoLoad(x, z); - if ((Chunk == NULL) || (!Chunk->IsValid())) + if ((Chunk == nullptr) || (!Chunk->IsValid())) { // Not present / not valid Result = false; @@ -2503,7 +2505,7 @@ void cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk != NULL) + if (Chunk != nullptr) { Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_Rand); } @@ -2520,7 +2522,7 @@ void cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Nu cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk != NULL) + if (Chunk != nullptr) { Chunk->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow); } @@ -2537,7 +2539,7 @@ void cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBl cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk != NULL) + if (Chunk != nullptr) { Chunk->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow); } @@ -2554,7 +2556,7 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk != NULL) + if (Chunk != nullptr) { Chunk->SetNextBlockTick(a_BlockX, a_BlockY, a_BlockZ); } @@ -2609,7 +2611,7 @@ void cChunkMap::TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } @@ -2678,7 +2680,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk != NULL) + if (Chunk != nullptr) { Chunk->QueueTickBlock(a_BlockX, a_BlockY, a_BlockZ); } @@ -2692,7 +2694,7 @@ void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTi { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); - if (Chunk != NULL) + if (Chunk != nullptr) { Chunk->SetAlwaysTicked(a_AlwaysTicked); } @@ -2728,7 +2730,7 @@ cChunkMap::cChunkLayer::~cChunkLayer() for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) { delete m_Chunks[i]; - m_Chunks[i] = NULL; // Must zero out, because further chunk deletions query the chunkmap for entities and that would touch deleted data + m_Chunks[i] = nullptr; // Must zero out, because further chunk deletions query the chunkmap for entities and that would touch deleted data } // for i - m_Chunks[] } @@ -2746,11 +2748,11 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkZ) if (!((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))) { ASSERT(!"Asking a cChunkLayer for a chunk that doesn't belong to it!"); - return NULL; + return nullptr; } int Index = LocalX + LocalZ * LAYER_SIZE; - if (m_Chunks[Index] == NULL) + if (m_Chunks[Index] == nullptr) { cChunk * neixm = (LocalX > 0) ? m_Chunks[Index - 1] : m_Parent->FindChunk(a_ChunkX - 1, a_ChunkZ); cChunk * neixp = (LocalX < LAYER_SIZE - 1) ? m_Chunks[Index + 1] : m_Parent->FindChunk(a_ChunkX + 1, a_ChunkZ); @@ -2773,7 +2775,7 @@ cChunk * cChunkMap::cChunkLayer::FindChunk(int a_ChunkX, int a_ChunkZ) if (!((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))) { ASSERT(!"Asking a cChunkLayer for a chunk that doesn't belong to it!"); - return NULL; + return nullptr; } int Index = LocalX + LocalZ * LAYER_SIZE; @@ -2790,7 +2792,7 @@ void cChunkMap::cChunkLayer::CollectMobCensus(cMobCensus& a_ToFill) // We do count every Mobs in the world. But we are assuming that every chunk not loaded by any client // doesn't affect us. Normally they should not have mobs because every "too far" mobs despawn // If they have (f.i. when player disconnect) we assume we don't have to make them live or despawn - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) { m_Chunks[i]->CollectMobCensus(a_ToFill); } @@ -2807,7 +2809,7 @@ void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner) for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { // We only spawn close to players - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) { m_Chunks[i]->SpawnMobs(a_MobSpawner); } @@ -2823,7 +2825,7 @@ void cChunkMap::cChunkLayer::Tick(float a_Dt) for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { // Only tick chunks that are valid and should be ticked: - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->ShouldBeTicked()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->ShouldBeTicked()) { m_Chunks[i]->Tick(a_Dt); } @@ -2838,7 +2840,7 @@ void cChunkMap::cChunkLayer::RemoveClient(cClientHandle * a_Client) { for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { - if (m_Chunks[i] != NULL) + if (m_Chunks[i] != nullptr) { m_Chunks[i]->RemoveClient(a_Client); } @@ -2854,7 +2856,7 @@ bool cChunkMap::cChunkLayer::ForEachEntity(cEntityCallback & a_Callback) // Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid()) { if (!m_Chunks[i]->ForEachEntity(a_Callback)) { @@ -2874,7 +2876,7 @@ bool cChunkMap::cChunkLayer::DoWithEntityByID(int a_EntityID, cEntityCallback & // Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid()) { if (m_Chunks[i]->DoWithEntityByID(a_EntityID, a_Callback, a_CallbackReturn)) { @@ -2893,7 +2895,7 @@ bool cChunkMap::cChunkLayer::HasEntity(int a_EntityID) { for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid()) { if (m_Chunks[i]->HasEntity(a_EntityID)) { @@ -2913,7 +2915,7 @@ int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const int NumChunks = 0; for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) { - if (m_Chunks[i] != NULL) + if (m_Chunks[i] != nullptr) { NumChunks++; } @@ -2931,7 +2933,7 @@ void cChunkMap::cChunkLayer::GetChunkStats(int & a_NumChunksValid, int & a_NumCh int NumDirty = 0; for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) { - if (m_Chunks[i] == NULL) + if (m_Chunks[i] == nullptr) { continue; } @@ -2954,7 +2956,7 @@ void cChunkMap::cChunkLayer::Save(void) cWorld * World = m_Parent->GetWorld(); for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) { - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty()) + if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty()) { World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()); } @@ -2970,22 +2972,24 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void) for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { if ( - (m_Chunks[i] != NULL) && // Is valid + (m_Chunks[i] != nullptr) && // Is valid (m_Chunks[i]->CanUnload()) && // Can unload - !cPluginManager::Get()->CallHookChunkUnloading(m_Parent->GetWorld(), m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()) // Plugins agree + !cPluginManager::Get()->CallHookChunkUnloading(*(m_Parent->GetWorld()), m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()) // Plugins agree ) { // The cChunk destructor calls our GetChunk() while removing its entities // so we still need to be able to return the chunk. Therefore we first delete, then NULLify // Doing otherwise results in bug http://forum.mc-server.org/showthread.php?tid=355 delete m_Chunks[i]; - m_Chunks[i] = NULL; + m_Chunks[i] = nullptr; } } // for i - m_Chunks[] } + + void cChunkMap::FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CSFastSetBlock); @@ -3030,7 +3034,7 @@ void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay) for (cChunkCoordsVector::const_iterator itr = WantedChunks.begin(); itr != WantedChunks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { continue; } @@ -3079,7 +3083,7 @@ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay) for (cChunkCoordsVector::const_iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr) { cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkZ); - if (Chunk == NULL) + if (Chunk == nullptr) { continue; } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 6e92833f1..51be5cb3d 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -70,29 +70,29 @@ public: // Broadcast respective packets to all clients of the chunk where the event is taking place // (Please keep these alpha-sorted) void BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle); - void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude = NULL); + void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr); + void BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude = nullptr); void BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude); - void BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityLook(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL); - void BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = NULL); - void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); - void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); - void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); - void BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); + void BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr); + void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityLook(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = nullptr); + void BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = nullptr); + void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = nullptr); + void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr); + void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = nullptr); + void BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); void BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ); /** Sends the block entity, if it is at the coords specified, to a_Client */ @@ -144,7 +144,7 @@ public: void FastSetQueuedBlocks(); void FastSetBlocks (sSetBlockList & a_BlockList); - void CollectPickupsByPlayer(cPlayer * a_Player); + void CollectPickupsByPlayer(cPlayer & a_Player); BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ); NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ); @@ -368,7 +368,7 @@ private: /** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */ cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ); - /** Returns the specified chunk, or NULL if not created yet */ + /** Returns the specified chunk, or nullptr if not created yet */ cChunk * FindChunk(int a_ChunkX, int a_ChunkZ); int GetX(void) const {return m_LayerX; } @@ -431,10 +431,10 @@ private: typedef std::list<cChunkStay *> cChunkStays; - /** Finds the cChunkLayer object responsible for the specified chunk; returns NULL if not found. Assumes m_CSLayers is locked. */ + /** Finds the cChunkLayer object responsible for the specified chunk; returns nullptr if not found. Assumes m_CSLayers is locked. */ cChunkLayer * FindLayerForChunk(int a_ChunkX, int a_ChunkZ); - /** Returns the specified cChunkLayer object; returns NULL if not found. Assumes m_CSLayers is locked. */ + /** Returns the specified cChunkLayer object; returns nullptr if not found. Assumes m_CSLayers is locked. */ cChunkLayer * FindLayer(int a_LayerX, int a_LayerZ); /** Returns the cChunkLayer object responsible for the specified chunk; creates it if not found. */ diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp index a3151eb3f..83d82884e 100644 --- a/src/ChunkSender.cpp +++ b/src/ChunkSender.cpp @@ -35,9 +35,9 @@ void cNotifyChunkSender::Call(int a_ChunkX, int a_ChunkZ) cChunkSender::cChunkSender(void) : super("ChunkSender"), - m_World(NULL), + m_World(nullptr), m_RemoveCount(0), - m_Notify(NULL) + m_Notify(nullptr) { m_Notify.SetChunkSender(this); } @@ -91,17 +91,45 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkZ) -void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) +void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, cClientHandle * a_Client) { - ASSERT(a_Client != NULL); + ASSERT(a_Client != nullptr); { + sSendChunk Chunk(a_ChunkX, a_ChunkZ, a_Client); + cCSLock Lock(m_CS); - if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, a_ChunkZ, a_Client)) != m_SendChunks.end()) + if ( + std::find(m_SendChunksLowPriority.begin(), m_SendChunksLowPriority.end(), Chunk) != m_SendChunksLowPriority.end() || + std::find(m_SendChunksMediumPriority.begin(), m_SendChunksMediumPriority.end(), Chunk) != m_SendChunksMediumPriority.end() || + std::find(m_SendChunksHighPriority.begin(), m_SendChunksHighPriority.end(), Chunk) != m_SendChunksHighPriority.end() + ) { // Already queued, bail out return; } - m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkZ, a_Client)); + + switch (a_Priority) + { + case E_CHUNK_PRIORITY_LOW: + { + m_SendChunksLowPriority.push_back(Chunk); + break; + } + case E_CHUNK_PRIORITY_MEDIUM: + { + m_SendChunksMediumPriority.push_back(Chunk); + break; + } + case E_CHUNK_PRIORITY_HIGH: + { + m_SendChunksHighPriority.push_back(Chunk); + break; + } + default: + { + ASSERT(!"Unknown chunk priority!"); + } + } } m_evtQueue.Set(); } @@ -114,15 +142,33 @@ void cChunkSender::RemoveClient(cClientHandle * a_Client) { { cCSLock Lock(m_CS); - for (sSendChunkList::iterator itr = m_SendChunks.begin(); itr != m_SendChunks.end();) + for (sSendChunkList::iterator itr = m_SendChunksLowPriority.begin(); itr != m_SendChunksLowPriority.end();) { if (itr->m_Client == a_Client) { - itr = m_SendChunks.erase(itr); + itr = m_SendChunksLowPriority.erase(itr); continue; } ++itr; - } // for itr - m_SendChunks[] + } // for itr - m_SendChunksLowPriority[] + for (sSendChunkList::iterator itr = m_SendChunksMediumPriority.begin(); itr != m_SendChunksMediumPriority.end();) + { + if (itr->m_Client == a_Client) + { + itr = m_SendChunksMediumPriority.erase(itr); + continue; + } + ++itr; + } // for itr - m_SendChunksMediumPriority[] + for (sSendChunkList::iterator itr = m_SendChunksHighPriority.begin(); itr != m_SendChunksHighPriority.end();) + { + if (itr->m_Client == a_Client) + { + itr = m_SendChunksHighPriority.erase(itr); + continue; + } + ++itr; + } // for itr - m_SendChunksHighPriority[] m_RemoveCount++; } m_evtQueue.Set(); @@ -138,7 +184,7 @@ void cChunkSender::Execute(void) while (!m_ShouldTerminate) { cCSLock Lock(m_CS); - while (m_ChunksReady.empty() && m_SendChunks.empty()) + while (m_ChunksReady.empty() && m_SendChunksLowPriority.empty() && m_SendChunksMediumPriority.empty() && m_SendChunksHighPriority.empty()) { int RemoveCount = m_RemoveCount; m_RemoveCount = 0; @@ -153,23 +199,41 @@ void cChunkSender::Execute(void) return; } } // while (empty) - - if (!m_ChunksReady.empty()) + + if (!m_SendChunksHighPriority.empty()) + { + // Take one from the queue: + sSendChunk Chunk(m_SendChunksHighPriority.front()); + m_SendChunksHighPriority.pop_front(); + Lock.Unlock(); + + SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); + } + else if (!m_ChunksReady.empty()) { // Take one from the queue: cChunkCoords Coords(m_ChunksReady.front()); m_ChunksReady.pop_front(); Lock.Unlock(); - SendChunk(Coords.m_ChunkX, Coords.m_ChunkZ, NULL); + SendChunk(Coords.m_ChunkX, Coords.m_ChunkZ, nullptr); + } + else if (!m_SendChunksMediumPriority.empty()) + { + // Take one from the queue: + sSendChunk Chunk(m_SendChunksMediumPriority.front()); + m_SendChunksMediumPriority.pop_front(); + Lock.Unlock(); + + SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); } else { // Take one from the queue: - sSendChunk Chunk(m_SendChunks.front()); - m_SendChunks.pop_front(); + sSendChunk Chunk(m_SendChunksLowPriority.front()); + m_SendChunksLowPriority.pop_front(); Lock.Unlock(); - + SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); } Lock.Lock(); @@ -189,45 +253,42 @@ void cChunkSender::Execute(void) void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); // Ask the client if it still wants the chunk: - if (a_Client != NULL) + if ((a_Client != nullptr) && !a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ)) { - if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ)) - { - return; - } + return; } - + // If the chunk has no clients, no need to packetize it: if (!m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ)) { return; } - + // If the chunk is not valid, do nothing - whoever needs it has queued it for loading / generating if (!m_World->IsChunkValid(a_ChunkX, a_ChunkZ)) { return; } - + // If the chunk is not lighted, queue it for relighting and get notified when it's ready: if (!m_World->IsChunkLighted(a_ChunkX, a_ChunkZ)) { m_World->QueueLightChunk(a_ChunkX, a_ChunkZ, &m_Notify); return; } - + // Query and prepare chunk data: if (!m_World->GetChunkData(a_ChunkX, a_ChunkZ, *this)) { return; } cChunkDataSerializer Data(m_BlockTypes, m_BlockMetas, m_BlockLight, m_BlockSkyLight, m_BiomeMap); - + // Send: - if (a_Client == NULL) + if (a_Client == nullptr) { m_World->BroadcastChunkData(a_ChunkX, a_ChunkZ, Data); } @@ -235,11 +296,11 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Clien { a_Client->SendChunkData(a_ChunkX, a_ChunkZ, Data); } - + // Send block-entity packets: for (sBlockCoords::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) { - if (a_Client == NULL) + if (a_Client == nullptr) { m_World->BroadcastBlockEntity(itr->m_BlockX, itr->m_BlockY, itr->m_BlockZ); } @@ -249,7 +310,7 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Clien } } // for itr - m_Packets[] m_BlockEntities.clear(); - + // TODO: Send entity spawn packets } diff --git a/src/ChunkSender.h b/src/ChunkSender.h index a0e9087a9..7cd7ddd86 100644 --- a/src/ChunkSender.h +++ b/src/ChunkSender.h @@ -75,6 +75,13 @@ class cChunkSender: public: cChunkSender(void); ~cChunkSender(); + + enum eChunkPriority + { + E_CHUNK_PRIORITY_HIGH = 0, + E_CHUNK_PRIORITY_MEDIUM = 1, + E_CHUNK_PRIORITY_LOW = 2, + }; bool Start(cWorld * a_World); @@ -84,7 +91,7 @@ public: void ChunkReady(int a_ChunkX, int a_ChunkZ); /// Queues a chunk to be sent to a specific client - void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); + void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, cClientHandle * a_Client); /// Removes the a_Client from all waiting chunk send operations void RemoveClient(cClientHandle * a_Client); @@ -136,7 +143,9 @@ protected: cCriticalSection m_CS; cChunkCoordsList m_ChunksReady; - sSendChunkList m_SendChunks; + sSendChunkList m_SendChunksLowPriority; + sSendChunkList m_SendChunksMediumPriority; + sSendChunkList m_SendChunksHighPriority; cEvent m_evtQueue; // Set when anything is added to m_ChunksReady cEvent m_evtRemoved; // Set when removed clients are safe to be deleted int m_RemoveCount; // Number of threads waiting for a client removal (m_evtRemoved needs to be set this many times) @@ -158,7 +167,7 @@ protected: virtual void Entity (cEntity * a_Entity) override; virtual void BlockEntity (cBlockEntity * a_Entity) override; - /// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == NULL + /// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == nullptr void SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); } ; diff --git a/src/ChunkStay.cpp b/src/ChunkStay.cpp index 38aa89a37..0772787de 100644 --- a/src/ChunkStay.cpp +++ b/src/ChunkStay.cpp @@ -12,7 +12,7 @@ cChunkStay::cChunkStay(void) : - m_ChunkMap(NULL) + m_ChunkMap(nullptr) { } @@ -31,7 +31,7 @@ cChunkStay::~cChunkStay() void cChunkStay::Clear(void) { - ASSERT(m_ChunkMap == NULL); + ASSERT(m_ChunkMap == nullptr); m_Chunks.clear(); } @@ -41,7 +41,7 @@ void cChunkStay::Clear(void) void cChunkStay::Add(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_ChunkMap == NULL); + ASSERT(m_ChunkMap == nullptr); for (cChunkCoordsVector::const_iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr) { @@ -60,7 +60,7 @@ void cChunkStay::Add(int a_ChunkX, int a_ChunkZ) void cChunkStay::Remove(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_ChunkMap == NULL); + ASSERT(m_ChunkMap == nullptr); for (cChunkCoordsVector::iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr) { @@ -79,7 +79,7 @@ void cChunkStay::Remove(int a_ChunkX, int a_ChunkZ) void cChunkStay::Enable(cChunkMap & a_ChunkMap) { - ASSERT(m_ChunkMap == NULL); + ASSERT(m_ChunkMap == nullptr); m_OutstandingChunks = m_Chunks; m_ChunkMap = &a_ChunkMap; @@ -92,10 +92,10 @@ void cChunkStay::Enable(cChunkMap & a_ChunkMap) void cChunkStay::Disable(void) { - ASSERT(m_ChunkMap != NULL); + ASSERT(m_ChunkMap != nullptr); cChunkMap * ChunkMap = m_ChunkMap; - m_ChunkMap = NULL; + m_ChunkMap = nullptr; ChunkMap->DelChunkStay(*this); } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 878d309c9..c4ce721c3 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -65,10 +65,11 @@ 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(NULL), + m_Player(nullptr), m_HasSentDC(false), m_LastStreamedChunkX(0x7fffffff), // bogus chunk coords to force streaming upon login m_LastStreamedChunkZ(0x7fffffff), @@ -92,7 +93,9 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) : m_NumBlockChangeInteractionsThisTick(0), m_UniqueID(0), m_HasSentPlayerChunk(false), - m_Locale("en_GB") + m_Locale("en_GB"), + m_LastPlacedSign(0, -1, 0), + m_ProtocolVersion(0) { m_Protocol = new cProtocolRecognizer(this); @@ -121,10 +124,10 @@ cClientHandle::~cClientHandle() m_ChunksToSend.clear(); } - if (m_Player != NULL) + if (m_Player != nullptr) { cWorld * World = m_Player->GetWorld(); - if (World != NULL) + if (World != nullptr) { if (!m_Username.empty()) { @@ -136,7 +139,7 @@ cClientHandle::~cClientHandle() m_Player->Destroy(); } delete m_Player; - m_Player = NULL; + m_Player = nullptr; } if (!m_HasSentDC) @@ -148,7 +151,7 @@ cClientHandle::~cClientHandle() cRoot::Get()->GetServer()->RemoveClient(this); delete m_Protocol; - m_Protocol = NULL; + m_Protocol = nullptr; LOGD("ClientHandle at %p deleted", this); } @@ -172,7 +175,7 @@ void cClientHandle::Destroy(void) // DEBUG: LOGD("%s: client %p, \"%s\"", __FUNCTION__, this, m_Username.c_str()); - if ((m_Player != NULL) && (m_Player->GetWorld() != NULL)) + if ((m_Player != nullptr) && (m_Player->GetWorld() != nullptr)) { RemoveFromAllChunks(); m_Player->GetWorld()->RemoveClientFromChunkSender(this); @@ -247,9 +250,12 @@ AString cClientHandle::GenerateOfflineUUID(const AString & a_Username) // xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B // Note that we generate a short UUID (without the dashes) + // First make the username lowercase: + AString lcUsername = StrToLower(a_Username); + // Generate an md5 checksum, and use it as base for the ID: unsigned char MD5[16]; - md5((const unsigned char *)a_Username.c_str(), a_Username.length(), MD5); + md5((const unsigned char *)lcUsername.c_str(), lcUsername.length(), MD5); MD5[6] &= 0x0f; // Need to trim to 4 bits only... MD5[8] &= 0x0f; // ... otherwise %01x overflows into two chars return Printf("%02x%02x%02x%02x%02x%02x3%01x%02x8%01x%02x%02x%02x%02x%02x%02x%02x", @@ -310,7 +316,7 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, return; } - ASSERT(m_Player == NULL); + ASSERT(m_Player == nullptr); m_Username = a_Name; @@ -331,7 +337,7 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, m_Player = new cPlayer(this, GetUsername()); cWorld * World = cRoot::Get()->GetWorld(m_Player->GetLoadedWorldName()); - if (World == NULL) + if (World == nullptr) { World = cRoot::Get()->GetDefaultWorld(); } @@ -401,53 +407,145 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, -void cClientHandle::StreamChunks(void) +bool cClientHandle::StreamNextChunk(void) { if ((m_State < csAuthenticated) || (m_State >= csDestroying)) { - return; + return true; } + ASSERT(m_Player != nullptr); - ASSERT(m_Player != NULL); + int ChunkPosX = m_Player->GetChunkX(); + int ChunkPosZ = m_Player->GetChunkZ(); + if ((m_LastStreamedChunkX == ChunkPosX) && (m_LastStreamedChunkZ == ChunkPosZ)) + { + // All chunks are already loaded. Abort loading. + return true; + } - int ChunkPosX = FAST_FLOOR_DIV((int)m_Player->GetPosX(), cChunkDef::Width); - int ChunkPosZ = FAST_FLOOR_DIV((int)m_Player->GetPosZ(), cChunkDef::Width); - if ((ChunkPosX == m_LastStreamedChunkX) && (ChunkPosZ == m_LastStreamedChunkZ)) + // Get the look vector and normalize it. + Vector3d Position = m_Player->GetEyePosition(); + Vector3d LookVector = m_Player->GetLookVector(); + LookVector.Normalize(); + + // Lock the list + 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_CurrentViewDistance; Range++) { - // Already streamed for this position - return; + Vector3d Vector = Position + LookVector * cChunkDef::Width * Range; + + // Get the chunk from the x/z coords. + int RangeX, RangeZ = 0; + cChunkDef::BlockToChunk(FloorC(Vector.x), FloorC(Vector.z), RangeX, RangeZ); + + for (size_t X = 0; X < 7; X++) + { + for (size_t Z = 0; Z < 7; Z++) + { + int ChunkX = RangeX + ((X >= 4) ? (3 - X) : X); + int ChunkZ = RangeZ + ((Z >= 4) ? (3 - Z) : Z); + cChunkCoords Coords(ChunkX, ChunkZ); + + // Checks if the chunk is in distance + if ((Diff(ChunkX, ChunkPosX) > m_CurrentViewDistance) || (Diff(ChunkZ, ChunkPosZ) > m_CurrentViewDistance)) + { + continue; + } + + // If the chunk already loading/loaded -> skip + if ( + (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), Coords) != m_ChunksToSend.end()) || + (std::find(m_LoadedChunks.begin(), m_LoadedChunks.end(), Coords) != m_LoadedChunks.end()) + ) + { + continue; + } + + // Unloaded chunk found -> Send it to the client. + Lock.Unlock(); + StreamChunk(ChunkX, ChunkZ, ((Range <= 2) ? cChunkSender::E_CHUNK_PRIORITY_HIGH : cChunkSender::E_CHUNK_PRIORITY_MEDIUM)); + return false; + } + } } + + // Low priority: Add all chunks that are in range. (From the center out to the edge) + 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; + for (int i = -d; i <= d; ++i) + { + CurcleChunks.push_back(cChunkCoords(ChunkPosX + d, ChunkPosZ + i)); + CurcleChunks.push_back(cChunkCoords(ChunkPosX - d, ChunkPosZ + i)); + } + for (int i = -d + 1; i < d; ++i) + { + CurcleChunks.push_back(cChunkCoords(ChunkPosX + i, ChunkPosZ + d)); + CurcleChunks.push_back(cChunkCoords(ChunkPosX + i, ChunkPosZ - d)); + } + + // For each the CurcleChunks list and send the first unloaded chunk: + for (cChunkCoordsList::iterator itr = CurcleChunks.begin(), end = CurcleChunks.end(); itr != end; ++itr) + { + cChunkCoords Coords = *itr; + + // If the chunk already loading/loaded -> skip + if ( + (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), Coords) != m_ChunksToSend.end()) || + (std::find(m_LoadedChunks.begin(), m_LoadedChunks.end(), Coords) != m_LoadedChunks.end()) + ) + { + continue; + } + + // Unloaded chunk found -> Send it to the client. + Lock.Unlock(); + StreamChunk(Coords.m_ChunkX, Coords.m_ChunkZ, cChunkSender::E_CHUNK_PRIORITY_LOW); + return false; + } + } + + // All chunks are loaded -> Sets the last loaded chunk coordinates to current coordinates m_LastStreamedChunkX = ChunkPosX; m_LastStreamedChunkZ = ChunkPosZ; - - LOGD("Streaming chunks centered on [%d, %d], view distance %d", ChunkPosX, ChunkPosZ, m_ViewDistance); - - cWorld * World = m_Player->GetWorld(); - ASSERT(World != NULL); + return true; +} - // Remove all loaded chunks that are no longer in range; deferred to out-of-CS: - cChunkCoordsList RemoveChunks; + + + + +void cClientHandle::UnloadOutOfRangeChunks(void) +{ + int ChunkPosX = FAST_FLOOR_DIV((int)m_Player->GetPosX(), cChunkDef::Width); + int ChunkPosZ = FAST_FLOOR_DIV((int)m_Player->GetPosZ(), cChunkDef::Width); + + cChunkCoordsList ChunksToRemove; { cCSLock Lock(m_CSChunkLists); for (cChunkCoordsList::iterator itr = m_LoadedChunks.begin(); itr != m_LoadedChunks.end();) { - int RelX = (*itr).m_ChunkX - ChunkPosX; - int RelZ = (*itr).m_ChunkZ - ChunkPosZ; - if ((RelX > m_ViewDistance) || (RelX < -m_ViewDistance) || (RelZ > m_ViewDistance) || (RelZ < -m_ViewDistance)) + int DiffX = Diff((*itr).m_ChunkX, ChunkPosX); + int DiffZ = Diff((*itr).m_ChunkZ, ChunkPosZ); + if ((DiffX > m_CurrentViewDistance) || (DiffZ > m_CurrentViewDistance)) { - RemoveChunks.push_back(*itr); + ChunksToRemove.push_back(*itr); itr = m_LoadedChunks.erase(itr); } else { ++itr; } - } // for itr - m_LoadedChunks[] + } + for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end();) { - int RelX = (*itr).m_ChunkX - ChunkPosX; - int RelZ = (*itr).m_ChunkZ - ChunkPosZ; - if ((RelX > m_ViewDistance) || (RelX < -m_ViewDistance) || (RelZ > m_ViewDistance) || (RelZ < -m_ViewDistance)) + int DiffX = Diff((*itr).m_ChunkX, ChunkPosX); + int DiffZ = Diff((*itr).m_ChunkZ, ChunkPosZ); + if ((DiffX > m_CurrentViewDistance) || (DiffZ > m_CurrentViewDistance)) { itr = m_ChunksToSend.erase(itr); } @@ -455,52 +553,21 @@ void cClientHandle::StreamChunks(void) { ++itr; } - } // for itr - m_ChunksToSend[] + } } - for (cChunkCoordsList::iterator itr = RemoveChunks.begin(); itr != RemoveChunks.end(); ++itr) - { - World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this); - m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); - } // for itr - RemoveChunks[] - - // Add all chunks that are in range and not yet in m_LoadedChunks: - // Queue these smartly - from the center out to the edge - for (int d = 0; d <= m_ViewDistance; ++d) // cycle through (square) distance, from nearest to furthest - { - // For each distance add chunks in a hollow square centered around current position: - for (int i = -d; i <= d; ++i) - { - StreamChunk(ChunkPosX + d, ChunkPosZ + i); - StreamChunk(ChunkPosX - d, ChunkPosZ + i); - } // for i - for (int i = -d + 1; i < d; ++i) - { - StreamChunk(ChunkPosX + i, ChunkPosZ + d); - StreamChunk(ChunkPosX + i, ChunkPosZ - d); - } // for i - } // for d - - // Touch chunks GENERATEDISTANCE ahead to let them generate: - for (int d = m_ViewDistance + 1; d <= m_ViewDistance + GENERATEDISTANCE; ++d) // cycle through (square) distance, from nearest to furthest + + for (cChunkCoordsList::iterator itr = ChunksToRemove.begin(); itr != ChunksToRemove.end(); ++itr) { - // For each distance touch chunks in a hollow square centered around current position: - for (int i = -d; i <= d; ++i) - { - World->TouchChunk(ChunkPosX + d, ChunkPosZ + i); - World->TouchChunk(ChunkPosX - d, ChunkPosZ + i); - } // for i - for (int i = -d + 1; i < d; ++i) - { - World->TouchChunk(ChunkPosX + i, ChunkPosZ + d); - World->TouchChunk(ChunkPosX + i, ChunkPosZ - d); - } // for i - } // for d + m_Player->GetWorld()->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this); + SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); + } } -void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) + +void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority) { if (m_State >= csDestroying) { @@ -509,7 +576,7 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) } cWorld * World = m_Player->GetWorld(); - ASSERT(World != NULL); + ASSERT(World != nullptr); if (World->AddChunkClient(a_ChunkX, a_ChunkZ, this)) { @@ -518,7 +585,7 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } - World->SendChunkTo(a_ChunkX, a_ChunkZ, this); + World->SendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, this); } } @@ -530,16 +597,18 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) void cClientHandle::RemoveFromAllChunks() { cWorld * World = m_Player->GetWorld(); - if (World != NULL) + if (World != nullptr) { World->RemoveClientFromChunks(this); } { + // Reset all chunk lists: cCSLock Lock(m_CSChunkLists); m_LoadedChunks.clear(); m_ChunksToSend.clear(); - + m_SentChunks.clear(); + // Also reset the LastStreamedChunk coords to bogus coords, // so that all chunks are streamed in subsequent StreamChunks() call (FS #407) m_LastStreamedChunkX = 0x7fffffff; @@ -551,6 +620,16 @@ void cClientHandle::RemoveFromAllChunks() +void cClientHandle::HandleNPCTrade(int a_SlotNum) +{ + // TODO + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + + + void cClientHandle::HandlePing(void) { // Somebody tries to retrieve information about the server @@ -573,16 +652,22 @@ void cClientHandle::HandlePing(void) bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Username) { - LOGD("LOGIN %s", a_Username.c_str()); + // If the protocol version hasn't been set yet, set it now: + if (m_ProtocolVersion == 0) + { + m_ProtocolVersion = a_ProtocolVersion; + } + m_Username = a_Username; - if (cRoot::Get()->GetPluginManager()->CallHookLogin(this, a_ProtocolVersion, a_Username)) + // Let the plugins know about this event, they may refuse the player: + if (cRoot::Get()->GetPluginManager()->CallHookLogin(*this, a_ProtocolVersion, a_Username)) { Destroy(); return false; } - // Schedule for authentication; until then, let them wait (but do not block) + // Schedule for authentication; until then, let the player wait (but do not block) m_State = csAuthenticating; cRoot::Get()->GetAuthenticator().Authenticate(GetUniqueID(), GetUsername(), m_Protocol->GetAuthServerID()); return true; @@ -628,7 +713,7 @@ void cClientHandle::HandlePlayerAbilities(bool a_CanFly, bool a_IsFlying, float void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround) { - if ((m_Player == NULL) || (m_State != csPlaying)) + if ((m_Player == nullptr) || (m_State != csPlaying)) { // The client hasn't been spawned yet and sends nonsense, we know better return; @@ -676,25 +761,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message) { - if (a_Channel == "MC|AdvCdm") - { - // Command block, set text, Client -> Server - HandleCommandBlockMessage(a_Message.c_str(), a_Message.size()); - } - else if (a_Channel == "MC|Brand") - { - // Client <-> Server branding exchange - SendPluginMessage("MC|Brand", "MCServer"); - } - else if (a_Channel == "MC|Beacon") - { - HandleBeaconSelection(a_Message.c_str(), a_Message.size()); - } - else if (a_Channel == "MC|ItemName") - { - HandleAnvilItemName(a_Message.c_str(), a_Message.size()); - } - else if (a_Channel == "REGISTER") + if (a_Channel == "REGISTER") { if (HasPluginChannel(a_Channel)) { @@ -777,17 +844,10 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList -void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) +void cClientHandle::HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEffect) { - if (a_Length < 14) - { - SendChat("Failure setting beacon selection; bad request", mtFailure); - LOGD("Malformed MC|Beacon packet."); - return; - } - cWindow * Window = m_Player->GetWindow(); - if ((Window == NULL) || (Window->GetWindowType() != cWindow::wtBeacon)) + if ((Window == nullptr) || (Window->GetWindowType() != cWindow::wtBeacon)) { return; } @@ -798,23 +858,15 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) return; } - cByteBuffer Buffer(a_Length); - Buffer.Write(a_Data, a_Length); - - int PrimaryEffectID, SecondaryEffectID; - Buffer.ReadBEInt(PrimaryEffectID); - Buffer.ReadBEInt(SecondaryEffectID); - cEntityEffect::eType PrimaryEffect = cEntityEffect::effNoEffect; - if ((PrimaryEffectID >= 0) && (PrimaryEffectID <= (int)cEntityEffect::effSaturation)) + if ((a_PrimaryEffect >= 0) && (a_PrimaryEffect <= (int)cEntityEffect::effSaturation)) { - PrimaryEffect = (cEntityEffect::eType)PrimaryEffectID; + PrimaryEffect = (cEntityEffect::eType)a_PrimaryEffect; } - cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect; - if ((SecondaryEffectID >= 0) && (SecondaryEffectID <= (int)cEntityEffect::effSaturation)) + if ((a_SecondaryEffect >= 0) && (a_SecondaryEffect <= (int)cEntityEffect::effSaturation)) { - SecondaryEffect = (cEntityEffect::eType)SecondaryEffectID; + SecondaryEffect = (cEntityEffect::eType)a_SecondaryEffect; } Window->SetSlot(*m_Player, 0, cItem()); @@ -841,52 +893,12 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) -void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length) +void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand) { - if (a_Length < 14) - { - SendChat("Failure setting command block command; bad request", mtFailure); - LOGD("Malformed MC|AdvCdm packet."); - return; - } - - cByteBuffer Buffer(a_Length); - Buffer.Write(a_Data, a_Length); - - int BlockX, BlockY, BlockZ; - - AString Command; - - char Mode; - - Buffer.ReadChar(Mode); - - switch (Mode) - { - case 0x00: - { - Buffer.ReadBEInt(BlockX); - Buffer.ReadBEInt(BlockY); - Buffer.ReadBEInt(BlockZ); - - Buffer.ReadVarUTF8String(Command); - break; - } - - default: - { - SendChat("Failure setting command block command; unhandled mode", mtFailure); - LOGD("Unhandled MC|AdvCdm packet mode."); - return; - } - } - cWorld * World = m_Player->GetWorld(); - if (World->AreCommandBlocksEnabled()) { - World->SetCommandBlockCommand(BlockX, BlockY, BlockZ, Command); - + World->SetCommandBlockCommand(a_BlockX, a_BlockY, a_BlockZ, a_NewCommand); SendChat("Successfully set command block command", mtSuccess); } else @@ -899,22 +911,26 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Leng -void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length) +void cClientHandle::HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand) { - if (a_Length < 1) - { - return; - } + // TODO + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + - if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil)) + +void cClientHandle::HandleAnvilItemName(const AString & a_ItemName) +{ + if ((m_Player->GetWindow() == nullptr) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil)) { return; } - AString Name(a_Data, a_Length); - if (Name.length() <= 30) + if (a_ItemName.length() <= 30) { - ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player); + ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(a_ItemName, m_Player); } } @@ -1148,10 +1164,18 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo FinishDigAnimation(); - if (!m_Player->IsGameModeCreative() && (a_OldBlock == E_BLOCK_BEDROCK)) + if (!m_Player->IsGameModeCreative()) { - Kick("You can't break a bedrock!"); - return; + if (a_OldBlock == E_BLOCK_BEDROCK) + { + Kick("You can't break a bedrock!"); + return; + } + if (a_OldBlock == E_BLOCK_BARRIER) + { + Kick("You can't break a barrier!"); + return; + } } cWorld * World = m_Player->GetWorld(); @@ -1478,6 +1502,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); @@ -1536,7 +1561,7 @@ void cClientHandle::HandleChat(const AString & a_Message) void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsOnGround) { - if ((m_Player == NULL) || (m_State != csPlaying)) + if ((m_Player == nullptr) || (m_State != csPlaying)) { return; } @@ -1636,7 +1661,7 @@ void cClientHandle::HandleWindowClick(char a_WindowID, short a_SlotNum, eClickAc ); cWindow * Window = m_Player->GetWindow(); - if (Window == NULL) + if (Window == nullptr) { LOGWARNING("Player \"%s\" clicked in a non-existent window. Ignoring", m_Username.c_str()); return; @@ -1655,8 +1680,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); + } } @@ -1728,7 +1756,7 @@ void cClientHandle::HandleUseEntity(int a_TargetEntityID, bool a_IsLeftClick) void cClientHandle::HandleRespawn(void) { - if (m_Player == NULL) + if (m_Player == nullptr) { Destroy(); return; @@ -1741,20 +1769,6 @@ void cClientHandle::HandleRespawn(void) -void cClientHandle::HandleDisconnect(const AString & a_Reason) -{ - LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str()); - - cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason); - - m_HasSentDC = true; - Destroy(); -} - - - - - void cClientHandle::HandleKeepAlive(int a_KeepAliveID) { if (a_KeepAliveID == m_PingID) @@ -1770,7 +1784,7 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID) bool cClientHandle::HandleHandshake(const AString & a_Username) { - if (!cRoot::Get()->GetPluginManager()->CallHookHandshake(this, a_Username)) + if (!cRoot::Get()->GetPluginManager()->CallHookHandshake(*this, a_Username)) { if (cRoot::Get()->GetServer()->GetNumPlayers() >= cRoot::Get()->GetServer()->GetMaxPlayers()) { @@ -1832,7 +1846,7 @@ void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting) void cClientHandle::HandleUnmount(void) { - if (m_Player == NULL) + if (m_Player == nullptr) { return; } @@ -1924,10 +1938,11 @@ void cClientHandle::RemoveFromWorld(void) { m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - Chunks[] - + // Here, we set last streamed values to bogus ones so everything is resent m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; + m_HasSentPlayerChunk = false; } @@ -1937,8 +1952,8 @@ void cClientHandle::RemoveFromWorld(void) bool cClientHandle::CheckBlockInteractionsRate(void) { - ASSERT(m_Player != NULL); - ASSERT(m_Player->GetWorld() != NULL); + ASSERT(m_Player != nullptr); + ASSERT(m_Player->GetWorld() != nullptr); if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS) { @@ -1969,11 +1984,11 @@ void cClientHandle::Tick(float a_Dt) Destroy(); } - if (m_Player == NULL) + if (m_Player == nullptr) { return; } - + // If the chunk the player's in was just sent, spawn the player: if (m_HasSentPlayerChunk && (m_State == csDownloadingWorld)) { @@ -1994,6 +2009,26 @@ void cClientHandle::Tick(float a_Dt) } } + if ((m_State >= csAuthenticated) && (m_State < csDestroying)) + { + // Stream 4 chunks per tick + for (int i = 0; i < 4; i++) + { + // Stream the next chunk + if (StreamNextChunk()) + { + // Streaming finished. All chunks are loaded. + break; + } + } + + // Unload all chunks that are out of the view distance (all 5 seconds) + if ((m_Player->GetWorld()->GetWorldAge() % 100) == 0) + { + UnloadOutOfRangeChunks(); + } + } + // Handle block break animation: if (m_BlockDigAnimStage > -1) { @@ -2030,7 +2065,7 @@ void cClientHandle::ServerTick(float a_Dt) if (m_State == csAuthenticated) { - StreamChunks(); + StreamNextChunk(); // Remove the client handle from the server, it will be ticked from its cPlayer object from now on cRoot::Get()->GetServer()->ClientMovedToWorld(this); @@ -2082,7 +2117,17 @@ void cClientHandle::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_Block void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + int ChunkX, ChunkZ = 0; + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); + cChunkCoords ChunkCoords = cChunkCoords(ChunkX, ChunkZ); + + // Do not send block changes in chunks that weren't sent to the client yet: + cCSLock Lock(m_CSChunkLists); + if (std::find(m_SentChunks.begin(), m_SentChunks.end(), ChunkCoords) != m_SentChunks.end()) + { + Lock.Unlock(); + m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + } } @@ -2092,8 +2137,15 @@ void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BL void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) { ASSERT(!a_Changes.empty()); // We don't want to be sending empty change packets! - - m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes); + + // Do not send block changes in chunks that weren't sent to the client yet: + cChunkCoords ChunkCoords = cChunkCoords(a_ChunkX, a_ChunkZ); + cCSLock Lock(m_CSChunkLists); + if (std::find(m_SentChunks.begin(), m_SentChunks.end(), ChunkCoords) != m_SentChunks.end()) + { + Lock.Unlock(); + m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes); + } } @@ -2103,10 +2155,10 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData) { cWorld * World = GetPlayer()->GetWorld(); - if (World == NULL) + if (World == nullptr) { World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); - if (World == NULL) + if (World == nullptr) { World = cRoot::Get()->GetDefaultWorld(); } @@ -2131,7 +2183,7 @@ void cClientHandle::SendChat(const cCompositeChat & a_Message) void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { - ASSERT(m_Player != NULL); + ASSERT(m_Player != nullptr); // Check chunks being sent, erase them from m_ChunksToSend: bool Found = false; @@ -2157,6 +2209,12 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); + // Add the chunk to the list of chunks sent to the player: + { + cCSLock Lock(m_CSChunkLists); + m_SentChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + } + // If it is the chunk the player's in, make them spawn (in the tick thread): if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld)) { @@ -2205,6 +2263,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); } @@ -2686,6 +2745,12 @@ void cClientHandle::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_D void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) { + // Remove the chunk from the list of chunks sent to the client: + { + cCSLock Lock(m_CSChunkLists); + m_SentChunks.remove(cChunkCoords(a_ChunkX, a_ChunkZ)); + } + m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ); } @@ -2760,7 +2825,7 @@ void cClientHandle::SendWindowOpen(const cWindow & a_Window) -void cClientHandle::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) +void cClientHandle::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) { m_Protocol->SendWindowProperty(a_Window, a_Property, a_Value); } @@ -2789,18 +2854,15 @@ void cClientHandle::SetUsername( const AString & a_Username) void cClientHandle::SetViewDistance(int a_ViewDistance) { - if (a_ViewDistance < MIN_VIEW_DISTANCE) - { - a_ViewDistance = MIN_VIEW_DISTANCE; - } - if (a_ViewDistance > MAX_VIEW_DISTANCE) + 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) { - a_ViewDistance = MAX_VIEW_DISTANCE; + m_CurrentViewDistance = Clamp(a_ViewDistance, cClientHandle::MIN_VIEW_DISTANCE, world->GetMaxViewDistance()); } - m_ViewDistance = a_ViewDistance; - - // Need to re-stream chunks for the change to become apparent: - StreamChunks(); } @@ -2950,7 +3012,7 @@ void cClientHandle::HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment) } if ( - (m_Player->GetWindow() == NULL) || + (m_Player->GetWindow() == nullptr) || (m_Player->GetWindow()->GetWindowID() != a_WindowID) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtEnchantment) ) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 0a936a2ca..f195b6be7 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -21,6 +21,7 @@ #include "Enchantments.h" #include "UI/SlotArea.h" #include "json/json.h" +#include "ChunkSender.h" @@ -113,7 +114,11 @@ public: /** Authenticates the specified user, called by cAuthenticator */ void Authenticate(const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties); - void StreamChunks(void); + /** This function sends a new unloaded chunk to the player. Returns true if all chunks are loaded. */ + bool StreamNextChunk(); + + /** Remove all loaded chunks that are no longer in range */ + void UnloadOutOfRangeChunks(void); // Removes the client from all chunks. Used when switching worlds or destroying the player void RemoveFromAllChunks(void); @@ -145,7 +150,9 @@ public: void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player); void SendDestroyEntity (const cEntity & a_Entity); void SendDisconnect (const AString & a_Reason); + void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ); + void SendEntityAnimation (const cEntity & a_Entity, char a_Animation); // tolua_export void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration); void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item); void SendEntityHeadLook (const cEntity & a_Entity); @@ -156,6 +163,8 @@ public: void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ); void SendEntityStatus (const cEntity & a_Entity, char a_Status); void SendEntityVelocity (const cEntity & a_Entity); + void SendExperience (void); + void SendExperienceOrb (const cExpOrb & a_ExpOrb); void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion); void SendGameMode (eGameMode a_GameMode); void SendHealth (void); @@ -164,15 +173,14 @@ public: void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale); void SendMapInfo (int a_ID, unsigned int a_Scale); void SendPaintingSpawn (const cPainting & a_Painting); - void SendPickupSpawn (const cPickup & a_Pickup); - void SendEntityAnimation (const cEntity & a_Entity, char a_Animation); // tolua_export void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount); + void SendPickupSpawn (const cPickup & a_Pickup); void SendPlayerAbilities (void); void SendPlayerListAddPlayer (const cPlayer & a_Player); void SendPlayerListRemovePlayer (const cPlayer & a_Player); + void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName); void SendPlayerListUpdateGameMode (const cPlayer & a_Player); void SendPlayerListUpdatePing (const cPlayer & a_Player); - void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName); void SendPlayerMaxSpeed (void); ///< Informs the client of the maximum player speed (1.6.1+) void SendPlayerMoveLook (void); void SendPlayerPosition (void); @@ -180,11 +188,8 @@ public: void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false); - void SendExperience (void); - void SendExperienceOrb (const cExpOrb & a_ExpOrb); - void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); - void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); + void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch); // tolua_export void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); @@ -204,7 +209,7 @@ public: void SendWholeInventory (const cWindow & a_Window); void SendWindowClose (const cWindow & a_Window); void SendWindowOpen (const cWindow & a_Window); - void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value); + void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value); // tolua_begin const AString & GetUsername(void) const; @@ -212,9 +217,15 @@ public: inline short GetPing(void) const { return m_Ping; } + /** 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; } @@ -222,6 +233,13 @@ public: bool HasPluginChannel(const AString & a_PluginChannel); + /** Called by the protocol when it receives the MC|Brand plugin message. Also callable by plugins. + Simply stores the string value. */ + void SetClientBrand(const AString & a_ClientBrand) { m_ClientBrand = a_ClientBrand; } + + /** Returns the client brand received in the MC|Brand plugin message or set by a plugin. */ + const AString & GetClientBrand(void) const { return m_ClientBrand; } + // tolua_end /** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */ @@ -236,13 +254,31 @@ public: void PacketError(unsigned char a_PacketType); // Calls that cProtocol descendants use for handling packets: - void HandleAnimation (char a_Animation); - void HandleChat (const AString & a_Message); - void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem); - void HandleDisconnect (const AString & a_Reason); - void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching); - void HandleEntityLeaveBed (int a_EntityID); - void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting); + void HandleAnimation(char a_Animation); + + /** Called when the protocol receives a MC|ItemName plugin message, indicating that the player named + an item in the anvil UI. */ + void HandleAnvilItemName(const AString & a_ItemName); + + /** Called when the protocol receives a MC|Beacon plugin message, indicating that the player set an effect + in the beacon UI. */ + void HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEffect); + + /** Called when the protocol detects a chat packet. */ + void HandleChat(const AString & a_Message); + + /** Called when the protocol receives a MC|AdvCdm plugin message, indicating that the player set a new + command in the command block UI, for a block-based commandblock. */ + void HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand); + + /** Called when the protocol receives a MC|AdvCdm plugin message, indicating that the player set a new + command in the command block UI, for an entity-based commandblock (minecart?). */ + void HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand); + + void HandleCreativeInventory (short a_SlotNum, const cItem & a_HeldItem); + void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching); + void HandleEntityLeaveBed (int a_EntityID); + void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting); /** Called when the protocol handshake has been received (for protocol versions that support it; otherwise the first instant when a username is received). @@ -252,6 +288,11 @@ public: void HandleKeepAlive (int a_KeepAliveID); void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status); + + /** Called when the protocol receives a MC|TrSel packet, indicating that the player used a trade in + the NPC UI. */ + void HandleNPCTrade(int a_SlotNum); + void HandlePing (void); void HandlePlayerAbilities (bool a_CanFly, bool a_IsFlying, float FlyingSpeed, float WalkingSpeed); void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround); @@ -286,18 +327,24 @@ public: /** Called when the player will enchant a Item */ void HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment); + + /** Called by the protocol recognizer when the protocol version is known. */ + void SetProtocolVersion(UInt32 a_ProtocolVersion) { m_ProtocolVersion = a_ProtocolVersion; } + + /** Returns the protocol version number of the protocol that the client is talking. Returns zero if the protocol version is not (yet) known. */ + UInt32 GetProtocolVersion(void) const { return m_ProtocolVersion; } // tolua_export 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; @@ -307,6 +354,7 @@ private: cCriticalSection m_CSChunkLists; cChunkCoordsList m_LoadedChunks; // Chunks that the player belongs to cChunkCoordsList m_ChunksToSend; // Chunks that need to be sent to the player (queued because they weren't generated yet or there's not enough time to send them) + cChunkCoordsList m_SentChunks; // Chunks that are currently sent to the client cProtocol * m_Protocol; @@ -322,7 +370,7 @@ private: cPlayer * m_Player; bool m_HasSentDC; ///< True if a D/C packet has been sent in either direction - + // Chunk position when the last StreamChunks() was called; used to avoid re-streaming while in the same chunk int m_LastStreamedChunkX; int m_LastStreamedChunkZ; @@ -390,9 +438,18 @@ 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; + + /** The brand identification of the client, as received in the MC|Brand plugin message or set from a plugin. */ + AString m_ClientBrand; + + /** The version of the protocol that the client is talking, or 0 if unknown. */ + UInt32 m_ProtocolVersion; /** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */ @@ -402,7 +459,7 @@ private: bool CheckBlockInteractionsRate(void); /** Adds a single chunk to be streamed to the client; used by StreamChunks() */ - void StreamChunk(int a_ChunkX, int a_ChunkZ); + void StreamChunk(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority); /** Handles the DIG_STARTED dig packet: */ void HandleBlockDigStarted (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta); @@ -422,15 +479,6 @@ private: /** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */ void UnregisterPluginChannels(const AStringVector & a_ChannelList); - /** Handles the "MC|Beacon" plugin message */ - void HandleBeaconSelection(const char * a_Data, size_t a_Length); - - /** Handles the "MC|AdvCdm" plugin message */ - void HandleCommandBlockMessage(const char * a_Data, size_t a_Length); - - /** Handles the "MC|ItemName" plugin message */ - void HandleAnvilItemName(const char * a_Data, size_t a_Length); - // cSocketThreads::cCallback overrides: virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index ed3409207..64fb21181 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -59,7 +59,7 @@ cCraftingGrid::cCraftingGrid(const cCraftingGrid & a_Original) : cCraftingGrid::~cCraftingGrid() { delete[] m_Items; - m_Items = NULL; + m_Items = nullptr; } @@ -280,10 +280,10 @@ cCraftingRecipes::~cCraftingRecipes() -void cCraftingRecipes::GetRecipe(const cPlayer * a_Player, const cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe) +void cCraftingRecipes::GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe) { // Allow plugins to intercept recipes using a pre-craft hook: - if (cRoot::Get()->GetPluginManager()->CallHookPreCrafting(a_Player, &a_CraftingGrid, &a_Recipe)) + if (cRoot::Get()->GetPluginManager()->CallHookPreCrafting(a_Player, a_CraftingGrid, a_Recipe)) { return; } @@ -291,10 +291,10 @@ void cCraftingRecipes::GetRecipe(const cPlayer * a_Player, const cCraftingGrid & // Built-in recipes: std::auto_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid.GetItems(), a_CraftingGrid.GetWidth(), a_CraftingGrid.GetHeight())); a_Recipe.Clear(); - if (Recipe.get() == NULL) + 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) @@ -304,7 +304,7 @@ void cCraftingRecipes::GetRecipe(const cPlayer * a_Player, const cCraftingGrid & a_Recipe.SetResult(Recipe->m_Result); // Allow plugins to intercept recipes after they are processed: - cRoot::Get()->GetPluginManager()->CallHookPostCrafting(a_Player, &a_CraftingGrid, &a_Recipe); + cRoot::Get()->GetPluginManager()->CallHookPostCrafting(a_Player, a_CraftingGrid, a_Recipe); } @@ -603,9 +603,9 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::FindRecipe(const cItem * a_Craftin // Search in the possibly minimized grid, but keep the stride: const cItem * Grid = a_CraftingGrid + GridLeft + (a_GridWidth * GridTop); cRecipe * Recipe = FindRecipeCropped(Grid, GridWidth, GridHeight, a_GridWidth); - if (Recipe == NULL) + if (Recipe == nullptr) { - return NULL; + return nullptr; } // A recipe has been found, move it to correspond to the original crafting grid: @@ -637,7 +637,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::FindRecipeCropped(const cItem * a_ for (int x = 0; x <= MaxOfsX; x++) for (int y = 0; y <= MaxOfsY; y++) { cRecipe * Recipe = MatchRecipe(a_CraftingGrid, a_GridWidth, a_GridHeight, a_GridStride, *itr, x, y); - if (Recipe != NULL) + if (Recipe != nullptr) { return Recipe; } @@ -645,7 +645,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::FindRecipeCropped(const cItem * a_ } // for itr - m_Recipes[] // No matching recipe found - return NULL; + return nullptr; } @@ -681,7 +681,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti ) { // Doesn't match - return NULL; + return nullptr; } HasMatched[itrS->x + a_OffsetX][itrS->y + a_OffsetY] = true; } // for itrS - Recipe->m_Ingredients[] @@ -743,7 +743,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti } // for x if (!Found) { - return NULL; + return nullptr; } } // for itrS - a_Recipe->m_Ingredients[] @@ -753,7 +753,7 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti if (!HasMatched[x][y] && !a_CraftingGrid[x + a_GridStride * y].IsEmpty()) { // There's an unmatched item in the grid - return NULL; + return nullptr; } } // for y, for x diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h index fe1e15817..44444d42e 100644 --- a/src/CraftingRecipes.h +++ b/src/CraftingRecipes.h @@ -115,7 +115,7 @@ public: ~cCraftingRecipes(); /// Returns the recipe for current crafting grid. Doesn't modify the grid. Clears a_Recipe if no recipe found. - void GetRecipe(const cPlayer * a_Player, const cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe); + void GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe); protected: @@ -157,13 +157,13 @@ protected: /// Moves the recipe to top-left corner, sets its MinWidth / MinHeight void NormalizeIngredients(cRecipe * a_Recipe); - /// Finds a recipe matching the crafting grid. Returns a newly allocated recipe (with all its coords set) or NULL if not found. Caller must delete return value! + /// Finds a recipe matching the crafting grid. Returns a newly allocated recipe (with all its coords set) or nullptr if not found. Caller must delete return value! cRecipe * FindRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight); /// Same as FindRecipe, but the grid is guaranteed to be of minimal dimensions needed cRecipe * FindRecipeCropped(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride); - /// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value! + /// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or nullptr if not matching. Caller must delete the return value! cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY); /** Searches for anything firework related, and does the data setting if appropriate */ diff --git a/src/Defines.h b/src/Defines.h index 6355b75b4..c2f46c241 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -39,7 +39,7 @@ enum eBlockFace BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block BLOCK_FACE_ZM = 2, // Interacting with the Z- face of the block BLOCK_FACE_ZP = 3, // Interacting with the Z+ face of the block - + // Synonyms using the (deprecated) world directions: BLOCK_FACE_BOTTOM = BLOCK_FACE_YM, // Interacting with the bottom face of the block BLOCK_FACE_TOP = BLOCK_FACE_YP, // Interacting with the top face of the block @@ -101,7 +101,7 @@ enum eClickAction caDblClick, // Add new actions here caUnknown = 255, - + // Keep this list in sync with ClickActionToString() function below! } ; @@ -116,14 +116,14 @@ enum eGameMode eGameMode_Creative = 1, eGameMode_Adventure = 2, eGameMode_Spectator = 3, - + // Easier-to-use synonyms: gmNotSet = eGameMode_NotSet, gmSurvival = eGameMode_Survival, gmCreative = eGameMode_Creative, gmAdventure = eGameMode_Adventure, gmSpectator = eGameMode_Spectator, - + // These two are used to check GameMode for validity when converting from integers. gmMax, // Gets automatically assigned gmMin = 0, @@ -138,7 +138,7 @@ enum eWeather eWeather_Sunny = 0, eWeather_Rain = 1, eWeather_ThunderStorm = 2, - + // Easier-to-use synonyms: wSunny = eWeather_Sunny, wRain = eWeather_Rain, @@ -218,7 +218,7 @@ inline const char * ClickActionToString(eClickAction a_ClickAction) case caLeftPaintEnd: return "caLeftPaintEnd"; case caRightPaintEnd: return "caRightPaintEnd"; case caDblClick: return "caDblClick"; - + case caUnknown: return "caUnknown"; } ASSERT(!"Unknown click action"); @@ -472,21 +472,21 @@ inline void AddFaceDirection(int & a_BlockX, unsigned char & a_BlockY, int & a_B { int Y = a_BlockY; AddFaceDirection(a_BlockX, Y, a_BlockZ, a_BlockFace, a_bInverse); - a_BlockY = Clamp<unsigned char>((unsigned char)Y, 0, 255); + a_BlockY = Clamp<unsigned char>(static_cast<unsigned char>(Y), 0, 255); } -#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f + inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a_Y, double & a_Z) { // a_X = sinf ( a_Pan / 180 * PI) * cosf ( a_Pitch / 180 * PI); // a_Y = -sinf ( a_Pitch / 180 * PI); // a_Z = -cosf ( a_Pan / 180 * PI) * cosf ( a_Pitch / 180 * PI); - a_X = cos(a_Pan / 180 * PI) * cos(a_Pitch / 180 * PI); - a_Y = sin(a_Pan / 180 * PI) * cos(a_Pitch / 180 * PI); - a_Z = sin(a_Pitch / 180 * PI); + a_X = cos(a_Pan / 180 * M_PI) * cos(a_Pitch / 180 * M_PI); + a_Y = sin(a_Pan / 180 * M_PI) * cos(a_Pitch / 180 * M_PI); + a_Z = sin(a_Pitch / 180 * M_PI); } @@ -502,10 +502,10 @@ inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, do } else { - a_Pan = atan2(a_Z, a_X) * 180 / PI - 90; + a_Pan = atan2(a_Z, a_X) * 180 / M_PI - 90; } - a_Pitch = atan2(a_Y, r) * 180 / PI; + a_Pitch = atan2(a_Y, r) * 180 / M_PI; } @@ -556,7 +556,7 @@ enum eMessageType mtPrivateMessage, // Player to player messaging identifier mtJoin, // A player has joined the server mtLeave, // A player has left the server - + // Common aliases: mtFail = mtFailure, mtError = mtFailure, @@ -626,9 +626,9 @@ namespace ItemCategory || (a_ItemID == E_ITEM_GOLD_HOE) || (a_ItemID == E_ITEM_DIAMOND_HOE); } - - - + + + inline bool IsShovel(short a_ItemID) { return (a_ItemID == E_ITEM_WOODEN_SHOVEL) @@ -648,9 +648,9 @@ namespace ItemCategory || IsHoe ( a_ItemID) || IsShovel ( a_ItemID); } - - - + + + inline bool IsHelmet(short a_ItemType) { return ( @@ -700,9 +700,9 @@ namespace ItemCategory (a_ItemType == E_ITEM_DIAMOND_BOOTS) ); } - - - + + + inline bool IsArmor(short a_ItemType) { return ( @@ -715,7 +715,3 @@ namespace ItemCategory } // tolua_end - - - - diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp index 264878c22..80a9810b6 100644 --- a/src/Enchantments.cpp +++ b/src/Enchantments.cpp @@ -6,6 +6,7 @@ #include "Enchantments.h" #include "WorldStorage/FastNBT.h" #include "FastRandom.h" +#include "Noise.h" @@ -1019,3 +1020,30 @@ cEnchantments cEnchantments::GetRandomEnchantmentFromVector(cWeightedEnchantment + +cEnchantments cEnchantments::GenerateEnchantmentFromVector(cWeightedEnchantments & a_Enchantments, int a_Seed) +{ + int AllWeights = 0; + for (const auto Enchantment : a_Enchantments) + { + AllWeights += Enchantment.m_Weight; + } + + cNoise Noise(a_Seed); + int RandomNumber = Noise.IntNoise1DInt(AllWeights) / 7 % AllWeights; + + for (const auto Enchantment : a_Enchantments) + { + RandomNumber -= Enchantment.m_Weight; + if (RandomNumber < 0) + { + return Enchantment.m_Enchantments; + } + } + + return cEnchantments(); +} + + + + diff --git a/src/Enchantments.h b/src/Enchantments.h index 824f6aa55..e4390a5f2 100644 --- a/src/Enchantments.h +++ b/src/Enchantments.h @@ -128,6 +128,9 @@ public: /** Gets random enchantment from Vector and returns it */ static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments); + /** Returns an enchantment from a Vector using cNoise. Mostly used for generators.*/ + static cEnchantments GenerateEnchantmentFromVector(cWeightedEnchantments & a_Enchantments, int a_Seed); + /** Returns true if a_Other doesn't contain exactly the same enchantments and levels */ bool operator !=(const cEnchantments & a_Other) const; diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index c265c5043..30f18f677 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -149,14 +149,14 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -void cArrowEntity::CollectedBy(cPlayer * a_Dest) +void cArrowEntity::CollectedBy(cPlayer & a_Dest) { - if (m_IsInGround && !m_bIsCollected && CanPickup(*a_Dest)) + if (m_IsInGround && !m_bIsCollected && CanPickup(a_Dest)) { // Do not add the arrow to the inventory when the player is in creative: - if (!a_Dest->IsGameModeCreative()) + if (!a_Dest.IsGameModeCreative()) { - int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); + int NumAdded = a_Dest.GetInventory().AddItem(E_ITEM_ARROW); if (NumAdded == 0) { // No space in the inventory @@ -164,7 +164,7 @@ void cArrowEntity::CollectedBy(cPlayer * a_Dest) } } - GetWorld()->BroadcastCollectEntity(*this, *a_Dest); + GetWorld()->BroadcastCollectEntity(*this, a_Dest); GetWorld()->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_bIsCollected = true; } @@ -217,7 +217,7 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); - if (Chunk == NULL) + if (Chunk == nullptr) { // Inside an unloaded chunk, abort return; @@ -229,3 +229,7 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) } } } + + + + diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h index a1e7a17e7..436ec0293 100644 --- a/src/Entities/ArrowEntity.h +++ b/src/Entities/ArrowEntity.h @@ -1,6 +1,11 @@ -// -// ArrowEntity.h -// + +// ArrowEntity.h + +// Declares the cArrowEntity representing the arrow that has been shot by the player or by a skeleton + + + + #pragma once @@ -19,7 +24,7 @@ class cArrowEntity : typedef cProjectileEntity super; public: - /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field + /** Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field */ enum ePickupState { psNoPickup = 0, @@ -31,33 +36,33 @@ public: CLASS_PROTODEF(cArrowEntity) - /// Creates a new arrow with psNoPickup state and default damage modifier coeff + /** Creates a new arrow with psNoPickup state and default damage modifier coeff */ cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - /// Creates a new arrow as shot by a player, initializes it from the player object + /** Creates a new arrow as shot by a player, initializes it from the player object */ cArrowEntity(cPlayer & a_Player, double a_Force); // tolua_begin - /// Returns whether the arrow can be picked up by players + /** Returns whether the arrow can be picked up by players */ ePickupState GetPickupState(void) const { return m_PickupState; } - /// Sets a new pickup state + /** Sets a new pickup state */ void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; } - /// Returns the damage modifier coeff. + /** Returns the damage modifier coeff. */ double GetDamageCoeff(void) const { return m_DamageCoeff; } - /// Sets the damage modifier coeff + /** Sets the damage modifier coeff */ void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } - /// Returns true if the specified player can pick the arrow up + /** Returns true if the specified player can pick the arrow up */ bool CanPickup(const cPlayer & a_Player) const; - /// Returns true if the arrow is set as critical + /** Returns true if the arrow is set as critical */ bool IsCritical(void) const { return m_IsCritical; } - /// Sets the IsCritical flag + /** Sets the IsCritical flag */ void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } /** Gets the block arrow is in */ @@ -70,34 +75,34 @@ public: protected: - /// Determines when the arrow can be picked up by players + /** Determines when the arrow can be picked up by players */ ePickupState m_PickupState; - /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow + /** The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow */ double m_DamageCoeff; - /// If true, the arrow deals more damage + /** If true, the arrow deals more damage */ bool m_IsCritical; - /// Timer for pickup collection animation or five minute timeout + /** Timer for pickup collection animation or five minute timeout */ float m_Timer; - /// Timer for client arrow position confirmation via TeleportEntity + /** Timer for client arrow position confirmation via TeleportEntity */ float m_HitGroundTimer; // Whether the arrow has already been teleported into the proper position in the ground. bool m_HasTeleported; - /// If true, the arrow is in the process of being collected - don't go to anyone else + /** If true, the arrow is in the process of being collected - don't go to anyone else */ bool m_bIsCollected; - /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air + /** Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air */ Vector3i m_HitBlockPos; // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - virtual void CollectedBy(cPlayer * a_Player) override; + virtual void CollectedBy(cPlayer & a_Player) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; }; // tolua_export diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp index 328a70846..953213bca 100644 --- a/src/Entities/Boat.cpp +++ b/src/Entities/Boat.cpp @@ -42,7 +42,7 @@ bool cBoat::DoTakeDamage(TakeDamageInfo & TDI) if (GetHealth() == 0) { - if (TDI.Attacker != NULL) + if (TDI.Attacker != nullptr) { if (TDI.Attacker->IsPlayer()) { @@ -64,7 +64,7 @@ void cBoat::OnRightClicked(cPlayer & a_Player) { super::OnRightClicked(a_Player); - if (m_Attachee != NULL) + if (m_Attachee != nullptr) { if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index da85dec50..afc61c73f 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -29,8 +29,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d : m_UniqueID(0) , m_Health(1) , m_MaxHealth(1) - , m_AttachedTo(NULL) - , m_Attachee(NULL) + , m_AttachedTo(nullptr) + , m_Attachee(nullptr) , m_bDirtyHead(true) , m_bDirtyOrientation(true) , m_bHasSentNoSpeed(true) @@ -38,9 +38,9 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Gravity(-9.81f) , m_LastPos(a_X, a_Y, a_Z) , m_IsInitialized(false) - , m_WorldTravellingFrom(NULL) + , m_WorldTravellingFrom(nullptr) , m_EntityType(a_EntityType) - , m_World(NULL) + , m_World(nullptr) , m_IsFireproof(false) , m_TicksSinceLastBurnDamage(0) , m_TicksSinceLastLavaDamage(0) @@ -73,7 +73,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d cEntity::~cEntity() { // Before deleting, the entity needs to have been removed from the world, if ever added - ASSERT((m_World == NULL) || !m_World->HasEntity(m_UniqueID)); + ASSERT((m_World == nullptr) || !m_World->HasEntity(m_UniqueID)); /* // DEBUG: @@ -85,11 +85,11 @@ cEntity::~cEntity() ); */ - if (m_AttachedTo != NULL) + if (m_AttachedTo != nullptr) { Detach(); } - if (m_Attachee != NULL) + if (m_Attachee != nullptr) { m_Attachee->Detach(); } @@ -242,7 +242,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R TDI.FinalDamage = a_FinalDamage; Vector3d Heading(0, 0, 0); - if (a_Attacker != NULL) + if (a_Attacker != nullptr) { Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11); Heading.y = 1.6; @@ -265,7 +265,7 @@ void cEntity::SetYawFromSpeed(void) SetYaw(0); return; } - SetYaw(atan2(m_Speed.x, m_Speed.z) * 180 / PI); + SetYaw(atan2(m_Speed.x, m_Speed.z) * 180 / M_PI); } @@ -282,7 +282,7 @@ void cEntity::SetPitchFromSpeed(void) SetPitch(0); return; } - SetPitch(atan2(m_Speed.y, xz) * 180 / PI); + SetPitch(atan2(m_Speed.y, xz) * 180 / M_PI); } @@ -308,7 +308,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) return false; } - if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + if ((a_TDI.Attacker != nullptr) && (a_TDI.Attacker->IsPlayer())) { cPlayer * Player = (cPlayer *)a_TDI.Attacker; @@ -544,7 +544,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = std::max(m_Health, 0); // Add knockback: - if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) + if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != nullptr)) { int KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); // More common enchantment if (KnockbackLevel < 1) @@ -571,7 +571,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { KilledBy(a_TDI); - if (a_TDI.Attacker != NULL) + if (a_TDI.Attacker != nullptr) { a_TDI.Attacker->Killed(this); } @@ -778,7 +778,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) m_InvulnerableTicks--; } - if (m_AttachedTo != NULL) + if (m_AttachedTo != nullptr) { Vector3d DeltaPos = m_Pos - m_AttachedTo->GetPosition(); if (DeltaPos.Length() > 0.5) @@ -1092,7 +1092,7 @@ void cEntity::TickBurning(cChunk & a_Chunk) { if (!m_IsFireproof) { - TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0); + TakeDamage(dtOnFire, nullptr, BURN_DAMAGE, 0); } m_TicksSinceLastBurnDamage = 0; } @@ -1163,7 +1163,7 @@ void cEntity::TickBurning(cChunk & a_Chunk) { if (!m_IsFireproof) { - TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0); + TakeDamage(dtLavaContact, nullptr, LAVA_DAMAGE, 0); } m_TicksSinceLastLavaDamage = 0; } @@ -1184,7 +1184,7 @@ void cEntity::TickBurning(cChunk & a_Chunk) { if (!m_IsFireproof) { - TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0); + TakeDamage(dtFireContact, nullptr, FIRE_DAMAGE, 0); } m_TicksSinceLastFireDamage = 0; } @@ -1213,7 +1213,7 @@ void cEntity::TickInVoid(cChunk & a_Chunk) { if (m_TicksSinceLastVoidDamage == 20) { - TakeDamage(dtInVoid, NULL, 2, 0); + TakeDamage(dtInVoid, nullptr, 2, 0); m_TicksSinceLastVoidDamage = 0; } else @@ -1239,7 +1239,7 @@ void cEntity::DetectCacti(void) (((GetPosY() - Y < 1) && (GetWorld()->GetBlock(X, Y, Z) == E_BLOCK_CACTUS)))) ) { - TakeDamage(dtCactusContact, NULL, 1, 0); + TakeDamage(dtCactusContact, nullptr, 1, 0); } } @@ -1380,7 +1380,7 @@ bool cEntity::DetectPortal() bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { UNUSED(a_ShouldSendRespawn); - ASSERT(a_World != NULL); + ASSERT(a_World != nullptr); if (GetWorld() == a_World) { @@ -1406,7 +1406,7 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) bool cEntity::MoveToWorld(const AString & a_WorldName, bool a_ShouldSendRespawn) { cWorld * World = cRoot::Get()->GetWorld(a_WorldName); - if (World == NULL) + if (World == nullptr) { LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str()); return false; @@ -1493,7 +1493,7 @@ void cEntity::HandleAir(void) if (m_AirTickTimer <= 0) { // Damage player - TakeDamage(dtDrowning, NULL, 1, 1, 0); + TakeDamage(dtDrowning, nullptr, 1, 1, 0); // Reset timer m_AirTickTimer = DROWNING_TICKS; } @@ -1708,7 +1708,7 @@ void cEntity::AttachTo(cEntity * a_AttachTo) // Already attached to that entity, nothing to do here return; } - if (m_AttachedTo != NULL) + if (m_AttachedTo != nullptr) { // Detach from any previous entity: Detach(); @@ -1726,14 +1726,14 @@ void cEntity::AttachTo(cEntity * a_AttachTo) void cEntity::Detach(void) { - if (m_AttachedTo == NULL) + if (m_AttachedTo == nullptr) { // Attached to no entity, our work is done return; } - m_AttachedTo->m_Attachee = NULL; - m_AttachedTo = NULL; - m_World->BroadcastAttachEntity(*this, NULL); + m_AttachedTo->m_Attachee = nullptr; + m_AttachedTo = nullptr; + m_World->BroadcastAttachEntity(*this, nullptr); } @@ -1956,7 +1956,7 @@ void cEntity::HandleSpeedFromAttachee(float a_Forward, float a_Sideways) void cEntity::SteerVehicle(float a_Forward, float a_Sideways) { - if (m_AttachedTo == NULL) + if (m_AttachedTo == nullptr) { return; } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 3fa7e80c1..af545fe4a 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -27,12 +27,12 @@ return super::GetClass(); \ } -#define POSX_TOINT (int)floor(GetPosX()) -#define POSY_TOINT (int)floor(GetPosY()) -#define POSZ_TOINT (int)floor(GetPosZ()) +#define POSX_TOINT FloorC(GetPosX()) +#define POSY_TOINT FloorC(GetPosY()) +#define POSZ_TOINT FloorC(GetPosZ()) #define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT) -#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); if ((ChunkVarName == NULL) || !ChunkVarName->IsValid()) { return; } +#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); if ((ChunkVarName == nullptr) || !ChunkVarName->IsValid()) { return; } @@ -172,13 +172,13 @@ public: /// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true) virtual bool IsA(const char * a_ClassName) const; - /// Returns the topmost class name for the object - virtual const char * GetClass(void) const; - - // Returns the class name of this class + /** Returns the class name of this class */ static const char * GetClassStatic(void); - /// Returns the topmost class's parent class name for the object. cEntity returns an empty string (no parent). + /** Returns the topmost class name for the object */ + virtual const char * GetClass(void) const; + + /** Returns the topmost class's parent class name for the object. cEntity returns an empty string (no parent). */ virtual const char * GetParentClass(void) const; cWorld * GetWorld(void) const { return m_World; } @@ -309,7 +309,7 @@ public: /// Returns the currently equipped boots; empty item if none virtual cItem GetEquippedBoots(void) const { return cItem(); } - /// Called when the health drops below zero. a_Killer may be NULL (environmental damage) + /// Called when the health drops below zero. a_Killer may be nullptr (environmental damage) virtual void KilledBy(TakeDamageInfo & a_TDI); /// Called when the entity kills another entity @@ -401,7 +401,7 @@ public: void SetWorldTravellingFrom(cWorld * a_World) { m_WorldTravellingFrom = a_World; } /// Updates clients of changes in the entity. - virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL); + virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = nullptr); /// Attaches to the specified entity; detaches from any previous one first void AttachTo(cEntity * a_AttachTo); @@ -450,7 +450,7 @@ public: virtual void OnRightClicked(cPlayer & a_Player) {} /// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy(). - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) { UNUSED(a_Drops); UNUSED(a_Killer); @@ -471,10 +471,10 @@ protected: int m_Health; int m_MaxHealth; - /// The entity to which this entity is attached (vehicle), NULL if none + /// The entity to which this entity is attached (vehicle), nullptr if none cEntity * m_AttachedTo; - /// The entity which is attached to this entity (rider), NULL if none + /// The entity which is attached to this entity (rider), nullptr if none cEntity * m_Attachee; /** Stores whether head yaw has been set manually */ @@ -502,7 +502,7 @@ protected: bool m_IsInitialized; /** World entity is travelling from - Set to a valid world pointer by MoveToWorld; reset to NULL when the entity is removed from the old world + Set to a valid world pointer by MoveToWorld; reset to nullptr when the entity is removed from the old world Can't be a simple boolean as context switches between worlds may leave the new chunk processing (and therefore immediately removing) the entity before the old chunk could remove it */ cWorld * m_WorldTravellingFrom; diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp index b1ddaa30e..bae686b77 100644 --- a/src/Entities/EntityEffect.cpp +++ b/src/Entities/EntityEffect.cpp @@ -216,7 +216,7 @@ cEntityEffect * cEntityEffect::CreateEntityEffect(cEntityEffect::eType a_EffectT } ASSERT(!"Unhandled entity effect type!"); - return NULL; + return nullptr; } @@ -329,7 +329,7 @@ void cEntityEffectInstantHealth::OnActivate(cPawn & a_Target) if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead()) { - a_Target.TakeDamage(dtPotionOfHarming, NULL, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage + a_Target.TakeDamage(dtPotionOfHarming, nullptr, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage return; } a_Target.Heal(amount); @@ -352,7 +352,7 @@ void cEntityEffectInstantDamage::OnActivate(cPawn & a_Target) a_Target.Heal(amount); return; } - a_Target.TakeDamage(dtPotionOfHarming, NULL, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage + a_Target.TakeDamage(dtPotionOfHarming, nullptr, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage } @@ -452,7 +452,7 @@ void cEntityEffectPoison::OnTick(cPawn & a_Target) // Cannot take poison damage when health is at 1 if (a_Target.GetHealth() > 1) { - a_Target.TakeDamage(dtPoisoning, NULL, 1, 0); + a_Target.TakeDamage(dtPoisoning, nullptr, 1, 0); } } } @@ -473,7 +473,7 @@ void cEntityEffectWither::OnTick(cPawn & a_Target) if ((m_Ticks % frequency) == 0) { - a_Target.TakeDamage(dtWither, NULL, 1, 0); + a_Target.TakeDamage(dtWither, nullptr, 1, 0); } } diff --git a/src/Entities/ExpBottleEntity.h b/src/Entities/ExpBottleEntity.h index d36110f97..715b9947e 100644 --- a/src/Entities/ExpBottleEntity.h +++ b/src/Entities/ExpBottleEntity.h @@ -1,6 +1,11 @@ -// -// ExpBottleEntity.h -// + +// ExpBottleEntity.h + +// Declares the cExpBottleEntity class representing the thrown exp bottle + + + + #pragma once @@ -33,6 +38,10 @@ protected: /** Breaks the bottle, fires its particle effects and sounds @param a_HitPos The position where the bottle will break */ - void Break(const Vector3d &a_HitPos); + void Break(const Vector3d & a_HitPos); }; // tolua_export + + + + diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp index 73d5cbfed..751308661 100644 --- a/src/Entities/ExpOrb.cpp +++ b/src/Entities/ExpOrb.cpp @@ -45,7 +45,7 @@ void cExpOrb::SpawnOn(cClientHandle & a_Client) void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk) { cPlayer * a_ClosestPlayer(m_World->FindClosestPlayer(Vector3f(GetPosition()), 5)); - if (a_ClosestPlayer != NULL) + if (a_ClosestPlayer != nullptr) { Vector3f a_PlayerPos(a_ClosestPlayer->GetPosition()); a_PlayerPos.y++; diff --git a/src/Entities/FireChargeEntity.h b/src/Entities/FireChargeEntity.h index 5df55bec4..eb08f5324 100644 --- a/src/Entities/FireChargeEntity.h +++ b/src/Entities/FireChargeEntity.h @@ -1,6 +1,11 @@ -// -// FireChargeEntity.h -// + +// FireChargeEntity.h + +// Declares the cFireChargeEntity representing the fire charge shot by the blaze + + + + #pragma once @@ -34,3 +39,7 @@ protected: virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; } ; // tolua_export + + + + diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp index 403a53c84..68d02640a 100644 --- a/src/Entities/FireworkEntity.cpp +++ b/src/Entities/FireworkEntity.cpp @@ -10,7 +10,7 @@ cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) : super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), - m_ExplodeTimer(0), + m_TicksToExplosion(a_Item.m_FireworkItem.m_FlightTimeInTicks), m_FireworkItem(a_Item) { } @@ -27,7 +27,9 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) if ((PosY < 0) || (PosY >= cChunkDef::Height)) { - goto setspeed; + AddSpeedY(1); + AddPosition(GetSpeed() * (a_Dt / 1000)); + return; } if (m_IsInGround) @@ -50,7 +52,6 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } } -setspeed: AddSpeedY(1); AddPosition(GetSpeed() * (a_Dt / 1000)); } @@ -63,11 +64,13 @@ void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) + if (m_TicksToExplosion <= 0) { + // TODO: Notify the plugins m_World->BroadcastEntityStatus(*this, esFireworkExploding); Destroy(); + return; } - m_ExplodeTimer++; + m_TicksToExplosion -= 1; } diff --git a/src/Entities/FireworkEntity.h b/src/Entities/FireworkEntity.h index 20f18b6dc..300ec571e 100644 --- a/src/Entities/FireworkEntity.h +++ b/src/Entities/FireworkEntity.h @@ -1,6 +1,11 @@ -// -// FireworkEntity.h -// + +// FireworkEntity.h + +// Declares the cFireworkEntity class representing the flying firework rocket + + + + #pragma once @@ -24,7 +29,22 @@ public: CLASS_PROTODEF(cFireworkEntity) cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item); + + // tolua_begin + + /** Returns the item used to create the rocket (has all the firework effects on it) */ const cItem & GetItem(void) const { return m_FireworkItem; } + + /** Sets the item that is used to create the rocket (has all the firework effects on it) */ + void SetItem(const cItem & a_Item) { m_FireworkItem = a_Item; } + + /** Returns the number of ticks left until the firework explosion. */ + int GetTicksToExplosion(void) const { return m_TicksToExplosion; } + + /** Sets the number of ticks left until the firework explosion. */ + void SetTicksToExplosion(int a_TicksToExplosion) { m_TicksToExplosion = a_TicksToExplosion; } + + // tolua_end protected: @@ -34,7 +54,11 @@ protected: private: - int m_ExplodeTimer; + int m_TicksToExplosion; cItem m_FireworkItem; }; // tolua_export + + + + diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp index 159429147..5fe6a1238 100644 --- a/src/Entities/Floater.cpp +++ b/src/Entities/Floater.cpp @@ -22,7 +22,7 @@ public: m_Pos(a_Pos), m_NextPos(a_NextPos), m_MinCoeff(1), - m_HitEntity(NULL) + m_HitEntity(nullptr) { } virtual bool Item(cEntity * a_Entity) override diff --git a/src/Entities/GhastFireballEntity.h b/src/Entities/GhastFireballEntity.h index 3ed72d9ef..bbce89d31 100644 --- a/src/Entities/GhastFireballEntity.h +++ b/src/Entities/GhastFireballEntity.h @@ -1,6 +1,11 @@ -// -// GhastFireballEntity.h -// + +// GhastFireballEntity.h + +// Declares the cGhastFireballEntity class representing the ghast fireball in flight. + + + + #pragma once @@ -36,3 +41,7 @@ protected: // TODO: Deflecting the fireballs by arrow- or sword- hits } ; // tolua_export + + + + diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp index 3276bc4a0..a6b9c40c8 100644 --- a/src/Entities/HangingEntity.cpp +++ b/src/Entities/HangingEntity.cpp @@ -9,9 +9,9 @@ -cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z) - : cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8) - , m_BlockFace(a_BlockFace) +cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_Facing, double a_X, double a_Y, double a_Z) : + cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8), + m_Facing(a_Facing) { SetMaxHealth(1); SetHealth(1); @@ -21,15 +21,23 @@ cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, -void cHangingEntity::SetDirection(eBlockFace a_BlockFace) +void cHangingEntity::SetFacing(eBlockFace a_Facing) { - if ((a_BlockFace < 2) || (a_BlockFace > 5)) + // Y-based faces are not allowed: + switch (a_Facing) { - ASSERT(!"Tried to set a bad direction!"); - return; + case BLOCK_FACE_NONE: + case BLOCK_FACE_YM: + case BLOCK_FACE_YP: + { + LOGWARNING("%s: Invalid facing: %d. Ignoring.", __FUNCTION__, a_Facing); + ASSERT(!"Tried to set a bad facing!"); + return; + } + default: break; } - m_BlockFace = a_BlockFace; + m_Facing = a_Facing; } @@ -41,7 +49,7 @@ void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle) int Dir = 0; // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces - switch (m_BlockFace) + switch (m_Facing) { case BLOCK_FACE_ZP: Dir = 0; break; case BLOCK_FACE_ZM: Dir = 2; break; @@ -49,8 +57,8 @@ void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle) case BLOCK_FACE_XP: Dir = 3; break; default: { - LOGINFO("Invalid face (%d) in a cHangingEntity at {%d, %d, %d}, adjusting to BLOCK_FACE_XP.", - m_BlockFace, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ() + LOGINFO("Invalid facing (%d) in a cHangingEntity at {%d, %d, %d}, adjusting to BLOCK_FACE_XP.", + m_Facing, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ() ); Dir = 3; } diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h index 1cc0034e1..67146a20b 100644 --- a/src/Entities/HangingEntity.h +++ b/src/Entities/HangingEntity.h @@ -11,36 +11,41 @@ class cHangingEntity : public cEntity { - // tolua_end typedef cEntity super; public: + // tolua_end + CLASS_PROTODEF(cHangingEntity) cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z); - /** Returns the orientation from the hanging entity */ - eBlockFace GetDirection() const { return m_BlockFace; } // tolua_export + // tolua_begin + + /** Returns the direction in which the entity is facing. */ + eBlockFace GetFacing() const { return m_Facing; } - /** Set the orientation from the hanging entity */ - void SetDirection(eBlockFace a_BlockFace); // tolua_export + /** Set the direction in which the entity is facing. */ + void SetFacing(eBlockFace a_Facing); - /** Returns the X coord. */ - int GetTileX() const { return POSX_TOINT; } // tolua_export + /** Returns the X coord of the block in which the entity resides. */ + int GetBlockX() const { return POSX_TOINT; } - /** Returns the Y coord. */ - int GetTileY() const { return POSY_TOINT; } // tolua_export + /** Returns the Y coord of the block in which the entity resides. */ + int GetBlockY() const { return POSY_TOINT; } - /** Returns the Z coord. */ - int GetTileZ() const { return POSZ_TOINT; } // tolua_export + /** Returns the Z coord of the block in which the entity resides. */ + int GetBlockZ() const { return POSZ_TOINT; } + + // tolua_end private: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override {} - eBlockFace m_BlockFace; + eBlockFace m_Facing; }; // tolua_export diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp index f512324eb..dfffcd3ed 100644 --- a/src/Entities/ItemFrame.cpp +++ b/src/Entities/ItemFrame.cpp @@ -9,10 +9,10 @@ -cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z) - : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z) - , m_Item(E_BLOCK_AIR) - , m_Rotation(0) +cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z) : + cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z), + m_Item(E_BLOCK_AIR), + m_ItemRotation(0) { } @@ -27,10 +27,10 @@ void cItemFrame::OnRightClicked(cPlayer & a_Player) if (!m_Item.IsEmpty()) { // Item not empty, rotate, clipping values to zero to three inclusive - m_Rotation++; - if (m_Rotation >= 8) + m_ItemRotation++; + if (m_ItemRotation >= 8) { - m_Rotation = 0; + m_ItemRotation = 0; } } else if (!a_Player.GetEquippedItem().IsEmpty()) @@ -62,7 +62,7 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI) return; } - if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer() && !((cPlayer *)a_TDI.Attacker)->IsGameModeCreative()) + if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPlayer() && !((cPlayer *)a_TDI.Attacker)->IsGameModeCreative()) { cItems Item; Item.push_back(m_Item); @@ -72,7 +72,7 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI) SetHealth(GetMaxHealth()); m_Item.Empty(); - m_Rotation = 0; + m_ItemRotation = 0; SetInvulnerableTicks(0); GetWorld()->BroadcastEntityMetadata(*this); } @@ -83,7 +83,7 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI) void cItemFrame::GetDrops(cItems & a_Items, cEntity * a_Killer) { - if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) + if ((a_Killer != nullptr) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) { a_Items.push_back(cItem(E_ITEM_ITEM_FRAME)); } diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h index a63b78b70..ced8c37af 100644 --- a/src/Entities/ItemFrame.h +++ b/src/Entities/ItemFrame.h @@ -11,26 +11,31 @@ class cItemFrame : public cHangingEntity { - // tolua_end typedef cHangingEntity super; public: + // tolua_end + CLASS_PROTODEF(cItemFrame) cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z); + // tolua_begin + /** Returns the item in the frame */ - const cItem & GetItem(void) { return m_Item; } // tolua_export + const cItem & GetItem(void) { return m_Item; } /** Set the item in the frame */ - void SetItem(cItem & a_Item) { m_Item = a_Item; } // tolua_export + void SetItem(cItem & a_Item) { m_Item = a_Item; } /** Returns the rotation from the item in the frame */ - Byte GetRotation(void) const { return m_Rotation; } // tolua_export + Byte GetItemRotation(void) const { return m_ItemRotation; } /** Set the rotation from the item in the frame */ - void SetRotation(Byte a_Rotation) { m_Rotation = a_Rotation; } // tolua_export + void SetItemRotation(Byte a_ItemRotation) { m_ItemRotation = a_ItemRotation; } + + // tolua_end private: @@ -39,7 +44,7 @@ private: virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; cItem m_Item; - Byte m_Rotation; + Byte m_ItemRotation; }; // tolua_export diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 2df64d5c1..22e046800 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -7,7 +7,6 @@ #include "Globals.h" #include "Minecart.h" -#include "../World.h" #include "../ClientHandle.h" #include "../Chunk.h" #include "Player.h" @@ -37,7 +36,7 @@ public: virtual bool Item(cEntity * a_Entity) override { - ASSERT(a_Entity != NULL); + ASSERT(a_Entity != nullptr); if (!a_Entity->IsPlayer() && !a_Entity->IsMob() && !a_Entity->IsMinecart() && !a_Entity->IsBoat()) { @@ -131,7 +130,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) int RelPosX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; int RelPosZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); - if (Chunk == NULL) + if (Chunk == nullptr) { // Inside an unloaded chunk, bail out all processing return; @@ -807,7 +806,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) { - cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID())); + cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == nullptr) ? -1 : m_Attachee->GetUniqueID())); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback); @@ -981,7 +980,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) { - if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative()) + if ((TDI.Attacker != nullptr) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative()) { Destroy(); TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative @@ -1075,7 +1074,7 @@ void cRideableMinecart::OnRightClicked(cPlayer & a_Player) { super::OnRightClicked(a_Player); - if (m_Attachee != NULL) + if (m_Attachee != nullptr) { if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) { @@ -1106,28 +1105,55 @@ void cRideableMinecart::OnRightClicked(cPlayer & a_Player) // cMinecartWithChest: cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) : - super(mpChest, a_X, a_Y, a_Z) + super(mpChest, a_X, a_Y, a_Z), + cEntityWindowOwner(this), + m_Contents(ContentsWidth, ContentsHeight) { + m_Contents.AddListener(*this); } -void cMinecartWithChest::SetSlot(size_t a_Idx, const cItem & a_Item) +void cMinecartWithChest::OnRightClicked(cPlayer & a_Player) { - ASSERT(a_Idx < ARRAYCOUNT(m_Items)); - - m_Items[a_Idx] = a_Item; + // If the window is not created, open it anew: + cWindow * Window = GetWindow(); + if (Window == nullptr) + { + OpenNewWindow(); + Window = GetWindow(); + } + + // Open the window for the player: + if (Window != nullptr) + { + if (a_Player.GetWindow() != Window) + { + a_Player.OpenWindow(Window); + } + } } -void cMinecartWithChest::OnRightClicked(cPlayer & a_Player) +void cMinecartWithChest::OpenNewWindow() +{ + OpenWindow(new cMinecartWithChestWindow(this)); +} + + + + + +void cMinecartWithChest::Destroyed() { - // TODO: Show the chest UI window to the player + cItems Pickups; + m_Contents.CopyToItems(Pickups); + GetWorld()->SpawnItemPickups(Pickups, GetPosX(), GetPosY() + 1, GetPosZ(), 4); } diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index 410d3c77d..40e22c641 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -10,6 +10,8 @@ #pragma once #include "Entity.h" +#include "World.h" +#include "../UI/WindowOwner.h" @@ -108,27 +110,46 @@ protected: class cMinecartWithChest : - public cMinecart + public cMinecart, + public cItemGrid::cListener, + public cEntityWindowOwner { typedef cMinecart super; public: CLASS_PROTODEF(cMinecartWithChest) - /// Number of item slots in the chest - static const int NumSlots = 9 * 3; - cMinecartWithChest(double a_X, double a_Y, double a_Z); + + enum + { + ContentsHeight = 3, + ContentsWidth = 9, + }; - const cItem & GetSlot(int a_Idx) const { return m_Items[a_Idx]; } - cItem & GetSlot(int a_Idx) { return m_Items[a_Idx]; } - - void SetSlot(size_t a_Idx, const cItem & a_Item); + 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); } protected: + cItemGrid m_Contents; + void OpenNewWindow(void); + virtual void Destroyed() override; - /// The chest contents: - cItem m_Items[NumSlots]; + // cItemGrid::cListener overrides: + virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) + { + UNUSED(a_SlotNum); + ASSERT(a_Grid == &m_Contents); + if (m_World != nullptr) + { + if (GetWindow() != nullptr) + { + GetWindow()->BroadcastWholeWindow(); + } + + m_World->MarkChunkDirty(GetChunkX(), GetChunkZ()); + } + } // cEntity overrides: virtual void OnRightClicked(cPlayer & a_Player) override; diff --git a/src/Entities/Painting.cpp b/src/Entities/Painting.cpp index e217556c7..1aa6da0a1 100644 --- a/src/Entities/Painting.cpp +++ b/src/Entities/Painting.cpp @@ -43,7 +43,7 @@ void cPainting::Tick(float a_Dt, cChunk & a_Chunk) void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer) { - if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) + if ((a_Killer != nullptr) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) { a_Items.push_back(cItem(E_ITEM_PAINTING)); } diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h index 9877c95c5..078270b42 100644 --- a/src/Entities/Painting.h +++ b/src/Entities/Painting.h @@ -11,15 +11,22 @@ class cPainting : public cEntity { - // tolua_end typedef cEntity super; public: + + // tolua_end + CLASS_PROTODEF(cPainting) cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z); - const AString & GetName(void) const { return m_Name; } // tolua_export - int GetDirection(void) const { return m_Direction; } // tolua_export + + // tolua_begin + + const AString & GetName(void) const { return m_Name; } + int GetDirection(void) const { return m_Direction; } + + // tolua_end private: diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 87b5bed07..e5e28446d 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -191,10 +191,8 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk) -bool cPickup::CollectedBy(cPlayer * a_Dest) +bool cPickup::CollectedBy(cPlayer & a_Dest) { - ASSERT(a_Dest != NULL); - if (m_bCollected) { // LOG("Pickup %d cannot be collected by \"%s\", because it has already been collected.", m_UniqueID, a_Dest->GetName().c_str()); @@ -214,21 +212,21 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) return false; } - int NumAdded = a_Dest->GetInventory().AddItem(m_Item); + int NumAdded = a_Dest.GetInventory().AddItem(m_Item); if (NumAdded > 0) { // Check achievements switch (m_Item.m_ItemType) { - case E_BLOCK_LOG: a_Dest->AwardAchievement(achMineWood); break; - case E_ITEM_LEATHER: a_Dest->AwardAchievement(achKillCow); break; - case E_ITEM_DIAMOND: a_Dest->AwardAchievement(achDiamonds); break; - case E_ITEM_BLAZE_ROD: a_Dest->AwardAchievement(achBlazeRod); break; + case E_BLOCK_LOG: a_Dest.AwardAchievement(achMineWood); break; + case E_ITEM_LEATHER: a_Dest.AwardAchievement(achKillCow); break; + case E_ITEM_DIAMOND: a_Dest.AwardAchievement(achDiamonds); break; + case E_ITEM_BLAZE_ROD: a_Dest.AwardAchievement(achBlazeRod); break; default: break; } m_Item.m_ItemCount -= NumAdded; - m_World->BroadcastCollectEntity(*this, *a_Dest); + m_World->BroadcastCollectEntity(*this, a_Dest); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) m_World->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); if (m_Item.m_ItemCount <= 0) diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h index 4d5250819..d1176a7cf 100644 --- a/src/Entities/Pickup.h +++ b/src/Entities/Pickup.h @@ -19,7 +19,7 @@ class cPickup : public cEntity { typedef cEntity super; - + public: // tolua_end @@ -32,15 +32,15 @@ public: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - bool CollectedBy(cPlayer * a_Dest); // tolua_export + bool CollectedBy(cPlayer & a_Dest); // tolua_export virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /** Returns the number of ticks that this entity has existed */ - int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export + int GetAge(void) const { return static_cast<int>(m_Timer / 50); } // tolua_export /** Set the number of ticks that this entity has existed */ - void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export + void SetAge(int a_Age) { m_Timer = static_cast<float>(a_Age * 50); } // tolua_export /** Returns true if the pickup has already been collected */ bool IsCollected(void) const { return m_bCollected; } // tolua_export @@ -59,7 +59,3 @@ private: bool m_bIsPlayerCreated; }; // tolua_export - - - - diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 66da14c0c..edcdb4799 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -20,7 +20,7 @@ #include "../WorldStorage/StatSerializer.h" #include "../CompositeChat.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "json/json.h" // 6000 ticks or 5 minutes @@ -56,8 +56,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : m_Stance(0.0), m_Inventory(*this), m_EnderChestContents(9, 3), - m_CurrentWindow(NULL), - m_InventoryWindow(NULL), + m_CurrentWindow(nullptr), + m_InventoryWindow(nullptr), m_GameMode(eGameMode_NotSet), m_IP(""), m_ClientHandle(a_Client), @@ -78,10 +78,10 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : m_IsChargingBow(false), m_BowCharge(0), m_FloaterID(-1), - m_Team(NULL), + m_Team(nullptr), m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), m_bIsTeleporting(false), - m_UUID((a_Client != NULL) ? a_Client->GetUUID() : ""), + m_UUID((a_Client != nullptr) ? a_Client->GetUUID() : ""), m_CustomName("") { m_InventoryWindow = new cInventoryWindow(*this); @@ -96,7 +96,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : m_PlayerName = a_PlayerName; - cWorld * World = NULL; + cWorld * World = nullptr; if (!LoadFromDisk(World)) { m_Inventory.Clear(); @@ -144,10 +144,10 @@ cPlayer::~cPlayer(void) SaveToDisk(); - m_ClientHandle = NULL; + m_ClientHandle = nullptr; delete m_InventoryWindow; - m_InventoryWindow = NULL; + m_InventoryWindow = nullptr; LOGD("Player %p deleted", this); } @@ -186,12 +186,12 @@ void cPlayer::SpawnOn(cClientHandle & a_Client) void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) { - if (m_ClientHandle != NULL) + if (m_ClientHandle != nullptr) { if (m_ClientHandle->IsDestroyed()) { // This should not happen, because destroying a client will remove it from the world, but just in case - m_ClientHandle = NULL; + m_ClientHandle = nullptr; return; } @@ -235,7 +235,6 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) CanMove = false; TeleportToCoords(m_LastPos.x, m_LastPos.y, m_LastPos.z); } - m_ClientHandle->StreamChunks(); } if (CanMove) @@ -245,7 +244,7 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) if (m_Health > 0) // make sure player is alive { - m_World->CollectPickupsByPlayer(this); + m_World->CollectPickupsByPlayer(*this); if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge())) { @@ -504,7 +503,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) if (Damage > 0) { // cPlayer makes sure damage isn't applied in creative, no need to check here - TakeDamage(dtFalling, NULL, Damage, Damage, 0); + TakeDamage(dtFalling, nullptr, Damage, Damage, 0); // Fall particles GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, (int)GetPosY() - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */); @@ -651,7 +650,7 @@ void cPlayer::AbortEating(void) void cPlayer::SendHealth(void) { - if (m_ClientHandle != NULL) + if (m_ClientHandle != nullptr) { m_ClientHandle->SendHealth(); } @@ -663,7 +662,7 @@ void cPlayer::SendHealth(void) void cPlayer::SendExperience(void) { - if (m_ClientHandle != NULL) + if (m_ClientHandle != nullptr) { m_ClientHandle->SendExperience(); m_bDirtyExperience = false; @@ -859,11 +858,11 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) } } - if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + if ((a_TDI.Attacker != nullptr) && (a_TDI.Attacker->IsPlayer())) { cPlayer * Attacker = (cPlayer *)a_TDI.Attacker; - if ((m_Team != NULL) && (m_Team == Attacker->m_Team)) + if ((m_Team != nullptr) && (m_Team == Attacker->m_Team)) { if (!m_Team->AllowsFriendlyFire()) { @@ -915,7 +914,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! - if ((a_TDI.Attacker == NULL) && m_World->ShouldBroadcastDeathMessages()) + if ((a_TDI.Attacker == nullptr) && m_World->ShouldBroadcastDeathMessages()) { AString DamageText; switch (a_TDI.DamageType) @@ -941,7 +940,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) } GetWorld()->BroadcastChatDeath(Printf("%s %s", GetName().c_str(), DamageText.c_str())); } - else if (a_TDI.Attacker == NULL) // && !m_World->ShouldBroadcastDeathMessages() by fallthrough + else if (a_TDI.Attacker == nullptr) // && !m_World->ShouldBroadcastDeathMessages() by fallthrough { // no-op } @@ -997,7 +996,7 @@ void cPlayer::Killed(cEntity * a_Victim) void cPlayer::Respawn(void) { - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); m_Health = GetMaxHealth(); SetInvulnerableTicks(20); @@ -1107,9 +1106,9 @@ void cPlayer::SetTeam(cTeam * a_Team) cTeam * cPlayer::UpdateTeam(void) { - if (m_World == NULL) + if (m_World == nullptr) { - SetTeam(NULL); + SetTeam(nullptr); } else { @@ -1142,7 +1141,7 @@ void cPlayer::OpenWindow(cWindow * a_Window) void cPlayer::CloseWindow(bool a_CanRefuse) { - if (m_CurrentWindow == NULL) + if (m_CurrentWindow == nullptr) { m_CurrentWindow = m_InventoryWindow; return; @@ -1167,7 +1166,7 @@ void cPlayer::CloseWindow(bool a_CanRefuse) void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse) { - if ((m_CurrentWindow == NULL) || (m_CurrentWindow->GetWindowID() != a_WindowID)) + if ((m_CurrentWindow == nullptr) || (m_CurrentWindow->GetWindowID() != a_WindowID)) { return; } @@ -1354,7 +1353,7 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos) // Y = -999 and X, Z = attempting to create speed, usually up to 0.03 // We cannot test m_AttachedTo, because when deattaching, the server thinks the client is already deattached while // the client may still send more of these nonsensical packets. - if (m_AttachedTo != NULL) + if (m_AttachedTo != nullptr) { Vector3d AddSpeed(a_NewPos); AddSpeed.y = 0; @@ -1581,7 +1580,7 @@ void cPlayer::TossItems(const cItems & a_Items) bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { - ASSERT(a_World != NULL); + ASSERT(a_World != nullptr); if (GetWorld() == a_World) { @@ -1590,7 +1589,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) } // Send the respawn packet: - if (a_ShouldSendRespawn && (m_ClientHandle != NULL)) + if (a_ShouldSendRespawn && (m_ClientHandle != nullptr)) { m_ClientHandle->SendRespawn(a_World->GetDimension()); } @@ -1603,6 +1602,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; } @@ -1652,7 +1654,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World) GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str(), OfflineUsage ); - if (a_World == NULL) + if (a_World == nullptr) { a_World = cRoot::Get()->GetDefaultWorld(); } @@ -1729,7 +1731,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) m_LoadedWorldName = root.get("world", "world").asString(); a_World = cRoot::Get()->GetWorld(GetLoadedWorldName(), false); - if (a_World == NULL) + if (a_World == nullptr) { a_World = cRoot::Get()->GetDefaultWorld(); } @@ -1795,7 +1797,7 @@ bool cPlayer::SaveToDisk() root["SpawnY"] = GetLastBedPos().y; root["SpawnZ"] = GetLastBedPos().z; - if (m_World != NULL) + if (m_World != nullptr) { root["world"] = m_World->GetName(); if (m_GameMode == m_World->GetGameMode()) @@ -1949,7 +1951,7 @@ void cPlayer::HandleFood(void) else if ((m_FoodLevel <= 0) && (m_Health > 1)) { // Damage from starving - TakeDamage(dtStarving, NULL, 1, 1, 0); + TakeDamage(dtStarving, nullptr, 1, 1, 0); } } } @@ -2018,7 +2020,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) { StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5); - if (m_AttachedTo == NULL) + if (m_AttachedTo == nullptr) { if (IsClimbing()) { @@ -2091,7 +2093,7 @@ void cPlayer::ApplyFoodExhaustionFromMovement() } // If riding anything, apply no food exhaustion - if (m_AttachedTo != NULL) + if (m_AttachedTo != nullptr) { return; } @@ -2134,14 +2136,19 @@ void cPlayer::ApplyFoodExhaustionFromMovement() void cPlayer::LoadRank(void) { // Load the values from cRankManager: - cRankManager & RankMgr = cRoot::Get()->GetRankManager(); - m_Rank = RankMgr.GetPlayerRankName(m_UUID); + cRankManager * RankMgr = cRoot::Get()->GetRankManager(); + m_Rank = RankMgr->GetPlayerRankName(m_UUID); if (m_Rank.empty()) { - m_Rank = RankMgr.GetDefaultRank(); + m_Rank = RankMgr->GetDefaultRank(); + } + else + { + // Update the name: + RankMgr->UpdatePlayerName(m_UUID, m_PlayerName); } - m_Permissions = RankMgr.GetPlayerPermissions(m_UUID); - RankMgr.GetRankVisuals(m_Rank, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode); + m_Permissions = RankMgr->GetPlayerPermissions(m_UUID); + RankMgr->GetRankVisuals(m_Rank, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode); // Break up the individual permissions on each dot, into m_SplitPermissions: m_SplitPermissions.clear(); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index ffd0b7e03..4bb51b556 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -176,17 +176,17 @@ public: AString GetIP(void) const { return m_IP; } // tolua_export - /** Returns the associated team, NULL if none */ + /** Returns the associated team, nullptr if none */ cTeam * GetTeam(void) { return m_Team; } // tolua_export - /** Sets the player team, NULL if none */ + /** Sets the player team, nullptr if none */ void SetTeam(cTeam * a_Team); + // tolua_end + /** Forces the player to query the scoreboard for his team */ cTeam * UpdateTeam(void); - // tolua_end - /** Return the associated statistic and achievement manager. */ cStatManager & GetStatManager() { return m_Stats; } @@ -421,9 +421,13 @@ public: /** Sets the player's bed (home) position */ void SetBedPos(const Vector3i & a_Pos) { m_LastBedPos = a_Pos; } + + // tolua_end /** Update movement-related statistics. */ void UpdateMovementStats(const Vector3d & a_DeltaPos); + + // tolua_begin /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index acc9bd674..1768714f8 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -135,7 +135,7 @@ public: m_Pos(a_Pos), m_NextPos(a_NextPos), m_MinCoeff(1), - m_HitEntity(NULL) + m_HitEntity(nullptr) { } @@ -221,9 +221,9 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height), m_ProjectileKind(a_Kind), m_CreatorData( - ((a_Creator != NULL) ? a_Creator->GetUniqueID() : -1), - ((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : ""), - ((a_Creator != NULL) ? a_Creator->GetEquippedWeapon().m_Enchantments : cEnchantments()) + ((a_Creator != nullptr) ? a_Creator->GetUniqueID() : -1), + ((a_Creator != nullptr) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : ""), + ((a_Creator != nullptr) ? a_Creator->GetEquippedWeapon().m_Enchantments : cEnchantments()) ), m_IsInGround(false) { @@ -251,7 +251,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) { Vector3d Speed; - if (a_Speed != NULL) + if (a_Speed != nullptr) { Speed = *a_Speed; } @@ -269,10 +269,10 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkFirework: { - ASSERT(a_Item != NULL); + ASSERT(a_Item != nullptr); if (a_Item->m_FireworkItem.m_Colours.empty()) { - return NULL; + return nullptr; } return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, *a_Item); @@ -280,7 +280,7 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, } LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind); - return NULL; + return nullptr; } @@ -424,8 +424,12 @@ void cProjectileEntity::SpawnOn(cClientHandle & a_Client) -void cProjectileEntity::CollectedBy(cPlayer * a_Dest) +void cProjectileEntity::CollectedBy(cPlayer & a_Dest) { // Overriden in arrow UNUSED(a_Dest); } + + + + diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 990136a32..2a98e31c7 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -1,7 +1,7 @@ // ProjectileEntity.h -// Declares the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types +// Declares the cProjectileEntity class representing the common base class for projectiles @@ -23,7 +23,7 @@ class cProjectileEntity : typedef cEntity super; public: - /// The kind of the projectile. The numbers correspond to the network type ID used for spawning via the 0x17 packet. + /** The kind of the projectile. The numbers correspond to the network type ID used for spawning them in the protocol. */ enum eKind { pkArrow = 60, @@ -46,24 +46,24 @@ public: cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); - static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = NULL); + static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); - /// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given + /** Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given */ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace); - /// Called by the physics blocktracer when the entity hits another entity + /** Called by the physics blocktracer when the entity hits another entity */ virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { UNUSED(a_EntityHit); UNUSED(a_HitPos); } - /// Called by Chunk when the projectile is eligible for player collection - virtual void CollectedBy(cPlayer * a_Dest); + /** Called by Chunk when the projectile is eligible for player collection */ + virtual void CollectedBy(cPlayer & a_Dest); // tolua_begin - /// Returns the kind of the projectile (fast class identification) + /** Returns the kind of the projectile (fast class identification) */ eKind GetProjectileKind(void) const { return m_ProjectileKind; } /** Returns the unique ID of the entity who created this projectile @@ -76,15 +76,15 @@ public: */ AString GetCreatorName(void) const { return m_CreatorData.m_Name; } - /// Returns the string that is used as the entity type (class name) in MCA files + /** Returns the string that is used as the entity type (class name) in MCA files */ AString GetMCAClassName(void) const; - /// Returns true if the projectile has hit the ground and is stuck there + /** Returns true if the projectile has hit the ground and is stuck there */ bool IsInGround(void) const { return m_IsInGround; } // tolua_end - /// Sets the internal InGround flag. To be used by MCA loader only! + /** Sets the internal InGround flag. To be used by MCA loader only! */ void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; } protected: @@ -110,11 +110,11 @@ protected: eKind m_ProjectileKind; /** The structure for containing the entity ID and name who has created this projectile - The ID and/or name may be NULL (e.g. for dispensers/mobs) + The ID and/or name may be nullptr (e.g. for dispensers/mobs) */ CreatorData m_CreatorData; - /// True if the projectile has hit the ground and is stuck there + /** True if the projectile has hit the ground and is stuck there */ bool m_IsInGround; // cEntity overrides: diff --git a/src/Entities/SplashPotionEntity.h b/src/Entities/SplashPotionEntity.h index 4afc5f204..9302d8292 100644 --- a/src/Entities/SplashPotionEntity.h +++ b/src/Entities/SplashPotionEntity.h @@ -1,6 +1,11 @@ -// -// SplashPotionEntity.h -// + +// SplashPotionEntity.h + +// Declares the cSplashPotionEntity class representing a splash potion that has been thrown + + + + #pragma once @@ -32,6 +37,7 @@ public: const cItem & a_Item ); + // tolua_begin cEntityEffect::eType GetEntityEffectType(void) const { return m_EntityEffectType; } cEntityEffect GetEntityEffect(void) const { return m_EntityEffect; } int GetPotionColor(void) const { return m_PotionColor; } @@ -39,6 +45,8 @@ public: void SetEntityEffectType(cEntityEffect::eType a_EntityEffectType) { m_EntityEffectType = a_EntityEffectType; } void SetEntityEffect(cEntityEffect a_EntityEffect) { m_EntityEffect = a_EntityEffect; } void SetPotionColor(int a_PotionColor) { m_PotionColor = a_PotionColor; } + + // tolua_end protected: @@ -77,3 +85,7 @@ private: /** Time in ticks to wait for the hit animation to begin before destroying */ int m_DestroyTimer; } ; // tolua_export + + + + diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp index 5ae85bee8..24c946a9c 100644 --- a/src/Entities/ThrownEggEntity.cpp +++ b/src/Entities/ThrownEggEntity.cpp @@ -44,6 +44,27 @@ void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_Hit +void cThrownEggEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else + { + super::Tick(a_Dt, a_Chunk); + } +} + + + + + void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos) { if (m_World->GetTickRandomNumber(7) == 1) diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h index a0b7d5340..6ffedf5b5 100644 --- a/src/Entities/ThrownEggEntity.h +++ b/src/Entities/ThrownEggEntity.h @@ -1,6 +1,11 @@ -// -// ThrownEggEntity.h -// + +// ThrownEggEntity.h + +// Declares the cThrownEggEntity class representing a regular thrown egg + + + + #pragma once @@ -29,23 +34,8 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - virtual void Tick (float a_Dt, cChunk & a_Chunk) override - { - if (m_DestroyTimer > 0) - { - m_DestroyTimer--; - if (m_DestroyTimer == 0) - { - Destroy(); - return; - } - } - else - { - super::Tick(a_Dt, a_Chunk); - } - } + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; // Randomly decides whether to spawn a chicken where the egg lands. void TrySpawnChicken(const Vector3d & a_HitPos); @@ -56,3 +46,7 @@ private: int m_DestroyTimer; } ; // tolua_export + + + + diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index c7407e6ae..8f1b62934 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ThrownEnderPearlEntity.h" @@ -45,6 +46,27 @@ void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d +void cThrownEnderPearlEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else + { + super::Tick(a_Dt, a_Chunk); + } +} + + + + + void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) { if (m_CreatorData.m_Name.empty()) diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h index 436450013..475ebde87 100644 --- a/src/Entities/ThrownEnderPearlEntity.h +++ b/src/Entities/ThrownEnderPearlEntity.h @@ -1,6 +1,11 @@ -// -// ThrownEnderPearlEntity.h -// + +// ThrownEnderPearlEntity.h + +// Declares the cThrownEnderPeralEntity class representing an ender pearl being thrown + + + + #pragma once @@ -29,23 +34,8 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - virtual void Tick (float a_Dt, cChunk & a_Chunk) override - { - if (m_DestroyTimer > 0) - { - m_DestroyTimer--; - if (m_DestroyTimer == 0) - { - Destroy(); - return; - } - } - else - { - super::Tick(a_Dt, a_Chunk); - } - } + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /** Teleports the creator where the ender pearl lands */ void TeleportCreator(const Vector3d & a_HitPos); @@ -56,3 +46,7 @@ private: int m_DestroyTimer; } ; // tolua_export + + + + diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp index 496397100..88e39d22e 100644 --- a/src/Entities/ThrownSnowballEntity.cpp +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -43,3 +43,28 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & m_DestroyTimer = 5; } + + + + + +void cThrownSnowballEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else + { + super::Tick(a_Dt, a_Chunk); + } +} + + + + diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h index 8d195ced1..f806996cc 100644 --- a/src/Entities/ThrownSnowballEntity.h +++ b/src/Entities/ThrownSnowballEntity.h @@ -1,6 +1,11 @@ -// -// ThrownSnowballEntity.h -// + +// ThrownSnowballEntity.h + +// Declares the cThrownSnowballEntity representing a snowball that has been thrown + + + + #pragma once @@ -29,23 +34,8 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - virtual void Tick (float a_Dt, cChunk & a_Chunk) override - { - if (m_DestroyTimer > 0) - { - m_DestroyTimer--; - if (m_DestroyTimer == 0) - { - Destroy(); - return; - } - } - else - { - super::Tick(a_Dt, a_Chunk); - } - } + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; private: @@ -53,3 +43,7 @@ private: int m_DestroyTimer; } ; // tolua_export + + + + diff --git a/src/Entities/WitherSkullEntity.h b/src/Entities/WitherSkullEntity.h index c59acd807..43a520388 100644 --- a/src/Entities/WitherSkullEntity.h +++ b/src/Entities/WitherSkullEntity.h @@ -1,8 +1,12 @@ -// WitherSkullEntity.h +// WitherSkullEntity.h // Declares the cWitherSkullEntity class representing the entity used by both blue and black wither skulls + + + + #pragma once #include "ProjectileEntity.h" @@ -30,6 +34,10 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; } ; // tolua_export + + + + diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index d200ef3d7..9b3b2ecbe 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -43,7 +43,7 @@ cFurnaceRecipe::~cFurnaceRecipe() { ClearRecipes(); delete m_pState; - m_pState = NULL; + m_pState = nullptr; } @@ -247,9 +247,9 @@ void cFurnaceRecipe::ClearRecipes(void) { cRecipe Recipe = *itr; delete Recipe.In; - Recipe.In = NULL; + Recipe.In = nullptr; delete Recipe.Out; - Recipe.Out = NULL; + Recipe.Out = nullptr; } m_pState->Recipes.clear(); @@ -257,7 +257,7 @@ void cFurnaceRecipe::ClearRecipes(void) { cFuel Fuel = *itr; delete Fuel.In; - Fuel.In = NULL; + Fuel.In = nullptr; } m_pState->Fuel.clear(); } diff --git a/src/FurnaceRecipe.h b/src/FurnaceRecipe.h index 6a1650695..936ef706d 100644 --- a/src/FurnaceRecipe.h +++ b/src/FurnaceRecipe.h @@ -32,7 +32,7 @@ public: int CookTime; ///< How long this recipe takes to smelt, in ticks }; - /** Returns a recipe for the specified input, NULL if no recipe found */ + /** Returns a recipe for the specified input, nullptr if no recipe found */ const cRecipe * GetRecipeFrom(const cItem & a_Ingredient) const; /** Returns the amount of time that the specified fuel burns, in ticks */ diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp index 3ee0bd4c5..2a4dbe794 100644 --- a/src/Generating/BioGen.cpp +++ b/src/Generating/BioGen.cpp @@ -5,7 +5,11 @@ #include "Globals.h" #include "BioGen.h" -#include "inifile/iniFile.h" +#include <chrono> +#include <iostream> +#include "IntGen.h" +#include "ProtIntGen.h" +#include "../IniFile.h" #include "../LinearUpscale.h" @@ -45,7 +49,7 @@ void cBioGenConstant::InitializeBiomeGen(cIniFile & a_IniFile) //////////////////////////////////////////////////////////////////////////////// // cBioGenCache: -cBioGenCache::cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize) : +cBioGenCache::cBioGenCache(cBiomeGenPtr a_BioGenToCache, int a_CacheSize) : m_BioGenToCache(a_BioGenToCache), m_CacheSize(a_CacheSize), m_CacheOrder(new int[a_CacheSize]), @@ -69,9 +73,9 @@ cBioGenCache::cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize) : cBioGenCache::~cBioGenCache() { delete[] m_CacheData; - m_CacheData = NULL; + m_CacheData = nullptr; delete[] m_CacheOrder; - m_CacheOrder = NULL; + m_CacheOrder = nullptr; } @@ -145,25 +149,13 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile) //////////////////////////////////////////////////////////////////////////////// // cBioGenMulticache: -cBioGenMulticache::cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength) : - m_CachesLength(a_CachesLength) +cBioGenMulticache::cBioGenMulticache(cBiomeGenPtr a_BioGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches) : + m_NumSubCaches(a_NumSubCaches) { - m_Caches.reserve(a_CachesLength); - for (size_t i = 0; i < a_CachesLength; i++) + m_Caches.reserve(a_NumSubCaches); + for (size_t i = 0; i < a_NumSubCaches; i++) { - m_Caches.push_back(new cBioGenCache(a_BioGenToCache, a_CacheSize)); - } -} - - - - - -cBioGenMulticache::~cBioGenMulticache() -{ - for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++) - { - delete *it; + m_Caches.push_back(cBiomeGenPtr(new cBioGenCache(a_BioGenToCache, a_SubCacheSize))); } } @@ -174,7 +166,7 @@ cBioGenMulticache::~cBioGenMulticache() void cBioGenMulticache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { const size_t coefficient = 3; - const size_t cacheIdx = ((size_t)a_ChunkX + coefficient * (size_t)a_ChunkZ) % m_CachesLength; + const size_t cacheIdx = ((size_t)a_ChunkX + coefficient * (size_t)a_ChunkZ) % m_NumSubCaches; m_Caches[cacheIdx]->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); } @@ -185,10 +177,9 @@ void cBioGenMulticache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMa void cBioGenMulticache::InitializeBiomeGen(cIniFile & a_IniFile) { - for (cBiomeGens::iterator it = m_Caches.begin(); it != m_Caches.end(); it++) + for (auto itr : m_Caches) { - cBiomeGen * tmp = *it; - tmp->InitializeBiomeGen(a_IniFile); + itr->InitializeBiomeGen(a_IniFile); } } @@ -737,8 +728,6 @@ void cBioGenMultiStepMap::FreezeWaterBiomes(cChunkDef::BiomeMap & a_BiomeMap, co cBioGenTwoLevel::cBioGenTwoLevel(int a_Seed) : m_VoronoiLarge(a_Seed + 1000), m_VoronoiSmall(a_Seed + 2000), - m_DistortX(a_Seed + 3000), - m_DistortZ(a_Seed + 4000), m_Noise1(a_Seed + 5001), m_Noise2(a_Seed + 5002), m_Noise3(a_Seed + 5003), @@ -762,19 +751,17 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1]; for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++) { - int BlockX = BaseX + x * 4; - int BlockZ = BaseZ + z * 4; - float BlockXF = (float)(16 * BlockX) / 128; - float BlockZF = (float)(16 * BlockZ) / 128; - double NoiseX = m_Noise1.CubicNoise2D(BlockXF / 16, BlockZF / 16); - NoiseX += 0.5 * m_Noise2.CubicNoise2D(BlockXF / 8, BlockZF / 8); - NoiseX += 0.08 * m_Noise3.CubicNoise2D(BlockXF, BlockZF); - double NoiseZ = m_Noise4.CubicNoise2D(BlockXF / 16, BlockZF / 16); - NoiseZ += 0.5 * m_Noise5.CubicNoise2D(BlockXF / 8, BlockZF / 8); - NoiseZ += 0.08 * m_Noise6.CubicNoise2D(BlockXF, BlockZF); + float BlockX = static_cast<float>(BaseX + x * 4); + float BlockZ = static_cast<float>(BaseZ + z * 4); + double NoiseX = m_AmpX1 * m_Noise1.CubicNoise2D(BlockX * m_FreqX1, BlockZ * m_FreqX1); + NoiseX += m_AmpX2 * m_Noise2.CubicNoise2D(BlockX * m_FreqX2, BlockZ * m_FreqX2); + NoiseX += m_AmpX3 * m_Noise3.CubicNoise2D(BlockX * m_FreqX3, BlockZ * m_FreqX3); + double NoiseZ = m_AmpZ1 * m_Noise4.CubicNoise2D(BlockX * m_FreqZ1, BlockZ * m_FreqZ1); + NoiseZ += m_AmpZ2 * m_Noise5.CubicNoise2D(BlockX * m_FreqZ2, BlockZ * m_FreqZ2); + NoiseZ += m_AmpZ3 * m_Noise6.CubicNoise2D(BlockX * m_FreqZ3, BlockZ * m_FreqZ3); - DistortX[4 * x][4 * z] = BlockX + (int)(64 * NoiseX); - DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ); + DistortX[4 * x][4 * z] = (int)(BlockX + NoiseX); + DistortZ[4 * x][4 * z] = (int)(BlockZ + NoiseZ); } LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]); @@ -789,7 +776,7 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 7; int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 11; int MinDist1 = (DistortX[x][z] - SeedX) * (DistortX[x][z] - SeedX) + (DistortZ[x][z] - SeedZ) * (DistortZ[x][z] - SeedZ); - cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 0 : 1)); + cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 1 : 0)); } } } @@ -915,30 +902,18 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile) { m_VoronoiLarge.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelLargeCellSize", 1024)); m_VoronoiSmall.SetCellSize(a_IniFile.GetValueSetI("Generator", "TwoLevelSmallCellSize", 128)); - m_DistortX.AddOctave( - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Freq", 0.01), - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Amp", 16) - ); - m_DistortX.AddOctave( - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Freq", 0.005), - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Amp", 8) - ); - m_DistortX.AddOctave( - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Freq", 0.0025), - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Amp", 4) - ); - m_DistortZ.AddOctave( - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Freq", 0.01), - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Amp", 16) - ); - m_DistortZ.AddOctave( - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Freq", 0.005), - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Amp", 8) - ); - m_DistortZ.AddOctave( - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Freq", 0.0025), - (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Amp", 4) - ); + m_FreqX1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Freq", 0.01); + m_AmpX1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave1Amp", 80); + m_FreqX2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Freq", 0.05); + m_AmpX2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave2Amp", 20); + m_FreqX3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Freq", 0.1), + m_AmpX3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortXOctave3Amp", 8); + m_FreqZ1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Freq", 0.01); + m_AmpZ1 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave1Amp", 80); + m_FreqZ2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Freq", 0.05); + m_AmpZ2 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave2Amp", 20); + m_FreqZ3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Freq", 0.1); + m_AmpZ3 = (float)a_IniFile.GetValueSetF("Generator", "TwoLevelDistortZOctave3Amp", 8); } @@ -946,9 +921,217 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile) //////////////////////////////////////////////////////////////////////////////// +// cBioGenGrown: + +class cBioGenGrown: + public cBiomeGen +{ +public: + cBioGenGrown(int a_Seed) + { + auto FinalRivers = + std::make_shared<cIntGenSmooth<8>> (a_Seed + 1, + std::make_shared<cIntGenZoom <10>> (a_Seed + 2, + std::make_shared<cIntGenRiver <7>> (a_Seed + 3, + std::make_shared<cIntGenZoom <9>> (a_Seed + 4, + std::make_shared<cIntGenSmooth<6>> (a_Seed + 5, + std::make_shared<cIntGenZoom <8>> (a_Seed + 8, + std::make_shared<cIntGenSmooth<6>> (a_Seed + 5, + std::make_shared<cIntGenZoom <8>> (a_Seed + 9, + std::make_shared<cIntGenSmooth<6>> (a_Seed + 5, + std::make_shared<cIntGenZoom <8>> (a_Seed + 10, + std::make_shared<cIntGenSmooth<6>> (a_Seed + 5, + std::make_shared<cIntGenSmooth<8>> (a_Seed + 6, + std::make_shared<cIntGenZoom <10>> (a_Seed + 11, + std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12 + )))))))))))))); + + auto alteration = + std::make_shared<cIntGenZoom <8>>(a_Seed, + std::make_shared<cIntGenLandOcean<6>>(a_Seed, 20 + )); + + auto alteration2 = + std::make_shared<cIntGenZoom <8>>(a_Seed + 1, + std::make_shared<cIntGenZoom <6>>(a_Seed + 2, + std::make_shared<cIntGenZoom <5>>(a_Seed + 1, + std::make_shared<cIntGenZoom <4>>(a_Seed + 2, + std::make_shared<cIntGenLandOcean<4>>(a_Seed + 1, 10 + ))))); + + auto FinalBiomes = + std::make_shared<cIntGenSmooth <8>> (a_Seed + 1, + std::make_shared<cIntGenZoom <10>>(a_Seed + 15, + std::make_shared<cIntGenSmooth <7>> (a_Seed + 1, + std::make_shared<cIntGenZoom <9>> (a_Seed + 16, + std::make_shared<cIntGenBeaches <6>> ( + std::make_shared<cIntGenZoom <8>> (a_Seed + 1, + std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2004, 10, + std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 10, 500, biDeepOcean, + std::make_shared<cIntGenReplaceRandomly<8>> (a_Seed + 1, biPlains, biSunflowerPlains, 20, + std::make_shared<cIntGenMBiomes <8>> (a_Seed + 5, alteration2, + std::make_shared<cIntGenAlternateBiomes<8>> (a_Seed + 1, alteration, + std::make_shared<cIntGenBiomeEdges <8>> (a_Seed + 3, + std::make_shared<cIntGenZoom <10>>(a_Seed + 2, + std::make_shared<cIntGenZoom <7>> (a_Seed + 4, + std::make_shared<cIntGenReplaceRandomly<5>> (a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50, + std::make_shared<cIntGenZoom <5>> (a_Seed + 8, + std::make_shared<cIntGenAddToOcean <4>> (a_Seed + 10, 300, biDeepOcean, + std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 9, 8, biMushroomIsland, + std::make_shared<cIntGenBiomes <8>> (a_Seed + 3000, + std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200, + std::make_shared<cIntGenZoom <8>> (a_Seed + 5, + std::make_shared<cIntGenRareBiomeGroups<6>> (a_Seed + 5, 50, + std::make_shared<cIntGenBiomeGroupEdges<6>> ( + std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200, + std::make_shared<cIntGenZoom <8>> (a_Seed + 7, + std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 8, 50, bgOcean, + std::make_shared<cIntGenReplaceRandomly<6>> (a_Seed + 101, bgIce, bgTemperate, 150, + std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 200, + std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 9, 50, bgOcean, + std::make_shared<cIntGenZoom <6>> (a_Seed + 10, + std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30 + ))))))))))))))))))))))))))))))); + + m_Gen = + std::make_shared<cIntGenSmooth <16>>(a_Seed, + std::make_shared<cIntGenZoom <18>>(a_Seed, + std::make_shared<cIntGenSmooth <11>>(a_Seed, + std::make_shared<cIntGenZoom <13>>(a_Seed, + std::make_shared<cIntGenMixRivers<8>> ( + FinalBiomes, FinalRivers + ))))); + } + + virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override + { + cIntGen<16, 16>::Values vals; + m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, vals); + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int x = 0; x < cChunkDef::Width; x++) + { + cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]); + } + } + } + +protected: + std::shared_ptr<cIntGen<16, 16>> m_Gen; +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cBioGenGrown: + +class cBioGenProtGrown: + public cBiomeGen +{ +public: + cBioGenProtGrown(int a_Seed) + { + auto FinalRivers = + std::make_shared<cProtIntGenSmooth>(a_Seed + 1, + std::make_shared<cProtIntGenZoom >(a_Seed + 2, + std::make_shared<cProtIntGenRiver >(a_Seed + 3, + std::make_shared<cProtIntGenZoom >(a_Seed + 4, + std::make_shared<cProtIntGenSmooth>(a_Seed + 5, + std::make_shared<cProtIntGenZoom >(a_Seed + 8, + std::make_shared<cProtIntGenSmooth>(a_Seed + 5, + std::make_shared<cProtIntGenZoom >(a_Seed + 9, + std::make_shared<cProtIntGenSmooth>(a_Seed + 5, + std::make_shared<cProtIntGenZoom >(a_Seed + 10, + std::make_shared<cProtIntGenSmooth>(a_Seed + 5, + std::make_shared<cProtIntGenSmooth>(a_Seed + 6, + std::make_shared<cProtIntGenZoom >(a_Seed + 11, + std::make_shared<cProtIntGenChoice>(a_Seed + 12, 2 + )))))))))))))); + + auto alteration = + std::make_shared<cProtIntGenZoom >(a_Seed, + std::make_shared<cProtIntGenLandOcean>(a_Seed, 20 + )); + + auto alteration2 = + std::make_shared<cProtIntGenZoom >(a_Seed + 1, + std::make_shared<cProtIntGenZoom >(a_Seed + 2, + std::make_shared<cProtIntGenZoom >(a_Seed + 1, + std::make_shared<cProtIntGenZoom >(a_Seed + 2, + std::make_shared<cProtIntGenLandOcean>(a_Seed + 1, 10 + ))))); + + auto FinalBiomes = + std::make_shared<cProtIntGenSmooth >(a_Seed + 1, + std::make_shared<cProtIntGenZoom >(a_Seed + 15, + std::make_shared<cProtIntGenSmooth >(a_Seed + 1, + std::make_shared<cProtIntGenZoom >(a_Seed + 16, + std::make_shared<cProtIntGenBeaches >( + std::make_shared<cProtIntGenZoom >(a_Seed + 1, + std::make_shared<cProtIntGenAddIslands >(a_Seed + 2004, 10, + std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 500, biDeepOcean, + std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 1, biPlains, biSunflowerPlains, 20, + std::make_shared<cProtIntGenMBiomes >(a_Seed + 5, alteration2, + std::make_shared<cProtIntGenAlternateBiomes>(a_Seed + 1, alteration, + std::make_shared<cProtIntGenBiomeEdges >(a_Seed + 3, + std::make_shared<cProtIntGenZoom >(a_Seed + 2, + std::make_shared<cProtIntGenZoom >(a_Seed + 4, + std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50, + std::make_shared<cProtIntGenZoom >(a_Seed + 8, + std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 300, biDeepOcean, + std::make_shared<cProtIntGenAddToOcean >(a_Seed + 9, 8, biMushroomIsland, + std::make_shared<cProtIntGenBiomes >(a_Seed + 3000, + std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200, + std::make_shared<cProtIntGenZoom >(a_Seed + 5, + std::make_shared<cProtIntGenRareBiomeGroups>(a_Seed + 5, 50, + std::make_shared<cProtIntGenBiomeGroupEdges>( + std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200, + std::make_shared<cProtIntGenZoom >(a_Seed + 7, + std::make_shared<cProtIntGenSetRandomly >(a_Seed + 8, 50, bgOcean, + std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 101, bgIce, bgTemperate, 150, + std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200, + std::make_shared<cProtIntGenSetRandomly >(a_Seed + 9, 50, bgOcean, + std::make_shared<cProtIntGenZoom >(a_Seed + 10, + std::make_shared<cProtIntGenLandOcean >(a_Seed + 100, 30 + ))))))))))))))))))))))))))))))); + + m_Gen = + std::make_shared<cProtIntGenSmooth >(a_Seed, + std::make_shared<cProtIntGenZoom >(a_Seed, + std::make_shared<cProtIntGenSmooth >(a_Seed, + std::make_shared<cProtIntGenZoom >(a_Seed, + std::make_shared<cProtIntGenMixRivers>( + FinalBiomes, FinalRivers + ))))); + } + + virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override + { + int vals[16 * 16]; + m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, 16, 16, vals); + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int x = 0; x < cChunkDef::Width; x++) + { + cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]); + } + } + } + +protected: + std::shared_ptr<cProtIntGen> m_Gen; +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// // cBiomeGen: -cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault) +cBiomeGenPtr cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault) { AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", ""); if (BiomeGenName.empty()) @@ -957,7 +1140,7 @@ cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a BiomeGenName = "MultiStepMap"; } - cBiomeGen * res = NULL; + cBiomeGen * res = nullptr; a_CacheOffByDefault = false; if (NoCaseCompare(BiomeGenName, "constant") == 0) { @@ -981,6 +1164,14 @@ cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a { res = new cBioGenTwoLevel(a_Seed); } + else if (NoCaseCompare(BiomeGenName, "grown") == 0) + { + res = new cBioGenGrown(a_Seed); + } + else if (NoCaseCompare(BiomeGenName, "grownprot") == 0) + { + res = new cBioGenProtGrown(a_Seed); + } else { if (NoCaseCompare(BiomeGenName, "multistepmap") != 0) @@ -1004,9 +1195,57 @@ cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a } res->InitializeBiomeGen(a_IniFile); - return res; + return cBiomeGenPtr(res); } + +//////////////////////////////////////////////////////////////////////////////// +// Performance tests: + +// Change to 1 to enable the perf test: +#if 0 + +class cBioGenPerfTest +{ +public: + cBioGenPerfTest() + { + std::cout << "BioGen performance tests commencing, please wait..." << std::endl; + TestGen("MultiStepMap", std::make_unique<cBioGenMultiStepMap>(1).get()); + TestGen("Grown", std::make_unique<cBioGenGrown>(1).get()); + TestGen("GrownProt", std::make_unique<cBioGenProtGrown>(1).get()); + std::cout << "BioGen performance tests complete." << std::endl; + } + +protected: + void TestGen(const AString && a_GenName, cBiomeGen * a_BioGen) + { + // Initialize the default settings for the generator: + cIniFile iniFile; + a_BioGen->InitializeBiomeGen(iniFile); + + // Generate the biomes: + auto start = std::chrono::system_clock::now(); + for (int z = 0; z < 100; z++) + { + for (int x = 0; x < 100; x++) + { + cChunkDef::BiomeMap biomes; + a_BioGen->GenBiomes(x, z, biomes); + } // for x + } // for z + auto dur = std::chrono::system_clock::now() - start; + double milliseconds = static_cast<double>((std::chrono::duration_cast<std::chrono::milliseconds>(dur)).count()); + + std::cout << a_GenName << ": " << 1000.0 * 100.0 * 100.0 / milliseconds << " chunks per second" << std::endl; + } +} g_BioGenPerfTest; + +#endif + + + + diff --git a/src/Generating/BioGen.h b/src/Generating/BioGen.h index 20d199611..5fd0844d9 100644 --- a/src/Generating/BioGen.h +++ b/src/Generating/BioGen.h @@ -48,12 +48,12 @@ class cBioGenCache : typedef cBiomeGen super; public: - cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize); // Doesn't take ownership of a_BioGenToCache - ~cBioGenCache(); + cBioGenCache(cBiomeGenPtr a_BioGenToCache, int a_CacheSize); + virtual ~cBioGenCache(); protected: - cBiomeGen * m_BioGenToCache; + cBiomeGenPtr m_BioGenToCache; struct sCacheData { @@ -87,19 +87,21 @@ class cBioGenMulticache : typedef cBiomeGen super; public: - /* - a_CacheSize defines the size of each singular cache - a_CachesLength defines how many caches are used for the multicache - */ - cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength); // Doesn't take ownership of a_BioGenToCache - ~cBioGenMulticache(); + /* Creates a new multicache - a cache that divides the caching into several sub-caches based on the chunk coords. + This allows us to use shorter cache depths with faster lookups for more covered area. (#381) + a_SubCacheSize defines the size of each sub-cache + a_NumSubCaches defines how many sub-caches are used for the multicache. */ + cBioGenMulticache(cBiomeGenPtr a_BioGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches); protected: - typedef std::vector<cBiomeGen *> cBiomeGens; + typedef std::vector<cBiomeGenPtr> cBiomeGenPtrs; + + /** Number of sub-caches. Pulled out of m_Caches.size() for faster access. */ + size_t m_NumSubCaches; - size_t m_CachesLength; - cBiomeGens m_Caches; + /** Individual sub-caches. */ + cBiomeGenPtrs m_Caches; virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; @@ -285,12 +287,7 @@ protected: /// The Voronoi map that decides biomes inside individual biome groups cVoronoiMap m_VoronoiSmall; - /// The noise used to distort the input X coord - cPerlinNoise m_DistortX; - - /// The noise used to distort the inupt Z coord - cPerlinNoise m_DistortZ; - + // The noises used for the distortion: cNoise m_Noise1; cNoise m_Noise2; cNoise m_Noise3; @@ -298,6 +295,14 @@ protected: cNoise m_Noise5; cNoise m_Noise6; + // Frequencies and amplitudes for the distortion noises: + float m_FreqX1, m_AmpX1; + float m_FreqX2, m_AmpX2; + float m_FreqX3, m_AmpX3; + float m_FreqZ1, m_AmpZ1; + float m_FreqZ2, m_AmpZ2; + float m_FreqZ3, m_AmpZ3; + // cBiomeGen overrides: virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt index 33d622b42..1a26bd0d5 100644 --- a/src/Generating/CMakeLists.txt +++ b/src/Generating/CMakeLists.txt @@ -46,6 +46,7 @@ SET (HDRS FinishGen.h GridStructGen.h HeiGen.h + IntGen.h MineShafts.h NetherFortGen.h Noise3DGenerator.h @@ -53,6 +54,7 @@ SET (HDRS PieceGenerator.h Prefab.h PrefabPiecePool.h + ProtIntGen.h RainbowRoadsGen.h Ravines.h RoughRavines.h @@ -65,5 +67,5 @@ SET (HDRS if(NOT MSVC) add_library(Generating ${SRCS} ${HDRS}) - target_link_libraries(Generating OSSupport iniFile Blocks) + target_link_libraries(Generating OSSupport Blocks) endif() diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index c0b646fd0..020d3bd0f 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -269,10 +269,10 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX LOGWARNING("%s: MaxRelX less than zero, adjusting to zero", __FUNCTION__); a_MaxRelX = 0; } - else if (a_MaxRelX >= cChunkDef::Width) + else if (a_MaxRelX > cChunkDef::Width) { LOGWARNING("%s: MaxRelX more than chunk width, adjusting to chunk width", __FUNCTION__); - a_MaxRelX = cChunkDef::Width - 1; + a_MaxRelX = cChunkDef::Width; } if (a_MinRelY < 0) @@ -290,10 +290,10 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX LOGWARNING("%s: MaxRelY less than zero, adjusting to zero", __FUNCTION__); a_MaxRelY = 0; } - else if (a_MaxRelY >= cChunkDef::Height) + else if (a_MaxRelY > cChunkDef::Height) { LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__); - a_MaxRelY = cChunkDef::Height - 1; + a_MaxRelY = cChunkDef::Height; } if (a_MinRelZ < 0) @@ -311,10 +311,10 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX LOGWARNING("%s: MaxRelZ less than zero, adjusting to zero", __FUNCTION__); a_MaxRelZ = 0; } - else if (a_MaxRelZ >= cChunkDef::Width) + else if (a_MaxRelZ > cChunkDef::Width) { LOGWARNING("%s: MaxRelZ more than chunk width, adjusting to chunk width", __FUNCTION__); - a_MaxRelZ = cChunkDef::Width - 1; + a_MaxRelZ = cChunkDef::Width; } // Prepare the block area: @@ -530,10 +530,10 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ) // The block entity is not created yet, try to create it and add to list: cBlockEntity * be = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), AbsX, a_RelY, AbsZ); - if (be == NULL) + if (be == nullptr) { // No block entity for this block type - return NULL; + return nullptr; } m_BlockEntities.push_back(be); return be; diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index eeea0c957..570132790 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -172,7 +172,7 @@ public: /** Returns the block entity at the specified coords. If there is no block entity at those coords, tries to create one, based on the block type - If the blocktype doesn't support a block entity, returns NULL. */ + If the blocktype doesn't support a block entity, returns nullptr. */ cBlockEntity * GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ); /** Updates the heightmap to match the current contents. diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index d615456c1..92e1bb31d 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -2,7 +2,7 @@ #include "Globals.h" #include "ChunkGenerator.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "ChunkDesc.h" #include "ComposableGenerator.h" #include "Noise3DGenerator.h" @@ -28,9 +28,9 @@ const unsigned int QUEUE_SKIP_LIMIT = 500; cChunkGenerator::cChunkGenerator(void) : super("cChunkGenerator"), m_Seed(0), // Will be overwritten by the actual generator - m_Generator(NULL), - m_PluginInterface(NULL), - m_ChunkSink(NULL) + m_Generator(nullptr), + m_PluginInterface(nullptr), + m_ChunkSink(nullptr) { } @@ -80,7 +80,7 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a m_Generator = new cComposableGenerator(*this); } - if (m_Generator == NULL) + if (m_Generator == nullptr) { LOGERROR("Generator could not start, aborting the server"); return false; @@ -103,7 +103,7 @@ void cChunkGenerator::Stop(void) Wait(); delete m_Generator; - m_Generator = NULL; + m_Generator = nullptr; } @@ -144,7 +144,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_Forc void cChunkGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { - if (m_Generator != NULL) + if (m_Generator != nullptr) { m_Generator->GenerateBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); } @@ -180,7 +180,7 @@ int cChunkGenerator::GetQueueLength(void) EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ) { - ASSERT(m_Generator != NULL); + ASSERT(m_Generator != nullptr); return m_Generator->GetBiomeAt(a_BlockX, a_BlockZ); } @@ -283,8 +283,8 @@ void cChunkGenerator::Execute(void) void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_PluginInterface != NULL); - ASSERT(m_ChunkSink != NULL); + ASSERT(m_PluginInterface != nullptr); + ASSERT(m_ChunkSink != nullptr); ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ)); cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ); diff --git a/src/Generating/CompoGen.cpp b/src/Generating/CompoGen.cpp index 178673e32..29b831dfd 100644 --- a/src/Generating/CompoGen.cpp +++ b/src/Generating/CompoGen.cpp @@ -12,7 +12,7 @@ #include "../BlockID.h" #include "../Item.h" #include "../LinearUpscale.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" @@ -663,7 +663,7 @@ void cCompoGenNether::InitializeCompoGen(cIniFile & a_IniFile) //////////////////////////////////////////////////////////////////////////////// // cCompoGenCache: -cCompoGenCache::cCompoGenCache(cTerrainCompositionGen & a_Underlying, int a_CacheSize) : +cCompoGenCache::cCompoGenCache(cTerrainCompositionGenPtr a_Underlying, int a_CacheSize) : m_Underlying(a_Underlying), m_CacheSize(a_CacheSize), m_CacheOrder(new int[a_CacheSize]), @@ -687,9 +687,9 @@ cCompoGenCache::cCompoGenCache(cTerrainCompositionGen & a_Underlying, int a_Cach cCompoGenCache::~cCompoGenCache() { delete[] m_CacheData; - m_CacheData = NULL; + m_CacheData = nullptr; delete[] m_CacheOrder; - m_CacheOrder = NULL; + m_CacheOrder = nullptr; } @@ -739,7 +739,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc) // Not in the cache: m_NumMisses++; - m_Underlying.ComposeTerrain(a_ChunkDesc); + m_Underlying->ComposeTerrain(a_ChunkDesc); // Insert it as the first item in the MRU order: int Idx = m_CacheOrder[m_CacheSize - 1]; @@ -760,7 +760,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc) void cCompoGenCache::InitializeCompoGen(cIniFile & a_IniFile) { - m_Underlying.InitializeCompoGen(a_IniFile); + m_Underlying->InitializeCompoGen(a_IniFile); } diff --git a/src/Generating/CompoGen.h b/src/Generating/CompoGen.h index 096b0fb5a..b145b6ba3 100644 --- a/src/Generating/CompoGen.h +++ b/src/Generating/CompoGen.h @@ -144,12 +144,12 @@ protected: -/// Caches most-recently-used chunk composition of another composition generator. Caches only the types and metas +/** Caches most-recently-used chunk composition of another composition generator. Caches only the types and metas */ class cCompoGenCache : public cTerrainCompositionGen { public: - cCompoGenCache(cTerrainCompositionGen & a_Underlying, int a_CacheSize); // Doesn't take ownership of a_Underlying + cCompoGenCache(cTerrainCompositionGenPtr a_Underlying, int a_CacheSize); // Doesn't take ownership of a_Underlying ~cCompoGenCache(); // cTerrainCompositionGen override: @@ -158,7 +158,7 @@ public: protected: - cTerrainCompositionGen & m_Underlying; + cTerrainCompositionGenPtr m_Underlying; struct sCacheData { diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 69068d231..5f46574c7 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -7,7 +7,7 @@ #include "ComposableGenerator.h" #include "../World.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "../Root.h" // Individual composed algorithms: @@ -39,7 +39,7 @@ //////////////////////////////////////////////////////////////////////////////// // cTerrainCompositionGen: -cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed) +cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed) { AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); if (CompoGenName.empty()) @@ -48,7 +48,7 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & CompoGenName = "Biomal"; } - cTerrainCompositionGen * res = NULL; + cTerrainCompositionGen * res = nullptr; if (NoCaseCompare(CompoGenName, "sameblock") == 0) { res = new cCompoGenSameBlock; @@ -73,6 +73,10 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & { res = new cCompoGenNether(a_Seed); } + else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0) + { + res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen); + } else if (NoCaseCompare(CompoGenName, "Noise3D") == 0) { res = new cNoise3DComposable(a_Seed); @@ -102,12 +106,12 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile.SetValue("Generator", "CompositionGen", "Biomal"); return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed); } - ASSERT(res != NULL); + ASSERT(res != nullptr); // Read the settings from the ini file: res->InitializeCompoGen(a_IniFile); - return res; + return cTerrainCompositionGenPtr(res); } @@ -119,12 +123,9 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) : super(a_ChunkGenerator), - m_BiomeGen(NULL), - m_HeightGen(NULL), - m_CompositionGen(NULL), - m_UnderlyingBiomeGen(NULL), - m_UnderlyingHeightGen(NULL), - m_UnderlyingCompositionGen(NULL) + m_BiomeGen(), + m_HeightGen(), + m_CompositionGen() { } @@ -132,33 +133,6 @@ cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) : -cComposableGenerator::~cComposableGenerator() -{ - // Delete the generating composition: - for (cFinishGenList::const_iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr) - { - delete *itr; - } - m_FinishGens.clear(); - - delete m_CompositionGen; - m_CompositionGen = NULL; - delete m_HeightGen; - m_HeightGen = NULL; - delete m_BiomeGen; - m_BiomeGen = NULL; - delete m_UnderlyingCompositionGen; - m_UnderlyingCompositionGen = NULL; - delete m_UnderlyingHeightGen; - m_UnderlyingHeightGen = NULL; - delete m_UnderlyingBiomeGen; - m_UnderlyingBiomeGen = NULL; -} - - - - - void cComposableGenerator::Initialize(cIniFile & a_IniFile) { super::Initialize(a_IniFile); @@ -175,7 +149,7 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile) void cComposableGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { - if (m_BiomeGen != NULL) // Quick fix for generator deinitializing before the world storage finishes loading + if (m_BiomeGen != nullptr) // Quick fix for generator deinitializing before the world storage finishes loading { m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap); } @@ -245,15 +219,14 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) CacheSize = 4; } LOGD("Using a cache for biomegen of size %d.", CacheSize); - m_UnderlyingBiomeGen = m_BiomeGen; if (MultiCacheLength > 0) { LOGD("Enabling multicache for biomegen of length %d.", MultiCacheLength); - m_BiomeGen = new cBioGenMulticache(m_UnderlyingBiomeGen, CacheSize, MultiCacheLength); + m_BiomeGen = cBiomeGenPtr(new cBioGenMulticache(m_BiomeGen, CacheSize, MultiCacheLength)); } else { - m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize); + m_BiomeGen = cBiomeGenPtr(new cBioGenCache(m_BiomeGen, CacheSize)); } } @@ -264,7 +237,7 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) { bool CacheOffByDefault = false; - m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, *m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault); + m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault); // Add a cache, if requested: int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64); @@ -278,8 +251,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) CacheSize = 4; } LOGD("Using a cache for Heightgen of size %d.", CacheSize); - m_UnderlyingHeightGen = m_HeightGen; - m_HeightGen = new cHeiGenCache(*m_UnderlyingHeightGen, CacheSize); + m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize)); } } @@ -289,13 +261,12 @@ 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_HeightGen, m_ChunkGenerator.GetSeed()); int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64); if (CompoGenCacheSize > 1) { - m_UnderlyingCompositionGen = m_CompositionGen; - m_CompositionGen = new cCompoGenCache(*m_UnderlyingCompositionGen, 32); + m_CompositionGen = cTerrainCompositionGenPtr(new cCompoGenCache(m_CompositionGen, 32)); } } @@ -319,7 +290,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10; int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel); - m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenBottomLava(BottomLavaLevel))); } else if (NoCaseCompare(*itr, "DeadBushes") == 0) { @@ -341,20 +312,20 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) AllowedBlocks.push_back(E_BLOCK_HARDENED_CLAY); AllowedBlocks.push_back(E_BLOCK_STAINED_CLAY); - m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks))); } else if (NoCaseCompare(*itr, "DirectOverhangs") == 0) { - m_FinishGens.push_back(new cStructGenDirectOverhangs(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenDirectOverhangs(Seed))); } else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0) { - m_FinishGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenDistortedMembraneOverhangs(Seed))); } else if (NoCaseCompare(*itr, "DualRidgeCaves") == 0) { float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3); - m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenDualRidgeCaves(Seed, Threshold))); } else if (NoCaseCompare(*itr, "DungeonRooms") == 0) { @@ -362,24 +333,24 @@ 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(new cDungeonRoomsFinisher(*m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)); + m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib))); } else if (NoCaseCompare(*itr, "Ice") == 0) { - m_FinishGens.push_back(new cFinishGenIce); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenIce)); } else if (NoCaseCompare(*itr, "LavaLakes") == 0) { int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10); - m_FinishGens.push_back(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_HeightGen, Probability))); } else if (NoCaseCompare(*itr, "LavaSprings") == 0) { - m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension))); } else if (NoCaseCompare(*itr, "MarbleCaves") == 0) { - m_FinishGens.push_back(new cStructGenMarbleCaves(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenMarbleCaves(Seed))); } else if (NoCaseCompare(*itr, "MineShafts") == 0) { @@ -389,10 +360,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600); int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200); int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200); - m_FinishGens.push_back(new cStructGenMineShafts( + m_FinishGens.push_back(cFinishGenPtr(new cStructGenMineShafts( Seed, GridSize, MaxOffset, MaxSystemSize, ChanceCorridor, ChanceCrossing, ChanceStaircase - )); + ))); } else if (NoCaseCompare(*itr, "Lilypads") == 0) { @@ -406,7 +377,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) AllowedBlocks.push_back(E_BLOCK_WATER); AllowedBlocks.push_back(E_BLOCK_STATIONARY_WATER); - m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks))); } else if (NoCaseCompare(*itr, "NaturalPatches") == 0) { @@ -422,24 +393,51 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) // Gravel vein cStructGenOreNests::OreInfo GravelVein; - GravelVein.BlockType = E_BLOCK_DIRT; + GravelVein.BlockType = E_BLOCK_GRAVEL; GravelVein.MaxHeight = 127; GravelVein.NumNests = 20; GravelVein.NestSize = 32; Ores.push_back(GravelVein); - m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)); + // Granite vein + cStructGenOreNests::OreInfo GraniteVein; + GraniteVein.BlockType = E_BLOCK_STONE; + GraniteVein.BlockMeta = 1; + GraniteVein.MaxHeight = 127; + GraniteVein.NumNests = 20; + GraniteVein.NestSize = 32; + Ores.push_back(GraniteVein); + + // Diorite vein + cStructGenOreNests::OreInfo DioriteVein; + DioriteVein.BlockType = E_BLOCK_STONE; + DioriteVein.BlockMeta = 3; + DioriteVein.MaxHeight = 127; + DioriteVein.NumNests = 20; + DioriteVein.NestSize = 32; + Ores.push_back(DioriteVein); + + // Andesite vein + cStructGenOreNests::OreInfo AndesiteVein; + AndesiteVein.BlockType = E_BLOCK_STONE; + AndesiteVein.BlockMeta = 5; + AndesiteVein.MaxHeight = 127; + AndesiteVein.NumNests = 20; + AndesiteVein.NestSize = 32; + Ores.push_back(AndesiteVein); + + m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE))); } else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0) { - m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenNetherClumpFoliage(Seed))); } else if (NoCaseCompare(*itr, "NetherForts") == 0) { int GridSize = a_IniFile.GetValueSetI("Generator", "NetherFortsGridSize", 512); int MaxOffset = a_IniFile.GetValueSetI("Generator", "NetherFortMaxOffset", 128); int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12); - m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth)); + m_FinishGens.push_back(cFinishGenPtr(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth))); } else if (NoCaseCompare(*itr, "NetherOreNests") == 0) { @@ -453,7 +451,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) QuartzVein.NestSize = 8; Ores.push_back(QuartzVein); - m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK))); } else if (NoCaseCompare(*itr, "OreNests") == 0) @@ -508,11 +506,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) DiamondVein.NestSize = 4; Ores.push_back(DiamondVein); - m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE))); } else if (NoCaseCompare(*itr, "POCPieces") == 0) { - m_FinishGens.push_back(new cPOCPieceGenerator(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cPOCPieceGenerator(Seed))); } else if (NoCaseCompare(*itr, "PreSimulator") == 0) { @@ -521,7 +519,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) bool PreSimulateWater = a_IniFile.GetValueSetB("Generator", "PreSimulatorWater", true); bool PreSimulateLava = a_IniFile.GetValueSetB("Generator", "PreSimulatorLava", true); - m_FinishGens.push_back(new cFinishGenPreSimulator(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPreSimulator(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava))); } else if (NoCaseCompare(*itr, "RainbowRoads") == 0) { @@ -529,11 +527,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int MaxOffset = a_IniFile.GetValueSetI("Generator", "RainbowRoadsMaxOffset", 128); int MaxDepth = a_IniFile.GetValueSetI("Generator", "RainbowRoadsMaxDepth", 30); int MaxSize = a_IniFile.GetValueSetI("Generator", "RainbowRoadsMaxSize", 260); - m_FinishGens.push_back(new cRainbowRoadsGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize)); + m_FinishGens.push_back(cFinishGenPtr(new cRainbowRoadsGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize))); } else if (NoCaseCompare(*itr, "Ravines") == 0) { - m_FinishGens.push_back(new cStructGenRavines(Seed, 128)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenRavines(Seed, 128))); } else if (NoCaseCompare(*itr, "RoughRavines") == 0) { @@ -553,7 +551,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) double MinCeilingHeightEdge = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightEdge", 38); double MaxCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxCeilingHeightCenter", 58); double MinCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightCenter", 36); - m_FinishGens.push_back(new cRoughRavines( + m_FinishGens.push_back(cFinishGenPtr(new cRoughRavines( Seed, MaxSize, MinSize, (float)MaxCenterWidth, (float)MinCenterWidth, (float)MaxRoughness, (float)MinRoughness, @@ -562,27 +560,27 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) (float)MaxCeilingHeightEdge, (float)MinCeilingHeightEdge, (float)MaxCeilingHeightCenter, (float)MinCeilingHeightCenter, GridSize, MaxOffset - )); + ))); } else if (NoCaseCompare(*itr, "Snow") == 0) { - m_FinishGens.push_back(new cFinishGenSnow); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSnow)); } else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0) { - m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSprinkleFoliage(Seed))); } else if (NoCaseCompare(*itr, "TallGrass") == 0) { - m_FinishGens.push_back(new cFinishGenTallGrass(Seed)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenTallGrass(Seed))); } else if (NoCaseCompare(*itr, "TestRails") == 0) { - m_FinishGens.push_back(new cTestRailsGen(Seed, 100, 1, 7, 50)); + m_FinishGens.push_back(cFinishGenPtr(new cTestRailsGen(Seed, 100, 1, 7, 50))); } else if (NoCaseCompare(*itr, "Trees") == 0) { - m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen))); } else if (NoCaseCompare(*itr, "UnderwaterBases") == 0) { @@ -590,7 +588,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(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, *m_BiomeGen)); + m_FinishGens.push_back(cFinishGenPtr(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen))); } else if (NoCaseCompare(*itr, "Villages") == 0) { @@ -600,23 +598,23 @@ 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(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, *m_BiomeGen, *m_HeightGen)); + m_FinishGens.push_back(cFinishGenPtr(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_HeightGen))); } else if (NoCaseCompare(*itr, "WaterLakes") == 0) { int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25); - m_FinishGens.push_back(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_HeightGen, Probability))); } else if (NoCaseCompare(*itr, "WaterSprings") == 0) { - m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension)); + m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension))); } else if (NoCaseCompare(*itr, "WormNestCaves") == 0) { int Size = a_IniFile.GetValueSetI("Generator", "WormNestCavesSize", 64); int Grid = a_IniFile.GetValueSetI("Generator", "WormNestCavesGrid", 96); int MaxOffset = a_IniFile.GetValueSetI("Generator", "WormNestMaxOffset", 32); - m_FinishGens.push_back(new cStructGenWormNestCaves(Seed, Size, Grid, MaxOffset)); + m_FinishGens.push_back(cFinishGenPtr(new cStructGenWormNestCaves(Seed, Size, Grid, MaxOffset))); } else { diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h index 6b7627d2e..a091f8d53 100644 --- a/src/Generating/ComposableGenerator.h +++ b/src/Generating/ComposableGenerator.h @@ -24,6 +24,16 @@ See http://forum.mc-server.org/showthread.php?tid=409 for details. +// Forward-declare the shared pointers to subgenerator classes: +class cBiomeGen; +class cTerrainHeightGen; +class cTerrainCompositionGen; +class cFinishGen; +typedef SharedPtr<cBiomeGen> cBiomeGenPtr; +typedef SharedPtr<cTerrainHeightGen> cTerrainHeightGenPtr; +typedef SharedPtr<cTerrainCompositionGen> cTerrainCompositionGenPtr; +typedef SharedPtr<cFinishGen> cFinishGenPtr; + // fwd: Noise3DGenerator.h class cNoise3DComposable; @@ -53,8 +63,7 @@ public: a_CacheOffByDefault gets set to whether the cache should be disabled by default. Used in BiomeVisualiser, too. Implemented in BioGen.cpp! */ - static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault); - + static cBiomeGenPtr CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault); } ; @@ -83,7 +92,7 @@ public: a_CacheOffByDefault gets set to whether the cache should be disabled by default Implemented in HeiGen.cpp! */ - static cTerrainHeightGen * CreateHeightGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault); + static cTerrainHeightGenPtr CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault); } ; @@ -109,7 +118,7 @@ public: 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 */ - static cTerrainCompositionGen * CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed); + static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed); } ; @@ -131,7 +140,7 @@ public: virtual void GenFinish(cChunkDesc & a_ChunkDesc) = 0; } ; -typedef std::list<cFinishGen *> cFinishGenList; +typedef std::list<cFinishGenPtr> cFinishGenList; @@ -144,7 +153,6 @@ class cComposableGenerator : public: cComposableGenerator(cChunkGenerator & a_ChunkGenerator); - virtual ~cComposableGenerator(); virtual void Initialize(cIniFile & a_IniFile) override; virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; @@ -152,15 +160,10 @@ public: protected: // The generation composition: - cBiomeGen * m_BiomeGen; - cTerrainHeightGen * m_HeightGen; - cTerrainCompositionGen * m_CompositionGen; - cFinishGenList m_FinishGens; - - // Generators underlying the caches: - cBiomeGen * m_UnderlyingBiomeGen; - cTerrainHeightGen * m_UnderlyingHeightGen; - cTerrainCompositionGen * m_UnderlyingCompositionGen; + cBiomeGenPtr m_BiomeGen; + cTerrainHeightGenPtr m_HeightGen; + cTerrainCompositionGenPtr m_CompositionGen; + cFinishGenList m_FinishGens; /** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */ diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index c18c402da..d5bc6ab55 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -7,7 +7,7 @@ #include "DistortedHeightmap.h" #include "../OSSupport/File.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "../LinearUpscale.h" @@ -227,15 +227,15 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] = /* biMesaPlateau */ { 2.0f, 2.0f}, // 39 // biomes 40 .. 128 are unused, 89 empty placeholders here: - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 40 .. 49 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 50 .. 59 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 60 .. 69 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 70 .. 79 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 80 .. 89 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 90 .. 99 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 100 .. 109 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 110 .. 119 - {}, {}, {}, {}, {}, {}, {}, {}, {}, // 120 .. 128 + {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}, // 40 .. 49 + {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}, // 50 .. 59 + {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}, // 60 .. 69 + {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}, // 70 .. 79 + {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}, // 80 .. 89 + {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}, // 90 .. 99 + {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}, // 100 .. 109 + {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: /* biSunflowerPlains */ { 1.0f, 1.0f}, // 129 @@ -246,22 +246,22 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] = /* biSwamplandM */ { 0.0f, 0.0f}, // 134 // Biomes 135 .. 139 unused, 5 empty placeholders here: - {}, {}, {}, {}, {}, // 135 .. 139 + {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 135 .. 139 /* biIcePlainsSpikes */ { 1.0f, 1.0f}, // 140 // Biomes 141 .. 148 unused, 8 empty placeholders here: - {}, {}, {}, {}, {}, {}, {}, {}, // 141 .. 148 + {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}, // 141 .. 148 /* biJungleM */ { 4.0f, 4.0f}, // 149 - {}, // 150 + {0.0f, 0.0f}, // 150 /* biJungleEdgeM */ { 3.0f, 3.0f}, // 151 - {}, {}, {}, // 152 .. 154 + {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 152 .. 154 /* biBirchForestM */ { 3.0f, 3.0f}, // 155 /* biBirchForestHillsM */ { 5.0f, 5.0f}, // 156 /* biRoofedForestM */ { 2.0f, 2.0f}, // 157 /* biColdTaigaM */ { 1.0f, 1.0f}, // 158 - {}, // 159 + {0.0f, 0.0f}, // 159 /* biMegaSpruceTaiga */ { 3.0f, 3.0f}, // 160 /* biMegaSpruceTaigaHills */ { 3.0f, 3.0f}, // 161 /* biExtremeHillsPlusM */ {32.0f, 32.0f}, // 162 @@ -276,13 +276,13 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] = -cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen) : +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_BiomeGen(a_BiomeGen), - m_UnderlyingHeiGen(a_Seed, a_BiomeGen), + m_UnderlyingHeiGen(new cHeiGenBiomal(a_Seed, a_BiomeGen)), m_HeightGen(m_UnderlyingHeiGen, 64), m_IsInitialized(false) { @@ -540,10 +540,11 @@ void cDistortedHeightmap::InitializeCompoGen(cIniFile & a_IniFile) int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z) { - int ChunkX = (int)floor(a_X / (NOISE_DATATYPE)16); - int ChunkZ = (int)floor(a_Z / (NOISE_DATATYPE)16); - int RelX = (int)(a_X - (NOISE_DATATYPE)ChunkX * cChunkDef::Width); - int RelZ = (int)(a_Z - (NOISE_DATATYPE)ChunkZ * cChunkDef::Width); + int RelX = (int)std::floor(a_X); + int RelY = 0; + int RelZ = (int)std::floor(a_Z); + int ChunkX, ChunkZ; + cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ); // If we're withing the same chunk, return the pre-cached heightmap: if ((ChunkX == m_CurChunkX) && (ChunkZ == m_CurChunkZ)) @@ -576,7 +577,7 @@ void cDistortedHeightmap::UpdateDistortAmps(void) { for (int x = -1; x <= 1; x++) { - m_BiomeGen.GenBiomes(m_CurChunkX + x, m_CurChunkZ + z, Biomes[x + 1][z + 1]); + m_BiomeGen->GenBiomes(m_CurChunkX + x, m_CurChunkZ + z, Biomes[x + 1][z + 1]); } // for x } // for z diff --git a/src/Generating/DistortedHeightmap.h b/src/Generating/DistortedHeightmap.h index e6b3c9d3f..d073f29e4 100644 --- a/src/Generating/DistortedHeightmap.h +++ b/src/Generating/DistortedHeightmap.h @@ -35,7 +35,7 @@ public: NIBBLETYPE BlockMeta; } ; - cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen); + cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen); protected: typedef cChunkDef::BiomeMap BiomeNeighbors[3][3]; @@ -64,9 +64,14 @@ protected: int m_CurChunkZ; NOISE_DATATYPE m_DistortedHeightmap[17 * 257 * 17]; - cBiomeGen & m_BiomeGen; - cHeiGenBiomal m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion) - cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen + /** The bime generator to query for biomes. */ + cBiomeGenPtr m_BiomeGen; + + /** The generator that provides the base heightmap (before distortion). */ + cTerrainHeightGenPtr m_UnderlyingHeiGen; + + /** Cache for m_UnderlyingHeiGen. */ + cHeiGenCache m_HeightGen; /// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization. cChunkDef::HeightMap m_CurChunkHeights; diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index f213455d6..3f328868d 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "DungeonRoomsFinisher.h" #include "../FastRandom.h" +#include "../BlockEntities/ChestEntity.h" @@ -175,7 +176,33 @@ protected: } a_ChunkDesc.SetBlockTypeMeta(RelX, m_FloorHeight + 1, RelZ, E_BLOCK_CHEST, (NIBBLETYPE)a_Chest.y); - // TODO: Fill the chest with random loot + // Fill the chest with random loot + static const cLootProbab LootProbab[] = + { + // Item, MinAmount, MaxAmount, Weight + { cItem(E_ITEM_GOLDEN_APPLE), 1, 1, 1 }, + { cItem(E_ITEM_DIAMOND_HORSE_ARMOR), 1, 1, 1 }, + { cItem(E_ITEM_GOLD_HORSE_ARMOR), 1, 1, 2 }, + { cItem(E_ITEM_13_DISC), 1, 1, 4 }, + { cItem(E_ITEM_CAT_DISC), 1, 1, 4 }, + { cItem(E_ITEM_IRON_HORSE_ARMOR), 1, 1, 5 }, + { cItem(E_ITEM_IRON), 1, 4, 10 }, + { cItem(E_ITEM_WHEAT), 1, 4, 10 }, + { cItem(E_ITEM_GUNPOWDER), 1, 4, 10 }, + { cItem(E_ITEM_STRING), 1, 4, 10 }, + { cItem(E_ITEM_REDSTONE_DUST), 1, 4, 10 }, + { cItem(E_ITEM_SADDLE), 1, 1, 10 }, + { cItem(E_ITEM_BUCKET), 1, 1, 10 }, + { cItem(E_ITEM_BREAD), 1, 1, 10 }, + { cItem(E_ITEM_NAME_TAG), 1, 1, 10 }, + } ; + + cChestEntity * ChestEntity = (cChestEntity *)a_ChunkDesc.GetBlockEntity(RelX, m_FloorHeight + 1, RelZ); + ASSERT((ChestEntity != nullptr) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST)); + cNoise Noise(a_ChunkDesc.GetChunkX() ^ a_ChunkDesc.GetChunkZ()); + int NumSlots = 3 + ((Noise.IntNoise3DInt(a_Chest.x, a_Chest.y, a_Chest.z) / 11) % 4); + int Seed = Noise.IntNoise2DInt(RelX, RelZ); + ChestEntity->GetContents().GenerateRandomLootWithBooks(LootProbab, ARRAYCOUNT(LootProbab), NumSlots, Seed); } @@ -193,6 +220,7 @@ protected: // The chunk is not intersecting the room at all, bail out return; } + int b = m_FloorHeight + 1; // Bottom int t = m_FloorHeight + 1 + ROOM_HEIGHT; // Top ReplaceCuboidRandom(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE, E_BLOCK_COBBLESTONE); // Floor @@ -230,7 +258,7 @@ protected: //////////////////////////////////////////////////////////////////////////////// // cDungeonRoomsFinisher: -cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) : +cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, 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_MaxHalfSize((a_MaxSize + 1) / 2), @@ -266,7 +294,7 @@ cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int 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); + 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); diff --git a/src/Generating/DungeonRoomsFinisher.h b/src/Generating/DungeonRoomsFinisher.h index 2b52c9de6..09dd0448a 100644 --- a/src/Generating/DungeonRoomsFinisher.h +++ b/src/Generating/DungeonRoomsFinisher.h @@ -26,12 +26,12 @@ public: a_HeightGen is the underlying height 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(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib); + cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, 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 */ - cTerrainHeightGen & m_HeightGen; + cTerrainHeightGenPtr m_HeightGen; /** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */ int m_MaxHalfSize; diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp index c94cd1eff..0111d2fa3 100644 --- a/src/Generating/EndGen.cpp +++ b/src/Generating/EndGen.cpp @@ -5,7 +5,7 @@ #include "Globals.h" #include "EndGen.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "../LinearUpscale.h" diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 96e3dc26b..b8afac09a 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -15,7 +15,7 @@ #include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway() #include "../Simulator/FireSimulator.h" #include "../World.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" @@ -199,6 +199,11 @@ void cFinishGenTallGrass::GenFinish(cChunkDesc & a_ChunkDesc) // 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 ( @@ -414,6 +419,11 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc) } break; } + default: + { + // There's no snow in the other biomes. + break; + } } } } // for z @@ -454,6 +464,11 @@ void cFinishGenIce::GenFinish(cChunkDesc & a_ChunkDesc) } break; } + default: + { + // No icy water in other biomes. + break; + } } } } // for z diff --git a/src/Generating/GridStructGen.cpp b/src/Generating/GridStructGen.cpp index 7090f14b1..3c08c1a39 100644 --- a/src/Generating/GridStructGen.cpp +++ b/src/Generating/GridStructGen.cpp @@ -135,7 +135,7 @@ void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructur int OriginX = GridX + ((m_Noise.IntNoise2DInt(GridX + 3, GridZ + 5) / 7) % (m_MaxOffsetX * 2)) - m_MaxOffsetX; int OriginZ = GridZ + ((m_Noise.IntNoise2DInt(GridX + 5, GridZ + 3) / 7) % (m_MaxOffsetZ * 2)) - m_MaxOffsetZ; cStructurePtr Structure = CreateStructure(GridX, GridZ, OriginX, OriginZ); - if (Structure.get() == NULL) + if (Structure.get() == nullptr) { Structure.reset(new cEmptyStructure(GridX, GridZ, OriginX, OriginZ)); } diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index 79d529a6a..1d9f1e3aa 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -6,7 +6,7 @@ #include "Globals.h" #include "HeiGen.h" #include "../LinearUpscale.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "DistortedHeightmap.h" #include "EndGen.h" #include "Noise3DGenerator.h" @@ -17,81 +17,6 @@ //////////////////////////////////////////////////////////////////////////////// -// cTerrainHeightGen: - -cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault) -{ - AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); - if (HeightGenName.empty()) - { - LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\"."); - HeightGenName = "Biomal"; - } - - a_CacheOffByDefault = false; - cTerrainHeightGen * res = NULL; - if (NoCaseCompare(HeightGenName, "flat") == 0) - { - res = new 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); - } - else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) - { - res = new cDistortedHeightmap(a_Seed, a_BiomeGen); - } - else if (NoCaseCompare(HeightGenName, "End") == 0) - { - res = new cEndGen(a_Seed); - } - else if (NoCaseCompare(HeightGenName, "Mountains") == 0) - { - res = new cHeiGenMountains(a_Seed); - } - else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) - { - res = new cNoise3DComposable(a_Seed); - } - else if (NoCaseCompare(HeightGenName, "biomal") == 0) - { - res = new cHeiGenBiomal(a_Seed, a_BiomeGen); - - /* - // Performance-testing: - LOGINFO("Measuring performance of cHeiGenBiomal..."); - clock_t BeginTick = clock(); - for (int x = 0; x < 500; x++) - { - cChunkDef::HeightMap Heights; - res->GenHeightMap(x * 5, x * 5, Heights); - } - clock_t Duration = clock() - BeginTick; - LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); - //*/ - } - else - { - // 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 res; -} - - - - - -//////////////////////////////////////////////////////////////////////////////// // cHeiGenFlat: void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) @@ -118,7 +43,7 @@ void cHeiGenFlat::InitializeHeightGen(cIniFile & a_IniFile) //////////////////////////////////////////////////////////////////////////////// // cHeiGenCache: -cHeiGenCache::cHeiGenCache(cTerrainHeightGen & a_HeiGenToCache, int a_CacheSize) : +cHeiGenCache::cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize) : m_HeiGenToCache(a_HeiGenToCache), m_CacheSize(a_CacheSize), m_CacheOrder(new int[a_CacheSize]), @@ -142,9 +67,9 @@ cHeiGenCache::cHeiGenCache(cTerrainHeightGen & a_HeiGenToCache, int a_CacheSize) cHeiGenCache::~cHeiGenCache() { delete[] m_CacheData; - m_CacheData = NULL; + m_CacheData = nullptr; delete[] m_CacheOrder; - m_CacheOrder = NULL; + m_CacheOrder = nullptr; } @@ -190,7 +115,7 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap // Not in the cache: m_NumMisses++; - m_HeiGenToCache.GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap); + m_HeiGenToCache->GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap); // Insert it as the first item in the MRU order: int Idx = m_CacheOrder[m_CacheSize - 1]; @@ -210,7 +135,7 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap void cHeiGenCache::InitializeHeightGen(cIniFile & a_IniFile) { - m_HeiGenToCache.InitializeHeightGen(a_IniFile); + m_HeiGenToCache->InitializeHeightGen(a_IniFile); } @@ -317,7 +242,9 @@ void cHeiGenClassic::InitializeHeightGen(cIniFile & a_IniFile) cHeiGenMountains::cHeiGenMountains(int a_Seed) : m_Seed(a_Seed), - m_Noise(a_Seed) + m_MountainNoise(a_Seed + 100), + m_DitchNoise(a_Seed + 200), + m_Perlin(a_Seed + 300) { } @@ -332,9 +259,11 @@ void cHeiGenMountains::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Heigh NOISE_DATATYPE StartZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width); NOISE_DATATYPE EndZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + cChunkDef::Width - 1); NOISE_DATATYPE Workspace[16 * 16]; - NOISE_DATATYPE Noise[16 * 16]; + NOISE_DATATYPE MountainNoise[16 * 16]; + NOISE_DATATYPE DitchNoise[16 * 16]; NOISE_DATATYPE PerlinNoise[16 * 16]; - m_Noise.Generate2D(Noise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); + m_MountainNoise.Generate2D(MountainNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); + m_DitchNoise.Generate2D(DitchNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); m_Perlin.Generate2D(PerlinNoise, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); for (int z = 0; z < cChunkDef::Width; z++) { @@ -342,7 +271,7 @@ void cHeiGenMountains::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Heigh for (int x = 0; x < cChunkDef::Width; x++) { int idx = IdxZ + x; - int hei = 100 - (int)((Noise[idx] + PerlinNoise[idx]) * 15); + int hei = 100 - (int)((MountainNoise[idx] - DitchNoise[idx] + PerlinNoise[idx]) * 15); if (hei < 10) { hei = 10; @@ -363,9 +292,12 @@ void cHeiGenMountains::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Heigh void cHeiGenMountains::InitializeHeightGen(cIniFile & a_IniFile) { // TODO: Read the params from an INI file - m_Noise.AddOctave(0.1f, 0.1f); - m_Noise.AddOctave(0.05f, 0.5f); - m_Noise.AddOctave(0.02f, 1.5f); + m_MountainNoise.AddOctave(0.1f, 0.2f); + m_MountainNoise.AddOctave(0.05f, 0.4f); + m_MountainNoise.AddOctave(0.02f, 1.0f); + m_DitchNoise.AddOctave(0.1f, 0.2f); + m_DitchNoise.AddOctave(0.05f, 0.4f); + m_DitchNoise.AddOctave(0.02f, 1.0f); m_Perlin.AddOctave(0.01f, 1.5f); } @@ -423,15 +355,15 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] = /* biMesaPlateau */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80}, // biomes 40 .. 128 are unused, 89 empty placeholders here: - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 40 .. 49 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 50 .. 59 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 60 .. 69 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 70 .. 79 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 80 .. 89 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 90 .. 99 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 100 .. 109 - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 110 .. 119 - {}, {}, {}, {}, {}, {}, {}, {}, {}, // 120 .. 128 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 40 .. 49 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 50 .. 59 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 60 .. 69 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 70 .. 79 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 80 .. 89 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 90 .. 99 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 100 .. 109 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 110 .. 119 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 120 .. 128 /* biSunflowerPlains */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 129 /* biDesertM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 130 @@ -441,22 +373,22 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] = /* biSwamplandM */ { 1.0f, 3.0f, 1.10f, 7.0f, 0.01f, 0.01f, 60}, // 134 // Biomes 135 .. 139 unused, 5 empty placeholders here: - {}, {}, {}, {}, {}, // 135 .. 139 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 135 .. 139 /* biIcePlainsSpikes */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 140 // Biomes 141 .. 148 unused, 8 empty placeholders here: - {}, {}, {}, {}, {}, {}, {}, {}, // 141 .. 148 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 141 .. 148 /* biJungleM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 149 - {}, // 150 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 150 /* biJungleEdgeM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 151 - {}, {}, {}, // 152 .. 154 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 152 .. 154 /* biBirchForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 155 /* biBirchForestHillsM */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 156 /* biRoofedForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 157 /* biColdTaigaM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 158 - {}, // 159 + {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 159 /* biMegaSpruceTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 160 /* biMegaSpruceTaigaHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 161 /* biExtremeHillsPlusM */ { 0.2f, 4.0f, 0.05f, 20.0f, 0.01f, 16.0f, 120}, // 162 @@ -479,7 +411,7 @@ void cHeiGenBiomal::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMa { for (int x = -1; x <= 1; x++) { - m_BiomeGen.GenBiomes(a_ChunkX + x, a_ChunkZ + z, Biomes[x + 1][z + 1]); + m_BiomeGen->GenBiomes(a_ChunkX + x, a_ChunkZ + z, Biomes[x + 1][z + 1]); } // for x } // for z @@ -604,3 +536,287 @@ NOISE_DATATYPE cHeiGenBiomal::GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX, +//////////////////////////////////////////////////////////////////////////////// +// cHeiGenMinMax: + +class cHeiGenMinMax: + public cTerrainHeightGen +{ + typedef cTerrainHeightGen super; + + /** Size of the averaging process, in columns (for each direction). Must be less than 16. */ + static const int AVERAGING_SIZE = 4; + +public: + cHeiGenMinMax(int a_Seed, cBiomeGenPtr a_BiomeGen): + m_Noise(a_Seed), + m_BiomeGen(a_BiomeGen), + m_TotalWeight(0) + { + // Initialize the weights: + for (int z = 0; z <= AVERAGING_SIZE * 2; z++) + { + for (int x = 0; x <= AVERAGING_SIZE * 2; x++) + { + m_Weights[z][x] = 1 + 2 * AVERAGING_SIZE - std::abs(x - AVERAGING_SIZE) - std::abs(z - AVERAGING_SIZE); + m_TotalWeight += m_Weights[z][x]; + } + } + + // Initialize the Perlin generator: + m_Perlin.AddOctave(0.04f, 0.2f); + m_Perlin.AddOctave(0.02f, 0.1f); + m_Perlin.AddOctave(0.01f, 0.05f); + } + + + virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) + { + // Generate the biomes for the 3*3 neighbors: + cChunkDef::BiomeMap neighborBiomes[3][3]; + for (int z = 0; z < 3; z++) for (int x = 0; x < 3; x++) + { + m_BiomeGen->GenBiomes(a_ChunkX + x - 1, a_ChunkZ + z - 1, neighborBiomes[z][x]); + } + + // Get the min and max heights based on the biomes: + double minHeight[cChunkDef::Width * cChunkDef::Width]; + double maxHeight[cChunkDef::Width * cChunkDef::Width]; + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int x = 0; x < cChunkDef::Width; x++) + { + // For each column, sum the min and max values of the neighborhood around it: + double min = 0, max = 0; + for (int relz = 0; relz <= AVERAGING_SIZE * 2; relz++) + { + int bz = z + 16 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start + int cz = bz / 16; // Chunk Z coord relative to the neighborBiomes start + bz = bz % 16; // Biome Z coord relative to cz in neighborBiomes + for (int relx = 0; relx <= AVERAGING_SIZE * 2; relx++) + { + int bx = x + 16 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start + int cx = bx / 16; // Chunk X coord relative to the neighborBiomes start + bx = bx % 16; // Biome X coord relative to cz in neighborBiomes + + // Get the biome's min and max heights: + double bmin, bmax; + getBiomeMinMax(cChunkDef::GetBiome(neighborBiomes[cz][cx], bx, bz), bmin, bmax); + + // Add them to the total, with the weight depending on their relative position to the column: + min += bmin * m_Weights[relz][relx]; + max += bmax * m_Weights[relz][relx]; + } // for relx + } // for relz + minHeight[x + z * cChunkDef::Width] = min / m_TotalWeight; + maxHeight[x + z * cChunkDef::Width] = max / m_TotalWeight; + } // for x + } // for z + + // Generate the base noise: + NOISE_DATATYPE noise[cChunkDef::Width * cChunkDef::Width]; + NOISE_DATATYPE workspace[cChunkDef::Width * cChunkDef::Width]; + NOISE_DATATYPE startX = static_cast<float>(a_ChunkX * cChunkDef::Width); + NOISE_DATATYPE endX = startX + cChunkDef::Width - 1; + NOISE_DATATYPE startZ = static_cast<float>(a_ChunkZ * cChunkDef::Width); + NOISE_DATATYPE endZ = startZ + cChunkDef::Width - 1; + m_Perlin.Generate2D(noise, 16, 16, startX, endX, startZ, endZ, workspace); + + // Make the height by ranging the noise between min and max: + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int x = 0; x < cChunkDef::Width; x++) + { + double min = minHeight[x + z * cChunkDef::Width]; + double max = maxHeight[x + z * cChunkDef::Width]; + double h = (max + min) / 2 + noise[x + z * cChunkDef::Width] * (max - min); + cChunkDef::SetHeight(a_HeightMap, x, z, static_cast<HEIGHTTYPE>(h)); + } + } + } + + + virtual void InitializeHeightGen(cIniFile & a_IniFile) + { + // No settings available + } + +protected: + cNoise m_Noise; + + cPerlinNoise m_Perlin; + + /** The biome generator to query for the underlying biomes. */ + cBiomeGenPtr m_BiomeGen; + + /** Weights applied to each of the min / max values in the neighborhood of the currently evaluated column. */ + double m_Weights[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1]; + + /** Sum of all the m_Weights items. */ + double m_TotalWeight; + + + /** Returns the minimum and maximum heights for the given biome. */ + void getBiomeMinMax(EMCSBiome a_Biome, double & a_Min, double & a_Max) + { + switch (a_Biome) + { + case biBeach: a_Min = 61; a_Max = 64; break; + case biBirchForest: a_Min = 63; a_Max = 75; break; + case biBirchForestHills: a_Min = 63; a_Max = 90; break; + case biBirchForestHillsM: a_Min = 63; a_Max = 90; break; + case biBirchForestM: a_Min = 63; a_Max = 75; break; + case biColdBeach: a_Min = 61; a_Max = 64; break; + case biColdTaiga: a_Min = 63; a_Max = 75; break; + case biColdTaigaHills: a_Min = 63; a_Max = 90; break; + case biColdTaigaM: a_Min = 63; a_Max = 75; break; + case biDeepOcean: a_Min = 30; a_Max = 60; break; + case biDesert: a_Min = 63; a_Max = 70; break; + case biDesertHills: a_Min = 63; a_Max = 85; break; + case biDesertM: a_Min = 63; a_Max = 70; break; + case biEnd: a_Min = 10; a_Max = 100; break; + case biExtremeHills: a_Min = 60; a_Max = 120; break; + case biExtremeHillsEdge: a_Min = 63; a_Max = 100; break; + case biExtremeHillsM: a_Min = 60; a_Max = 120; break; + case biExtremeHillsPlus: a_Min = 60; a_Max = 140; break; + case biExtremeHillsPlusM: a_Min = 60; a_Max = 140; break; + case biFlowerForest: a_Min = 63; a_Max = 75; break; + case biForest: a_Min = 63; a_Max = 75; break; + case biForestHills: a_Min = 63; a_Max = 90; break; + case biFrozenOcean: a_Min = 45; a_Max = 64; break; + case biFrozenRiver: a_Min = 60; a_Max = 62; break; + case biIceMountains: a_Min = 63; a_Max = 90; break; + case biIcePlains: a_Min = 63; a_Max = 70; break; + case biIcePlainsSpikes: a_Min = 60; a_Max = 70; break; + case biJungle: a_Min = 60; a_Max = 80; break; + case biJungleEdge: a_Min = 62; a_Max = 75; break; + case biJungleEdgeM: a_Min = 62; a_Max = 75; break; + case biJungleHills: a_Min = 60; a_Max = 90; break; + case biJungleM: a_Min = 60; a_Max = 75; break; + case biMegaSpruceTaiga: a_Min = 63; a_Max = 75; break; + case biMegaSpruceTaigaHills: a_Min = 63; a_Max = 90; break; + case biMegaTaiga: a_Min = 63; a_Max = 75; break; + case biMegaTaigaHills: a_Min = 63; a_Max = 90; break; + case biMesa: a_Min = 63; a_Max = 90; break; + case biMesaBryce: a_Min = 60; a_Max = 67; break; + case biMesaPlateau: a_Min = 75; a_Max = 85; break; + case biMesaPlateauF: a_Min = 80; a_Max = 90; break; + case biMesaPlateauFM: a_Min = 80; a_Max = 90; break; + case biMesaPlateauM: a_Min = 75; a_Max = 85; break; + case biMushroomIsland: a_Min = 63; a_Max = 90; break; + case biMushroomShore: a_Min = 60; a_Max = 75; break; + case biNether: a_Min = 10; a_Max = 100; break; + case biOcean: a_Min = 45; a_Max = 64; break; + case biPlains: a_Min = 63; a_Max = 70; break; + case biRiver: a_Min = 60; a_Max = 62; break; + case biRoofedForest: a_Min = 63; a_Max = 75; break; + case biRoofedForestM: a_Min = 63; a_Max = 75; break; + case biSavanna: a_Min = 63; a_Max = 75; break; + case biSavannaM: a_Min = 63; a_Max = 80; break; + case biSavannaPlateau: a_Min = 75; a_Max = 100; break; + case biSavannaPlateauM: a_Min = 80; a_Max = 160; break; + case biStoneBeach: a_Min = 60; a_Max = 64; break; + case biSunflowerPlains: a_Min = 63; a_Max = 70; break; + case biSwampland: a_Min = 60; a_Max = 67; break; + case biSwamplandM: a_Min = 61; a_Max = 67; break; + case biTaiga: a_Min = 63; a_Max = 75; break; + case biTaigaHills: a_Min = 63; a_Max = 90; break; + case biTaigaM: a_Min = 63; a_Max = 80; break; + default: + { + ASSERT(!"Unknown biome"); + a_Min = 10; + a_Max = 10; + break; + } + } + } +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cTerrainHeightGen: + +cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault) +{ + AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); + if (HeightGenName.empty()) + { + LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\"."); + HeightGenName = "Biomal"; + } + + a_CacheOffByDefault = false; + cTerrainHeightGen * res = nullptr; + if (NoCaseCompare(HeightGenName, "flat") == 0) + { + res = new 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); + } + else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) + { + res = new cDistortedHeightmap(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(HeightGenName, "End") == 0) + { + res = new cEndGen(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "MinMax") == 0) + { + res = new cHeiGenMinMax(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(HeightGenName, "Mountains") == 0) + { + res = new cHeiGenMountains(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0) + { + res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) + { + res = new cNoise3DComposable(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "biomal") == 0) + { + res = new cHeiGenBiomal(a_Seed, a_BiomeGen); + + /* + // Performance-testing: + LOGINFO("Measuring performance of cHeiGenBiomal..."); + clock_t BeginTick = clock(); + for (int x = 0; x < 500; x++) + { + cChunkDef::HeightMap Heights; + res->GenHeightMap(x * 5, x * 5, Heights); + } + clock_t Duration = clock() - BeginTick; + LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); + //*/ + } + else + { + // 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); +} + + + + + diff --git a/src/Generating/HeiGen.h b/src/Generating/HeiGen.h index 5c106c7d9..6ae5ba362 100644 --- a/src/Generating/HeiGen.h +++ b/src/Generating/HeiGen.h @@ -45,7 +45,7 @@ class cHeiGenCache : public cTerrainHeightGen { public: - cHeiGenCache(cTerrainHeightGen & a_HeiGenToCache, int a_CacheSize); // Doesn't take ownership of a_HeiGenToCache + cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize); ~cHeiGenCache(); // cTerrainHeightGen overrides: @@ -57,7 +57,7 @@ public: protected: - cTerrainHeightGen & m_HeiGenToCache; + cTerrainHeightGenPtr m_HeiGenToCache; struct sCacheData { @@ -115,7 +115,8 @@ public: protected: int m_Seed; - cRidgedMultiNoise m_Noise; + cRidgedMultiNoise m_MountainNoise; + cRidgedMultiNoise m_DitchNoise; cPerlinNoise m_Perlin; // cTerrainHeightGen overrides: @@ -131,7 +132,7 @@ class cHeiGenBiomal : public cTerrainHeightGen { public: - cHeiGenBiomal(int a_Seed, cBiomeGen & a_BiomeGen) : + cHeiGenBiomal(int a_Seed, cBiomeGenPtr a_BiomeGen) : m_Noise(a_Seed), m_BiomeGen(a_BiomeGen) { @@ -141,8 +142,8 @@ protected: typedef cChunkDef::BiomeMap BiomeNeighbors[3][3]; - cNoise m_Noise; - cBiomeGen & m_BiomeGen; + cNoise m_Noise; + cBiomeGenPtr m_BiomeGen; // Per-biome terrain generator parameters: struct sGenParam diff --git a/src/Generating/IntGen.h b/src/Generating/IntGen.h new file mode 100644 index 000000000..b25e378c0 --- /dev/null +++ b/src/Generating/IntGen.h @@ -0,0 +1,1406 @@ + +// IntGen.h + +// Declares the cIntGen class and descendants for generating and filtering various 2D arrays of ints + +/* +The integers generated may be interpreted in several ways: +- land/see designators + - 0 = ocean + - >0 = land +- biome group + - 0 = ocean + - 1 = desert biomes + - 2 = temperate biomes + - 3 = mountains (hills and forests) + - 4 = ice biomes +- biome group with "bgfRare" flag (for generating rare biomes for the group) +- biome IDs +The interpretation depends on the generator used and on the position in the chain. + +The generators can be chained together - one produces data that another one consumes. +Some of such chain connections require changing the data dimensions between the two, which is handled automatically +by using templates. +*/ + + + + + +#pragma once + +#include "../BiomeDef.h" + + + + + +/** Constants representing the biome group designators. */ +const int bgOcean = 0; +const int bgDesert = 1; +const int bgTemperate = 2; +const int bgMountains = 3; +const int bgIce = 4; +const int bgLandOceanMax = 4; // Maximum biome group value generated in the landOcean generator +const int bgfRare = 1024; // Flag added to values to generate rare biomes for the group + + + + + +/** Interface that all the generator classes provide. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGen +{ +public: + /** Force a virtual destructor in all descendants. + Descendants contain virtual functions and are referred to via pointer-to-base, so they need a virtual destructor. */ + virtual ~cIntGen() {} + + /** Holds the array of values generated by this class (descendant). */ + typedef int Values[SizeX * SizeZ]; + + /** Generates the array of templated size into a_Values, based on given min coords. */ + virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) = 0; +}; + + + + + +/** Provides additional cNoise member and its helper functions. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenWithNoise : + public cIntGen<SizeX, SizeZ> +{ + typedef cIntGen<SizeX, SizeZ> super; + +public: + cIntGenWithNoise(int a_Seed) : + m_Noise(a_Seed) + { + } + +protected: + cNoise m_Noise; + + /** Chooses one of a_Val1 or a_Val2, based on m_Noise and the coordinates for querying the noise. */ + int ChooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2) + { + int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7; + return ((rnd & 1) == 0) ? a_Val1 : a_Val2; + } + + /** Chooses one of a_ValN, based on m_Noise and the coordinates for querying the noise. */ + int ChooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2, int a_Val3, int a_Val4) + { + int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7; + switch (rnd % 4) + { + case 0: return a_Val1; + case 1: return a_Val2; + case 2: return a_Val3; + default: return a_Val4; + } + } +}; + + + + + + +/** Generates a 2D array of random integers in the specified range [0 .. Range). */ +template <int Range, int SizeX, int SizeZ = SizeX> +class cIntGenChoice : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + cIntGenChoice(int a_Seed) : + super(a_Seed) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + for (int z = 0; z < SizeZ; z++) + { + int BaseZ = a_MinZ + z; + for (int x = 0; x < SizeX; x++) + { + a_Values[x + SizeX * z] = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7) % Range; + } + } // for z + } +}; + + + + + + +/** Decides between the ocean and landmass biomes. +Has a threshold (in percent) of how much land, the larger the threshold, the more land. +Generates 0 for ocean, biome group ID for landmass. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenLandOcean : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + cIntGenLandOcean(int a_Seed, int a_Threshold) : + super(a_Seed), + m_Threshold(a_Threshold) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + for (int z = 0; z < SizeZ; z++) + { + int BaseZ = a_MinZ + z; + for (int x = 0; x < SizeX; x++) + { + int rnd = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7); + a_Values[x + SizeX * z] = ((rnd % 100) < m_Threshold) ? ((rnd / 101) % bgLandOceanMax + 1) : 0; + } + } + + // If the centerpoint of the world is within the area, set it to bgTemperate, always: + if ((a_MinX <= 0) && (a_MinZ <= 0) && (a_MinX + SizeX > 0) && (a_MinZ + SizeZ > 0)) + { + a_Values[-a_MinX - a_MinZ * SizeX] = bgTemperate; + } + } + +protected: + int m_Threshold; +}; + + + + + +/** Zooms the underlying value array to twice the size. Uses random-neighbor for the pixels in-between. +This means that the zoome out image is randomly distorted. Applying zoom several times provides all +the distortion that the generators need. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenZoom : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +protected: + static const int m_LowerSizeX = (SizeX / 2) + 2; + static const int m_LowerSizeZ = (SizeZ / 2) + 2; + +public: + typedef std::shared_ptr<cIntGen<m_LowerSizeX, m_LowerSizeZ>> Underlying; + + + cIntGenZoom(int a_Seed, Underlying a_UnderlyingGen) : + super(a_Seed), + m_UnderlyingGen(a_UnderlyingGen) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying data with half the resolution: + int lowerMinX = a_MinX >> 1; + int lowerMinZ = a_MinZ >> 1; + int lowerData[m_LowerSizeX * m_LowerSizeZ]; + m_UnderlyingGen->GetInts(lowerMinX, lowerMinZ, lowerData); + const int lowStepX = (m_LowerSizeX - 1) * 2; + const int lowStepZ = (m_LowerSizeZ - 1) * 2; + int cache[lowStepX * lowStepZ]; + + // Discreet-interpolate the values into twice the size: + for (int z = 0; z < m_LowerSizeZ - 1; ++z) + { + int idx = (z * 2) * lowStepX; + int PrevZ0 = lowerData[z * m_LowerSizeX]; + int PrevZ1 = lowerData[(z + 1) * m_LowerSizeX]; + + for (int x = 0; x < m_LowerSizeX - 1; ++x) + { + int ValX1Z0 = lowerData[x + 1 + z * m_LowerSizeX]; + int ValX1Z1 = lowerData[x + 1 + (z + 1) * m_LowerSizeX]; + int RndX = (x + lowerMinX) * 2; + int RndZ = (z + lowerMinZ) * 2; + cache[idx] = PrevZ0; + cache[idx + lowStepX] = super::ChooseRandomOne(RndX, RndZ + 1, PrevZ0, PrevZ1); + cache[idx + 1] = super::ChooseRandomOne(RndX, RndZ - 1, PrevZ0, ValX1Z0); + cache[idx + 1 + lowStepX] = super::ChooseRandomOne(RndX, RndZ, PrevZ0, ValX1Z0, PrevZ1, ValX1Z1); + idx += 2; + PrevZ0 = ValX1Z0; + PrevZ1 = ValX1Z1; + } + } + + // Copy from Cache into a_Values; take into account the even/odd offsets in a_Min: + for (int z = 0; z < SizeZ; ++z) + { + memcpy(a_Values + z * SizeX, cache + (z + (a_MinZ & 1)) * lowStepX + (a_MinX & 1), SizeX * sizeof(int)); + } + } + +protected: + Underlying m_UnderlyingGen; +}; + + + + + +/** Smoothes out some artifacts generated by the zooming - mostly single-pixel values. +Compares each pixel to its neighbors and if the neighbors are equal, changes the pixel to their value. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenSmooth : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + static const int m_LowerSizeX = SizeX + 2; + static const int m_LowerSizeZ = SizeZ + 2; + +public: + typedef std::shared_ptr<cIntGen<m_LowerSizeX, m_LowerSizeZ>> Underlying; + + + cIntGenSmooth(int a_Seed, Underlying a_Underlying) : + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying values: + int lowerData[m_LowerSizeX * m_LowerSizeZ]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerData); + + // Smooth - for each square check if the surroundings are the same, if so, expand them diagonally. + // Also get rid of single-pixel irregularities (A-B-A): + for (int z = 0; z < SizeZ; z++) + { + int NoiseZ = a_MinZ + z; + for (int x = 0; x < SizeX; x++) + { + int val = lowerData[x + 1 + (z + 1) * m_LowerSizeX]; + int above = lowerData[x + 1 + z * m_LowerSizeX]; + int below = lowerData[x + 1 + (z + 2) * m_LowerSizeX]; + int left = lowerData[x + (z + 1) * m_LowerSizeX]; + int right = lowerData[x + 2 + (z + 1) * m_LowerSizeX]; + + if ((left == right) && (above == below)) + { + if (((super::m_Noise.IntNoise2DInt(a_MinX + x, NoiseZ) / 7) % 2) == 0) + { + val = left; + } + else + { + val = above; + } + } + else + { + if (left == right) + { + val = left; + } + + if (above == below) + { + val = above; + } + } + + a_Values[x + z * SizeX] = val; + } + } + } + +protected: + Underlying m_Underlying; +}; + + + + + +/** Converts land biomes at the edge of an ocean into the respective beach biome. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenBeaches : + public cIntGen<SizeX, SizeZ> +{ + typedef cIntGen<SizeX, SizeZ> super; + static const int m_UnderlyingSizeX = SizeX + 2; + static const int m_UnderlyingSizeZ = SizeZ + 2; + +public: + typedef std::shared_ptr<cIntGen<m_UnderlyingSizeX, m_UnderlyingSizeZ>> Underlying; + + + cIntGenBeaches(Underlying a_Underlying) : + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Map for biome -> its beach: + static const int ToBeach[] = + { + /* biOcean */ biOcean, + /* biPlains */ biBeach, + /* biDesert */ biBeach, + /* biExtremeHills */ biStoneBeach, + /* biForest */ biBeach, + /* biTaiga */ biColdBeach, + /* biSwampland */ biSwampland, + /* biRiver */ biRiver, + /* biNether */ biNether, + /* biEnd */ biEnd, + /* biFrozenOcean */ biColdBeach, + /* biFrozenRiver */ biColdBeach, + /* biIcePlains */ biColdBeach, + /* biIceMountains */ biColdBeach, + /* biMushroomIsland */ biMushroomShore, + /* biMushroomShore */ biMushroomShore, + /* biBeach */ biBeach, + /* biDesertHills */ biBeach, + /* biForestHills */ biBeach, + /* biTaigaHills */ biColdBeach, + /* biExtremeHillsEdge */ biStoneBeach, + /* biJungle */ biBeach, + /* biJungleHills */ biBeach, + /* biJungleEdge */ biBeach, + /* biDeepOcean */ biOcean, + /* biStoneBeach */ biStoneBeach, + /* biColdBeach */ biColdBeach, + /* biBirchForest */ biBeach, + /* biBirchForestHills */ biBeach, + /* biRoofedForest */ biBeach, + /* biColdTaiga */ biColdBeach, + /* biColdTaigaHills */ biColdBeach, + /* biMegaTaiga */ biStoneBeach, + /* biMegaTaigaHills */ biStoneBeach, + /* biExtremeHillsPlus */ biStoneBeach, + /* biSavanna */ biBeach, + /* biSavannaPlateau */ biBeach, + /* biMesa */ biMesa, + /* biMesaPlateauF */ biMesa, + /* biMesaPlateau */ biMesa, + }; + + // Generate the underlying values: + int lowerValues[m_UnderlyingSizeX * m_UnderlyingSizeZ]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerValues); + + // Add beaches between ocean and biomes: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int val = lowerValues[x + 1 + (z + 1) * m_UnderlyingSizeX]; + int above = lowerValues[x + 1 + z * m_UnderlyingSizeX]; + int below = lowerValues[x + 1 + (z + 2) * m_UnderlyingSizeX]; + int left = lowerValues[x + (z + 1) * m_UnderlyingSizeX]; + int right = lowerValues[x + 2 + (z + 1) * m_UnderlyingSizeX]; + if (!IsBiomeOcean(val)) + { + if (IsBiomeOcean(above) || IsBiomeOcean(below) || IsBiomeOcean(left) || IsBiomeOcean(right)) + { + // First convert the value to a regular biome (drop the M flag), then modulo by our biome count: + val = ToBeach[(val % 128) % ARRAYCOUNT(ToBeach)]; + } + } + a_Values[x + z * SizeX] = val; + } + } + } + +protected: + Underlying m_Underlying; +}; + + + + + +/** Generates the underlying numbers and then randomly changes some ocean group pixels into random land +biome group pixels, based on the predefined chance. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenAddIslands : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenAddIslands(int a_Seed, int a_Chance, Underlying a_Underlying) : + super(a_Seed), + m_Chance(a_Chance), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + m_Underlying->GetInts(a_MinX, a_MinZ, a_Values); + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + if (a_Values[x + z * SizeX] == bgOcean) + { + int rnd = super::m_Noise.IntNoise2DInt(a_MinX + x, a_MinZ + z) / 7; + if (rnd % 1000 < m_Chance) + { + a_Values[x + z * SizeX] = (rnd / 1003) % bgLandOceanMax; + } + } + } // for x + } // for z + } + +protected: + /** Chance, in permille, of an island being generated in ocean. */ + int m_Chance; + + Underlying m_Underlying; +}; + + + + + +/** A filter that adds an edge biome group between two biome groups that need an edge between them. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenBiomeGroupEdges : + public cIntGen<SizeX, SizeZ> +{ + typedef cIntGen<SizeX, SizeZ> super; + + static const int m_UnderlyingSizeX = SizeX + 2; + static const int m_UnderlyingSizeZ = SizeZ + 2; + +public: + + typedef std::shared_ptr<cIntGen<m_UnderlyingSizeX, m_UnderlyingSizeZ>> Underlying; + + cIntGenBiomeGroupEdges(Underlying a_Underlying) : + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) + { + // Generate the underlying biome groups: + int lowerValues[m_UnderlyingSizeX * m_UnderlyingSizeZ]; + m_Underlying->GetInts(a_MinX, a_MinZ, lowerValues); + + // Change the biomes on incompatible edges into an edge biome: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int val = lowerValues[x + 1 + (z + 1) * m_UnderlyingSizeX]; + int above = lowerValues[x + 1 + z * m_UnderlyingSizeX]; + int below = lowerValues[x + 1 + (z + 2) * m_UnderlyingSizeX]; + int left = lowerValues[x + (z + 1) * m_UnderlyingSizeX]; + int right = lowerValues[x + 2 + (z + 1) * m_UnderlyingSizeX]; + switch (val) + { + // Desert should neighbor only oceans, desert and temperates; change to temperate when another: + case bgDesert: + { + if ( + !isDesertCompatible(above) || + !isDesertCompatible(below) || + !isDesertCompatible(left) || + !isDesertCompatible(right) + ) + { + val = bgTemperate; + } + break; + } // case bgDesert + + // Ice should not neighbor deserts; change to temperate: + case bgIce: + { + if ( + (above == bgDesert) || + (below == bgDesert) || + (left == bgDesert) || + (right == bgDesert) + ) + { + val = bgTemperate; + } + break; + } // case bgIce + } + a_Values[x + z * SizeX] = val; + } // for x + } // for z + } + +protected: + Underlying m_Underlying; + + + inline bool isDesertCompatible(int a_BiomeGroup) + { + switch (a_BiomeGroup) + { + case bgOcean: + case bgDesert: + case bgTemperate: + { + return true; + } + default: + { + return false; + } + } + } +}; + + + + + +/** Turns biome group indices into real biomes. +For each pixel, takes its biome group and chooses a random biome from that group; replaces the value with +that biome. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenBiomes : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenBiomes(int a_Seed, Underlying a_Underlying) : + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Define the per-biome-group biomes: + static const int oceanBiomes[] = + { + biOcean, // biDeepOcean, + }; + + // Same as oceanBiomes, there are no rare oceanic biomes (mushroom islands are handled separately) + static const int rareOceanBiomes[] = + { + biOcean, + }; + + static const int desertBiomes[] = + { + biDesert, biDesert, biDesert, biDesert, biDesert, biDesert, biSavanna, biSavanna, biPlains, + }; + + static const int rareDesertBiomes[] = + { + biMesaPlateau, biMesaPlateauF, + }; + + static const int temperateBiomes[] = + { + biForest, biForest, biRoofedForest, biExtremeHills, biPlains, biBirchForest, biSwampland, + }; + + static const int rareTemperateBiomes[] = + { + biJungle, // Jungle is not strictly temperate, but let's piggyback it here + }; + + static const int mountainBiomes[] = + { + biExtremeHills, biForest, biTaiga, biPlains, + }; + + static const int rareMountainBiomes[] = + { + biMegaTaiga, + }; + + static const int iceBiomes[] = + { + biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga, + }; + + // Same as iceBiomes, there's no rare ice biome + static const int rareIceBiomes[] = + { + biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga, + }; + + static const cBiomesInGroups biomesInGroups[] = + { + /* bgOcean */ { static_cast<int>(ARRAYCOUNT(oceanBiomes)), oceanBiomes}, + /* bgDesert */ { static_cast<int>(ARRAYCOUNT(desertBiomes)), desertBiomes}, + /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(temperateBiomes)), temperateBiomes}, + /* bgMountains */ { static_cast<int>(ARRAYCOUNT(mountainBiomes)), mountainBiomes}, + /* bgIce */ { static_cast<int>(ARRAYCOUNT(iceBiomes)), iceBiomes}, + }; + + static const cBiomesInGroups rareBiomesInGroups[] = + { + /* bgOcean */ { static_cast<int>(ARRAYCOUNT(rareOceanBiomes)), rareOceanBiomes}, + /* bgDesert */ { static_cast<int>(ARRAYCOUNT(rareDesertBiomes)), rareDesertBiomes}, + /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(rareTemperateBiomes)), rareTemperateBiomes}, + /* bgMountains */ { static_cast<int>(ARRAYCOUNT(rareMountainBiomes)), rareMountainBiomes}, + /* bgIce */ { static_cast<int>(ARRAYCOUNT(rareIceBiomes)), rareIceBiomes}, + }; + + // Generate the underlying values, representing biome groups: + m_Underlying->GetInts(a_MinX, a_MinZ, a_Values); + + // Overwrite each biome group with a random biome from that group: + for (int z = 0; z < SizeZ; z++) + { + int IdxZ = z * SizeX; + for (int x = 0; x < SizeX; x++) + { + int val = a_Values[x + IdxZ]; + const cBiomesInGroups & Biomes = (val > bgfRare) ? + rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] : + biomesInGroups[val % ARRAYCOUNT(biomesInGroups)]; + int rnd = (super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7); + a_Values[x + IdxZ] = Biomes.Biomes[rnd % Biomes.Count]; + } + } + } + +protected: + + struct cBiomesInGroups + { + const int Count; + const int * Biomes; + }; + + + /** The underlying int generator */ + Underlying m_Underlying; +}; + + + + + +/** Randomly replaces pixels of one value to another value, using the given chance. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenReplaceRandomly : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenReplaceRandomly(int a_From, int a_To, int a_Chance, int a_Seed, Underlying a_Underlying) : + super(a_Seed), + m_From(a_From), + m_To(a_To), + m_Chance(a_Chance), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying values: + m_Underlying->GetInts(a_MinX, a_MinZ, a_Values); + + // Replace some of the values: + for (int z = 0; z < SizeZ; z++) + { + int idxZ = z * SizeX; + for (int x = 0; x < SizeX; x++) + { + int idx = x + idxZ; + if (a_Values[idx] == m_From) + { + int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7; + if (rnd % 1000 < m_Chance) + { + a_Values[idx] = m_To; + } + } + } + } // for z + } + + +protected: + /** The original value to be replaced. */ + int m_From; + + /** The destination value to which to replace. */ + int m_To; + + /** Chance, in permille, of replacing the value. */ + int m_Chance; + + Underlying m_Underlying; +}; + + + + + +/** Mixer that joins together finalized biomes and rivers. +It first checks for oceans, if there is an ocean in the Biomes, it keeps the ocean. +If there's no ocean, it checks Rivers for a river, if there is a river, it uses the Biomes to select either +regular river or frozen river, based on the biome. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenMixRivers: + public cIntGen<SizeX, SizeZ> +{ + typedef cIntGen<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenMixRivers(Underlying a_Biomes, Underlying a_Rivers): + m_Biomes(a_Biomes), + m_Rivers(a_Rivers) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying data: + m_Biomes->GetInts(a_MinX, a_MinZ, a_Values); + typename super::Values riverData; + m_Rivers->GetInts(a_MinX, a_MinZ, riverData); + + // Mix the values: + for (int z = 0; z < SizeZ; z++) + { + int idxZ = z * SizeX; + for (int x = 0; x < SizeX; x++) + { + int idx = x + idxZ; + if (IsBiomeOcean(a_Values[idx])) + { + // Oceans are kept without any changes + continue; + } + if (riverData[idx] != biRiver) + { + // There's no river, keep the current value + continue; + } + + // There's a river, change the output to a river or a frozen river, based on the original biome: + if (IsBiomeVeryCold((EMCSBiome)a_Values[idx])) + { + a_Values[idx] = biFrozenRiver; + } + else + { + a_Values[idx] = biRiver; + } + } // for x + } // for z + } + +protected: + Underlying m_Biomes; + Underlying m_Rivers; +}; + + + + + +/** Generates a river based on the underlying data. +This is basically an edge detector over the underlying data. The rivers are the edges where the underlying data +changes from one pixel to its neighbor. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenRiver: + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + static const int UnderlyingSizeX = SizeX + 2; + static const int UnderlyingSizeZ = SizeZ + 2; + +public: + typedef std::shared_ptr<cIntGen<UnderlyingSizeX, UnderlyingSizeZ>> Underlying; + + + cIntGenRiver(int a_Seed, Underlying a_Underlying): + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying data: + int Cache[UnderlyingSizeX * UnderlyingSizeZ]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache); + + // Detect the edges: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int Above = Cache[x + 1 + z * UnderlyingSizeX]; + int Below = Cache[x + 1 + (z + 2) * UnderlyingSizeX]; + int Left = Cache[x + (z + 1) * UnderlyingSizeX]; + int Right = Cache[x + 2 + (z + 1) * UnderlyingSizeX]; + int val = Cache[x + 1 + (z + 1) * UnderlyingSizeX]; + + if ((val == Above) && (val == Below) && (val == Left) && (val == Right)) + { + val = 0; + } + else + { + val = biRiver; + } + a_Values[x + z * SizeX] = val; + } // for x + } // for z + } + +protected: + Underlying m_Underlying; +}; + + + + + +/** Turns some of the oceans into the specified biome. Used for mushroom and deep ocean. +The biome is only placed if at least 3 of its neighbors are ocean and only with the specified chance. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenAddToOcean: + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + static const int UnderlyingSizeX = SizeX + 2; + static const int UnderlyingSizeZ = SizeZ + 2; + +public: + typedef std::shared_ptr<cIntGen<UnderlyingSizeX, UnderlyingSizeZ>> Underlying; + + + cIntGenAddToOcean(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying): + super(a_Seed), + m_Chance(a_Chance), + m_ToValue(a_ToValue), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying data: + int Cache[UnderlyingSizeX * UnderlyingSizeZ]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache); + + // Add the mushroom islands: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int val = Cache[x + 1 + (z + 1) * UnderlyingSizeX]; + if (!IsBiomeOcean(val)) + { + a_Values[x + z * SizeX] = val; + continue; + } + + // Count the ocean neighbors: + int Above = Cache[x + 1 + z * UnderlyingSizeX]; + int Below = Cache[x + 1 + (z + 2) * UnderlyingSizeX]; + int Left = Cache[x + (z + 1) * UnderlyingSizeX]; + int Right = Cache[x + 2 + (z + 1) * UnderlyingSizeX]; + int NumOceanNeighbors = 0; + if (IsBiomeOcean(Above)) + { + NumOceanNeighbors += 1; + } + if (IsBiomeOcean(Below)) + { + NumOceanNeighbors += 1; + } + if (IsBiomeOcean(Left)) + { + NumOceanNeighbors += 1; + } + if (IsBiomeOcean(Right)) + { + NumOceanNeighbors += 1; + } + + // If at least 3 ocean neighbors and the chance is right, change: + if ( + (NumOceanNeighbors >= 3) && + ((super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7) % 1000 < m_Chance) + ) + { + a_Values[x + z * SizeX] = m_ToValue; + } + else + { + a_Values[x + z * SizeX] = val; + } + } // for x + } // for z + } + +protected: + /** Chance, in permille, of changing the biome. */ + int m_Chance; + + /** The value to change the ocean into. */ + int m_ToValue; + + Underlying m_Underlying; +}; + + + + + +/** Changes random pixels of the underlying data to the specified value. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenSetRandomly : + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + cIntGenSetRandomly(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying) : + super(a_Seed), + m_Chance(a_Chance), + m_ToValue(a_ToValue), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying data: + m_Underlying->GetInts(a_MinX, a_MinZ, a_Values); + + // Change random pixels to bgOcean: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7; + if (rnd % 1000 < m_Chance) + { + a_Values[x + z * SizeX] = m_ToValue; + } + } + } + } + +protected: + /** Chance, in permille, of changing each pixel. */ + int m_Chance; + + /** The value to which to set the pixel. */ + int m_ToValue; + + Underlying m_Underlying; +}; + + + + + + +/** Adds a "rare" flag to random biome groups, based on the given chance. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenRareBiomeGroups: + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenRareBiomeGroups(int a_Seed, int a_Chance, Underlying a_Underlying): + super(a_Seed), + m_Chance(a_Chance), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying data: + m_Underlying->GetInts(a_MinX, a_MinZ, a_Values); + + // Change some of the biome groups into rare biome groups: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7; + if (rnd % 1000 < m_Chance) + { + int idx = x + SizeX * z; + a_Values[idx] = a_Values[idx] | bgfRare; + } + } + } + } + +protected: + /** Chance, in permille, of changing each pixel into the rare biome group. */ + int m_Chance; + + /** The underlying generator. */ + Underlying m_Underlying; +}; + + + + + +/** Changes biomes in the parent data into an alternate versions (usually "hill" variants), in such places +that have their alterations set. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenAlternateBiomes: + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenAlternateBiomes(int a_Seed, Underlying a_Alterations, Underlying a_BaseBiomes): + super(a_Seed), + m_Alterations(a_Alterations), + m_BaseBiomes(a_BaseBiomes) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the base biomes and the alterations: + m_BaseBiomes->GetInts(a_MinX, a_MinZ, a_Values); + typename super::Values alterations; + m_Alterations->GetInts(a_MinX, a_MinZ, alterations); + + // Change the biomes into their alternate versions: + for (int idx = 0; idx < SizeX * SizeZ; ++idx) + { + if (alterations[idx] == 0) + { + // No change + continue; + } + + // Change to alternate biomes: + int val = a_Values[idx]; + switch (val) + { + case biBirchForest: val = biBirchForestHills; break; + case biDesert: val = biDesertHills; break; + case biExtremeHills: val = biExtremeHillsPlus; break; + case biForest: val = biForestHills; break; + case biIcePlains: val = biIceMountains; break; + case biJungle: val = biJungleHills; break; + case biMegaTaiga: val = biMegaTaigaHills; break; + case biMesaPlateau: val = biMesa; break; + case biMesaPlateauF: val = biMesa; break; + case biMesaPlateauM: val = biMesa; break; + case biMesaPlateauFM: val = biMesa; break; + case biPlains: val = biForest; break; + case biRoofedForest: val = biPlains; break; + case biSavanna: val = biSavannaPlateau; break; + case biTaiga: val = biTaigaHills; break; + } + a_Values[idx] = val; + } // for idx - a_Values[] + } + +protected: + Underlying m_Alterations; + Underlying m_BaseBiomes; +}; + + + + + +/** Adds an edge between two specifically incompatible biomes, such as mesa and forest. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenBiomeEdges: + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + static const int m_LowerSizeX = SizeX + 2; + static const int m_LowerSizeZ = SizeZ + 2; + +public: + typedef std::shared_ptr<cIntGen<m_LowerSizeX, m_LowerSizeZ>> Underlying; + + + cIntGenBiomeEdges(int a_Seed, Underlying a_Underlying): + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying biomes: + typename Underlying::element_type::Values lowerValues; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerValues); + + // Convert incompatible edges into neutral biomes: + for (int z = 0; z < SizeZ; z++) + { + for (int x = 0; x < SizeX; x++) + { + int biome = lowerValues[x + 1 + (z + 1) * m_LowerSizeX]; + int above = lowerValues[x + 1 + z * m_LowerSizeX]; + int below = lowerValues[x + 1 + (z + 2) * m_LowerSizeX]; + int left = lowerValues[x + (z + 1) * m_LowerSizeX]; + int right = lowerValues[x + 2 + (z + 1) * m_LowerSizeX]; + + switch (biome) + { + case biDesert: + case biDesertM: + case biDesertHills: + { + if ( + IsBiomeVeryCold(static_cast<EMCSBiome>(above)) || + IsBiomeVeryCold(static_cast<EMCSBiome>(below)) || + IsBiomeVeryCold(static_cast<EMCSBiome>(left)) || + IsBiomeVeryCold(static_cast<EMCSBiome>(right)) + ) + { + biome = biPlains; + } + break; + } // case biDesert + + case biMesaPlateau: + case biMesaPlateauF: + case biMesaPlateauFM: + case biMesaPlateauM: + { + if ( + !isMesaCompatible(above) || + !isMesaCompatible(below) || + !isMesaCompatible(left) || + !isMesaCompatible(right) + ) + { + biome = biDesert; + } + break; + } // Mesa biomes + + case biJungle: + case biJungleM: + { + if ( + !isJungleCompatible(above) || + !isJungleCompatible(below) || + !isJungleCompatible(left) || + !isJungleCompatible(right) + ) + { + biome = (biome == biJungle) ? biJungleEdge : biJungleEdgeM; + } + break; + } // Jungle biomes + + case biSwampland: + case biSwamplandM: + { + if ( + IsBiomeNoDownfall(static_cast<EMCSBiome>(above)) || + IsBiomeNoDownfall(static_cast<EMCSBiome>(below)) || + IsBiomeNoDownfall(static_cast<EMCSBiome>(left)) || + IsBiomeNoDownfall(static_cast<EMCSBiome>(right)) + ) + { + biome = biPlains; + } + break; + } // Swampland biomes + } // switch (biome) + + a_Values[x + z * SizeX] = biome; + } // for x + } // for z + } + + +protected: + Underlying m_Underlying; + + + bool isMesaCompatible(int a_Biome) + { + switch (a_Biome) + { + case biDesert: + case biMesa: + case biMesaBryce: + case biMesaPlateau: + case biMesaPlateauF: + case biMesaPlateauFM: + case biMesaPlateauM: + case biOcean: + case biDeepOcean: + { + return true; + } + default: + { + return false; + } + } + } + + + bool isJungleCompatible(int a_Biome) + { + switch (a_Biome) + { + case biJungle: + case biJungleM: + case biJungleEdge: + case biJungleEdgeM: + case biJungleHills: + { + return true; + } + default: + { + return false; + } + } + } +}; + + + + + +/** Changes biomes in the parent data into their alternate versions ("M" variants), in such places that +have their alterations set. */ +template <int SizeX, int SizeZ = SizeX> +class cIntGenMBiomes: + public cIntGenWithNoise<SizeX, SizeZ> +{ + typedef cIntGenWithNoise<SizeX, SizeZ> super; + +public: + typedef std::shared_ptr<cIntGen<SizeX, SizeZ>> Underlying; + + + cIntGenMBiomes(int a_Seed, Underlying a_Alteration, Underlying a_Underlying): + super(a_Seed), + m_Underlying(a_Underlying), + m_Alteration(a_Alteration) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, typename super::Values & a_Values) override + { + // Generate the underlying biomes and the alterations: + m_Underlying->GetInts(a_MinX, a_MinZ, a_Values); + typename super::Values alterations; + m_Alteration->GetInts(a_MinX, a_MinZ, alterations); + + // Wherever alterations are nonzero, change into alternate biome, if available: + for (int idx = 0; idx < SizeX * SizeZ; ++idx) + { + if (alterations[idx] == 0) + { + continue; + } + + // Ice spikes biome was removed from here, because it was generated way too often + switch (a_Values[idx]) + { + case biPlains: a_Values[idx] = biSunflowerPlains; break; + case biDesert: a_Values[idx] = biDesertM; break; + case biExtremeHills: a_Values[idx] = biExtremeHillsM; break; + case biForest: a_Values[idx] = biFlowerForest; break; + case biTaiga: a_Values[idx] = biTaigaM; break; + case biSwampland: a_Values[idx] = biSwamplandM; break; + case biJungle: a_Values[idx] = biJungleM; break; + case biJungleEdge: a_Values[idx] = biJungleEdgeM; break; + case biBirchForest: a_Values[idx] = biBirchForestM; break; + case biBirchForestHills: a_Values[idx] = biBirchForestHillsM; break; + case biRoofedForest: a_Values[idx] = biRoofedForestM; break; + case biColdTaiga: a_Values[idx] = biColdTaigaM; break; + case biMegaSpruceTaiga: a_Values[idx] = biMegaSpruceTaiga; break; + case biMegaSpruceTaigaHills: a_Values[idx] = biMegaSpruceTaigaHills; break; + case biExtremeHillsPlus: a_Values[idx] = biExtremeHillsPlusM; break; + case biSavanna: a_Values[idx] = biSavannaM; break; + case biSavannaPlateau: a_Values[idx] = biSavannaPlateauM; break; + case biMesa: a_Values[idx] = biMesaBryce; break; + case biMesaPlateauF: a_Values[idx] = biMesaPlateauFM; break; + case biMesaPlateau: a_Values[idx] = biMesaBryce; break; + } + } // for idx - a_Values[] / alterations[] + } + +protected: + Underlying m_Underlying; + Underlying m_Alteration; +}; + + + + diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp index 0532aff39..55b3b64dd 100644 --- a/src/Generating/MineShafts.cpp +++ b/src/Generating/MineShafts.cpp @@ -112,7 +112,7 @@ class cMineShaftCorridor : public: /** Creates a new Corridor attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. - May return NULL if cannot fit. + May return nullptr if cannot fit. */ static cMineShaft * CreateAndFit( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, @@ -165,7 +165,7 @@ class cMineShaftCrossing : public: /** Creates a new Crossing attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. - May return NULL if cannot fit. + May return nullptr if cannot fit. */ static cMineShaft * CreateAndFit( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, @@ -199,7 +199,7 @@ public: /** Creates a new Staircase attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. - May return NULL if cannot fit. + May return nullptr if cannot fit. */ static cMineShaft * CreateAndFit( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, @@ -351,7 +351,7 @@ void cStructGenMineShafts::cMineShaftSystem::AppendBranch( return; } - cMineShaft * Next = NULL; + cMineShaft * Next = nullptr; int rnd = (a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_RecursionLevel * 16, a_PivotZ) / 13) % m_ProbLevelStaircase; if (rnd < m_ProbLevelCorridor) { @@ -365,7 +365,7 @@ void cStructGenMineShafts::cMineShaftSystem::AppendBranch( { Next = cMineShaftStaircase::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise); } - if (Next == NULL) + if (Next == nullptr) { return; } @@ -552,7 +552,7 @@ cMineShaft * cMineShaftCorridor::CreateAndFit( } if (!a_ParentSystem.CanAppend(BoundingBox)) { - return NULL; + return nullptr; } return new cMineShaftCorridor(a_ParentSystem, BoundingBox, NumSegments, a_Direction, a_Noise); } @@ -796,7 +796,7 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) { a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p1.y + 1, z, E_BLOCK_CHEST, Meta); cChestEntity * ChestEntity = (cChestEntity *)a_ChunkDesc.GetBlockEntity(x, m_BoundingBox.p1.y + 1, z); - ASSERT((ChestEntity != NULL) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST)); + ASSERT((ChestEntity != nullptr) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST)); cNoise Noise(a_ChunkDesc.GetChunkX() ^ a_ChunkDesc.GetChunkZ()); int NumSlots = 3 + ((Noise.IntNoise3DInt(x, m_BoundingBox.p1.y, z) / 11) % 4); int Seed = Noise.IntNoise2DInt(x, z); @@ -1006,7 +1006,7 @@ cMineShaft * cMineShaftCrossing::CreateAndFit( } if (!a_ParentSystem.CanAppend(BoundingBox)) { - return NULL; + return nullptr; } return new cMineShaftCrossing(a_ParentSystem, BoundingBox); } @@ -1157,7 +1157,7 @@ cMineShaft * cMineShaftStaircase::CreateAndFit( } if (!a_ParentSystem.CanAppend(Box)) { - return NULL; + return nullptr; } return new cMineShaftStaircase(a_ParentSystem, Box, a_Direction, Slope); } diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index c3ca30384..f2af75999 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -6,7 +6,7 @@ #include "Globals.h" #include "Noise3DGenerator.h" #include "../OSSupport/File.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "../LinearInterpolation.h" #include "../LinearUpscale.h" @@ -61,6 +61,35 @@ public: +/** Linearly interpolates between two values. +Assumes that a_Ratio is in range [0, 1]. */ +inline static NOISE_DATATYPE Lerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio) +{ + return a_Val1 + (a_Val2 - a_Val1) * a_Ratio; +} + + + + + +/** Linearly interpolates between two values, clamping the ratio to [0, 1] first. */ +inline static NOISE_DATATYPE ClampedLerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio) +{ + if (a_Ratio < 0) + { + return a_Val1; + } + if (a_Ratio > 1) + { + return a_Val2; + } + return Lerp(a_Val1, a_Val2, a_Ratio); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cNoise3DGenerator: @@ -346,9 +375,10 @@ void cNoise3DGenerator::ComposeTerrain(cChunkDesc & a_ChunkDesc) // cNoise3DComposable: cNoise3DComposable::cNoise3DComposable(int a_Seed) : - m_Noise1(a_Seed + 1000), - m_Noise2(a_Seed + 2000), - m_Noise3(a_Seed + 3000) + m_ChoiceNoise(a_Seed), + m_DensityNoiseA(a_Seed + 1), + m_DensityNoiseB(a_Seed + 2), + m_BaseNoise(a_Seed + 3) { } @@ -359,13 +389,51 @@ cNoise3DComposable::cNoise3DComposable(int a_Seed) : void cNoise3DComposable::Initialize(cIniFile & a_IniFile) { // Params: + // The defaults generate extreme hills terrain m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62); - m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0); + m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.045); m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 75); - m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 10); - m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyY", 10); - m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyZ", 10); - m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DAirThreshold", 0.5); + m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 40); + m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyY", 40); + m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyZ", 40); + m_BaseFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DBaseFrequencyX", 40); + m_BaseFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DBaseFrequencyZ", 40); + m_ChoiceFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DChoiceFrequencyX", 40); + m_ChoiceFrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DChoiceFrequencyY", 80); + m_ChoiceFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DChoiceFrequencyZ", 40); + m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DAirThreshold", 0); + int NumChoiceOctaves = a_IniFile.GetValueSetI("Generator", "Noise3DNumChoiceOctaves", 4); + int NumDensityOctaves = a_IniFile.GetValueSetI("Generator", "Noise3DNumDensityOctaves", 6); + int NumBaseOctaves = a_IniFile.GetValueSetI("Generator", "Noise3DNumBaseOctaves", 6); + NOISE_DATATYPE BaseNoiseAmplitude = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DBaseAmplitude", 1); + + // Add octaves for the choice noise: + NOISE_DATATYPE wavlen = 1, ampl = 0.5; + for (int i = 0; i < NumChoiceOctaves; i++) + { + m_ChoiceNoise.AddOctave(wavlen, ampl); + wavlen = wavlen * 2; + ampl = ampl / 2; + } + + // Add octaves for the density noises: + wavlen = 1, ampl = 1; + for (int i = 0; i < NumDensityOctaves; i++) + { + m_DensityNoiseA.AddOctave(wavlen, ampl); + m_DensityNoiseB.AddOctave(wavlen, ampl); + wavlen = wavlen * 2; + ampl = ampl / 2; + } + + // Add octaves for the base noise: + wavlen = 1, ampl = BaseNoiseAmplitude; + for (int i = 0; i < NumBaseOctaves; i++) + { + m_BaseNoise.AddOctave(wavlen, ampl); + wavlen = wavlen * 2; + ampl = ampl / 2; + } } @@ -376,126 +444,399 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) { if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ)) { - // The noise for this chunk is already generated in m_Noise + // The noise for this chunk is already generated in m_NoiseArray return; } m_LastChunkX = a_ChunkX; m_LastChunkZ = a_ChunkZ; - // Upscaling parameters: - const int UPSCALE_X = 8; - const int UPSCALE_Y = 4; - const int UPSCALE_Z = 8; - - // Precalculate a "height" array: - NOISE_DATATYPE Height[17 * 17]; // x + 17 * z - for (int z = 0; z < 17; z += UPSCALE_Z) + // Generate all the noises: + NOISE_DATATYPE ChoiceNoise[5 * 5 * 33]; + NOISE_DATATYPE Workspace[5 * 5 * 33]; + NOISE_DATATYPE DensityNoiseA[5 * 5 * 33]; + NOISE_DATATYPE DensityNoiseB[5 * 5 * 33]; + NOISE_DATATYPE BaseNoise[5 * 5]; + NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width); + NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width); + // Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z": + m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace); + m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace); + m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace); + m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace); + + // Calculate the final noise based on the partial noises: + for (int y = 0; y < 33; y++) { - NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + z)) / m_FrequencyZ; - for (int x = 0; x < 17; x += UPSCALE_X) + NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - m_MidPoint) * m_HeightAmplification; + + // If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope: + if (AddHeight < 0) { - NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - NOISE_DATATYPE val = std::abs(m_Noise1.CubicNoise2D(NoiseX / 5, NoiseZ / 5)) * m_HeightAmplification + 1; - Height[x + 17 * z] = val * val * val; + AddHeight *= 4; } - } - for (int y = 0; y < 257; y += UPSCALE_Y) - { - NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)y) / m_FrequencyY; - NOISE_DATATYPE AddHeight = (y - m_MidPoint) / 20; - AddHeight *= AddHeight * AddHeight; - NOISE_DATATYPE * CurFloor = &(m_NoiseArray[y * 17 * 17]); - for (int z = 0; z < 17; z += UPSCALE_Z) + for (int z = 0; z < 5; z++) { - NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + z)) / m_FrequencyZ; - for (int x = 0; x < 17; x += UPSCALE_X) + for (int x = 0; x < 5; x++) { - NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - CurFloor[x + 17 * z] = ( - m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 + - m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) + - m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2 + - AddHeight / Height[x + 17 * z] - ); + int idx = x + 5 * z + 5 * 5 * y; + Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z]; } } - // Linear-interpolate this XZ floor: - LinearUpscale2DArrayInPlace<17, 17, UPSCALE_X, UPSCALE_Z>(CurFloor); } + LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8); +} + + - // Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis - for (int y = 1; y < cChunkDef::Height; y++) + + +void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) +{ + GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ); + + for (int z = 0; z < cChunkDef::Width; z++) { - if ((y % UPSCALE_Y) == 0) + for (int x = 0; x < cChunkDef::Width; x++) { - // This is the interpolation source floor, already calculated - continue; - } - int LoFloorY = (y / UPSCALE_Y) * UPSCALE_Y; - int HiFloorY = LoFloorY + UPSCALE_Y; - NOISE_DATATYPE * LoFloor = &(m_NoiseArray[LoFloorY * 17 * 17]); - NOISE_DATATYPE * HiFloor = &(m_NoiseArray[HiFloorY * 17 * 17]); - NOISE_DATATYPE * CurFloor = &(m_NoiseArray[y * 17 * 17]); - NOISE_DATATYPE Ratio = ((NOISE_DATATYPE)(y % UPSCALE_Y)) / UPSCALE_Y; - int idx = 0; - for (int z = 0; z < cChunkDef::Width; z++) + cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel); + for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--) + { + if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold) + { + cChunkDef::SetHeight(a_HeightMap, x, z, y); + break; + } + } // for y + } // for x + } // for z +} + + + + + +void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc) +{ + GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); + + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); + + // Make basic terrain composition: + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int x = 0; x < cChunkDef::Width; x++) { - for (int x = 0; x < cChunkDef::Width; x++) + int LastAir = a_ChunkDesc.GetHeight(x, z) + 1; + bool HasHadWater = false; + for (int y = LastAir; y < m_SeaLevel; y++) { - CurFloor[idx] = LoFloor[idx] + (HiFloor[idx] - LoFloor[idx]) * Ratio; - idx += 1; + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER); } - idx += 1; // Skipping one X column + for (int y = LastAir - 1; y > 0; y--) + { + if (m_NoiseArray[x + 17 * z + 17 * 17 * y] > m_AirThreshold) + { + // "air" part + LastAir = y; + if (y < m_SeaLevel) + { + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER); + HasHadWater = true; + } + continue; + } + // "ground" part: + if (LastAir - y > 4) + { + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STONE); + continue; + } + if (HasHadWater) + { + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_SAND); + } + else + { + a_ChunkDesc.SetBlockType(x, y, z, (LastAir == y + 1) ? E_BLOCK_GRASS : E_BLOCK_DIRT); + } + } // for y + a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK); + } // for x + } // for z +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cBiomalNoise3DComposable: + +cBiomalNoise3DComposable::cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen) : + m_ChoiceNoise(a_Seed), + m_DensityNoiseA(a_Seed + 1), + m_DensityNoiseB(a_Seed + 2), + m_BaseNoise(a_Seed + 3), + m_BiomeGen(a_BiomeGen) +{ + // Generate the weight distribution for summing up neighboring biomes: + m_WeightSum = 0; + for (int z = 0; z <= AVERAGING_SIZE * 2; z++) + { + for (int x = 0; x <= AVERAGING_SIZE * 2; x++) + { + m_Weight[z][x] = static_cast<NOISE_DATATYPE>((5 - std::abs(5 - x)) + (5 - std::abs(5 - z))); + m_WeightSum += m_Weight[z][x]; } } +} + + + + + +void cBiomalNoise3DComposable::Initialize(cIniFile & a_IniFile) +{ + // Params: + // The defaults generate extreme hills terrain + m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DSeaLevel", 62); + m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyX", 40); + m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyY", 40); + m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyZ", 40); + m_BaseFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseFrequencyX", 40); + m_BaseFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseFrequencyZ", 40); + m_ChoiceFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyX", 40); + m_ChoiceFrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyY", 80); + m_ChoiceFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyZ", 40); + m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DAirThreshold", 0); + int NumChoiceOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumChoiceOctaves", 4); + int NumDensityOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumDensityOctaves", 6); + int NumBaseOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumBaseOctaves", 6); + NOISE_DATATYPE BaseNoiseAmplitude = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseAmplitude", 1); + + // Add octaves for the choice noise: + NOISE_DATATYPE wavlen = 1, ampl = 0.5; + for (int i = 0; i < NumChoiceOctaves; i++) + { + m_ChoiceNoise.AddOctave(wavlen, ampl); + wavlen = wavlen * 2; + ampl = ampl / 2; + } - // The noise array is now fully interpolated - /* - // DEBUG: Output two images of the array, sliced by XY and XZ: - cFile f1; - if (f1.Open(Printf("Chunk_%d_%d_XY.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite)) + // Add octaves for the density noises: + wavlen = 1, ampl = 1; + for (int i = 0; i < NumDensityOctaves; i++) { - for (int z = 0; z < cChunkDef::Width; z++) + m_DensityNoiseA.AddOctave(wavlen, ampl); + m_DensityNoiseB.AddOctave(wavlen, ampl); + wavlen = wavlen * 2; + ampl = ampl / 2; + } + + // Add octaves for the base noise: + wavlen = 1, ampl = BaseNoiseAmplitude; + for (int i = 0; i < NumBaseOctaves; i++) + { + m_BaseNoise.AddOctave(wavlen, ampl); + wavlen = wavlen * 2; + ampl = ampl / 2; + } +} + + + + + +void cBiomalNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) +{ + if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ)) + { + // The noise for this chunk is already generated in m_NoiseArray + return; + } + m_LastChunkX = a_ChunkX; + m_LastChunkZ = a_ChunkZ; + + // Calculate the parameters for the biomes: + ChunkParam MidPoint; + ChunkParam HeightAmp; + CalcBiomeParamArrays(a_ChunkX, a_ChunkZ, HeightAmp, MidPoint); + + // Generate all the noises: + NOISE_DATATYPE ChoiceNoise[5 * 5 * 33]; + NOISE_DATATYPE Workspace[5 * 5 * 33]; + NOISE_DATATYPE DensityNoiseA[5 * 5 * 33]; + NOISE_DATATYPE DensityNoiseB[5 * 5 * 33]; + NOISE_DATATYPE BaseNoise[5 * 5]; + NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width); + NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width); + // Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z": + m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace); + m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace); + m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace); + m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace); + + // Calculate the final noise based on the partial noises: + for (int y = 0; y < 33; y++) + { + NOISE_DATATYPE BlockHeight = static_cast<NOISE_DATATYPE>(y * 8); + for (int z = 0; z < 5; z++) { - for (int y = 0; y < cChunkDef::Height; y++) + for (int x = 0; x < 5; x++) { - int idx = y * 17 * 17 + z * 17; - unsigned char buf[16]; - for (int x = 0; x < cChunkDef::Width; x++) + NOISE_DATATYPE AddHeight = (BlockHeight - MidPoint[x + 5 * z]) * HeightAmp[x + 5 * z]; + + // If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope: + if (AddHeight < 0) { - buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 128 * m_Noise[idx++])))); + AddHeight *= 4; } - f1.Write(buf, 16); - } // for y - } // for z - } // if (XY file open) - cFile f2; - if (f2.Open(Printf("Chunk_%d_%d_XZ.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite)) + int idx = x + 5 * z + 5 * 5 * y; + Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z]; + } + } + } + LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8); +} + + + + + +void cBiomalNoise3DComposable::CalcBiomeParamArrays(int a_ChunkX, int a_ChunkZ, ChunkParam & a_HeightAmp, ChunkParam & a_MidPoint) +{ + // Generate the 3*3 chunks of biomes around this chunk: + cChunkDef::BiomeMap neighborBiomes[3 * 3]; + for (int z = 0; z < 3; z++) { - for (int y = 0; y < cChunkDef::Height; y++) + for (int x = 0; x < 3; x++) { - for (int z = 0; z < cChunkDef::Width; z++) + m_BiomeGen->GenBiomes(a_ChunkX + x - 1, a_ChunkZ + z - 1, neighborBiomes[x + 3 * z]); + } + } + + // Sum up the biome values: + for (int z = 0; z < 5; z++) + { + for (int x = 0; x < 5; x++) + { + NOISE_DATATYPE totalHeightAmp = 0; + NOISE_DATATYPE totalMidPoint = 0; + // Add up the biomes around this point: + for (int relz = 0; relz <= AVERAGING_SIZE * 2; ++relz) { - int idx = y * 17 * 17 + z * 17; - unsigned char buf[16]; - for (int x = 0; x < cChunkDef::Width; x++) + int colz = 16 + z * 4 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start + int neicellz = colz / 16; // Chunk Z coord relative to the neighborBiomes start + int neirelz = colz % 16; // Biome Z coord relative to cz in neighborBiomes + for (int relx = 0; relx <= AVERAGING_SIZE * 2; ++relx) { - buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 128 * m_Noise[idx++])))); - } - f2.Write(buf, 16); - } // for z - } // for y - } // if (XZ file open) - */ + int colx = 16 + x * 4 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start + int neicellx = colx / 16; // Chunk X coord relative to the neighborBiomes start + int neirelx = colx % 16; // Biome X coord relative to cz in neighborBiomes + EMCSBiome biome = cChunkDef::GetBiome(neighborBiomes[neicellx + neicellz * 3], neirelx, neirelz); + NOISE_DATATYPE heightAmp, midPoint; + GetBiomeParams(biome, heightAmp, midPoint); + totalHeightAmp += heightAmp * m_Weight[relz][relx]; + totalMidPoint += midPoint * m_Weight[relz][relx]; + } // for relx + } // for relz + a_HeightAmp[x + 5 * z] = totalHeightAmp / m_WeightSum; + a_MidPoint[x + 5 * z] = totalMidPoint / m_WeightSum; + } // for x + } // for z } -void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) +void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint) +{ + switch (a_Biome) + { + case biBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break; + case biBirchForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break; + case biBirchForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biBirchForestHillsM: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biBirchForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break; + case biColdBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break; + case biDesertHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biDeepOcean: a_HeightAmp = 0.17f; a_MidPoint = 35; break; + case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break; + case biEnd: a_HeightAmp = 0.15f; a_MidPoint = 64; break; + case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break; + case biExtremeHillsPlus: a_HeightAmp = 0.04f; a_MidPoint = 80; break; + case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break; + case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break; + case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break; + case biFrozenOcean: a_HeightAmp = 0.17f; a_MidPoint = 47; break; + case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break; + case biIcePlainsSpikes: a_HeightAmp = 0.3f; a_MidPoint = 62; break; + case biJungle: a_HeightAmp = 0.1f; a_MidPoint = 63; break; + case biJungleHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biJungleM: a_HeightAmp = 0.1f; a_MidPoint = 63; break; + case biMegaSpruceTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biMegaTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + case biMushroomShore: a_HeightAmp = 0.15f; a_MidPoint = 15; break; + case biOcean: a_HeightAmp = 0.3f; a_MidPoint = 62; break; + case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break; + case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break; + case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break; + case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break; + case biTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; + + /* + // Still missing: + case biColdTaiga: a_HeightAmp = 0.15f; a_MidPoint = 30; break; + case biColdTaigaHills: a_HeightAmp = 0.15f; a_MidPoint = 31; break; + case biColdTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biDesertM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biExtremeHillsEdge: a_HeightAmp = 0.15f; a_MidPoint = 20; break; + case biExtremeHillsM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biExtremeHillsPlusM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biJungleEdge: a_HeightAmp = 0.15f; a_MidPoint = 23; break; + case biJungleEdgeM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biMegaSpruceTaiga: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biMegaTaiga: a_HeightAmp = 0.15f; a_MidPoint = 32; break; + case biMesa: a_HeightAmp = 0.15f; a_MidPoint = 37; break; + case biMesaBryce: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biMesaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 39; break; + case biMesaPlateauF: a_HeightAmp = 0.15f; a_MidPoint = 38; break; + case biMesaPlateauFM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biMesaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biMushroomIsland: a_HeightAmp = 0.15f; a_MidPoint = 14; break; + case biNether: a_HeightAmp = 0.15f; a_MidPoint = 68; break; + case biRoofedForest: a_HeightAmp = 0.15f; a_MidPoint = 29; break; + case biRoofedForestM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biSavanna: a_HeightAmp = 0.15f; a_MidPoint = 35; break; + case biSavannaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biSavannaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 36; break; + case biSavannaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biStoneBeach: a_HeightAmp = 0.15f; a_MidPoint = 25; break; + case biSunflowerPlains: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + case biTaiga: a_HeightAmp = 0.15f; a_MidPoint = 65; break; + case biTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break; + */ + + default: + { + // Make a crazy terrain so that it stands out + a_HeightAmp = 0.001f; + a_MidPoint = 90; + break; + } + } +} + + + + + +void cBiomalNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) { GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ); @@ -520,7 +861,7 @@ void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Hei -void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc) +void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc) { GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h index 42f61a854..ba541fbcc 100644 --- a/src/Generating/Noise3DGenerator.h +++ b/src/Generating/Noise3DGenerator.h @@ -1,7 +1,11 @@ // Noise3DGenerator.h -// Generates terrain using 3D noise, rather than composing. Is a test. +// Declares cNoise3DGenerator and cNoise3DComposable classes, representing 3D-noise-based generators. +// They generate terrain shape by combining a lerp of two 3D noises with a vertical linear gradient +// cNoise3DGenerator is obsolete and unmaintained. +// cNoise3DComposable is used to test parameter combinations for single-biome worlds. + @@ -74,31 +78,147 @@ public: void Initialize(cIniFile & a_IniFile); protected: - cNoise m_Noise1; - cNoise m_Noise2; - cNoise m_Noise3; + /** The noise that is used to choose between density noise A and B. */ + cPerlinNoise m_ChoiceNoise; + + /** Density 3D noise, variant A. */ + cPerlinNoise m_DensityNoiseA; + + /** Density 3D noise, variant B. */ + cPerlinNoise m_DensityNoiseB; + + /** Heightmap-like noise used to provide variance for low-amplitude biomes. */ + cPerlinNoise m_BaseNoise; - int m_SeaLevel; + /** Block height of the sealevel, used for composing the terrain. */ + int m_SeaLevel; + + /** The main parameter of the generator, specifies the slope of the vertical linear gradient. + A higher value means a steeper slope and a smaller total amplitude of the generated terrain. */ NOISE_DATATYPE m_HeightAmplification; - NOISE_DATATYPE m_MidPoint; // Where the vertical "center" of the noise should be + + /** Where the vertical "center" of the noise should be, as block height. */ + NOISE_DATATYPE m_MidPoint; + + // Frequency of the 3D noise's first octave: NOISE_DATATYPE m_FrequencyX; NOISE_DATATYPE m_FrequencyY; NOISE_DATATYPE m_FrequencyZ; + + // Frequency of the base terrain noise: + NOISE_DATATYPE m_BaseFrequencyX; + NOISE_DATATYPE m_BaseFrequencyZ; + + // Frequency of the choice noise: + NOISE_DATATYPE m_ChoiceFrequencyX; + NOISE_DATATYPE m_ChoiceFrequencyY; + NOISE_DATATYPE m_ChoiceFrequencyZ; + + // Threshold for when the values are considered air: NOISE_DATATYPE m_AirThreshold; + // Cache for the last calculated chunk (reused between heightmap and composition queries): int m_LastChunkX; int m_LastChunkZ; NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y - /// Generates the 3D noise array used for terrain generation, unless the LastChunk coords are equal to coords given + /** Generates the 3D noise array used for terrain generation (m_NoiseArray), unless the LastChunk coords are equal to coords given */ void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ); // cTerrainHeightGen overrides: virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override; + virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); } + + // cTerrainCompositionGen overrides: + virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override; + virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); } +} ; + + + + + +class cBiomalNoise3DComposable : + public cTerrainHeightGen, + public cTerrainCompositionGen +{ +public: + cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen); + + void Initialize(cIniFile & a_IniFile); + +protected: + /** Number of columns around the pixel to query for biomes for averaging. */ + static const int AVERAGING_SIZE = 5; + + /** Type used for a single parameter across the entire (downscaled) chunk. */ + typedef NOISE_DATATYPE ChunkParam[5 * 5]; + + + /** The noise that is used to choose between density noise A and B. */ + cPerlinNoise m_ChoiceNoise; + + /** Density 3D noise, variant A. */ + cPerlinNoise m_DensityNoiseA; + + /** Density 3D noise, variant B. */ + cPerlinNoise m_DensityNoiseB; + + /** Heightmap-like noise used to provide variance for low-amplitude biomes. */ + cPerlinNoise m_BaseNoise; + + /** The underlying biome generator. */ + cBiomeGenPtr m_BiomeGen; + + /** Block height of the sealevel, used for composing the terrain. */ + int m_SeaLevel; + + // Frequency of the 3D noise's first octave: + NOISE_DATATYPE m_FrequencyX; + NOISE_DATATYPE m_FrequencyY; + NOISE_DATATYPE m_FrequencyZ; + + // Frequency of the base terrain noise: + NOISE_DATATYPE m_BaseFrequencyX; + NOISE_DATATYPE m_BaseFrequencyZ; + + // Frequency of the choice noise: + NOISE_DATATYPE m_ChoiceFrequencyX; + NOISE_DATATYPE m_ChoiceFrequencyY; + NOISE_DATATYPE m_ChoiceFrequencyZ; + + // Threshold for when the values are considered air: + NOISE_DATATYPE m_AirThreshold; + + // Cache for the last calculated chunk (reused between heightmap and composition queries): + int m_LastChunkX; + int m_LastChunkZ; + NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y + + /** Weights for summing up neighboring biomes. */ + NOISE_DATATYPE m_Weight[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1]; + + /** The sum of m_Weight[]. */ + NOISE_DATATYPE m_WeightSum; + + + /** Generates the 3D noise array used for terrain generation (m_NoiseArray), unless the LastChunk coords are equal to coords given */ + void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ); + + /** Calculates the biome-related parameters for the chunk. */ + void CalcBiomeParamArrays(int a_ChunkX, int a_ChunkZ, ChunkParam & a_HeightAmp, ChunkParam & a_MidPoint); + + /** Returns the parameters for the specified biome. */ + void GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint); + + // cTerrainHeightGen overrides: + virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override; + virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); } // cTerrainCompositionGen overrides: virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override; + virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); } } ; diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index ae4b6e36c..97aa646fc 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -289,7 +289,7 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece m_NumCCWRotations(a_NumCCWRotations), m_HasBeenMovedToGround(false) { - m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1); + m_Depth = (m_Parent == nullptr) ? 0 : (m_Parent->GetDepth() + 1); m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z); m_HitBox.Sort(); } @@ -402,7 +402,7 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i } int Rotation = Rotations[rnd % NumRotations]; - cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation); + cPlacedPiece * res = new cPlacedPiece(nullptr, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation); // Place the piece's connectors into a_OutConnectors: const cPiece::cConnectors & Conn = StartingPiece->GetConnectors(); diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index 6da3c3d10..761986690 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -328,7 +328,7 @@ void cPrefab::AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Dire void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) { - ASSERT(a_CharMapDef != NULL); + ASSERT(a_CharMapDef != nullptr); // Initialize the charmap to all-invalid values: for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++) @@ -389,7 +389,7 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma void cPrefab::ParseConnectors(const char * a_ConnectorsDef) { - ASSERT(a_ConnectorsDef != NULL); + ASSERT(a_ConnectorsDef != nullptr); AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n"); for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr) @@ -436,7 +436,7 @@ void cPrefab::ParseConnectors(const char * a_ConnectorsDef) void cPrefab::ParseDepthWeight(const char * a_DepthWeightDef) { // The member needn't be defined at all, if so, skip: - if (a_DepthWeightDef == NULL) + if (a_DepthWeightDef == nullptr) { return; } diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp index 122b9d2af..895555ef8 100644 --- a/src/Generating/PrefabPiecePool.cpp +++ b/src/Generating/PrefabPiecePool.cpp @@ -16,7 +16,7 @@ cPrefabPiecePool::cPrefabPiecePool( ) { AddPieceDefs(a_PieceDefs, a_NumPieceDefs); - if (a_StartingPieceDefs != NULL) + if (a_StartingPieceDefs != nullptr) { AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs); } @@ -56,7 +56,7 @@ void cPrefabPiecePool::Clear(void) void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs) { - ASSERT(a_PieceDefs != NULL); + ASSERT(a_PieceDefs != nullptr); for (size_t i = 0; i < a_NumPieceDefs; i++) { cPrefab * Prefab = new cPrefab(a_PieceDefs[i]); @@ -71,7 +71,7 @@ void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_ void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs) { - ASSERT(a_StartingPieceDefs != NULL); + ASSERT(a_StartingPieceDefs != nullptr); for (size_t i = 0; i < a_NumStartingPieceDefs; i++) { cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]); diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt index 2c62aa73d..68f6491c4 100644 --- a/src/Generating/Prefabs/CMakeLists.txt +++ b/src/Generating/Prefabs/CMakeLists.txt @@ -29,5 +29,5 @@ SET (HDRS if(NOT MSVC) add_library(Generating_Prefabs ${SRCS} ${HDRS}) - target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks) + target_link_libraries(Generating_Prefabs OSSupport Blocks) endif() diff --git a/src/Generating/ProtIntGen.h b/src/Generating/ProtIntGen.h new file mode 100644 index 000000000..73ed27096 --- /dev/null +++ b/src/Generating/ProtIntGen.h @@ -0,0 +1,1351 @@ + +// ProtIntGen.h + +// Declares the prototyping integer generators - cProtIntGen class and its descendants + +/* +These classes generate 2D arrays of integers that have various interpretations. The main purpose of these +classes is to provide fast prototyping for cIntGen classes - unlike cIntGen classes, these are not +template-based and so they take care of the underlying sizes automatically. This makes them easier to chain +and re-chain, since the size parameters don't need to be adjusted after each such case. Their performance is, +however, slightly worse, which is why we use cIntGen classes in the final generator. + +Because there is no SizeX / SizeZ template param, the generators would have to either alloc memory for each +underlying generator's values, or use a maximum-size buffer. We chose the latter, to avoid memory allocation +overhead; this however means that there's (an arbitrary) limit to the size of the generated data. +*/ + + + + + +#pragma once + +// We need the biome group constants defined there: +#include "IntGen.h" + + + + + +/** Interface that all the generator classes provide. */ +class cProtIntGen +{ +protected: + /** Maximum size of the generated area. + Adjust the constant if you need larger areas, these are just so that we can use fixed-size buffers. */ + static const int m_BufferSize = 900; + +public: + + /** Type of the generic interface used for storing links to the underlying generators. */ + typedef std::shared_ptr<cProtIntGen> Underlying; + + + /** Force a virtual destructor in all descendants. + Descendants contain virtual functions and are referred to via pointer-to-base, so they need a virtual destructor. */ + virtual ~cProtIntGen() {} + + /** Generates the array of specified size into a_Values, based on given min coords. */ + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) = 0; +}; + + + + + +/** Provides additional cNoise member and its helper functions. */ +class cProtIntGenWithNoise : + public cProtIntGen +{ + typedef cProtIntGen super; + +public: + cProtIntGenWithNoise(int a_Seed) : + m_Noise(a_Seed) + { + } + +protected: + cNoise m_Noise; + + /** Chooses one of a_Val1 or a_Val2, based on m_Noise and the coordinates for querying the noise. */ + int chooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2) + { + int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7; + return ((rnd & 1) == 0) ? a_Val1 : a_Val2; + } + + /** Chooses one of a_ValN, based on m_Noise and the coordinates for querying the noise. */ + int chooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2, int a_Val3, int a_Val4) + { + int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7; + switch (rnd % 4) + { + case 0: return a_Val1; + case 1: return a_Val2; + case 2: return a_Val3; + default: return a_Val4; + } + } +}; + + + + + + +/** Generates a 2D array of random integers in the specified range [0 .. Range). */ +class cProtIntGenChoice : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenChoice(int a_Seed, int a_Range) : + super(a_Seed), + m_Range(a_Range) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + for (int z = 0; z < a_SizeZ; z++) + { + int BaseZ = a_MinZ + z; + for (int x = 0; x < a_SizeX; x++) + { + a_Values[x + a_SizeX * z] = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7) % m_Range; + } + } // for z + } + +protected: + int m_Range; +}; + + + + + + +/** Decides between the ocean and landmass biomes. +Has a threshold (in percent) of how much land, the larger the threshold, the more land. +Generates 0 for ocean, biome group ID for landmass. */ +class cProtIntGenLandOcean : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenLandOcean(int a_Seed, int a_Threshold) : + super(a_Seed), + m_Threshold(a_Threshold) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + for (int z = 0; z < a_SizeZ; z++) + { + int BaseZ = a_MinZ + z; + for (int x = 0; x < a_SizeX; x++) + { + int rnd = (super::m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7); + a_Values[x + a_SizeX * z] = ((rnd % 100) < m_Threshold) ? ((rnd / 101) % bgLandOceanMax + 1) : 0; + } + } + + // If the centerpoint of the world is within the area, set it to bgTemperate, always: + if ((a_MinX <= 0) && (a_MinZ <= 0) && (a_MinX + a_SizeX > 0) && (a_MinZ + a_SizeZ > 0)) + { + a_Values[-a_MinX - a_MinZ * a_SizeX] = bgTemperate; + } + } + +protected: + int m_Threshold; +}; + + + + + +/** Zooms the underlying value array to twice the size. Uses random-neighbor for the pixels in-between. +This means that the zoome out image is randomly distorted. Applying zoom several times provides all +the distortion that the generators need. */ +class cProtIntGenZoom : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenZoom(int a_Seed, Underlying a_UnderlyingGen) : + super(a_Seed), + m_UnderlyingGen(a_UnderlyingGen) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Get the coords for the lower generator: + int lowerMinX = a_MinX >> 1; + int lowerMinZ = a_MinZ >> 1; + int lowerSizeX = a_SizeX / 2 + 2; + int lowerSizeZ = a_SizeZ / 2 + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + ASSERT(lowerSizeX > 0); + ASSERT(lowerSizeZ > 0); + + // Generate the underlying data with half the resolution: + int lowerData[m_BufferSize]; + m_UnderlyingGen->GetInts(lowerMinX, lowerMinZ, lowerSizeX, lowerSizeZ, lowerData); + const int lowStepX = (lowerSizeX - 1) * 2; + int cache[m_BufferSize]; + + // Discreet-interpolate the values into twice the size: + for (int z = 0; z < lowerSizeZ - 1; ++z) + { + int idx = (z * 2) * lowStepX; + int PrevZ0 = lowerData[z * lowerSizeX]; + int PrevZ1 = lowerData[(z + 1) * lowerSizeX]; + + for (int x = 0; x < lowerSizeX - 1; ++x) + { + int ValX1Z0 = lowerData[x + 1 + z * lowerSizeX]; + int ValX1Z1 = lowerData[x + 1 + (z + 1) * lowerSizeX]; + int RndX = (x + lowerMinX) * 2; + int RndZ = (z + lowerMinZ) * 2; + cache[idx] = PrevZ0; + cache[idx + lowStepX] = super::chooseRandomOne(RndX, RndZ + 1, PrevZ0, PrevZ1); + cache[idx + 1] = super::chooseRandomOne(RndX, RndZ - 1, PrevZ0, ValX1Z0); + cache[idx + 1 + lowStepX] = super::chooseRandomOne(RndX, RndZ, PrevZ0, ValX1Z0, PrevZ1, ValX1Z1); + idx += 2; + PrevZ0 = ValX1Z0; + PrevZ1 = ValX1Z1; + } + } + + // Copy from Cache into a_Values; take into account the even/odd offsets in a_Min: + for (int z = 0; z < a_SizeZ; ++z) + { + memcpy(a_Values + z * a_SizeX, cache + (z + (a_MinZ & 1)) * lowStepX + (a_MinX & 1), a_SizeX * sizeof(int)); + } + } + +protected: + Underlying m_UnderlyingGen; +}; + + + + + +/** Smoothes out some artifacts generated by the zooming - mostly single-pixel values. +Compares each pixel to its neighbors and if the neighbors are equal, changes the pixel to their value. */ +class cProtIntGenSmooth : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenSmooth(int a_Seed, Underlying a_Underlying) : + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying values: + int lowerSizeX = a_SizeX + 2; + int lowerSizeZ = a_SizeZ + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + int lowerData[m_BufferSize]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerData); + + // Smooth - for each square check if the surroundings are the same, if so, expand them diagonally. + // Also get rid of single-pixel irregularities (A-B-A): + for (int z = 0; z < a_SizeZ; z++) + { + int NoiseZ = a_MinZ + z; + for (int x = 0; x < a_SizeX; x++) + { + int val = lowerData[x + 1 + (z + 1) * lowerSizeX]; + int above = lowerData[x + 1 + z * lowerSizeX]; + int below = lowerData[x + 1 + (z + 2) * lowerSizeX]; + int left = lowerData[x + (z + 1) * lowerSizeX]; + int right = lowerData[x + 2 + (z + 1) * lowerSizeX]; + + if ((left == right) && (above == below)) + { + if (((super::m_Noise.IntNoise2DInt(a_MinX + x, NoiseZ) / 7) % 2) == 0) + { + val = left; + } + else + { + val = above; + } + } + else + { + if (left == right) + { + val = left; + } + + if (above == below) + { + val = above; + } + } + + a_Values[x + z * a_SizeX] = val; + } + } + } + +protected: + Underlying m_Underlying; +}; + + + + + +/** Converts land biomes at the edge of an ocean into the respective beach biome. */ +class cProtIntGenBeaches : + public cProtIntGen +{ + typedef cProtIntGen super; + +public: + cProtIntGenBeaches(Underlying a_Underlying) : + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Map for biome -> its beach: + static const int ToBeach[] = + { + /* biOcean */ biOcean, + /* biPlains */ biBeach, + /* biDesert */ biBeach, + /* biExtremeHills */ biStoneBeach, + /* biForest */ biBeach, + /* biTaiga */ biColdBeach, + /* biSwampland */ biSwampland, + /* biRiver */ biRiver, + /* biNether */ biNether, + /* biEnd */ biEnd, + /* biFrozenOcean */ biColdBeach, + /* biFrozenRiver */ biColdBeach, + /* biIcePlains */ biColdBeach, + /* biIceMountains */ biColdBeach, + /* biMushroomIsland */ biMushroomShore, + /* biMushroomShore */ biMushroomShore, + /* biBeach */ biBeach, + /* biDesertHills */ biBeach, + /* biForestHills */ biBeach, + /* biTaigaHills */ biColdBeach, + /* biExtremeHillsEdge */ biStoneBeach, + /* biJungle */ biBeach, + /* biJungleHills */ biBeach, + /* biJungleEdge */ biBeach, + /* biDeepOcean */ biOcean, + /* biStoneBeach */ biStoneBeach, + /* biColdBeach */ biColdBeach, + /* biBirchForest */ biBeach, + /* biBirchForestHills */ biBeach, + /* biRoofedForest */ biBeach, + /* biColdTaiga */ biColdBeach, + /* biColdTaigaHills */ biColdBeach, + /* biMegaTaiga */ biStoneBeach, + /* biMegaTaigaHills */ biStoneBeach, + /* biExtremeHillsPlus */ biStoneBeach, + /* biSavanna */ biBeach, + /* biSavannaPlateau */ biBeach, + /* biMesa */ biMesa, + /* biMesaPlateauF */ biMesa, + /* biMesaPlateau */ biMesa, + }; + + // Generate the underlying values: + int lowerSizeX = a_SizeX + 2; + int lowerSizeZ = a_SizeZ + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + int lowerValues[m_BufferSize]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues); + + // Add beaches between ocean and biomes: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int val = lowerValues[x + 1 + (z + 1) * lowerSizeX]; + int above = lowerValues[x + 1 + z * lowerSizeX]; + int below = lowerValues[x + 1 + (z + 2) * lowerSizeX]; + int left = lowerValues[x + (z + 1) * lowerSizeX]; + int right = lowerValues[x + 2 + (z + 1) * lowerSizeX]; + if (!IsBiomeOcean(val)) + { + if (IsBiomeOcean(above) || IsBiomeOcean(below) || IsBiomeOcean(left) || IsBiomeOcean(right)) + { + // First convert the value to a regular biome (drop the M flag), then modulo by our biome count: + val = ToBeach[(val % 128) % ARRAYCOUNT(ToBeach)]; + } + } + a_Values[x + z * a_SizeX] = val; + } + } + } + +protected: + Underlying m_Underlying; +}; + + + + + +/** Generates the underlying numbers and then randomly changes some ocean group pixels into random land +biome group pixels, based on the predefined chance. */ +class cProtIntGenAddIslands : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + typedef std::shared_ptr<cProtIntGen> Underlying; + + + cProtIntGenAddIslands(int a_Seed, int a_Chance, Underlying a_Underlying) : + super(a_Seed), + m_Chance(a_Chance), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + if (a_Values[x + z * a_SizeX] == bgOcean) + { + int rnd = super::m_Noise.IntNoise2DInt(a_MinX + x, a_MinZ + z) / 7; + if (rnd % 1000 < m_Chance) + { + a_Values[x + z * a_SizeX] = (rnd / 1003) % bgLandOceanMax; + } + } + } + } + } + +protected: + /** Chance of each ocean pixel being converted, in permille. */ + int m_Chance; + + Underlying m_Underlying; +}; + + + + + +/** A filter that adds an edge biome group between two biome groups that need an edge between them. */ +class cProtIntGenBiomeGroupEdges : + public cProtIntGen +{ + typedef cProtIntGen super; + +public: + cProtIntGenBiomeGroupEdges(Underlying a_Underlying) : + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) + { + // Generate the underlying biome groups: + int lowerSizeX = a_SizeX + 2; + int lowerSizeZ = a_SizeZ + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + int lowerValues[m_BufferSize]; + m_Underlying->GetInts(a_MinX, a_MinZ, lowerSizeX, lowerSizeZ, lowerValues); + + // Change the biomes on incompatible edges into an edge biome: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int val = lowerValues[x + 1 + (z + 1) * lowerSizeX]; + int Above = lowerValues[x + 1 + z * lowerSizeX]; + int Below = lowerValues[x + 1 + (z + 2) * lowerSizeX]; + int Left = lowerValues[x + (z + 1) * lowerSizeX]; + int Right = lowerValues[x + 2 + (z + 1) * lowerSizeX]; + switch (val) + { + // Desert should neighbor only oceans, desert and temperates; change to temperate when another: + case bgDesert: + { + if ( + !isDesertCompatible(Above) || + !isDesertCompatible(Below) || + !isDesertCompatible(Left) || + !isDesertCompatible(Right) + ) + { + val = bgTemperate; + } + break; + } // case bgDesert + + // Ice should not neighbor deserts; change to temperate: + case bgIce: + { + if ( + (Above == bgDesert) || + (Below == bgDesert) || + (Left == bgDesert) || + (Right == bgDesert) + ) + { + val = bgTemperate; + } + break; + } // case bgIce + } + a_Values[x + z * a_SizeX] = val; + } // for x + } // for z + } + +protected: + Underlying m_Underlying; + + + inline bool isDesertCompatible(int a_BiomeGroup) + { + switch (a_BiomeGroup) + { + case bgOcean: + case bgDesert: + case bgTemperate: + { + return true; + } + default: + { + return false; + } + } + } +}; + + + + + +/** Turns biome group indices into real biomes. +For each pixel, takes its biome group and chooses a random biome from that group; replaces the value with +that biome. */ +class cProtIntGenBiomes : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenBiomes(int a_Seed, Underlying a_Underlying) : + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Define the per-biome-group biomes: + static const int oceanBiomes[] = + { + biOcean, // biDeepOcean, + }; + + // Same as oceanBiomes, there are no rare oceanic biomes (mushroom islands are handled separately) + static const int rareOceanBiomes[] = + { + biOcean, + }; + + static const int desertBiomes[] = + { + biDesert, biDesert, biDesert, biDesert, biDesert, biDesert, biSavanna, biSavanna, biPlains, + }; + + static const int rareDesertBiomes[] = + { + biMesaPlateau, biMesaPlateauF, + }; + + static const int temperateBiomes[] = + { + biForest, biForest, biRoofedForest, biExtremeHills, biPlains, biBirchForest, biSwampland, + }; + + static const int rareTemperateBiomes[] = + { + biJungle, // Jungle is not strictly temperate, but let's piggyback it here + }; + + static const int mountainBiomes[] = + { + biExtremeHills, biForest, biTaiga, biPlains, + }; + + static const int rareMountainBiomes[] = + { + biMegaTaiga, + }; + + static const int iceBiomes[] = + { + biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga, + }; + + // Same as iceBiomes, there's no rare ice biome + static const int rareIceBiomes[] = + { + biIcePlains, biIcePlains, biIcePlains, biIcePlains, biColdTaiga, + }; + + static const cBiomesInGroups biomesInGroups[] = + { + /* bgOcean */ { static_cast<int>(ARRAYCOUNT(oceanBiomes)), oceanBiomes}, + /* bgDesert */ { static_cast<int>(ARRAYCOUNT(desertBiomes)), desertBiomes}, + /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(temperateBiomes)), temperateBiomes}, + /* bgMountains */ { static_cast<int>(ARRAYCOUNT(mountainBiomes)), mountainBiomes}, + /* bgIce */ { static_cast<int>(ARRAYCOUNT(iceBiomes)), iceBiomes}, + }; + + static const cBiomesInGroups rareBiomesInGroups[] = + { + /* bgOcean */ { static_cast<int>(ARRAYCOUNT(rareOceanBiomes)), rareOceanBiomes}, + /* bgDesert */ { static_cast<int>(ARRAYCOUNT(rareDesertBiomes)), rareDesertBiomes}, + /* bgTemperate */ { static_cast<int>(ARRAYCOUNT(rareTemperateBiomes)), rareTemperateBiomes}, + /* bgMountains */ { static_cast<int>(ARRAYCOUNT(rareMountainBiomes)), rareMountainBiomes}, + /* bgIce */ { static_cast<int>(ARRAYCOUNT(rareIceBiomes)), rareIceBiomes}, + }; + + // Generate the underlying values, representing biome groups: + m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + + // Overwrite each biome group with a random biome from that group: + // Take care of the bgfRare flag + for (int z = 0; z < a_SizeZ; z++) + { + int IdxZ = z * a_SizeX; + for (int x = 0; x < a_SizeX; x++) + { + int val = a_Values[x + IdxZ]; + const cBiomesInGroups & Biomes = (val > bgfRare) ? + rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] : + biomesInGroups[val % ARRAYCOUNT(biomesInGroups)]; + int rnd = (super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7); + a_Values[x + IdxZ] = Biomes.Biomes[rnd % Biomes.Count]; + } + } + } + +protected: + + struct cBiomesInGroups + { + const int Count; + const int * Biomes; + }; + + + /** The underlying int generator */ + Underlying m_Underlying; +}; + + + + + +/** Randomly replaces pixels of one value to another value, using the given chance. */ +class cProtIntGenReplaceRandomly : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + typedef std::shared_ptr<cProtIntGen> Underlying; + + + cProtIntGenReplaceRandomly(int a_Seed, int a_From, int a_To, int a_Chance, Underlying a_Underlying) : + super(a_Seed), + m_From(a_From), + m_To(a_To), + m_Chance(a_Chance), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying values: + m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + + // Replace some of the values: + for (int z = 0; z < a_SizeZ; z++) + { + int idxZ = z * a_SizeX; + for (int x = 0; x < a_SizeX; x++) + { + int idx = x + idxZ; + if (a_Values[idx] == m_From) + { + int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7; + if (rnd % 1000 < m_Chance) + { + a_Values[idx] = m_To; + } + } + } + } // for z + } + + +protected: + /** The original value to be replaced. */ + int m_From; + + /** The destination value to which to replace. */ + int m_To; + + /** Chance, in permille, of replacing the value. */ + int m_Chance; + + Underlying m_Underlying; +}; + + + + + +/** Mixer that joins together finalized biomes and rivers. +It first checks for oceans, if there is an ocean in the Biomes, it keeps the ocean. +If there's no ocean, it checks Rivers for a river, if there is a river, it uses the Biomes to select either +regular river or frozen river, based on the biome. */ +class cProtIntGenMixRivers: + public cProtIntGen +{ + typedef cProtIntGen super; + +public: + cProtIntGenMixRivers(Underlying a_Biomes, Underlying a_Rivers): + m_Biomes(a_Biomes), + m_Rivers(a_Rivers) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying data: + ASSERT(a_SizeX * a_SizeZ <= m_BufferSize); + m_Biomes->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + int riverData[m_BufferSize]; + m_Rivers->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, riverData); + + // Mix the values: + for (int z = 0; z < a_SizeZ; z++) + { + int idxZ = z * a_SizeX; + for (int x = 0; x < a_SizeX; x++) + { + int idx = x + idxZ; + if (IsBiomeOcean(a_Values[idx])) + { + // Oceans are kept without any changes + continue; + } + if (riverData[idx] != biRiver) + { + // There's no river, keep the current value + continue; + } + + // There's a river, change the output to a river or a frozen river, based on the original biome: + if (IsBiomeVeryCold((EMCSBiome)a_Values[idx])) + { + a_Values[idx] = biFrozenRiver; + } + else + { + a_Values[idx] = biRiver; + } + } // for x + } // for z + } + +protected: + Underlying m_Biomes; + Underlying m_Rivers; +}; + + + + + +/** Generates a river based on the underlying data. +This is basically an edge detector over the underlying data. The rivers are the edges where the underlying +data changes from one pixel to its neighbor. */ +class cProtIntGenRiver: + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenRiver(int a_Seed, Underlying a_Underlying): + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying data: + int lowerSizeX = a_SizeX + 2; + int lowerSizeZ = a_SizeZ + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + int lowerValues[m_BufferSize]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues); + + // Detect the edges: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int Above = lowerValues[x + 1 + z * lowerSizeX]; + int Below = lowerValues[x + 1 + (z + 2) * lowerSizeX]; + int Left = lowerValues[x + (z + 1) * lowerSizeX]; + int Right = lowerValues[x + 2 + (z + 1) * lowerSizeX]; + int val = lowerValues[x + 1 + (z + 1) * lowerSizeX]; + + if ((val == Above) && (val == Below) && (val == Left) && (val == Right)) + { + val = 0; + } + else + { + val = biRiver; + } + a_Values[x + z * a_SizeX] = val; + } // for x + } // for z + } + +protected: + Underlying m_Underlying; +}; + + + + + +/** Turns some of the oceans into the specified biome. Used for mushroom and deep ocean. +The biome is only placed if at least 3 of its neighbors are ocean and only with the specified chance. */ +class cProtIntGenAddToOcean: + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenAddToOcean(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying): + super(a_Seed), + m_Chance(a_Chance), + m_ToValue(a_ToValue), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying data: + int lowerSizeX = a_SizeX + 2; + int lowerSizeZ = a_SizeZ + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + int lowerValues[m_BufferSize]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues); + + // Add the mushroom islands: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int val = lowerValues[x + 1 + (z + 1) * lowerSizeX]; + if (!IsBiomeOcean(val)) + { + a_Values[x + z * a_SizeX] = val; + continue; + } + + // Count the ocean neighbors: + int Above = lowerValues[x + 1 + z * lowerSizeX]; + int Below = lowerValues[x + 1 + (z + 2) * lowerSizeX]; + int Left = lowerValues[x + (z + 1) * lowerSizeX]; + int Right = lowerValues[x + 2 + (z + 1) * lowerSizeX]; + int NumOceanNeighbors = 0; + if (IsBiomeOcean(Above)) + { + NumOceanNeighbors += 1; + } + if (IsBiomeOcean(Below)) + { + NumOceanNeighbors += 1; + } + if (IsBiomeOcean(Left)) + { + NumOceanNeighbors += 1; + } + if (IsBiomeOcean(Right)) + { + NumOceanNeighbors += 1; + } + + // If at least 3 ocean neighbors and the chance is right, change: + if ( + (NumOceanNeighbors >= 3) && + ((super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7) % 1000 < m_Chance) + ) + { + a_Values[x + z * a_SizeX] = m_ToValue; + } + else + { + a_Values[x + z * a_SizeX] = val; + } + } // for x + } // for z + } + +protected: + /** Chance, in permille, of changing the biome. */ + int m_Chance; + + /** The value to change the ocean into. */ + int m_ToValue; + + Underlying m_Underlying; +}; + + + + + +/** Changes random pixels of the underlying data to the specified value. */ +class cProtIntGenSetRandomly : + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenSetRandomly(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying) : + super(a_Seed), + m_Chance(a_Chance), + m_ToValue(a_ToValue), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying data: + m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + + // Change random pixels to bgOcean: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7; + if (rnd % 1000 < m_Chance) + { + a_Values[x + z * a_SizeX] = m_ToValue; + } + } + } + } + +protected: + /** Chance, in permille, of changing each pixel. */ + int m_Chance; + + /** The value to which to set the pixel. */ + int m_ToValue; + + Underlying m_Underlying; +}; + + + + + + +/** Adds a "rare" flag to random biome groups, based on the given chance. */ +class cProtIntGenRareBiomeGroups: + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenRareBiomeGroups(int a_Seed, int a_Chance, Underlying a_Underlying): + super(a_Seed), + m_Chance(a_Chance), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying data: + m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + + // Change some of the biome groups into rare biome groups: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int rnd = super::m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7; + if (rnd % 1000 < m_Chance) + { + int idx = x + a_SizeX * z; + a_Values[idx] = a_Values[idx] | bgfRare; + } + } + } + } + +protected: + /** Chance, in permille, of changing each pixel into the rare biome group. */ + int m_Chance; + + /** The underlying generator. */ + Underlying m_Underlying; +}; + + + + + +/** Changes biomes in the parent data into an alternate versions (usually "hill" variants), in such places +that have their alterations set. */ +class cProtIntGenAlternateBiomes: + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenAlternateBiomes(int a_Seed, Underlying a_Alterations, Underlying a_BaseBiomes): + super(a_Seed), + m_Alterations(a_Alterations), + m_BaseBiomes(a_BaseBiomes) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the base biomes and the alterations: + m_BaseBiomes->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + int alterations[m_BufferSize]; + m_Alterations->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, alterations); + + // Change the biomes into their alternate versions: + int len = a_SizeX * a_SizeZ; + for (int idx = 0; idx < len; ++idx) + { + if (alterations[idx] == 0) + { + // No change + continue; + } + + // Change to alternate biomes: + int val = a_Values[idx]; + switch (val) + { + case biBirchForest: val = biBirchForestHills; break; + case biDesert: val = biDesertHills; break; + case biExtremeHills: val = biExtremeHillsPlus; break; + case biForest: val = biForestHills; break; + case biIcePlains: val = biIceMountains; break; + case biJungle: val = biJungleHills; break; + case biMegaTaiga: val = biMegaTaigaHills; break; + case biMesaPlateau: val = biMesa; break; + case biMesaPlateauF: val = biMesa; break; + case biMesaPlateauM: val = biMesa; break; + case biMesaPlateauFM: val = biMesa; break; + case biPlains: val = biForest; break; + case biRoofedForest: val = biPlains; break; + case biSavanna: val = biSavannaPlateau; break; + case biTaiga: val = biTaigaHills; break; + } + a_Values[idx] = val; + } // for idx - a_Values[] + } + +protected: + Underlying m_Alterations; + Underlying m_BaseBiomes; +}; + + + + + +/** Adds an edge between two specifically incompatible biomes, such as mesa and forest. */ +class cProtIntGenBiomeEdges: + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenBiomeEdges(int a_Seed, Underlying a_Underlying): + super(a_Seed), + m_Underlying(a_Underlying) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying biomes: + int lowerSizeX = a_SizeX + 2; + int lowerSizeZ = a_SizeZ + 2; + ASSERT(lowerSizeX * lowerSizeZ <= m_BufferSize); + int lowerValues[m_BufferSize]; + m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, lowerSizeX, lowerSizeZ, lowerValues); + + // Convert incompatible edges into neutral biomes: + for (int z = 0; z < a_SizeZ; z++) + { + for (int x = 0; x < a_SizeX; x++) + { + int biome = lowerValues[x + 1 + (z + 1) * lowerSizeX]; + int above = lowerValues[x + 1 + z * lowerSizeX]; + int below = lowerValues[x + 1 + (z + 2) * lowerSizeX]; + int left = lowerValues[x + (z + 1) * lowerSizeX]; + int right = lowerValues[x + 2 + (z + 1) * lowerSizeX]; + + switch (biome) + { + case biDesert: + case biDesertM: + case biDesertHills: + { + if ( + IsBiomeVeryCold(static_cast<EMCSBiome>(above)) || + IsBiomeVeryCold(static_cast<EMCSBiome>(below)) || + IsBiomeVeryCold(static_cast<EMCSBiome>(left)) || + IsBiomeVeryCold(static_cast<EMCSBiome>(right)) + ) + { + biome = biPlains; + } + break; + } // case biDesert + + case biMesaPlateau: + case biMesaPlateauF: + case biMesaPlateauFM: + case biMesaPlateauM: + { + if ( + !isMesaCompatible(above) || + !isMesaCompatible(below) || + !isMesaCompatible(left) || + !isMesaCompatible(right) + ) + { + biome = biDesert; + } + break; + } // Mesa biomes + + case biJungle: + case biJungleM: + { + if ( + !isJungleCompatible(above) || + !isJungleCompatible(below) || + !isJungleCompatible(left) || + !isJungleCompatible(right) + ) + { + biome = (biome == biJungle) ? biJungleEdge : biJungleEdgeM; + } + break; + } // Jungle biomes + + case biSwampland: + case biSwamplandM: + { + if ( + IsBiomeNoDownfall(static_cast<EMCSBiome>(above)) || + IsBiomeNoDownfall(static_cast<EMCSBiome>(below)) || + IsBiomeNoDownfall(static_cast<EMCSBiome>(left)) || + IsBiomeNoDownfall(static_cast<EMCSBiome>(right)) + ) + { + biome = biPlains; + } + break; + } // Swampland biomes + } // switch (biome) + + a_Values[x + z * a_SizeX] = biome; + } // for x + } // for z + } + + +protected: + Underlying m_Underlying; + + + bool isMesaCompatible(int a_Biome) + { + switch (a_Biome) + { + case biDesert: + case biMesa: + case biMesaBryce: + case biMesaPlateau: + case biMesaPlateauF: + case biMesaPlateauFM: + case biMesaPlateauM: + case biOcean: + case biDeepOcean: + { + return true; + } + default: + { + return false; + } + } + } + + + bool isJungleCompatible(int a_Biome) + { + switch (a_Biome) + { + case biJungle: + case biJungleM: + case biJungleEdge: + case biJungleEdgeM: + case biJungleHills: + { + return true; + } + default: + { + return false; + } + } + } +}; + + + + + +/** Changes biomes in the parent data into their alternate versions ("M" variants), in such places that +have their alterations set. */ +class cProtIntGenMBiomes: + public cProtIntGenWithNoise +{ + typedef cProtIntGenWithNoise super; + +public: + cProtIntGenMBiomes(int a_Seed, Underlying a_Alteration, Underlying a_Underlying): + super(a_Seed), + m_Underlying(a_Underlying), + m_Alteration(a_Alteration) + { + } + + + virtual void GetInts(int a_MinX, int a_MinZ, int a_SizeX, int a_SizeZ, int * a_Values) override + { + // Generate the underlying biomes and the alterations: + m_Underlying->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, a_Values); + int alterations[m_BufferSize]; + m_Alteration->GetInts(a_MinX, a_MinZ, a_SizeX, a_SizeZ, alterations); + + // Wherever alterations are nonzero, change into alternate biome, if available: + int len = a_SizeX * a_SizeZ; + for (int idx = 0; idx < len; ++idx) + { + if (alterations[idx] == 0) + { + continue; + } + + // Ice spikes biome was removed from here, because it was generated way too often + switch (a_Values[idx]) + { + case biPlains: a_Values[idx] = biSunflowerPlains; break; + case biDesert: a_Values[idx] = biDesertM; break; + case biExtremeHills: a_Values[idx] = biExtremeHillsM; break; + case biForest: a_Values[idx] = biFlowerForest; break; + case biTaiga: a_Values[idx] = biTaigaM; break; + case biSwampland: a_Values[idx] = biSwamplandM; break; + case biJungle: a_Values[idx] = biJungleM; break; + case biJungleEdge: a_Values[idx] = biJungleEdgeM; break; + case biBirchForest: a_Values[idx] = biBirchForestM; break; + case biBirchForestHills: a_Values[idx] = biBirchForestHillsM; break; + case biRoofedForest: a_Values[idx] = biRoofedForestM; break; + case biColdTaiga: a_Values[idx] = biColdTaigaM; break; + case biMegaSpruceTaiga: a_Values[idx] = biMegaSpruceTaiga; break; + case biMegaSpruceTaigaHills: a_Values[idx] = biMegaSpruceTaigaHills; break; + case biExtremeHillsPlus: a_Values[idx] = biExtremeHillsPlusM; break; + case biSavanna: a_Values[idx] = biSavannaM; break; + case biSavannaPlateau: a_Values[idx] = biSavannaPlateauM; break; + case biMesa: a_Values[idx] = biMesaBryce; break; + case biMesaPlateauF: a_Values[idx] = biMesaPlateauFM; break; + case biMesaPlateau: a_Values[idx] = biMesaBryce; break; + } + } // for idx - a_Values[] / alterations[] + } + +protected: + Underlying m_Underlying; + Underlying m_Alteration; +}; + + + + diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index 731324b0d..bdefcd8c1 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -272,13 +272,14 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc) int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkZ = a_ChunkDesc.GetChunkZ(); cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); + cChunkDesc::BlockNibbleBytes & BlockMetas = a_ChunkDesc.GetBlockMetasUncompressed(); int seq = 1; // Generate the ores from the ore list. for (OreList::const_iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr) { - GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, seq); + GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->BlockMeta, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, BlockMetas, seq); seq++; } } @@ -287,7 +288,7 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc) -void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq) +void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, NIBBLETYPE a_BlockMeta, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, cChunkDesc::BlockNibbleBytes & a_BlockMetas, int a_Seq) { // This function generates several "nests" of ore, each nest consisting of number of ore blocks relatively adjacent to each other. // It does so by making a random XYZ walk and adding ore along the way in cuboids of different (random) sizes @@ -341,6 +342,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore if (a_BlockTypes[Index] == m_ToReplace) { a_BlockTypes[Index] = a_OreType; + a_BlockMetas[Index] = a_BlockMeta; } Num++; } // for z @@ -409,7 +411,7 @@ void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a // Find the minimum height in this chunk: cChunkDef::HeightMap HeightMap; - m_HeiGen.GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap); + m_HeiGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap); HEIGHTTYPE MinHeight = HeightMap[0]; for (size_t i = 1; i < ARRAYCOUNT(HeightMap); i++) { diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h index 55d5bc1c7..906fdd722 100644 --- a/src/Generating/StructGen.h +++ b/src/Generating/StructGen.h @@ -24,7 +24,7 @@ class cStructGenTrees : public cFinishGen { public: - cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) : + cStructGenTrees(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, cTerrainCompositionGenPtr a_CompositionGen) : m_Seed(a_Seed), m_Noise(a_Seed), m_BiomeGen(a_BiomeGen), @@ -36,9 +36,9 @@ protected: int m_Seed; cNoise m_Noise; - cBiomeGen * m_BiomeGen; - cTerrainHeightGen * m_HeightGen; - cTerrainCompositionGen * m_CompositionGen; + cBiomeGenPtr m_BiomeGen; + cTerrainHeightGenPtr m_HeightGen; + cTerrainCompositionGenPtr m_CompositionGen; /** Generates and applies an image of a single tree. Parts of the tree inside the chunk are applied to a_BlockX. @@ -78,10 +78,20 @@ class cStructGenOreNests : public: struct OreInfo { - BLOCKTYPE BlockType; // The type of the nest. - int MaxHeight; // The highest possible a nest can occur - int NumNests; // How many nests per chunk - int NestSize; // The amount of blocks a nest can have. + BLOCKTYPE BlockType; // The type of the nest. + NIBBLETYPE BlockMeta; // The block meta + int MaxHeight; // The highest possible a nest can occur + int NumNests; // How many nests per chunk + int NestSize; // The amount of blocks a nest can have. + + OreInfo() : + BlockType(0), + BlockMeta(0), + MaxHeight(0), + NumNests(0), + NestSize(0) + { + } }; typedef std::vector<OreInfo> OreList; @@ -103,7 +113,7 @@ protected: // cFinishGen override: virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; - void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq); + void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, NIBBLETYPE a_BlockMeta, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, cChunkDesc::BlockNibbleBytes & a_BlockMetas, int a_Seq); } ; @@ -114,7 +124,7 @@ class cStructGenLakes : public cFinishGen { public: - cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen, int a_Probability) : + cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGenPtr a_HeiGen, int a_Probability) : m_Noise(a_Seed), m_Seed(a_Seed), m_Fluid(a_Fluid), @@ -124,11 +134,11 @@ public: } protected: - cNoise m_Noise; - int m_Seed; - BLOCKTYPE m_Fluid; - cTerrainHeightGen & m_HeiGen; - int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake + cNoise m_Noise; + int m_Seed; + BLOCKTYPE m_Fluid; + cTerrainHeightGenPtr m_HeiGen; + int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake // cFinishGen override: virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 1b0f2dc14..7fd6d6f07 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -224,8 +224,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biMegaTaiga: case biMegaTaigaHills: case biExtremeHillsPlus: - case biSavanna: - case biSavannaPlateau: case biMesa: case biMesaPlateauF: case biMesaPlateau: @@ -241,8 +239,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biMegaSpruceTaiga: case biMegaSpruceTaigaHills: case biExtremeHillsPlusM: - case biSavannaM: - case biSavannaPlateauM: case biMesaBryce: case biMesaPlateauFM: case biMesaPlateauM: @@ -252,6 +248,15 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No return; } + case biSavanna: + case biSavannaPlateau: + case biSavannaM: + case biSavannaPlateauM: + { + GetAcaciaTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); + return; + } + case biRoofedForest: case biRoofedForestM: { @@ -403,7 +408,72 @@ void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Nois void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) { - // TODO + // Calculate a base height + int Height = 2 + (a_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 11 % 3); + + // Create the trunk + for (int i = 0; i < Height; i++) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_ACACIA_WOOD)); + } + + // Array with possible directions for a branch to go to. + const Vector3i AvailableDirections[] = + { + { -1, 1, 0 }, { 0, 1, -1 }, + { -1, 1, 1 }, { -1, 1, -1 }, + { 1, 1, 1 }, { 1, 1, -1 }, + { 1, 1, 0 }, { 0, 1, 1 }, + }; + + // Set the starting point of the branch + Vector3i BranchPos = Vector3i(a_BlockX, a_BlockY + Height - 1, a_BlockZ); + + // Get a direction for the trunk to go to. + Vector3i BranchDirection = AvailableDirections[a_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) % 8]; + + // Calculate a height for the branch between 1 and 3 + int BranchHeight = a_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) % 3 + 1; + + // Place the logs of the branch. + for (int i = 0; i < BranchHeight; i++) + { + BranchPos = BranchPos + BranchDirection; + a_LogBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y, BranchPos.z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_ACACIA_WOOD)); + } + + // Add the leaves to the top of the branch + PushCoordBlocks(BranchPos.x, BranchPos.y, BranchPos.z, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD); + PushCoordBlocks(BranchPos.x, BranchPos.y + 1, BranchPos.z, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD); + a_OtherBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y + 1, BranchPos.z, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD)); + + // Choose if we have to add another branch + bool TwoTop = (a_Noise.IntNoise3D(a_BlockX, a_BlockY, a_BlockZ) < 0 ? true : false); + if (!TwoTop) + { + return; + } + + // Reset the starting point of the branch + BranchPos = Vector3i(a_BlockX, a_BlockY + Height - 1, a_BlockZ); + + // Invert the direction of the previous branch. + BranchDirection = Vector3d(-BranchDirection.x, 1, -BranchDirection.z); + + // Calculate a new height for the second branch + BranchHeight = a_Noise.IntNoise3DInt(a_BlockX * a_Seq, a_BlockY * a_Seq * 10, a_BlockZ * a_Seq) % 3 + 1; + + // Place the logs in the same way as the first branch + for (int i = 0; i < BranchHeight; i++) + { + BranchPos = BranchPos + BranchDirection; + a_LogBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y, BranchPos.z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_ACACIA_WOOD)); + } + + // And add the leaves ontop of the second branch + PushCoordBlocks(BranchPos.x, BranchPos.y, BranchPos.z, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD); + PushCoordBlocks(BranchPos.x, BranchPos.y + 1, BranchPos.z, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD); + a_OtherBlocks.push_back(sSetBlock(BranchPos.x, BranchPos.y + 1, BranchPos.z, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_ACACIA_WOOD)); } diff --git a/src/Generating/UnderwaterBaseGen.cpp b/src/Generating/UnderwaterBaseGen.cpp index 9278ea546..8916f4b5f 100644 --- a/src/Generating/UnderwaterBaseGen.cpp +++ b/src/Generating/UnderwaterBaseGen.cpp @@ -93,7 +93,7 @@ protected: -cUnderwaterBaseGen::cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen) : +cUnderwaterBaseGen::cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGenPtr a_BiomeGen) : super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSize, a_MaxSize, 100), m_Noise(a_Seed + 1000), m_MaxDepth(a_MaxDepth), @@ -112,7 +112,7 @@ cGridStructGen::cStructurePtr cUnderwaterBaseGen::CreateStructure(int a_GridX, i int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ); cChunkDef::BiomeMap Biomes; - m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes); + m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes); // Check if all the biomes are ocean: // If just one is not, no base is created, because it's likely that an unfriendly biome is too close diff --git a/src/Generating/UnderwaterBaseGen.h b/src/Generating/UnderwaterBaseGen.h index d6267b602..b24eb1075 100644 --- a/src/Generating/UnderwaterBaseGen.h +++ b/src/Generating/UnderwaterBaseGen.h @@ -22,7 +22,7 @@ class cUnderwaterBaseGen : typedef cGridStructGen super; public: - cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen); + cUnderwaterBaseGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, cBiomeGenPtr a_BiomeGen); protected: class cUnderwaterBase; // fwd: UnderwaterBaseGen.cpp @@ -38,7 +38,7 @@ protected: int m_MaxSize; /** The underlying biome generator that defines whether the base is created or not */ - cBiomeGen & m_BiomeGen; + cBiomeGenPtr m_BiomeGen; // cGridStructGen overrides: diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index a7f66b75e..a9b359b6a 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -116,7 +116,7 @@ public: int a_MaxSize, int a_Density, cPiecePool & a_Prefabs, - cTerrainHeightGen & a_HeightGen, + cTerrainHeightGenPtr a_HeightGen, BLOCKTYPE a_RoadBlock, BLOCKTYPE a_WaterRoadBlock ) : @@ -175,7 +175,7 @@ protected: cPiecePool & m_Prefabs; /** The underlying height generator, used for placing the structures on top of the terrain. */ - cTerrainHeightGen & m_HeightGen; + cTerrainHeightGenPtr m_HeightGen; /** The village pieces, placed by the generator. */ cPlacedPieces m_Pieces; @@ -194,7 +194,7 @@ protected: // Each intersecting prefab is placed on ground, then drawn // Each intersecting road is drawn by replacing top soil blocks with gravel / sandstone blocks cChunkDef::HeightMap HeightMap; // Heightmap for this chunk, used by roads - m_HeightGen.GenHeightMap(a_Chunk.GetChunkX(), a_Chunk.GetChunkZ(), HeightMap); + m_HeightGen->GenHeightMap(a_Chunk.GetChunkX(), a_Chunk.GetChunkZ(), HeightMap); for (cPlacedPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) { cPrefab & Prefab = (cPrefab &)((*itr)->GetPiece()); @@ -224,7 +224,7 @@ protected: int BlockY; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cChunkDef::HeightMap HeightMap; - m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap); + m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap); int TerrainHeight = cChunkDef::GetHeight(HeightMap, BlockX, BlockZ); a_Piece.MoveToGroundBy(TerrainHeight - FirstConnector.m_Pos.y + 1); } @@ -359,7 +359,7 @@ static cVillagePiecePool * g_PlainsVillagePools[] = -cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) : +cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen) : super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSize, a_MaxSize, 100), m_Noise(a_Seed + 1000), m_MaxDepth(a_MaxDepth), @@ -381,11 +381,11 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_GridX, int a_Gr int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ); cChunkDef::BiomeMap Biomes; - m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes); + m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes); // Check if all the biomes are village-friendly: // If just one is not, no village is created, because it's likely that an unfriendly biome is too close - cVillagePiecePool * VillagePrefabs = NULL; + cVillagePiecePool * VillagePrefabs = nullptr; BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL; BLOCKTYPE WaterRoadBlock = E_BLOCK_PLANKS; int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11; @@ -432,7 +432,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_GridX, int a_Gr } // Create a village based on the chosen prefabs: - if (VillagePrefabs == NULL) + if (VillagePrefabs == nullptr) { return cStructurePtr(); } diff --git a/src/Generating/VillageGen.h b/src/Generating/VillageGen.h index 694ea2358..ed8d739df 100644 --- a/src/Generating/VillageGen.h +++ b/src/Generating/VillageGen.h @@ -21,7 +21,7 @@ class cVillageGen : { typedef cGridStructGen super; public: - cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen); + cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen); protected: class cVillage; // fwd: VillageGen.cpp @@ -42,10 +42,10 @@ protected: int m_MaxDensity; /** The underlying biome generator that defines whether the village is created or not */ - cBiomeGen & m_BiomeGen; + cBiomeGenPtr m_BiomeGen; /** The underlying height generator, used to position the prefabs crossing chunk borders */ - cTerrainHeightGen & m_HeightGen; + cTerrainHeightGenPtr m_HeightGen; // cGridStructGen overrides: diff --git a/src/Globals.h b/src/Globals.h index 0926457da..582f5fdaa 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -17,7 +17,6 @@ #pragma warning(disable:4100) // Unreferenced formal parameter // Useful warnings from warning level 4: - #pragma warning(3 : 4127) // Conditional expression is constant #pragma warning(3 : 4189) // Local variable is initialized but not referenced #pragma warning(3 : 4245) // Conversion from 'type1' to 'type2', signed/unsigned mismatch #pragma warning(3 : 4310) // Cast truncates constant value @@ -26,7 +25,10 @@ #pragma warning(3 : 4701) // Potentially unitialized local variable used #pragma warning(3 : 4702) // Unreachable code #pragma warning(3 : 4706) // Assignment within conditional expression - + + // 2014-10-23 xoft: Disabled this because the new C++11 headers in MSVC produce tons of these warnings uselessly + // #pragma warning(3 : 4127) // Conditional expression is constant + // Disabling this warning, because we know what we're doing when we're doing this: #pragma warning(disable: 4355) // 'this' used in initializer list @@ -51,6 +53,9 @@ #define NORETURN __declspec(noreturn) + // Use non-standard defines in <cmath> + #define _USE_MATH_DEFINES + #elif defined(__GNUC__) // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)? @@ -226,10 +231,10 @@ template class SizeChecker<UInt16, 2>; // CRT stuff: #include <sys/stat.h> -#include <assert.h> -#include <stdio.h> -#include <math.h> -#include <stdarg.h> +#include <cassert> +#include <cstdio> +#include <cmath> +#include <cstdarg> @@ -358,19 +363,8 @@ void inline LOGD(const char* a_Format, ...) #define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0)) #endif -// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr: -// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed. -#if (defined(_MSC_VER) && (_MSC_VER < 1600)) - // MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier - #define SharedPtr std::tr1::shared_ptr -#elif (defined(_MSC_VER) || (__cplusplus >= 201103L)) - // C++11 has std::shared_ptr in <memory>, included earlier - #define SharedPtr std::shared_ptr -#else - // C++03 has std::tr1::shared_ptr in <tr1/memory> - #include <tr1/memory> - #define SharedPtr std::tr1::shared_ptr -#endif +// Unified shared ptr from before C++11. Also no silly undercores. +#define SharedPtr std::shared_ptr @@ -400,6 +394,30 @@ T Clamp(T a_Value, T a_Min, T a_Max) +/** Floors a value, then casts it to C (an int by default) */ +template <typename C = int, typename T> +typename std::enable_if<std::is_arithmetic<T>::value, C>::type FloorC(T a_Value) +{ + return static_cast<C>(std::floor(a_Value)); +} + +/** Ceils a value, then casts it to C (an int by default) */ +template <typename C = int, typename T> +typename std::enable_if<std::is_arithmetic<T>::value, C>::type CeilC(T a_Value) +{ + return static_cast<C>(std::ceil(a_Value)); +} + + + +//temporary replacement for std::make_unique until we get c++14 +template <class T, class... Args> +std::unique_ptr<T> make_unique(Args&&... args) +{ + return std::unique_ptr<T>(new T(args...)); +} + + #ifndef TOLUA_TEMPLATE_BIND #define TOLUA_TEMPLATE_BIND(x) #endif @@ -415,3 +433,4 @@ T Clamp(T a_Value, T a_Min, T a_Max) #include "BlockInfo.h" + diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index bf46bb241..d5dbf0199 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -15,7 +15,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : m_HTTPServer(a_HTTPServer), m_State(wcsRecvHeaders), - m_CurrentRequest(NULL), + m_CurrentRequest(nullptr), m_CurrentRequestBodyRemaining(0) { // LOGD("HTTP: New connection at %p", this); @@ -29,7 +29,7 @@ cHTTPConnection::~cHTTPConnection() { // LOGD("HTTP: Connection deleting: %p", this); delete m_CurrentRequest; - m_CurrentRequest = NULL; + m_CurrentRequest = nullptr; } @@ -136,7 +136,7 @@ void cHTTPConnection::AwaitNextRequest(void) void cHTTPConnection::Terminate(void) { - if (m_CurrentRequest != NULL) + if (m_CurrentRequest != nullptr) { m_HTTPServer.RequestFinished(*this, *m_CurrentRequest); } @@ -153,7 +153,7 @@ bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { case wcsRecvHeaders: { - if (m_CurrentRequest == NULL) + if (m_CurrentRequest == nullptr) { m_CurrentRequest = new cHTTPRequest; } @@ -162,7 +162,7 @@ bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) if (BytesConsumed == AString::npos) { delete m_CurrentRequest; - m_CurrentRequest = NULL; + m_CurrentRequest = nullptr; m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); return true; @@ -196,7 +196,7 @@ bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) case wcsRecvBody: { - ASSERT(m_CurrentRequest != NULL); + ASSERT(m_CurrentRequest != nullptr); if (m_CurrentRequestBodyRemaining > 0) { size_t BytesToConsume = std::min(m_CurrentRequestBodyRemaining, (size_t)a_Size); @@ -214,7 +214,7 @@ bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) return true; } delete m_CurrentRequest; - m_CurrentRequest = NULL; + m_CurrentRequest = nullptr; } break; } @@ -243,7 +243,7 @@ void cHTTPConnection::GetOutgoingData(AString & a_Data) void cHTTPConnection::SocketClosed(void) { - if (m_CurrentRequest != NULL) + if (m_CurrentRequest != nullptr) { m_HTTPServer.RequestFinished(*this, *m_CurrentRequest); } diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h index 6ea8a1ae8..ccbf26466 100644 --- a/src/HTTPServer/HTTPConnection.h +++ b/src/HTTPServer/HTTPConnection.h @@ -31,10 +31,10 @@ public: enum eState { - wcsRecvHeaders, ///< Receiving request headers (m_CurrentRequest is created if NULL) + wcsRecvHeaders, ///< Receiving request headers (m_CurrentRequest is created if nullptr) wcsRecvBody, ///< Receiving request body (m_CurrentRequest is valid) - wcsRecvIdle, ///< Has received the entire body, waiting to send the response (m_CurrentRequest == NULL) - wcsSendingResp, ///< Sending response body (m_CurrentRequest == NULL) + wcsRecvIdle, ///< Has received the entire body, waiting to send the response (m_CurrentRequest == nullptr) + wcsSendingResp, ///< Sending response body (m_CurrentRequest == nullptr) wcsInvalid, ///< The request was malformed, the connection is closing } ; diff --git a/src/HTTPServer/HTTPFormParser.cpp b/src/HTTPServer/HTTPFormParser.cpp index c50c6dcf2..72872078b 100644 --- a/src/HTTPServer/HTTPFormParser.cpp +++ b/src/HTTPServer/HTTPFormParser.cpp @@ -86,7 +86,7 @@ void cHTTPFormParser::Parse(const char * a_Data, size_t a_Size) } case fpkMultipart: { - ASSERT(m_MultipartParser.get() != NULL); + ASSERT(m_MultipartParser.get() != nullptr); m_MultipartParser->Parse(a_Data, a_Size); break; } @@ -145,7 +145,7 @@ bool cHTTPFormParser::HasFormData(const cHTTPRequest & a_Request) void cHTTPFormParser::BeginMultipart(const cHTTPRequest & a_Request) { - ASSERT(m_MultipartParser.get() == NULL); + ASSERT(m_MultipartParser.get() == nullptr); m_MultipartParser.reset(new cMultipartParser(a_Request.GetContentType(), *this)); } diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index 65d73fd87..f6c0204ae 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -70,7 +70,7 @@ cHTTPRequest::cHTTPRequest(void) : super(mkRequest), m_EnvelopeParser(*this), m_IsValid(true), - m_UserData(NULL), + m_UserData(nullptr), m_HasAuth(false), m_AllowKeepAlive(false) { diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index 0c41b54b2..9ab030a1f 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -44,7 +44,7 @@ class cDebugCallbacks : UNUSED(a_Connection); cHTTPFormParser * FormParser = (cHTTPFormParser *)(a_Request.GetUserData()); - if (FormParser != NULL) + if (FormParser != nullptr) { FormParser->Parse(a_Data, a_Size); } @@ -54,7 +54,7 @@ class cDebugCallbacks : virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override { cHTTPFormParser * FormParser = (cHTTPFormParser *)(a_Request.GetUserData()); - if (FormParser != NULL) + if (FormParser != nullptr) { if (FormParser->Finish()) { @@ -124,7 +124,7 @@ class cDebugCallbacks : cHTTPServer::cHTTPServer(void) : m_ListenThreadIPv4(*this, cSocket::IPv4, "WebServer"), m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer"), - m_Callbacks(NULL) + m_Callbacks(nullptr) { } @@ -168,7 +168,7 @@ bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_Port } // Notify the admin about the HTTPS / HTTP status - if (m_Cert.get() == NULL) + if (m_Cert.get() == nullptr) { LOGWARNING("WebServer: The server is running in unsecured HTTP mode."); LOGINFO("Put a valid HTTPS certificate in file 'webadmin/httpscert.crt' and its corresponding private key to 'webadmin/httpskey.pem' (without any password) to enable HTTPS support"); @@ -235,7 +235,7 @@ void cHTTPServer::Stop(void) void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket) { cHTTPConnection * Connection; - if (m_Cert.get() != NULL) + if (m_Cert.get() != nullptr) { Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey); } diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h index 522b7da62..73d4cbdd0 100644 --- a/src/HTTPServer/HTTPServer.h +++ b/src/HTTPServer/HTTPServer.h @@ -11,7 +11,7 @@ #include "../OSSupport/ListenThread.h" #include "../OSSupport/SocketThreads.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "PolarSSL++/RsaPrivateKey.h" #include "PolarSSL++/CryptoKey.h" #include "PolarSSL++/X509Cert.h" diff --git a/lib/inifile/iniFile.cpp b/src/IniFile.cpp index 7cfe7661f..ded7e4199 100644 --- a/lib/inifile/iniFile.cpp +++ b/src/IniFile.cpp @@ -9,7 +9,7 @@ // Email: Shane.Hill@dsto.defence.gov.au // Reason: Remove dependancy on MFC. Code should compile on any // platform. -////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// /* !! MODIFIED BY FAKETRUTH and xoft !! @@ -24,7 +24,7 @@ #include <ctype.h> // Local Includes -#include "iniFile.h" +#include "IniFile.h" #if defined(WIN32) #define iniEOL endl @@ -32,10 +32,6 @@ #define iniEOL '\r' << endl #endif -#ifndef _WIN32 - #define sscanf_s(buffer, stringbuffer, ...) (sscanf(buffer, stringbuffer, __VA_ARGS__)) -#endif - using namespace std; @@ -83,7 +79,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) } } - bool IsFirstLine = true; + bool IsFirstLine = true; while (getline(f, line)) { @@ -465,20 +461,6 @@ bool cIniFile::SetValueF(const AString & a_KeyName, const AString & a_ValueName, -bool cIniFile::SetValueV(const AString & a_KeyName, const AString & a_ValueName, const char * a_Format, ...) -{ - va_list args; - va_start(args, a_Format); - AString Data; - AppendVPrintf(Data, a_Format, args); - va_end(args); - return SetValue(a_KeyName, a_ValueName, Data); -} - - - - - AString cIniFile::GetValue(const int keyID, const int valueID, const AString & defValue) const { if ((keyID < (int)keys.size()) && (valueID < (int)keys[keyID].names.size())) @@ -884,7 +866,7 @@ AString cIniFile::CheckCase(const AString & s) const void cIniFile::RemoveBom(AString & a_line) const { - // The BOM sequence for UTF-8 is 0xEF,0xBB,0xBF + // The BOM sequence for UTF-8 is 0xEF, 0xBB, 0xBF static unsigned const char BOM[] = { 0xEF, 0xBB, 0xBF }; // The BOM sequence, if present, is always th e first three characters of the input. diff --git a/lib/inifile/iniFile.h b/src/IniFile.h index 33229bff0..e5879f46c 100644 --- a/lib/inifile/iniFile.h +++ b/src/IniFile.h @@ -9,7 +9,7 @@ // Email: Shane.Hill@dsto.defence.gov.au // Reason: Remove dependancy on MFC. Code should compile on any // platform. Tested on Windows/Linux/Irix -////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// /* !! MODIFIED BY FAKETRUTH and madmaxoft!! @@ -154,12 +154,6 @@ public: } bool SetValueF(const AString & a_KeyName, const AString & a_ValueName, const double a_Value, const bool a_CreateIfNotExists = true); - // tolua_end - - bool SetValueV( const AString & a_KeyName, const AString & a_ValueName, const char * a_Format, ...); - - // tolua_begin - // Deletes specified value. // Returns true if value existed and deleted, false otherwise. bool DeleteValueByID(const int keyID, const int valueID); diff --git a/src/Inventory.cpp b/src/Inventory.cpp index 832a079bc..51ac32da9 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -220,7 +220,7 @@ void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item) int GridSlotNum = 0; cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum); - if (Grid == NULL) + if (Grid == nullptr) { LOGWARNING("%s(%d): requesting an invalid itemgrid. Ignoring.", __FUNCTION__, a_SlotNum); return; @@ -278,7 +278,7 @@ const cItem & cInventory::GetSlot(int a_SlotNum) const } int GridSlotNum = 0; const cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum); - if (Grid == NULL) + if (Grid == nullptr) { // Something went wrong, but we don't know what. We must return a value, so return the first inventory slot LOGWARNING("%s(%d): requesting an invalid ItemGrid, returning the first inventory slot instead.", __FUNCTION__, a_SlotNum); @@ -372,7 +372,7 @@ int cInventory::ChangeSlotCount(int a_SlotNum, int a_AddToCount) { int GridSlotNum = 0; cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum); - if (Grid == NULL) + if (Grid == nullptr) { LOGWARNING("%s: invalid slot number, expected 0 .. %d, got %d; ignoring", __FUNCTION__, invNumSlots, a_SlotNum); return -1; @@ -398,7 +398,7 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount) int GridSlotNum = 0; cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum); - if (Grid == NULL) + if (Grid == nullptr) { LOGWARNING("%s(%d, %d): requesting an invalid grid, ignoring.", __FUNCTION__, a_SlotNum, a_Amount); return false; @@ -640,7 +640,7 @@ bool cInventory::LoadFromJson(Json::Value & a_Value) int GridSlotNum = 0; cItemGrid * Grid = GetGridForSlotNum(SlotIdx - 5, GridSlotNum); - ASSERT(Grid != NULL); + ASSERT(Grid != nullptr); Grid->SetSlot(GridSlotNum, Item); } // for itr - a_Value[] return true; @@ -708,7 +708,7 @@ void cInventory::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) // Armor update needs broadcast to other players: cWorld * World = m_Owner.GetWorld(); - if ((a_ItemGrid == &m_ArmorSlots) && (World != NULL)) + if ((a_ItemGrid == &m_ArmorSlots) && (World != nullptr)) { World->BroadcastEntityEquipment( m_Owner, ArmorSlotNumToEntityEquipmentID(a_SlotNum), diff --git a/src/Inventory.h b/src/Inventory.h index 5628fb0da..4e76bc0d3 100644 --- a/src/Inventory.h +++ b/src/Inventory.h @@ -179,10 +179,10 @@ protected: cPlayer & m_Owner; - /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */ + /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return nullptr for invalid SlotNum */ const cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const; - /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */ + /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return nullptr for invalid SlotNum */ cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum); // cItemGrid::cListener override: diff --git a/src/Item.cpp b/src/Item.cpp index ebdf99ca5..36c444328 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -391,7 +391,7 @@ cItem * cItems::Get(int a_Idx) if ((a_Idx < 0) || (a_Idx >= (int)size())) { LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently " SIZE_T_FMT " items. Returning a nil.", a_Idx, size()); - return NULL; + return nullptr; } return &at(a_Idx); } diff --git a/src/ItemGrid.cpp b/src/ItemGrid.cpp index 2344dc0a5..55fb36a17 100644 --- a/src/ItemGrid.cpp +++ b/src/ItemGrid.cpp @@ -28,7 +28,7 @@ cItemGrid::cItemGrid(int a_Width, int a_Height) : cItemGrid::~cItemGrid() { delete[] m_Slots; - m_Slots = NULL; + m_Slots = nullptr; } @@ -637,14 +637,35 @@ void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, s int Rnd = (Noise.IntNoise1DInt(i) / 7); int LootRnd = Rnd % TotalProbab; Rnd >>= 8; - cItem CurrentLoot = cItem(E_ITEM_BOOK, 1, 0); // TODO: enchantment + cItem CurrentLoot = cItem(E_ITEM_ENCHANTED_BOOK, 1, 0); + + // Choose the enchantments + cWeightedEnchantments Enchantments; + cEnchantments::AddItemEnchantmentWeights(Enchantments, E_ITEM_BOOK, 24 + Noise.IntNoise2DInt(a_Seed, TotalProbab) % 7); + int NumEnchantments = Noise.IntNoise3DInt(TotalProbab, Rnd, a_Seed) % 5; // The number of enchantments this book wil get. + + for (int j = 0; j <= NumEnchantments; j++) + { + cEnchantments Enchantment = cEnchantments::GenerateEnchantmentFromVector(Enchantments, Noise.IntNoise2DInt(NumEnchantments, i)); + CurrentLoot.m_Enchantments.Add(Enchantment); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment); + } + for (size_t j = 0; j < a_CountLootProbabs; j++) { - LootRnd -= a_LootProbabs[i].m_Weight; + LootRnd -= a_LootProbabs[j].m_Weight; if (LootRnd < 0) { - CurrentLoot = a_LootProbabs[i].m_Item; - CurrentLoot.m_ItemCount = a_LootProbabs[i].m_MinAmount + (Rnd % (a_LootProbabs[i].m_MaxAmount - a_LootProbabs[i].m_MinAmount)); + CurrentLoot = a_LootProbabs[j].m_Item; + if ((a_LootProbabs[j].m_MaxAmount - a_LootProbabs[j].m_MinAmount) > 0) + { + CurrentLoot.m_ItemCount = a_LootProbabs[j].m_MinAmount + (Rnd % (a_LootProbabs[j].m_MaxAmount - a_LootProbabs[j].m_MinAmount)); + } + else + { + CurrentLoot.m_ItemCount = a_LootProbabs[j].m_MinAmount; + } Rnd >>= 8; break; } diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index f29cc5d59..cf2fe9ad2 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -29,7 +29,7 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override { - ASSERT(a_Player != NULL); + ASSERT(a_Player != nullptr); // Check if the player has an arrow in the inventory, or is in Creative: if (!(a_Player->IsGameModeCreative() || a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW)))) @@ -45,7 +45,7 @@ public: virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override { // Actual shot - produce the arrow with speed based on the ticks that the bow was charged - ASSERT(a_Player != NULL); + ASSERT(a_Player != nullptr); int BowCharge = a_Player->FinishChargingBow(); double Force = (double)BowCharge / 20.0; @@ -65,14 +65,14 @@ public: // Create the arrow entity: cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); - if (Arrow == NULL) + if (Arrow == nullptr) { return; } if (!Arrow->Initialize(*a_Player->GetWorld())) { delete Arrow; - Arrow = NULL; + Arrow = nullptr; return; } a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force); diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h index 953673382..9238d771b 100644 --- a/src/Items/ItemEmptyMap.h +++ b/src/Items/ItemEmptyMap.h @@ -50,7 +50,7 @@ public: return true; } - if (NewMap == NULL) + if (NewMap == nullptr) { return true; } diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index caa623abc..9272a723d 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -83,7 +83,7 @@ cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) memset(m_ItemHandler, 0, sizeof(m_ItemHandler)); m_HandlerInitialized = true; } - if (m_ItemHandler[a_ItemType] == NULL) + if (m_ItemHandler[a_ItemType] == nullptr) { m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType); } @@ -278,7 +278,7 @@ void cItemHandler::Deinit() for (int i = 0; i < 2267; i++) { delete m_ItemHandler[i]; - m_ItemHandler[i] = NULL; + m_ItemHandler[i] = nullptr; } memset(m_ItemHandler, 0, sizeof(m_ItemHandler)); // Don't leave any dangling pointers around, just in case m_HandlerInitialized = false; @@ -572,8 +572,11 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) case E_BLOCK_COBBLESTONE: case E_BLOCK_COBBLESTONE_STAIRS: case E_BLOCK_COBBLESTONE_WALL: + case E_BLOCK_COBWEB: + case E_BLOCK_DEAD_BUSH: case E_BLOCK_DIAMOND_BLOCK: case E_BLOCK_DIAMOND_ORE: + case E_BLOCK_DOUBLE_NEW_STONE_SLAB: case E_BLOCK_DOUBLE_STONE_SLAB: case E_BLOCK_EMERALD_ORE: case E_BLOCK_ENCHANTMENT_TABLE: @@ -587,6 +590,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) case E_BLOCK_LAPIS_BLOCK: case E_BLOCK_LAPIS_ORE: case E_BLOCK_LIT_FURNACE: + case E_BLOCK_MOB_SPAWNER: case E_BLOCK_MOSSY_COBBLESTONE: case E_BLOCK_NETHER_BRICK: case E_BLOCK_NETHER_BRICK_STAIRS: @@ -594,6 +598,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) case E_BLOCK_NETHERRACK: case E_BLOCK_NEW_STONE_SLAB: case E_BLOCK_OBSIDIAN: + case E_BLOCK_PACKED_ICE: case E_BLOCK_PRISMARINE_BLOCK: case E_BLOCK_RED_SANDSTONE: case E_BLOCK_RED_SANDSTONE_STAIRS: @@ -608,8 +613,6 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_SLAB: case E_BLOCK_VINES: - case E_BLOCK_PACKED_ICE: - case E_BLOCK_MOB_SPAWNER: { return false; } diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h index de8b9a061..ae3723323 100644 --- a/src/Items/ItemHoe.h +++ b/src/Items/ItemHoe.h @@ -24,12 +24,35 @@ public: { return false; } - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + BLOCKTYPE Block; + NIBBLETYPE BlockMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta); + if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR)) { - a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FARMLAND, 0); + BLOCKTYPE NewBlock = E_BLOCK_FARMLAND; + if (Block == E_BLOCK_DIRT) + { + switch (BlockMeta) + { + case E_META_DIRT_COARSE: + { + // Transform to normal dirt + NewBlock = E_BLOCK_DIRT; + break; + } + case E_META_DIRT_PODZOL: + { + // You can't transform this block with a hoe in vanilla + return false; + } + default: break; + } + } + + a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, NewBlock, 0); a_World->BroadcastSoundEffect("dig.gravel", a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 1.0f, 0.8f); a_Player->UseEquippedItem(); return true; diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index 87e20ecf0..5d22c1cb8 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -37,7 +37,7 @@ public: if (!ItemFrame->Initialize(*a_World)) { delete ItemFrame; - ItemFrame = NULL; + ItemFrame = nullptr; return false; } diff --git a/src/Items/ItemMap.h b/src/Items/ItemMap.h index 056fe0fe7..2dbbb3dc0 100644 --- a/src/Items/ItemMap.h +++ b/src/Items/ItemMap.h @@ -31,7 +31,7 @@ public: { cMap * Map = a_World->GetMapManager().GetMapData((unsigned)a_Item.m_ItemDamage); - if (Map == NULL) + if (Map == nullptr) { return; } diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 63038de51..ed0a4711c 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -56,7 +56,7 @@ public: double x = (double)a_BlockX + 0.5; double y = (double)a_BlockY + 0.5; double z = (double)a_BlockZ + 0.5; - cMinecart * Minecart = NULL; + cMinecart * Minecart = nullptr; switch (m_ItemType) { case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break; diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h index e0cf5d711..b5dc179f8 100644 --- a/src/Items/ItemPickaxe.h +++ b/src/Items/ItemPickaxe.h @@ -41,11 +41,11 @@ public: case E_BLOCK_DIAMOND_BLOCK: case E_BLOCK_DIAMOND_ORE: + case E_BLOCK_EMERALD_ORE: case E_BLOCK_GOLD_BLOCK: case E_BLOCK_GOLD_ORE: case E_BLOCK_REDSTONE_ORE: case E_BLOCK_REDSTONE_ORE_GLOWING: - case E_BLOCK_EMERALD_ORE: { return PickaxeLevel() >= 3; } @@ -59,29 +59,34 @@ public: } case E_BLOCK_ANVIL: - case E_BLOCK_ENCHANTMENT_TABLE: - case E_BLOCK_FURNACE: - case E_BLOCK_LIT_FURNACE: + case E_BLOCK_BRICK: + case E_BLOCK_CAULDRON: case E_BLOCK_COAL_ORE: - case E_BLOCK_STONE: case E_BLOCK_COBBLESTONE: + case E_BLOCK_COBBLESTONE_STAIRS: + case E_BLOCK_COBBLESTONE_WALL: + case E_BLOCK_DOUBLE_NEW_STONE_SLAB: + case E_BLOCK_DOUBLE_STONE_SLAB: + case E_BLOCK_ENCHANTMENT_TABLE: case E_BLOCK_END_STONE: + case E_BLOCK_FURNACE: + case E_BLOCK_LIT_FURNACE: + case E_BLOCK_MOB_SPAWNER: case E_BLOCK_MOSSY_COBBLESTONE: - case E_BLOCK_SANDSTONE_STAIRS: - case E_BLOCK_SANDSTONE: - case E_BLOCK_STONE_BRICKS: case E_BLOCK_NETHER_BRICK: + case E_BLOCK_NETHER_BRICK_STAIRS: case E_BLOCK_NETHERRACK: - case E_BLOCK_STONE_SLAB: - case E_BLOCK_DOUBLE_STONE_SLAB: - case E_BLOCK_STONE_PRESSURE_PLATE: - case E_BLOCK_BRICK: - case E_BLOCK_COBBLESTONE_STAIRS: - case E_BLOCK_COBBLESTONE_WALL: + case E_BLOCK_NEW_STONE_SLAB: + case E_BLOCK_PRISMARINE_BLOCK: + case E_BLOCK_RED_SANDSTONE: + case E_BLOCK_RED_SANDSTONE_STAIRS: + case E_BLOCK_SANDSTONE: + case E_BLOCK_SANDSTONE_STAIRS: + case E_BLOCK_STONE: + case E_BLOCK_STONE_BRICKS: case E_BLOCK_STONE_BRICK_STAIRS: - case E_BLOCK_NETHER_BRICK_STAIRS: - case E_BLOCK_CAULDRON: - case E_BLOCK_MOB_SPAWNER: + case E_BLOCK_STONE_PRESSURE_PLATE: + case E_BLOCK_STONE_SLAB: { return PickaxeLevel() >= 1; } diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h index fa2794df2..73343f629 100644 --- a/src/Items/ItemShears.h +++ b/src/Items/ItemShears.h @@ -28,21 +28,25 @@ public: virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override { - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + BLOCKTYPE Block; + NIBBLETYPE BlockMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta); + if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES)) { - NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + cItems Drops; cBlockHandler * Handler = cBlockInfo::GetHandler(Block); - cItems Drops; - Handler->ConvertToPickups(Drops, Meta); - Drops.push_back(cItem(Block, 1, Meta & 3)); + Handler->ConvertToPickups(Drops, BlockMeta); + Drops.Add(Block, 1, BlockMeta & 3); a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ); a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ); a_Player->UseEquippedItem(); return true; } + return false; } @@ -53,12 +57,10 @@ public: { case E_BLOCK_COBWEB: case E_BLOCK_VINES: - case E_BLOCK_LEAVES: - case E_BLOCK_NEW_LEAVES: { return true; } - } // switch (a_BlockType) + } return super::CanHarvestBlock(a_BlockType); } @@ -71,12 +73,21 @@ public: virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ) override { - super::OnBlockDestroyed(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ); + BLOCKTYPE Block; + NIBBLETYPE BlockMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta); - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - if ((Block == E_BLOCK_TRIPWIRE) || (Block == E_BLOCK_VINES)) + super::OnBlockDestroyed(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ); + switch (Block) { - a_Player->UseEquippedItem(); + case E_BLOCK_COBWEB: + case E_BLOCK_DEAD_BUSH: + case E_BLOCK_TRIPWIRE: + case E_BLOCK_VINES: + case E_BLOCK_WOOL: + { + a_Player->UseEquippedItem(); + } } } } ; diff --git a/src/LeakFinder.h b/src/LeakFinder.h index e63b9ec5d..ceaa53782 100644 --- a/src/LeakFinder.h +++ b/src/LeakFinder.h @@ -68,7 +68,7 @@ public: LeakFinderShowCompleteCallstack = 0x1000 } LeakFinderOptions; - LeakFinderOutput(int options = OptionsAll, LPCSTR szSymPath = NULL); + LeakFinderOutput(int options = OptionsAll, LPCSTR szSymPath = nullptr); virtual void OnLeakSearchStart(LPCSTR sszLeakFinderName); virtual void OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize); protected: @@ -110,7 +110,7 @@ class ZZZ_LeakFinder public: ZZZ_LeakFinder() { - m_pXml = NULL; + m_pXml = nullptr; #ifdef XML_LEAK_FINDER m_pXml = new LeakFinderXmlOutput(); #endif @@ -119,7 +119,7 @@ public: ~ZZZ_LeakFinder() { DeinitLeakFinder(m_pXml); - if (m_pXml != NULL) delete m_pXml; + if (m_pXml != nullptr) delete m_pXml; } protected: LeakFinderXmlOutput *m_pXml; @@ -148,7 +148,7 @@ ZZZ_LeakFinder zzz_LeakFinder; -extern void DumpUsedMemory(LeakFinderOutput * output = NULL); +extern void DumpUsedMemory(LeakFinderOutput * output = nullptr); diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp index 652b03e46..ae5e746e7 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -91,7 +91,7 @@ public: cLightingThread::cLightingThread(void) : super("cLightingThread"), - m_World(NULL), + m_World(nullptr), m_MaxHeight(0), m_NumSeeds(0) { @@ -112,7 +112,7 @@ cLightingThread::~cLightingThread() bool cLightingThread::Start(cWorld * a_World) { - ASSERT(m_World == NULL); // Not started yet + ASSERT(m_World == nullptr); // Not started yet m_World = a_World; return super::Start(); @@ -151,7 +151,7 @@ void cLightingThread::Stop(void) void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter) { - ASSERT(m_World != NULL); // Did you call Start() properly? + ASSERT(m_World != nullptr); // Did you call Start() properly? cChunkStay * ChunkStay = new cLightingChunkStay(*this, a_ChunkX, a_ChunkZ, a_CallbackAfter); { @@ -310,7 +310,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item) m_World->ChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ, BlockLight, SkyLight); - if (a_Item.m_CallbackAfter != NULL) + if (a_Item.m_CallbackAfter != nullptr) { a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ); } diff --git a/src/LightingThread.h b/src/LightingThread.h index f71d2cf1a..87eb9c6d8 100644 --- a/src/LightingThread.h +++ b/src/LightingThread.h @@ -61,7 +61,7 @@ public: void Stop(void); /** Queues the entire chunk for lighting */ - void QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter = NULL); + void QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter = nullptr); /** Blocks until the queue is empty or the thread is terminated */ void WaitForQueueEmpty(void); diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp index 1b42081c2..90f97cd23 100644 --- a/src/LineBlockTracer.cpp +++ b/src/LineBlockTracer.cpp @@ -198,7 +198,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) for (;;) { // Report the current block through the callbacks: - if (a_Chunk == NULL) + if (a_Chunk == nullptr) { m_Callbacks->OnNoChunk(); return false; @@ -228,7 +228,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) // Update the current chunk a_Chunk = a_Chunk->GetNeighborChunk(m_CurrentX, m_CurrentZ); - if (a_Chunk == NULL) + if (a_Chunk == nullptr) { m_Callbacks->OnNoChunk(); return false; diff --git a/src/LinearUpscale.h b/src/LinearUpscale.h index a49f4bdf9..1b0fbd89a 100644 --- a/src/LinearUpscale.h +++ b/src/LinearUpscale.h @@ -95,8 +95,8 @@ template <typename TYPE> void LinearUpscale2DArray( const int MAX_UPSCALE_X = 128; const int MAX_UPSCALE_Y = 128; - ASSERT(a_Src != NULL); - ASSERT(a_Dst != NULL); + ASSERT(a_Src != nullptr); + ASSERT(a_Dst != nullptr); ASSERT(a_SrcSizeX > 0); ASSERT(a_SrcSizeY > 0); ASSERT(a_UpscaleX > 0); @@ -166,8 +166,8 @@ template <typename TYPE> void LinearUpscale3DArray( const int MAX_UPSCALE_Y = 128; const int MAX_UPSCALE_Z = 128; - ASSERT(a_Src != NULL); - ASSERT(a_Dst != NULL); + ASSERT(a_Src != nullptr); + ASSERT(a_Dst != nullptr); ASSERT(a_SrcSizeX > 0); ASSERT(a_SrcSizeY > 0); ASSERT(a_SrcSizeZ > 0); diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index 77e2aaf67..5c7097956 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -280,7 +280,7 @@ cFileListener::cFileListener(void) { cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); AString FileName; - FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(NULL)); + FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(nullptr)); m_File.Open(FileName, cFile::fmAppend); } diff --git a/src/Map.cpp b/src/Map.cpp index c106ccd83..fbde00cf7 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -21,7 +21,7 @@ cMapDecorator::cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, int a , m_PixelX(a_X) , m_PixelZ(a_Z) , m_Rot(a_Rot) - , m_Player(NULL) + , m_Player(nullptr) { } @@ -43,9 +43,9 @@ cMapDecorator::cMapDecorator(cMap * a_Map, cPlayer * a_Player) void cMapDecorator::Update(void) { - if (m_Player != NULL) + if (m_Player != nullptr) { - ASSERT(m_Map != NULL); + ASSERT(m_Map != nullptr); unsigned int PixelWidth = m_Map->GetPixelWidth(); int InsideWidth = (m_Map->GetWidth() / 2) - 1; @@ -221,7 +221,7 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z) virtual bool Item(cChunk * a_Chunk) override { - if (a_Chunk == NULL) + if (a_Chunk == nullptr) { return false; } @@ -322,7 +322,7 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z) } } CalculatePixelCb(this, RelX, RelZ); - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb); SetPixel(a_X, a_Z, CalculatePixelCb.GetPixelData()); @@ -349,7 +349,7 @@ void cMap::UpdateDecorators(void) void cMap::AddPlayer(cPlayer * a_Player, Int64 a_WorldAge) { cClientHandle * Handle = a_Player->GetClientHandle(); - if (Handle == NULL) + if (Handle == nullptr) { return; } @@ -454,10 +454,10 @@ void cMap::StreamNext(cMapClient & a_Client) void cMap::UpdateClient(cPlayer * a_Player) { - ASSERT(a_Player != NULL); + ASSERT(a_Player != nullptr); cClientHandle * Handle = a_Player->GetClientHandle(); - if (Handle == NULL) + if (Handle == nullptr) { return; } @@ -498,7 +498,7 @@ void cMap::EraseData(void) eDimension cMap::GetDimension(void) const { - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); return m_World->GetDimension(); } diff --git a/src/MapManager.cpp b/src/MapManager.cpp index e7df75118..2a3ab192b 100644 --- a/src/MapManager.cpp +++ b/src/MapManager.cpp @@ -15,7 +15,7 @@ cMapManager::cMapManager(cWorld * a_World) : m_World(a_World) { - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); } @@ -27,7 +27,7 @@ bool cMapManager::DoWithMap(int a_ID, cMapCallback & a_Callback) cCSLock Lock(m_CS); cMap * Map = GetMapData(a_ID); - if (Map == NULL) + if (Map == nullptr) { return false; } @@ -68,7 +68,7 @@ cMap * cMapManager::GetMapData(unsigned int a_ID) } else { - return NULL; + return nullptr; } } @@ -83,7 +83,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale) if (m_MapData.size() >= 65536) { LOGWARN("Could not craft map - Too many maps in use"); - return NULL; + return nullptr; } cMap Map((unsigned)m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale); diff --git a/src/MapManager.h b/src/MapManager.h index a40ec2630..2cc6a7bce 100644 --- a/src/MapManager.h +++ b/src/MapManager.h @@ -31,12 +31,12 @@ public: cMapManager(cWorld * a_World); - /** Returns the map with the specified ID, NULL if out of range. + /** Returns the map with the specified ID, nullptr if out of range. WARNING: The returned map object is not thread safe. */ cMap * GetMapData(unsigned int a_ID); - /** Creates a new map. Returns NULL on error */ + /** Creates a new map. Returns nullptr on error */ cMap * CreateMap(int a_CenterX, int a_CenterY, int a_Scale = 3); /** Calls the callback for the map with the specified ID. diff --git a/src/MersenneTwister.h b/src/MersenneTwister.h index 759b8a1ae..e83a470e2 100644 --- a/src/MersenneTwister.h +++ b/src/MersenneTwister.h @@ -19,11 +19,11 @@ // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // Copyright (C) 2000 - 2009, Richard J. Wagner // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: -// +// // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // @@ -31,10 +31,10 @@ // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // -// 3. The names of its contributors may not be used to endorse or promote -// products derived from this software without specific prior written +// 3. The names of its contributors may not be used to endorse or promote +// products derived from this software without specific prior written // permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -63,13 +63,13 @@ class MTRand { // Data public: typedef UInt32 uint32; // unsigned integer type, at least 32 bits - + enum { N = 624 }; // length of state vector enum { SAVE = N + 1 }; // length of array for save() protected: enum { M = 397 }; // period parameter - + uint32 state[N]; // internal state uint32 *pNext; // next value to get from state uint32 left; // number of values left before reload needed @@ -80,11 +80,11 @@ public: MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or array MTRand(); // auto-initialize with /dev/urandom or time() and clock() MTRand( const MTRand& o ); // copy - + // Do NOT use for CRYPTOGRAPHY without securely hashing several returned // values together, otherwise the generator state can be learned after // reading 624 consecutive values. - + // Access to 32-bit random numbers uint32 randInt(); // integer in [0,2^32-1] uint32 randInt( const uint32 n ); // integer in [0,n] for n < 2^32 @@ -95,18 +95,18 @@ public: double randDblExc(); // real number in (0,1) double randDblExc( const double n ); // real number in (0,n) double operator()(); // same as rand() - + // Access to 53-bit random numbers (capacity of IEEE double precision) double rand53(); // real number in [0,1) - + // Access to nonuniform random number distributions double randNorm( const double mean = 0.0, const double stddev = 1.0 ); - + // Re-seeding functions with same behavior as initializers void seed( const uint32 oneSeed ); void seed( uint32 *const bigSeed, const uint32 seedLength = N ); void seed(); - + // Saving and loading generator state void save( uint32* saveArray ) const; // to array of size SAVE void load( uint32 *const loadArray ); // from such array @@ -136,9 +136,9 @@ inline MTRand::uint32 MTRand::hash( time_t t, clock_t c ) // Get a uint32 from t and c // Better than uint32(x) in case x is floating point in [0,1] // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) - + static uint32 differ = 0; // guarantee time-based seeds will change - + uint32 h1 = 0; unsigned char *p = (unsigned char *) &t; for( size_t i = 0; i < sizeof(t); ++i ) @@ -185,7 +185,7 @@ inline void MTRand::reload() for( i = M; --i; ++p ) *p = twist( p[MmN], p[0], p[1] ); *p = twist( p[MmN], p[0], state[0] ); - + left = N, pNext = state; } @@ -207,7 +207,7 @@ inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength ) initialize(19650218UL); uint32 i = 1; uint32 j = 0; - uint32 k = ( (uint32)N > seedLength ? (uint32)N : seedLength ); + uint32 k = ( static_cast<uint32>(N) > seedLength ? static_cast<uint32>(N) : seedLength ); for( ; k; --k ) { state[i] = @@ -235,7 +235,7 @@ inline void MTRand::seed() { // Seed the generator with an array from /dev/urandom if available // Otherwise use a hash of time() and clock() values - + // First try getting an array from /dev/urandom /* // Commented out by FakeTruth because doing this 200 times a tick is SUUUUPEERRR SLOW!!~~!\D5Ne @@ -252,7 +252,7 @@ inline void MTRand::seed() if( success ) { seed( bigSeed, N ); return; } } */ - + // Was not successful, so use time() and clock() instead seed( hash( time(NULL), clock() ) ); } @@ -280,10 +280,10 @@ inline MTRand::uint32 MTRand::randInt() { // Pull a 32-bit integer from the generator state // Every other access function simply transforms the numbers extracted here - + if( left == 0 ) reload(); --left; - + uint32 s1; s1 = *pNext++; s1 ^= (s1 >> 11); @@ -302,7 +302,7 @@ inline MTRand::uint32 MTRand::randInt( const uint32 n ) used |= used >> 4; used |= used >> 8; used |= used >> 16; - + // Draw numbers until one is found in [0,n] uint32 i; do diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index fb73e0b1b..a1d375e9e 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -302,7 +302,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R cMonster* cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int& a_MaxPackSize) { - cMonster* toReturn = NULL; + cMonster* toReturn = nullptr; if (m_NewPack) { m_MobType = ChooseMobType(a_Biome); diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index be2f71f7a..41ef26e2a 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -26,7 +26,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt) { super::InStateChasing(a_Dt); - if (m_Target != NULL) + if (m_Target != nullptr) { if (m_Target->IsPlayer()) { @@ -74,7 +74,7 @@ void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk) CheckEventSeePlayer(); } - if (m_Target == NULL) + if (m_Target == nullptr) return; cTracer LineOfSight(GetWorld()); @@ -95,7 +95,7 @@ void cAggressiveMonster::Attack(float a_Dt) { m_AttackInterval += a_Dt * m_AttackRate; - if ((m_Target == NULL) || (m_AttackInterval < 3.0)) + if ((m_Target == nullptr) || (m_AttackInterval < 3.0)) { return; } diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index b4104d530..16869c79d 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -19,7 +19,7 @@ cBlaze::cBlaze(void) : void cBlaze::GetDrops(cItems & a_Drops, cEntity * a_Killer) { - if ((a_Killer != NULL) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf"))) + if ((a_Killer != nullptr) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf"))) { int LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_BLAZE_ROD); @@ -34,20 +34,20 @@ void cBlaze::Attack(float a_Dt) { m_AttackInterval += a_Dt * m_AttackRate; - if (m_Target != NULL && m_AttackInterval > 3.0) + if (m_Target != nullptr && m_AttackInterval > 3.0) { // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; cFireChargeEntity * FireCharge = new cFireChargeEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (FireCharge == NULL) + if (FireCharge == nullptr) { return; } if (!FireCharge->Initialize(*m_World)) { delete FireCharge; - FireCharge = NULL; + FireCharge = nullptr; return; } m_World->BroadcastSpawnEntity(*FireCharge); diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h index f283b1070..e2a4ad9f1 100644 --- a/src/Mobs/Blaze.h +++ b/src/Mobs/Blaze.h @@ -17,6 +17,6 @@ public: CLASS_PROTODEF(cBlaze) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void Attack(float a_Dt) override; } ; diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt index 2c092c15f..bbbb9287a 100644 --- a/src/Mobs/CMakeLists.txt +++ b/src/Mobs/CMakeLists.txt @@ -54,6 +54,7 @@ SET (HDRS IronGolem.h MagmaCube.h Monster.h + MonsterTypes.h Mooshroom.h Ocelot.h PassiveAggressiveMonster.h diff --git a/src/Mobs/CaveSpider.cpp b/src/Mobs/CaveSpider.cpp index 118a6e93b..045b47e73 100644 --- a/src/Mobs/CaveSpider.cpp +++ b/src/Mobs/CaveSpider.cpp @@ -45,12 +45,12 @@ void cCaveSpider::Attack(float a_Dt) void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STRING); - if ((a_Killer != NULL) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf"))) + if ((a_Killer != nullptr) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf"))) { AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_SPIDER_EYE); } diff --git a/src/Mobs/CaveSpider.h b/src/Mobs/CaveSpider.h index f9ed10e1b..494ba1360 100644 --- a/src/Mobs/CaveSpider.h +++ b/src/Mobs/CaveSpider.h @@ -18,7 +18,7 @@ public: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Attack(float a_Dt) override; - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; diff --git a/src/Mobs/Chicken.cpp b/src/Mobs/Chicken.cpp index f7e44238f..634867cfa 100644 --- a/src/Mobs/Chicken.cpp +++ b/src/Mobs/Chicken.cpp @@ -49,7 +49,7 @@ void cChicken::Tick(float a_Dt, cChunk & a_Chunk) void cChicken::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Chicken.h b/src/Mobs/Chicken.h index b1a50b61c..07b921884 100644 --- a/src/Mobs/Chicken.h +++ b/src/Mobs/Chicken.h @@ -16,7 +16,7 @@ public: CLASS_PROTODEF(cChicken) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_SEEDS); } diff --git a/src/Mobs/Cow.cpp b/src/Mobs/Cow.cpp index 9914df6b5..7dc6f3f37 100644 --- a/src/Mobs/Cow.cpp +++ b/src/Mobs/Cow.cpp @@ -22,7 +22,7 @@ cCow::cCow(void) : void cCow::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Cow.h b/src/Mobs/Cow.h index 8814b7e09..ee1a4fafe 100644 --- a/src/Mobs/Cow.h +++ b/src/Mobs/Cow.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cCow) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); } diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp index 02718edf8..a073224cf 100644 --- a/src/Mobs/Creeper.cpp +++ b/src/Mobs/Creeper.cpp @@ -61,13 +61,13 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer) } int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER); - if ((a_Killer != NULL) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0)) + if ((a_Killer != nullptr) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0)) { class cProjectileCreatorCallback : public cEntityCallback { diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h index 747daca09..bf3272e22 100644 --- a/src/Mobs/Creeper.h +++ b/src/Mobs/Creeper.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cCreeper) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Attack(float a_Dt) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/src/Mobs/EnderDragon.h b/src/Mobs/EnderDragon.h index 1d4cd657c..e4ca9dcf9 100644 --- a/src/Mobs/EnderDragon.h +++ b/src/Mobs/EnderDragon.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cEnderDragon) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 51255beb3..56ea10245 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -15,7 +15,7 @@ class cPlayerLookCheck : { public: cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) : - m_Player(NULL), + m_Player(nullptr), m_EndermanPos(a_EndermanPos), m_SightDistance(a_SightDistance) { @@ -92,7 +92,7 @@ cEnderman::cEnderman(void) : void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } @@ -104,7 +104,7 @@ void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cEnderman::CheckEventSeePlayer() { - if (m_Target != NULL) + if (m_Target != nullptr) { return; } @@ -115,7 +115,7 @@ void cEnderman::CheckEventSeePlayer() return; } - ASSERT(Callback.GetPlayer() != NULL); + ASSERT(Callback.GetPlayer() != nullptr); if (!CheckLight()) { @@ -181,3 +181,23 @@ bool cEnderman::CheckLight() return true; } + + + + + +void cEnderman::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + + // TODO take damage in rain + + // Take damage when touching water, drowning damage seems to be most appropriate + if (IsSwimming()) + { + EventLosePlayer(); + TakeDamage(dtDrowning, nullptr, 1, 0); + // TODO teleport to a safe location + } + +} diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h index 4583746e7..28bbceb84 100644 --- a/src/Mobs/Enderman.h +++ b/src/Mobs/Enderman.h @@ -17,10 +17,11 @@ public: CLASS_PROTODEF(cEnderman) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void CheckEventSeePlayer(void) override; virtual void CheckEventLostPlayer(void) override; virtual void EventLosePlayer(void) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; bool IsScreaming(void) const {return m_bIsScreaming; } BLOCKTYPE GetCarriedBlock(void) const {return CarriedBlock; } diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index 6aac14779..c65c0d29a 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -20,7 +20,7 @@ cGhast::cGhast(void) : void cGhast::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } @@ -36,20 +36,20 @@ void cGhast::Attack(float a_Dt) { m_AttackInterval += a_Dt * m_AttackRate; - if (m_Target != NULL && m_AttackInterval > 3.0) + if (m_Target != nullptr && m_AttackInterval > 3.0) { // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; cGhastFireballEntity * GhastBall = new cGhastFireballEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (GhastBall == NULL) + if (GhastBall == nullptr) { return; } if (!GhastBall->Initialize(*m_World)) { delete GhastBall; - GhastBall = NULL; + GhastBall = nullptr; return; } m_World->BroadcastSpawnEntity(*GhastBall); diff --git a/src/Mobs/Ghast.h b/src/Mobs/Ghast.h index 1d4e6b94a..a28940a01 100644 --- a/src/Mobs/Ghast.h +++ b/src/Mobs/Ghast.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cGhast) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void Attack(float a_Dt) override; bool IsCharging(void) const {return false; } diff --git a/src/Mobs/Giant.h b/src/Mobs/Giant.h index 7c04c9b4f..8d3060940 100644 --- a/src/Mobs/Giant.h +++ b/src/Mobs/Giant.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cGiant) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; diff --git a/src/Mobs/Horse.cpp b/src/Mobs/Horse.cpp index 67a09d4ab..d92f0d023 100644 --- a/src/Mobs/Horse.cpp +++ b/src/Mobs/Horse.cpp @@ -49,7 +49,7 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk) } } - if ((m_Attachee != NULL) && (!m_bIsTame)) + if ((m_Attachee != nullptr) && (!m_bIsTame)) { if (m_TameAttemptTimes < m_TimesToTame) { @@ -113,7 +113,7 @@ void cHorse::OnRightClicked(cPlayer & a_Player) } else { - if (m_Attachee != NULL) + if (m_Attachee != nullptr) { if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) { @@ -141,7 +141,7 @@ void cHorse::OnRightClicked(cPlayer & a_Player) void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Horse.h b/src/Mobs/Horse.h index 47189b3b0..4c644e512 100644 --- a/src/Mobs/Horse.h +++ b/src/Mobs/Horse.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cHorse) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void OnRightClicked(cPlayer & a_Player) override; diff --git a/src/Mobs/IronGolem.h b/src/Mobs/IronGolem.h index c5341ed76..721ca2701 100644 --- a/src/Mobs/IronGolem.h +++ b/src/Mobs/IronGolem.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cIronGolem) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; // Iron golems do not drown nor float virtual void HandleAir(void) override {} diff --git a/src/Mobs/MagmaCube.h b/src/Mobs/MagmaCube.h index bfe63fa2e..d66ea423a 100644 --- a/src/Mobs/MagmaCube.h +++ b/src/Mobs/MagmaCube.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cMagmaCube) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; int GetSize(void) const { return m_Size; } protected: diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 12ca6bbbe..23b4d9f45 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -62,6 +62,16 @@ static const struct +eMonsterType StringToMobType(const AString & a_MobString) +{ + LOGWARNING("%s: Function is obsolete, use cMonster::StringToMobType() instead", __FUNCTION__); + return cMonster::StringToMobType(a_MobString); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cMonster: @@ -69,7 +79,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A : super(etMonster, a_Width, a_Height) , m_EMState(IDLE) , m_EMPersonality(AGGRESSIVE) - , m_Target(NULL) + , m_Target(nullptr) , m_bMovingToDestination(false) , m_LastGroundHeight(POSY_TOINT) , m_IdleInterval(0) @@ -264,8 +274,8 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) return; } - if ((m_Target != NULL) && m_Target->IsDestroyed()) - m_Target = NULL; + if ((m_Target != nullptr) && m_Target->IsDestroyed()) + m_Target = nullptr; // Burning in daylight HandleDaylightBurning(a_Chunk); @@ -369,7 +379,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) void cMonster::SetPitchAndYawFromDestination() { Vector3d FinalDestination = m_FinalDestination; - if (m_Target != NULL) + if (m_Target != nullptr) { if (m_Target->IsPlayer()) { @@ -413,7 +423,7 @@ void cMonster::HandleFalling() if (Damage > 0) { - TakeDamage(dtFalling, NULL, Damage, Damage, 0); + TakeDamage(dtFalling, nullptr, Damage, Damage, 0); // Fall particles GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */); @@ -469,7 +479,7 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI) m_World->BroadcastSoundEffect(m_SoundHurt, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f); } - if (a_TDI.Attacker != NULL) + if (a_TDI.Attacker != nullptr) { m_Target = a_TDI.Attacker; } @@ -546,7 +556,7 @@ void cMonster::KilledBy(TakeDamageInfo & a_TDI) break; } } - if ((a_TDI.Attacker != NULL) && (!IsBaby())) + if ((a_TDI.Attacker != nullptr) && (!IsBaby())) { m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward); } @@ -583,7 +593,7 @@ void cMonster::CheckEventSeePlayer(void) // TODO: Rewrite this to use cWorld's DoWithPlayers() cPlayer * Closest = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance, false); - if (Closest != NULL) + if (Closest != nullptr) { EventSeePlayer(Closest); } @@ -595,7 +605,7 @@ void cMonster::CheckEventSeePlayer(void) void cMonster::CheckEventLostPlayer(void) { - if (m_Target != NULL) + if (m_Target != nullptr) { if ((m_Target->GetPosition() - GetPosition()).Length() > m_SightDistance) { @@ -625,7 +635,7 @@ void cMonster::EventSeePlayer(cEntity * a_SeenPlayer) void cMonster::EventLosePlayer(void) { - m_Target = NULL; + m_Target = nullptr; m_EMState = IDLE; } @@ -687,7 +697,7 @@ void cMonster::InStateEscaping(float a_Dt) { UNUSED(a_Dt); - if (m_Target != NULL) + if (m_Target != nullptr) { Vector3d newloc = GetPosition(); newloc.x = (m_Target->GetPosition().x < newloc.x)? (newloc.x + m_SightDistance): (newloc.x - m_SightDistance); @@ -714,7 +724,7 @@ void cMonster::SetCustomName(const AString & a_CustomName) m_CustomName = a_CustomName.substr(0, 64); } - if (m_World != NULL) + if (m_World != nullptr) { m_World->BroadcastEntityMetadata(*this); } @@ -727,7 +737,7 @@ void cMonster::SetCustomName(const AString & a_CustomName) void cMonster::SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible) { m_CustomNameAlwaysVisible = a_CustomNameAlwaysVisible; - if (m_World != NULL) + if (m_World != nullptr) { m_World->BroadcastEntityMetadata(*this); } @@ -883,7 +893,7 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily) cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) { cFastRandom Random; - cMonster * toReturn = NULL; + cMonster * toReturn = nullptr; // Create the mob entity switch (a_MobType) diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 0fa620b3a..96c2a6bdd 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -25,9 +25,6 @@ class cMonster : typedef cPawn super; public: - //Depreciated - typedef eMonsterType eType; - enum eFamily { mfHostile = 0, // Spider, Zombies ... @@ -38,12 +35,12 @@ public: mfNoSpawn, mfUnhandled, // Nothing. Be sure this is the last and the others are in order } ; - + // tolua_end - + enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState; enum MPersonality{PASSIVE, AGGRESSIVE, COWARDLY} m_EMPersonality; - + /** Creates the mob object. If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig() a_MobType is the type of the mob (also used in the protocol ( http://wiki.vg/Entities#Mobs 2012_12_22)) @@ -52,47 +49,47 @@ public: cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); CLASS_PROTODEF(cMonster) - + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; - + virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export virtual bool ReachedDestination(void); - + // tolua_begin eMonsterType GetMobType(void) const { return m_MobType; } eFamily GetMobFamily(void) const; // tolua_end - + virtual void CheckEventSeePlayer(void); virtual void EventSeePlayer(cEntity * a_Player); - + /// Reads the monster configuration for the specified monster name and assigns it to this object. void GetMonsterConfig(const AString & a_Name); - + /** Returns whether this mob is undead (skeleton, zombie, etc.) */ virtual bool IsUndead(void); - + virtual void EventLosePlayer(void); virtual void CheckEventLostPlayer(void); - + virtual void InStateIdle (float a_Dt); virtual void InStateChasing (float a_Dt); virtual void InStateEscaping(float a_Dt); - - int GetAttackRate() { return (int)m_AttackRate; } + + int GetAttackRate() { return static_cast<int>(m_AttackRate); } void SetAttackRate(float a_AttackRate) { m_AttackRate = a_AttackRate; } void SetAttackRange(int a_AttackRange) { m_AttackRange = a_AttackRange; } void SetAttackDamage(int a_AttackDamage) { m_AttackDamage = a_AttackDamage; } void SetSightDistance(int a_SightDistance) { m_SightDistance = a_SightDistance; } - + float GetDropChanceWeapon() { return m_DropChanceWeapon; } float GetDropChanceHelmet() { return m_DropChanceHelmet; } float GetDropChanceChestplate() { return m_DropChanceChestplate; } @@ -105,7 +102,7 @@ public: void SetDropChanceLeggings(float a_DropChanceLeggings) { m_DropChanceLeggings = a_DropChanceLeggings; } void SetDropChanceBoots(float a_DropChanceBoots) { m_DropChanceBoots = a_DropChanceBoots; } void SetCanPickUpLoot(bool a_CanPickUpLoot) { m_CanPickUpLoot = a_CanPickUpLoot; } - + /// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; } @@ -116,7 +113,7 @@ public: virtual bool IsBaby (void) const { return false; } virtual bool IsTame (void) const { return false; } virtual bool IsSitting (void) const { return false; } - + // tolua_begin /** Returns true if the monster has a custom name. */ @@ -138,10 +135,10 @@ public: /// Translates MobType enum to a string, empty string if unknown static AString MobTypeToString(eMonsterType a_MobType); - + /// Translates MobType string to the enum, mtInvalidType if not recognized static eMonsterType StringToMobType(const AString & a_MobTypeName); - + /// Returns the mob family based on the type static eFamily FamilyFromType(eMonsterType a_MobType); @@ -149,7 +146,7 @@ public: static int GetSpawnDelay(cMonster::eFamily a_MobFamily); // tolua_end - + /** Creates a new object of the specified mob. a_MobType is the type of the mob to be created Asserts and returns null if mob type is not specified @@ -157,7 +154,7 @@ public: static cMonster * NewMonsterFromType(eMonsterType a_MobType); protected: - + /* ======= PATHFINDING ======= */ /** A pointer to the entity this mobile is aiming to reach */ @@ -171,7 +168,7 @@ protected: /** Stores if mobile is currently moving towards the ultimate, final destination */ bool m_bMovingToDestination; - + /** Finds the first non-air block position (not the highest, as cWorld::GetHeight does) If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1 If current Y is solid, goes up to find first nonsolid block, and returns that */ @@ -230,14 +227,14 @@ protected: int m_AttackRange; float m_AttackInterval; int m_SightDistance; - + float m_DropChanceWeapon; float m_DropChanceHelmet; float m_DropChanceChestplate; float m_DropChanceLeggings; float m_DropChanceBoots; bool m_CanPickUpLoot; - + void HandleDaylightBurning(cChunk & a_Chunk); bool m_BurnsInDaylight; @@ -245,22 +242,18 @@ protected: /** Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops*/ void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0); - + /** Adds a item a_Item with the chance of a_Chance (in percent) to itemdrops a_Drops*/ void AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth = 0); - + /** Adds one rare item out of the list of rare items a_Items modified by the looting level a_LootingLevel(I-III or custom) to the itemdrop a_Drops*/ void AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a_LootingLevel); - + /** Adds armor that is equipped with the chance saved in m_DropChance[...] (this will be greter than 1 if piccked up or 0.085 + (0.01 per LootingLevel) if born with) to the drop*/ void AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel); - + /** Adds weapon that is equipped with the chance saved in m_DropChance[...] (this will be greter than 1 if piccked up or 0.085 + (0.01 per LootingLevel) if born with) to the drop*/ void AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel); - - -} ; // tolua_export - - +} ; // tolua_export diff --git a/src/Mobs/MonsterTypes.h b/src/Mobs/MonsterTypes.h index 7a73e99f4..852eb3446 100644 --- a/src/Mobs/MonsterTypes.h +++ b/src/Mobs/MonsterTypes.h @@ -37,5 +37,18 @@ enum eMonsterType mtZombie = E_META_SPAWN_EGG_ZOMBIE, mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN, } ; + + + + + +/** Translates a mob string ("ocelot") to mobtype (mtOcelot). +OBSOLETE, use cMonster::StringToMobType() instead. +Implemented in Monster.cpp. */ +extern eMonsterType StringToMobType(const AString & a_MobString); + // tolua_end + + + diff --git a/src/Mobs/Mooshroom.cpp b/src/Mobs/Mooshroom.cpp index 99958720f..ec533cfca 100644 --- a/src/Mobs/Mooshroom.cpp +++ b/src/Mobs/Mooshroom.cpp @@ -25,7 +25,7 @@ cMooshroom::cMooshroom(void) : void cMooshroom::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Mooshroom.h b/src/Mobs/Mooshroom.h index fb002c2bf..754725c92 100644 --- a/src/Mobs/Mooshroom.h +++ b/src/Mobs/Mooshroom.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cMooshroom) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); } diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp index e0cc2fd21..cb8650cb9 100644 --- a/src/Mobs/PassiveAggressiveMonster.cpp +++ b/src/Mobs/PassiveAggressiveMonster.cpp @@ -26,7 +26,7 @@ bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) return false; } - if ((m_Target != NULL) && (m_Target->IsPlayer())) + if ((m_Target != nullptr) && (m_Target->IsPlayer())) { if (!((cPlayer *)m_Target)->IsGameModeCreative()) { diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp index be3043e3d..1048616d0 100644 --- a/src/Mobs/PassiveMonster.cpp +++ b/src/Mobs/PassiveMonster.cpp @@ -24,7 +24,7 @@ bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { return false; } - if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL)) + if ((a_TDI.Attacker != this) && (a_TDI.Attacker != nullptr)) { m_EMState = ESCAPING; } @@ -49,7 +49,7 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk) return; } cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance); - if (a_Closest_Player != NULL) + if (a_Closest_Player != nullptr) { if (a_Closest_Player->GetEquippedItem().IsEqual(FollowedItem)) { diff --git a/src/Mobs/Pig.cpp b/src/Mobs/Pig.cpp index 1f77cf613..55a4412ca 100644 --- a/src/Mobs/Pig.cpp +++ b/src/Mobs/Pig.cpp @@ -22,7 +22,7 @@ cPig::cPig(void) : void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } @@ -41,7 +41,7 @@ void cPig::OnRightClicked(cPlayer & a_Player) { if (m_bIsSaddled) { - if (m_Attachee != NULL) + if (m_Attachee != nullptr) { if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) { @@ -85,7 +85,7 @@ void cPig::Tick(float a_Dt, cChunk & a_Chunk) super::Tick(a_Dt, a_Chunk); // If the attachee player is holding a carrot-on-stick, let them drive this pig: - if (m_bIsSaddled && (m_Attachee != NULL)) + if (m_bIsSaddled && (m_Attachee != nullptr)) { if (m_Attachee->IsPlayer() && (m_Attachee->GetEquippedWeapon().m_ItemType == E_ITEM_CARROT_ON_STICK)) { diff --git a/src/Mobs/Pig.h b/src/Mobs/Pig.h index 534a0ca6f..953850b3a 100644 --- a/src/Mobs/Pig.h +++ b/src/Mobs/Pig.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cPig) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp index cbb33cb90..c46404391 100644 --- a/src/Mobs/Sheep.cpp +++ b/src/Mobs/Sheep.cpp @@ -41,7 +41,7 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer) } int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Sheep.h b/src/Mobs/Sheep.h index 28e1c7254..16d5fddd3 100644 --- a/src/Mobs/Sheep.h +++ b/src/Mobs/Sheep.h @@ -22,7 +22,7 @@ public: CLASS_PROTODEF(cSheep) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index cd707f4bb..f17bc307c 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -23,7 +23,7 @@ cSkeleton::cSkeleton(bool IsWither) : void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } @@ -71,20 +71,20 @@ void cSkeleton::Attack(float a_Dt) { m_AttackInterval += a_Dt * m_AttackRate; - if (m_Target != NULL && m_AttackInterval > 3.0) + if (m_Target != nullptr && m_AttackInterval > 3.0) { // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; cArrowEntity * Arrow = new cArrowEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (Arrow == NULL) + if (Arrow == nullptr) { return; } if (!Arrow->Initialize(*m_World)) { delete Arrow; - Arrow = NULL; + Arrow = nullptr; return; } m_World->BroadcastSpawnEntity(*Arrow); diff --git a/src/Mobs/Skeleton.h b/src/Mobs/Skeleton.h index 577588b32..cd1c6c3f0 100644 --- a/src/Mobs/Skeleton.h +++ b/src/Mobs/Skeleton.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cSkeleton) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void MoveToPosition(const Vector3d & a_Position) override; virtual void Attack(float a_Dt) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; diff --git a/src/Mobs/Slime.cpp b/src/Mobs/Slime.cpp index b709ec664..1c68c5189 100644 --- a/src/Mobs/Slime.cpp +++ b/src/Mobs/Slime.cpp @@ -30,7 +30,7 @@ cSlime::cSlime(int a_Size) : void cSlime::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Slime.h b/src/Mobs/Slime.h index f0b800f94..a177a279c 100644 --- a/src/Mobs/Slime.h +++ b/src/Mobs/Slime.h @@ -19,7 +19,7 @@ public: CLASS_PROTODEF(cSlime) // cAggressiveMonster overrides: - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void Attack(float a_Dt) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override; diff --git a/src/Mobs/SnowGolem.h b/src/Mobs/SnowGolem.h index aba89e52d..f036b1867 100644 --- a/src/Mobs/SnowGolem.h +++ b/src/Mobs/SnowGolem.h @@ -18,7 +18,7 @@ public: CLASS_PROTODEF(cSnowGolem) virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; diff --git a/src/Mobs/Spider.cpp b/src/Mobs/Spider.cpp index 8b978ff6b..deb263c41 100644 --- a/src/Mobs/Spider.cpp +++ b/src/Mobs/Spider.cpp @@ -19,12 +19,12 @@ cSpider::cSpider(void) : void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STRING); - if ((a_Killer != NULL) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf"))) + if ((a_Killer != nullptr) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf"))) { AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_SPIDER_EYE); } diff --git a/src/Mobs/Spider.h b/src/Mobs/Spider.h index 813d2e266..24134c00f 100644 --- a/src/Mobs/Spider.h +++ b/src/Mobs/Spider.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cSpider) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; } ; diff --git a/src/Mobs/Squid.cpp b/src/Mobs/Squid.cpp index bd0e141a0..59ee963ae 100644 --- a/src/Mobs/Squid.cpp +++ b/src/Mobs/Squid.cpp @@ -22,7 +22,7 @@ void cSquid::GetDrops(cItems & a_Drops, cEntity * a_Killer) { // Drops 0-3 Ink Sacs int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Squid.h b/src/Mobs/Squid.h index b57340427..a46d738c6 100644 --- a/src/Mobs/Squid.h +++ b/src/Mobs/Squid.h @@ -19,7 +19,7 @@ public: CLASS_PROTODEF(cSquid) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; // Squids do not drown (or float) virtual void HandleAir(void) override {} diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp index 0efd5501e..5c9999a59 100644 --- a/src/Mobs/Villager.cpp +++ b/src/Mobs/Villager.cpp @@ -30,7 +30,7 @@ bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) return false; } - if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer()) + if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPlayer()) { if (m_World->GetTickRandomNumber(5) == 3) { diff --git a/src/Mobs/Witch.cpp b/src/Mobs/Witch.cpp index 6956f7b7a..747a11f97 100644 --- a/src/Mobs/Witch.cpp +++ b/src/Mobs/Witch.cpp @@ -19,7 +19,7 @@ cWitch::cWitch(void) : void cWitch::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Witch.h b/src/Mobs/Witch.h index bd059f61d..03691fef1 100644 --- a/src/Mobs/Witch.h +++ b/src/Mobs/Witch.h @@ -18,7 +18,7 @@ public: CLASS_PROTODEF(cWitch) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; bool IsAngry(void) const {return ((m_EMState == ATTACKING) || (m_EMState == CHASING)); } } ; diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index 2403823ed..a20fed3d3 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -26,7 +26,7 @@ public: // cEntity overrides virtual bool Initialize(cWorld & a_World) override; - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override; diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index 4fe1ff1d6..4711d5a7a 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -47,7 +47,7 @@ void cWolf::Attack(float a_Dt) { UNUSED(a_Dt); - if ((m_Target != NULL) && (m_Target->IsPlayer())) + if ((m_Target != nullptr) && (m_Target->IsPlayer())) { if (((cPlayer *)m_Target)->GetName() != m_OwnerName) { @@ -157,7 +157,7 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk) } cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance); - if (a_Closest_Player != NULL) + if (a_Closest_Player != nullptr) { switch (a_Closest_Player->GetEquippedItem().m_ItemType) { diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp index 30225c32d..63042e252 100644 --- a/src/Mobs/Zombie.cpp +++ b/src/Mobs/Zombie.cpp @@ -24,7 +24,7 @@ cZombie::cZombie(bool a_IsVillagerZombie) : void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } diff --git a/src/Mobs/Zombie.h b/src/Mobs/Zombie.h index 118b6e6e7..809c2a6fe 100644 --- a/src/Mobs/Zombie.h +++ b/src/Mobs/Zombie.h @@ -16,7 +16,7 @@ public: CLASS_PROTODEF(cZombie) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void MoveToPosition(const Vector3d & a_Position) override; virtual bool IsUndead(void) override { return true; } diff --git a/src/Mobs/ZombiePigman.cpp b/src/Mobs/ZombiePigman.cpp index 05350f877..8b415b0af 100644 --- a/src/Mobs/ZombiePigman.cpp +++ b/src/Mobs/ZombiePigman.cpp @@ -19,7 +19,7 @@ cZombiePigman::cZombiePigman(void) : void cZombiePigman::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; - if (a_Killer != NULL) + if (a_Killer != nullptr) { LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting); } @@ -41,7 +41,7 @@ void cZombiePigman::KilledBy(TakeDamageInfo & a_TDI) { super::KilledBy(a_TDI); - if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + if ((a_TDI.Attacker != nullptr) && (a_TDI.Attacker->IsPlayer())) { // TODO: Anger all nearby zombie pigmen // TODO: In vanilla, if one player angers ZPs, do they attack any nearby player, or only that one attacker? diff --git a/src/Mobs/ZombiePigman.h b/src/Mobs/ZombiePigman.h index bae0115eb..d8b886ca4 100644 --- a/src/Mobs/ZombiePigman.h +++ b/src/Mobs/ZombiePigman.h @@ -16,7 +16,7 @@ public: CLASS_PROTODEF(cZombiePigman) - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual bool IsUndead(void) override { return true; } diff --git a/src/MonsterConfig.cpp b/src/MonsterConfig.cpp index f5e078213..ae2cbbc6b 100644 --- a/src/MonsterConfig.cpp +++ b/src/MonsterConfig.cpp @@ -3,7 +3,7 @@ #include "MonsterConfig.h" #include "Mobs/Monster.h" -#include "inifile/iniFile.h" +#include "IniFile.h" @@ -47,7 +47,7 @@ cMonsterConfig::cMonsterConfig(void) cMonsterConfig::~cMonsterConfig() { delete m_pState; - m_pState = NULL; + m_pState = nullptr; } diff --git a/src/Noise.cpp b/src/Noise.cpp index 71e801f30..8fcfe2920 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -845,7 +845,7 @@ void cPerlinNoise::Generate2D( return; } - bool ShouldFreeWorkspace = (a_Workspace == NULL); + bool ShouldFreeWorkspace = (a_Workspace == nullptr); int ArrayCount = a_SizeX * a_SizeY; if (ShouldFreeWorkspace) { @@ -886,7 +886,7 @@ void cPerlinNoise::Generate2D( if (ShouldFreeWorkspace) { delete[] a_Workspace; - a_Workspace = NULL; + a_Workspace = nullptr; } } @@ -910,7 +910,7 @@ void cPerlinNoise::Generate3D( return; } - bool ShouldFreeWorkspace = (a_Workspace == NULL); + bool ShouldFreeWorkspace = (a_Workspace == nullptr); int ArrayCount = a_SizeX * a_SizeY * a_SizeZ; if (ShouldFreeWorkspace) { @@ -953,7 +953,7 @@ void cPerlinNoise::Generate3D( if (ShouldFreeWorkspace) { delete[] a_Workspace; - a_Workspace = NULL; + a_Workspace = nullptr; } } @@ -1015,7 +1015,7 @@ void cRidgedMultiNoise::Generate2D( return; } - bool ShouldFreeWorkspace = (a_Workspace == NULL); + bool ShouldFreeWorkspace = (a_Workspace == nullptr); int ArrayCount = a_SizeX * a_SizeY; if (ShouldFreeWorkspace) { @@ -1056,7 +1056,7 @@ void cRidgedMultiNoise::Generate2D( if (ShouldFreeWorkspace) { delete[] a_Workspace; - a_Workspace = NULL; + a_Workspace = nullptr; } } @@ -1080,7 +1080,7 @@ void cRidgedMultiNoise::Generate3D( return; } - bool ShouldFreeWorkspace = (a_Workspace == NULL); + bool ShouldFreeWorkspace = (a_Workspace == nullptr); int ArrayCount = a_SizeX * a_SizeY * a_SizeZ; if (ShouldFreeWorkspace) { @@ -1123,7 +1123,7 @@ void cRidgedMultiNoise::Generate3D( if (ShouldFreeWorkspace) { delete[] a_Workspace; - a_Workspace = NULL; + a_Workspace = nullptr; } } diff --git a/src/Noise.h b/src/Noise.h index 4cf8d4ad8..b7a90d5b7 100644 --- a/src/Noise.h +++ b/src/Noise.h @@ -155,7 +155,7 @@ public: NOISE_DATATYPE * a_Array, ///< Array to generate into int a_SizeX, ///< Count of the array NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash + NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash ) const; @@ -164,7 +164,7 @@ public: int a_SizeX, int a_SizeY, ///< Count of the array, in each direction NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash + NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash ) const; @@ -174,7 +174,7 @@ public: NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ, ///< Noise-space coords of the array in the Z direction - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash + NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash ) const; protected: @@ -219,7 +219,7 @@ public: NOISE_DATATYPE * a_Array, ///< Array to generate into int a_SizeX, ///< Count of the array NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash + NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash ) const; @@ -228,7 +228,7 @@ public: int a_SizeX, int a_SizeY, ///< Count of the array, in each direction NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash + NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash ) const; @@ -238,7 +238,7 @@ public: NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ, ///< Noise-space coords of the array in the Z direction - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash + NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash ) const; protected: diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index a42fcbed4..c3eabeef6 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -39,6 +39,10 @@ if(NOT MSVC) add_library(OSSupport ${SRCS} ${HDRS}) if(UNIX) + if(NOT APPLE) + target_link_libraries(OSSupport rt) + endif() + target_link_libraries(OSSupport pthread) endif() endif() diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp index 9401ec257..a5361e1a6 100644 --- a/src/OSSupport/Errors.cpp +++ b/src/OSSupport/Errors.cpp @@ -10,7 +10,7 @@ AString GetOSErrorString( int a_ErrNo) #ifdef _WIN32 - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), NULL); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), nullptr); Printf(Out, "%d: %s", a_ErrNo, buffer); if (!Out.empty() && (Out[Out.length() - 1] == '\n')) { @@ -25,7 +25,7 @@ AString GetOSErrorString( int a_ErrNo) #if !defined(__APPLE__) && ( _GNU_SOURCE) && !defined(ANDROID_NDK) // GNU version of strerror_r() char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer)); - if (res != NULL) + if (res != nullptr) { Printf(Out, "%d: %s", a_ErrNo, res); return Out; diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp index 74f823216..87bc110ce 100644 --- a/src/OSSupport/Event.cpp +++ b/src/OSSupport/Event.cpp @@ -15,8 +15,8 @@ cEvent::cEvent(void) { #ifdef _WIN32 - m_Event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (m_Event == NULL) + m_Event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (m_Event == nullptr) { LOGERROR("cEvent: cannot create event, GLE = %u. Aborting server.", (unsigned)GetLastError()); abort(); @@ -71,7 +71,7 @@ cEvent::~cEvent() { sem_destroy(m_Event); delete m_Event; - m_Event = NULL; + m_Event = nullptr; } #endif } @@ -102,6 +102,53 @@ void cEvent::Wait(void) +bool cEvent::Wait(int a_TimeoutMSec) +{ + #ifdef _WIN32 + DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMSec); + switch (res) + { + case WAIT_OBJECT_0: return true; // Regular event signalled + case WAIT_TIMEOUT: return false; // Regular event timeout + default: + { + LOGWARN("cEvent: waiting for the event failed: %u, GLE = %u. Continuing, but server may be unstable.", (unsigned)res, (unsigned)GetLastError()); + return false; + } + } + #else + // Get the current time: + timespec timeout; + if (clock_gettime(CLOCK_REALTIME, &timeout) == -1) + { + LOGWARN("cEvent: Getting current time failed: %i, err = %s. Continuing, but the server may be unstable.", errno, GetOSErrorString(errno).c_str()); + return false; + } + + // Add the specified timeout: + timeout.tv_sec += a_TimeoutMSec / 1000; + timeout.tv_nsec += (a_TimeoutMSec % 1000) * 1000000; // 1 msec = 1000000 usec + + // Wait with timeout: + int res = sem_timedwait(m_Event, &timeout); + switch (res) + { + case 0: return true; // Regular event signalled + case ETIMEDOUT: return false; // Regular even timeout + default: + { + AString error = GetOSErrorString(errno); + LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str()); + return false; + } + } + #endif +} + + + + + void cEvent::Set(void) { #ifdef _WIN32 diff --git a/src/OSSupport/Event.h b/src/OSSupport/Event.h index 71f418c0c..e2fa65a05 100644 --- a/src/OSSupport/Event.h +++ b/src/OSSupport/Event.h @@ -24,6 +24,10 @@ public: void Wait(void); void Set (void); + + /** Waits for the event until either it is signalled, or the (relative) timeout is passed. + Returns true if the event was signalled, false if the timeout was hit or there was an error. */ + bool Wait(int a_TimeoutMSec); private: diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index cb6031da6..8957dfaef 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -17,7 +17,7 @@ cFile::cFile(void) : #ifdef USE_STDIO_FILE - m_File(NULL) + m_File(nullptr) #else m_File(INVALID_HANDLE_VALUE) #endif // USE_STDIO_FILE @@ -31,7 +31,7 @@ cFile::cFile(void) : cFile::cFile(const AString & iFileName, eMode iMode) : #ifdef USE_STDIO_FILE - m_File(NULL) + m_File(nullptr) #else m_File(INVALID_HANDLE_VALUE) #endif // USE_STDIO_FILE @@ -64,7 +64,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) Close(); } - const char * Mode = NULL; + const char * Mode = nullptr; switch (iMode) { case fmRead: Mode = "rb"; break; @@ -72,7 +72,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) case fmReadWrite: Mode = "rb+"; break; case fmAppend: Mode = "a+"; break; } - if (Mode == NULL) + if (Mode == nullptr) { ASSERT(!"Unhandled file mode"); return false; @@ -84,7 +84,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode); #endif // _WIN32 - if ((m_File == NULL) && (iMode == fmReadWrite)) + if ((m_File == nullptr) && (iMode == fmReadWrite)) { // Fix for MS not following C spec, opening "a" mode files for writing at the end only // The file open operation has been tried with "read update", fails if file not found @@ -98,7 +98,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) #endif // _WIN32 } - return (m_File != NULL); + return (m_File != nullptr); } @@ -114,7 +114,7 @@ void cFile::Close(void) } fclose(m_File); - m_File = NULL; + m_File = nullptr; } @@ -123,7 +123,7 @@ void cFile::Close(void) bool cFile::IsOpen(void) const { - return (m_File != NULL); + return (m_File != nullptr); } @@ -366,7 +366,7 @@ int cFile::GetSize(const AString & a_FileName) bool cFile::CreateFolder(const AString & a_FolderPath) { #ifdef _WIN32 - return (CreateDirectoryA(a_FolderPath.c_str(), NULL) != 0); + return (CreateDirectoryA(a_FolderPath.c_str(), nullptr) != 0); #else return (mkdir(a_FolderPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0); #endif @@ -415,13 +415,13 @@ AStringVector cFile::GetFolderContents(const AString & a_Folder) { Folder = "."; } - if ((dp = opendir(Folder.c_str())) == NULL) + if ((dp = opendir(Folder.c_str())) == nullptr) { LOGERROR("Error (%i) opening directory \"%s\"\n", errno, Folder.c_str()); } else { - while ((dirp = readdir(dp)) != NULL) + while ((dirp = readdir(dp)) != nullptr) { AllFiles.push_back(dirp->d_name); } diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp index 22d887783..32d84a0d5 100644 --- a/src/OSSupport/GZipFile.cpp +++ b/src/OSSupport/GZipFile.cpp @@ -11,7 +11,7 @@ cGZipFile::cGZipFile(void) : - m_File(NULL), m_Mode(fmRead) + m_File(nullptr), m_Mode(fmRead) { } @@ -30,14 +30,14 @@ cGZipFile::~cGZipFile() bool cGZipFile::Open(const AString & a_FileName, eMode a_Mode) { - if (m_File != NULL) + if (m_File != nullptr) { ASSERT(!"A file is already open in this object"); return false; } m_File = gzopen(a_FileName.c_str(), (a_Mode == fmRead) ? "r" : "w"); m_Mode = a_Mode; - return (m_File != NULL); + return (m_File != nullptr); } @@ -46,10 +46,10 @@ bool cGZipFile::Open(const AString & a_FileName, eMode a_Mode) void cGZipFile::Close(void) { - if (m_File != NULL) + if (m_File != nullptr) { gzclose(m_File); - m_File = NULL; + m_File = nullptr; } } @@ -59,7 +59,7 @@ void cGZipFile::Close(void) int cGZipFile::ReadRestOfFile(AString & a_Contents) { - if (m_File == NULL) + if (m_File == nullptr) { ASSERT(!"No file has been opened"); return -1; @@ -90,7 +90,7 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents) bool cGZipFile::Write(const char * a_Contents, int a_Size) { - if (m_File == NULL) + if (m_File == nullptr) { ASSERT(!"No file has been opened"); return false; diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h index 5de5f31c4..5c8d28d2d 100644 --- a/src/OSSupport/IsThread.h +++ b/src/OSSupport/IsThread.h @@ -31,20 +31,20 @@ protected: /// The overriden Execute() method should check this value periodically and terminate if this is true volatile bool m_ShouldTerminate; - + public: cIsThread(const AString & iThreadName); virtual ~cIsThread(); - + /// Starts the thread; returns without waiting for the actual start bool Start(void); - + /// Signals the thread to terminate and waits until it's finished void Stop(void); - + /// Waits for the thread to finish. Doesn't signalize the ShouldTerminate flag bool Wait(void); - + /// Returns the OS-dependent thread ID for the caller's thread static unsigned long GetCurrentID(void); @@ -53,7 +53,7 @@ public: protected: AString m_ThreadName; - + // Value used for "no handle": #ifdef _WIN32 #define NULL_HANDLE NULL @@ -62,34 +62,34 @@ protected: #endif #ifdef _WIN32 - + DWORD m_ThreadID; HANDLE m_Handle; - + static DWORD __stdcall thrExecute(LPVOID a_Param) { // Create a window so that the thread can be identified by 3rd party tools: HWND IdentificationWnd = CreateWindowA("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL); - + // Run the thread: ((cIsThread *)a_Param)->Execute(); - + // Destroy the identification window: DestroyWindow(IdentificationWnd); - + return 0; } - + #else // _WIN32 - + pthread_t m_Handle; - + static void * thrExecute(void * a_Param) { - ((cIsThread *)a_Param)->Execute(); + (static_cast<cIsThread *>(a_Param))->Execute(); return NULL; } - + #endif // else _WIN32 } ; @@ -98,7 +98,3 @@ protected: #endif // CISTHREAD_H_INCLUDED - - - - diff --git a/src/OSSupport/ListenThread.cpp b/src/OSSupport/ListenThread.cpp index 02e98acfc..b029634e9 100644 --- a/src/OSSupport/ListenThread.cpp +++ b/src/OSSupport/ListenThread.cpp @@ -214,7 +214,7 @@ void cListenThread::Execute(void) timeval tv; // On Linux select() doesn't seem to wake up when socket is closed, so let's kinda busy-wait: tv.tv_sec = 1; tv.tv_usec = 0; - if (select((int)Highest + 1, &fdRead, NULL, NULL, &tv) == -1) + if (select((int)Highest + 1, &fdRead, nullptr, nullptr, &tv) == -1) { LOG("select(R) call failed in cListenThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; diff --git a/src/OSSupport/Semaphore.cpp b/src/OSSupport/Semaphore.cpp index c1fc7d9c7..6a2d57901 100644 --- a/src/OSSupport/Semaphore.cpp +++ b/src/OSSupport/Semaphore.cpp @@ -36,7 +36,7 @@ cSemaphore::cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount /* } #else m_Handle = CreateSemaphore( - NULL, // security attribute + nullptr, // security attribute a_InitialCount, // initial count a_MaxCount, // maximum count 0 // name (optional) @@ -98,7 +98,7 @@ void cSemaphore::Signal() LOG("ERROR: Could not signal cSemaphore. (%i)", errno); } #else - ReleaseSemaphore( m_Handle, 1, NULL); + ReleaseSemaphore( m_Handle, 1, nullptr); #endif } diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index c07d31c8b..5025a09ad 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -292,7 +292,7 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por { // It is not an IP Address string, but rather a regular hostname, resolve: hostent * hp = gethostbyname(a_HostNameOrAddr.c_str()); - if (hp == NULL) + if (hp == nullptr) { LOGWARNING("%s: Could not resolve hostname \"%s\"", __FUNCTION__, a_HostNameOrAddr.c_str()); CloseSocket(); diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp index f436318a5..7a3ef4274 100644 --- a/src/OSSupport/SocketThreads.cpp +++ b/src/OSSupport/SocketThreads.cpp @@ -61,7 +61,7 @@ bool cSocketThreads::AddClient(const cSocket & a_Socket, cCallback * a_Client) // There was an error launching the thread (but it was already logged along with the reason) LOGERROR("A new cSocketThread failed to start"); delete Thread; - Thread = NULL; + Thread = nullptr; return false; } Thread->AddClient(a_Socket, a_Client); @@ -233,7 +233,7 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client) // More data to send, shut down reading and wait for the rest to get sent: m_Slots[i].m_State = sSlot::ssWritingRestOut; } - m_Slots[i].m_Client = NULL; + m_Slots[i].m_Client = nullptr; } // Notify the thread of the change: @@ -407,7 +407,7 @@ void cSocketThreads::cSocketThread::Execute(void) timeval Timeout; Timeout.tv_sec = 5; Timeout.tv_usec = 0; - if (select((int)Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1) + if (select((int)Highest + 1, &fdRead, &fdWrite, nullptr, &Timeout) == -1) { LOG("select() call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; @@ -519,7 +519,7 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read) } else { - if (m_Slots[i].m_Client != NULL) + if (m_Slots[i].m_Client != nullptr) { m_Slots[i].m_Client->DataReceived(Buffer, Received); } @@ -545,7 +545,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) if (m_Slots[i].m_Outgoing.empty()) { // Request another chunk of outgoing data: - if (m_Slots[i].m_Client != NULL) + if (m_Slots[i].m_Client != nullptr) { AString Data; m_Slots[i].m_Client->GetOutgoingData(Data); @@ -573,7 +573,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write) int Err = cSocket::GetLastError(); LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), GetOSErrorString(Err).c_str()); m_Slots[i].m_Socket.CloseSocket(); - if (m_Slots[i].m_Client != NULL) + if (m_Slots[i].m_Client != nullptr) { m_Slots[i].m_Client->SocketClosed(); } @@ -668,7 +668,7 @@ void cSocketThreads::cSocketThread::QueueOutgoingData(void) cCSLock Lock(m_Parent->m_CS); for (int i = 0; i < m_NumSlots; i++) { - if (m_Slots[i].m_Client != NULL) + if (m_Slots[i].m_Client != nullptr) { AString Data; m_Slots[i].m_Client->GetOutgoingData(Data); diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index 944f5f3bc..df819468d 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -137,7 +137,7 @@ private: /** The socket is primarily owned by this object */ cSocket m_Socket; - /** The callback to call for events. May be NULL */ + /** The callback to call for events. May be nullptr */ cCallback * m_Client; /** If sending writes only partial data, the rest is stored here for another send. diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp index 699bc57ee..59e1281ac 100644 --- a/src/PolarSSL++/BlockingSslClientSocket.cpp +++ b/src/PolarSSL++/BlockingSslClientSocket.cpp @@ -48,7 +48,7 @@ bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Po } // If we have been assigned a trusted CA root cert store, push it into the SSL context: - if (m_CACerts.get() != NULL) + if (m_CACerts.get() != nullptr) { m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName); } @@ -72,7 +72,7 @@ bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Po bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName) { // Warn if used multiple times, but don't signal an error: - if (m_CACerts.get() != NULL) + if (m_CACerts.get() != nullptr) { LOGWARNING( "SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s", diff --git a/src/PolarSSL++/CallbackSslContext.cpp b/src/PolarSSL++/CallbackSslContext.cpp index c4d19b2a0..e061e3f03 100644 --- a/src/PolarSSL++/CallbackSslContext.cpp +++ b/src/PolarSSL++/CallbackSslContext.cpp @@ -12,7 +12,7 @@ cCallbackSslContext::cCallbackSslContext(void) : - m_Callbacks(NULL) + m_Callbacks(nullptr) { // Nothing needed, but the constructor needs to exist so } @@ -32,7 +32,7 @@ cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) { - if (m_Callbacks == NULL) + if (m_Callbacks == nullptr) { LOGWARNING("SSL: Trying to receive data with no callbacks, aborting."); return POLARSSL_ERR_NET_RECV_FAILED; @@ -46,7 +46,7 @@ int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_Num int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) { - if (m_Callbacks == NULL) + if (m_Callbacks == nullptr) { LOGWARNING("SSL: Trying to send data with no callbacks, aborting."); return POLARSSL_ERR_NET_SEND_FAILED; diff --git a/src/PolarSSL++/CryptoKey.cpp b/src/PolarSSL++/CryptoKey.cpp index 0763c387b..7c4f021b3 100644 --- a/src/PolarSSL++/CryptoKey.cpp +++ b/src/PolarSSL++/CryptoKey.cpp @@ -123,7 +123,7 @@ int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AStri if (a_Password.empty()) { - return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0); + return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, nullptr, 0); } else { diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index 482470c3a..902267f90 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -46,7 +46,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & // Set the CtrDrbg context, create a new one if needed: m_CtrDrbg = a_CtrDrbg; - if (m_CtrDrbg.get() == NULL) + if (m_CtrDrbg.get() == nullptr) { m_CtrDrbg.reset(new cCtrDrbgContext); m_CtrDrbg->Initialize("MCServer", 8); @@ -98,7 +98,7 @@ void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKe ASSERT(m_IsValid); // Call Initialize() first // Check that both the cert and the key is valid: - if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + if ((a_OwnCert.get() == nullptr) || (a_OwnCertPrivKey.get() == nullptr)) { LOGWARNING("SSL: Own certificate is not valid, skipping the set."); return; @@ -121,7 +121,7 @@ void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr ASSERT(m_IsValid); // Call Initialize() first // Check that both the cert and the key is valid: - if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + if ((a_OwnCert.get() == nullptr) || (a_OwnCertPrivKey.get() == nullptr)) { LOGWARNING("SSL: Own certificate is not valid, skipping the set."); return; @@ -150,7 +150,7 @@ void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_Ex // Set the trusted CA root cert store: ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED); - ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), NULL, m_ExpectedPeerName.empty() ? NULL : m_ExpectedPeerName.c_str()); + ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), nullptr, m_ExpectedPeerName.empty() ? nullptr : m_ExpectedPeerName.c_str()); } diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index 984000795..c9e4296a2 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -7,7 +7,7 @@ #include "../Server.h" #include "../ClientHandle.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "json/json.h" #include "PolarSSL++/BlockingSslClientSocket.h" diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt index 5426c58fa..7c97e67bc 100644 --- a/src/Protocol/CMakeLists.txt +++ b/src/Protocol/CMakeLists.txt @@ -8,11 +8,6 @@ SET (SRCS Authenticator.cpp ChunkDataSerializer.cpp MojangAPI.cpp - Protocol125.cpp - Protocol132.cpp - Protocol14x.cpp - Protocol15x.cpp - Protocol16x.cpp Protocol17x.cpp Protocol18x.cpp ProtocolRecognizer.cpp) @@ -22,11 +17,6 @@ SET (HDRS ChunkDataSerializer.h MojangAPI.h Protocol.h - Protocol125.h - Protocol132.h - Protocol14x.h - Protocol15x.h - Protocol16x.h Protocol17x.h Protocol18x.h ProtocolRecognizer.h) diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 28da83c31..67f513e44 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -7,10 +7,12 @@ #include "MojangAPI.h" #include "SQLiteCpp/Database.h" #include "SQLiteCpp/Statement.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" #include "json/json.h" #include "PolarSSL++/BlockingSslClientSocket.h" #include "../RankManager.h" +#include "../OSSupport/IsThread.h" +#include "../Root.h" @@ -152,6 +154,41 @@ cMojangAPI::sProfile::sProfile( //////////////////////////////////////////////////////////////////////////////// +// cMojangAPI::cUpdateThread: + +class cMojangAPI::cUpdateThread : + public cIsThread +{ + typedef cIsThread super; +public: + cUpdateThread() : + super("cMojangAPI::cUpdateThread") + { + } + + ~cUpdateThread() + { + m_evtNotify.Set(); + Stop(); + } + +protected: + cEvent m_evtNotify; + + virtual void Execute(void) override + { + do + { + cRoot::Get()->GetMojangAPI().Update(); + } while (!m_evtNotify.Wait(60 * 60 * 1000)); // Repeat every 60 minutes + } +} ; + + + + + +//////////////////////////////////////////////////////////////////////////////// // cMojangAPI: cMojangAPI::cMojangAPI(void) : @@ -159,7 +196,8 @@ cMojangAPI::cMojangAPI(void) : m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS), m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER), m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS), - m_RankMgr(NULL) + m_RankMgr(nullptr), + m_UpdateThread(new cUpdateThread()) { } @@ -176,13 +214,17 @@ cMojangAPI::~cMojangAPI() -void cMojangAPI::Start(cIniFile & a_SettingsIni) +void cMojangAPI::Start(cIniFile & a_SettingsIni, bool a_ShouldAuth) { m_NameToUUIDServer = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); m_NameToUUIDAddress = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); m_UUIDToProfileServer = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER); m_UUIDToProfileAddress = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS); LoadCachesFromDisk(); + if (a_ShouldAuth) + { + m_UpdateThread->Start(); + } } @@ -293,7 +335,7 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID) { AString UUID = MakeUUIDShort(a_UUID); - Int64 Now = time(NULL); + Int64 Now = time(nullptr); { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now); @@ -312,7 +354,7 @@ void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties) { AString UUID = MakeUUIDShort(a_UUID); - Int64 Now = time(NULL); + Int64 Now = time(nullptr); { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now); @@ -465,21 +507,7 @@ void cMojangAPI::LoadCachesFromDisk(void) db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)"); - // Clean up old entries: - { - SQLite::Statement stmt(db, "DELETE FROM PlayerNameToUUID WHERE DateTime < ?"); - Int64 LimitDateTime = time(NULL) - MAX_AGE; - stmt.bind(1, LimitDateTime); - stmt.exec(); - } - { - SQLite::Statement stmt(db, "DELETE FROM UUIDToProfile WHERE DateTime < ?"); - Int64 LimitDateTime = time(NULL) - MAX_AGE; - stmt.bind(1, LimitDateTime); - stmt.exec(); - } - - // Retrieve all remaining entries: + // Retrieve all entries: { SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID"); while (stmt.executeStep()) @@ -530,7 +558,7 @@ void cMojangAPI::SaveCachesToDisk(void) db.exec("DELETE FROM UUIDToProfile"); // Save all cache entries - m_PlayerNameToUUID: - Int64 LimitDateTime = time(NULL) - MAX_AGE; + Int64 LimitDateTime = time(nullptr) - MAX_AGE; { SQLite::Statement stmt(db, "INSERT INTO PlayerNameToUUID(PlayerName, UUID, DateTime) VALUES (?, ?, ?)"); cCSLock Lock(m_CSNameToUUID); @@ -596,18 +624,27 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) - while (!NamesToQuery.empty()) + QueryNamesToUUIDs(NamesToQuery); +} + + + + + +void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery) +{ + while (!a_NamesToQuery.empty()) { // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; - AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); + AStringVector::iterator itr = a_NamesToQuery.begin(), end = a_NamesToQuery.end(); for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); } // for itr - a_PlayerNames[] - NamesToQuery.erase(NamesToQuery.begin(), itr); + a_NamesToQuery.erase(a_NamesToQuery.begin(), itr); Json::FastWriter Writer; AString RequestBody = Writer.write(root); @@ -660,7 +697,7 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) // Store the returned results into cache: Json::Value::UInt JsonCount = root.size(); - Int64 Now = time(NULL); + Int64 Now = time(nullptr); { cCSLock Lock(m_CSNameToUUID); for (Json::Value::UInt idx = 0; idx < JsonCount; ++idx) @@ -705,12 +742,22 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) // Check if already present: { + cCSLock Lock(m_CSUUIDToProfile); if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end()) { return; } } + QueryUUIDToProfile(a_UUID); +} + + + + + +void cMojangAPI::QueryUUIDToProfile(const AString & a_UUID) +{ // Create the request address: AString Address = m_UUIDToProfileAddress; ReplaceString(Address, "%UUID%", a_UUID); @@ -784,7 +831,7 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) return; } Json::Value Properties = root.get("properties", ""); - Int64 Now = time(NULL); + Int64 Now = time(nullptr); { cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); @@ -808,7 +855,7 @@ void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const AString & a_ { // Notify the rank manager: cCSLock Lock(m_CSRankMgr); - if (m_RankMgr != NULL) + if (m_RankMgr != nullptr) { m_RankMgr->NotifyNameUUID(a_PlayerName, a_UUID); } @@ -817,3 +864,51 @@ void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const AString & a_ + +void cMojangAPI::Update(void) +{ + Int64 LimitDateTime = time(nullptr) - MAX_AGE; + + // Re-query all playernames that are stale: + AStringVector PlayerNames; + { + cCSLock Lock(m_CSNameToUUID); + for (cProfileMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr) + { + if (itr->second.m_DateTime < LimitDateTime) + { + PlayerNames.push_back(itr->first); + } + } // for itr - m_NameToUUID[] + } + if (!PlayerNames.empty()) + { + LOG("cMojangAPI: Updating name-to-uuid cache for %u names", (unsigned)PlayerNames.size()); + QueryNamesToUUIDs(PlayerNames); + } + + // Re-query all profiles that are stale: + AStringVector ProfileUUIDs; + { + cCSLock Lock(m_CSUUIDToProfile); + for (cProfileMap::const_iterator itr = m_UUIDToProfile.begin(), end = m_UUIDToProfile.end(); itr != end; ++itr) + { + if (itr->second.m_DateTime < LimitDateTime) + { + ProfileUUIDs.push_back(itr->first); + } + } // for itr - m_UUIDToProfile[] + } + if (!ProfileUUIDs.empty()) + { + LOG("cMojangAPI: Updating uuid-to-profile cache for %u uuids", (unsigned)ProfileUUIDs.size()); + for (AStringVector::const_iterator itr = ProfileUUIDs.begin(), end = ProfileUUIDs.end(); itr != end; ++itr) + { + QueryUUIDToProfile(*itr); + } + } +} + + + + diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index 252d32543..0dc2617b6 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -38,7 +38,7 @@ public: /** Initializes the API; reads the settings from the specified ini file. Loads cached results from disk. */ - void Start(cIniFile & a_SettingsIni); + void Start(cIniFile & a_SettingsIni, bool a_ShouldAuth); /** Connects to the specified server using SSL, sends the given request and receives the response. Checks Mojang certificates using the hard-coded Starfield root CA certificate. @@ -89,10 +89,14 @@ public: the profile to the respective mapping caches and updtes their datetime stamp to now. */ void AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties); - /** Sets the m_RankMgr that is used for name-uuid notifications. Accepts NULL to remove the binding. */ + /** Sets the m_RankMgr that is used for name-uuid notifications. Accepts nullptr to remove the binding. */ void SetRankManager(cRankManager * a_RankManager) { m_RankMgr = a_RankManager; } protected: + /** The thread that periodically checks for stale data and re-queries it from the server. */ + class cUpdateThread; + + /** Holds data for a single player profile. */ struct sProfile { @@ -108,7 +112,7 @@ protected: m_UUID(), m_Textures(), m_TexturesSignature(), - m_DateTime(time(NULL)) + m_DateTime(time(nullptr)) { } @@ -172,11 +176,14 @@ protected: /** Protects m_UUIDToProfile against simultaneous multi-threaded access. */ cCriticalSection m_CSUUIDToProfile; - /** The rank manager that is notified of the name-uuid pairings. May be NULL. Protected by m_CSRankMgr. */ + /** The rank manager that is notified of the name-uuid pairings. May be nullptr. Protected by m_CSRankMgr. */ cRankManager * m_RankMgr; /** Protects m_RankMgr agains simultaneous multi-threaded access. */ cCriticalSection m_CSRankMgr; + + /** The thread that periodically updates the stale data in the DB from the Mojang servers. */ + SharedPtr<cUpdateThread> m_UpdateThread; /** Loads the caches from a disk storage. */ @@ -189,15 +196,29 @@ protected: Names that are not valid are not added into the cache. ASSUMEs that a_PlayerNames contains lowercased player names. */ void CacheNamesToUUIDs(const AStringVector & a_PlayerNames); + + /** Queries all the specified names and stores them into the m_PlayerNameToUUID cache. + Names that are not valid are not added into the cache. + ASSUMEs that a_PlayerNames contans lowercased player names. + For performance reasons takes a non-const reference and modifies the list given to it, until empty. */ + void QueryNamesToUUIDs(AStringVector & a_PlayerNames); /** Makes sure the specified UUID is in the m_UUIDToProfile cache. If missing, downloads it from Mojang API servers. UUIDs that are not valid will not be added into the cache. ASSUMEs that a_UUID is a lowercased short UUID. */ void CacheUUIDToProfile(const AString & a_UUID); + /** Queries the specified UUID's profile and stores it in the m_UUIDToProfile cache. If already present, updates the cache entry. + UUIDs that are not valid will not be added into the cache. + ASSUMEs that a_UUID is a lowercased short UUID. */ + void QueryUUIDToProfile(const AString & a_UUID); + /** Called for each name-uuid pairing that is discovered. If assigned, notifies the m_RankManager of the event. */ void NotifyNameUUID(const AString & a_PlayerName, const AString & a_PlayerUUID); + + /** Updates the stale values in the DB from the Mojang servers. Called from the cUpdateThread, blocks on the HTTPS API calls. */ + void Update(void); } ; // tolua_export diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index b2ee92918..02a8a52f6 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -130,7 +130,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) = 0; virtual void SendWindowClose (const cWindow & a_Window) = 0; virtual void SendWindowOpen (const cWindow & a_Window) = 0; - virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) = 0; + virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) = 0; /// Returns the ServerID used for authentication through session.minecraft.net virtual AString GetAuthServerID(void) = 0; @@ -138,108 +138,9 @@ public: protected: cClientHandle * m_Client; cCriticalSection m_CSPacket; // Each SendXYZ() function must acquire this CS in order to send the whole packet at once - + /// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it virtual void SendData(const char * a_Data, size_t a_Size) = 0; - - /// Called after writing each packet, enables descendants to flush their buffers - virtual void Flush(void) {} - - // Helpers for writing partial packet data, write using SendData() - void WriteByte(Byte a_Value) - { - SendData((const char *)&a_Value, 1); - } - - void WriteChar(char a_Value) - { - SendData(&a_Value, 1); - } - - void WriteShort(short a_Value) - { - u_short Value = htons((u_short)a_Value); - SendData((const char *)&Value, 2); - } - - /* - void WriteShort(unsigned short a_Value) - { - a_Value = htons(a_Value); - SendData((const char *)&a_Value, 2); - } - */ - - void WriteInt(int a_Value) - { - u_long Value = htonl((u_long)a_Value); - SendData((const char *)&Value, 4); - } - - void WriteUInt(unsigned int a_Value) - { - a_Value = htonl(a_Value); - SendData((const char *)&a_Value, 4); - } - - void WriteInt64 (Int64 a_Value) - { - UInt64 Value = HostToNetwork8(&a_Value); - SendData((const char *)&Value, 8); - } - - void WriteFloat (float a_Value) - { - UInt32 val = HostToNetwork4(&a_Value); - SendData((const char *)&val, 4); - } - - void WriteDouble(double a_Value) - { - UInt64 val = HostToNetwork8(&a_Value); - SendData((const char *)&val, 8); - } - - void WriteString(const AString & a_Value) - { - AString UTF16; - UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16); - WriteShort((short)(UTF16.size() / 2)); - SendData(UTF16.data(), UTF16.size()); - } - - void WriteBool(bool a_Value) - { - WriteByte(a_Value ? 1 : 0); - } - - void WriteVectorI(const Vector3i & a_Vector) - { - WriteInt(a_Vector.x); - WriteInt(a_Vector.y); - WriteInt(a_Vector.z); - } - - void WriteVarInt(UInt32 a_Value) - { - // A 32-bit integer can be encoded by at most 5 bytes: - unsigned char b[5]; - size_t idx = 0; - do - { - b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); - a_Value = a_Value >> 7; - idx++; - } while (a_Value > 0); - - SendData((const char *)b, idx); - } - - void WriteVarUTF8String(const AString & a_String) - { - WriteVarInt((UInt32)a_String.size()); - SendData(a_String.data(), a_String.size()); - } } ; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp deleted file mode 100644 index 369a35e18..000000000 --- a/src/Protocol/Protocol125.cpp +++ /dev/null @@ -1,2175 +0,0 @@ - -// Protocol125.cpp - -// Implements the cProtocol125 class representing the release 1.2.5 protocol (#29) -/* -Documentation: - - protocol: http://wiki.vg/wiki/index.php?title=Protocol&oldid=2513 - - session handling: http://wiki.vg/wiki/index.php?title=Session&oldid=2262 - - slot format: http://wiki.vg/wiki/index.php?title=Slot_Data&oldid=2152 -*/ - -#include "Globals.h" - -#include "Protocol125.h" - -#include "../ClientHandle.h" -#include "../World.h" -#include "ChunkDataSerializer.h" -#include "../Entities/Entity.h" -#include "../Entities/ExpOrb.h" -#include "../Mobs/Monster.h" -#include "../Entities/Pickup.h" -#include "../Entities/Player.h" -#include "../ChatColor.h" -#include "../UI/Window.h" -#include "../Root.h" -#include "../Server.h" - -#include "../Entities/ArrowEntity.h" -#include "../Entities/Minecart.h" -#include "../Entities/FallingBlock.h" - -#include "../Mobs/IncludeAllMonsters.h" - -#include "../CompositeChat.h" - - - - - -enum -{ - PACKET_KEEP_ALIVE = 0x00, - PACKET_LOGIN = 0x01, - PACKET_HANDSHAKE = 0x02, - PACKET_CHAT = 0x03, - PACKET_UPDATE_TIME = 0x04, - PACKET_ENTITY_EQUIPMENT = 0x05, - PACKET_USE_ENTITY = 0x07, - PACKET_UPDATE_HEALTH = 0x08, - PACKET_RESPAWN = 0x09, - PACKET_PLAYER_ON_GROUND = 0x0a, - PACKET_PLAYER_POS = 0x0b, - PACKET_PLAYER_LOOK = 0x0c, - PACKET_PLAYER_MOVE_LOOK = 0x0d, - PACKET_BLOCK_DIG = 0x0e, - PACKET_BLOCK_PLACE = 0x0f, - PACKET_SLOT_SELECTED = 0x10, - PACKET_USE_BED = 0x11, - PACKET_ANIMATION = 0x12, - PACKET_PACKET_ENTITY_ACTION = 0x13, - PACKET_PLAYER_SPAWN = 0x14, - PACKET_PICKUP_SPAWN = 0x15, - PACKET_COLLECT_PICKUP = 0x16, - PACKET_SPAWN_OBJECT = 0x17, - PACKET_SPAWN_MOB = 0x18, - PACKET_ENTITY_VELOCITY = 0x1c, - PACKET_DESTROY_ENTITY = 0x1d, - PACKET_ENTITY = 0x1e, - PACKET_ENT_REL_MOVE = 0x1f, - PACKET_ENT_LOOK = 0x20, - PACKET_ENT_REL_MOVE_LOOK = 0x21, - PACKET_ENT_TELEPORT = 0x22, - PACKET_ENT_HEAD_LOOK = 0x23, - PACKET_ENT_STATUS = 0x26, - PACKET_ATTACH_ENTITY = 0x27, - PACKET_METADATA = 0x28, - PACKET_ENTITY_EFFECT = 0x29, - PACKET_SPAWN_EXPERIENCE_ORB = 0x1A, - PACKET_REMOVE_ENTITY_EFFECT = 0x2a, - PACKET_EXPERIENCE = 0x2b, - PACKET_PRE_CHUNK = 0x32, - PACKET_MAP_CHUNK = 0x33, - PACKET_MULTI_BLOCK = 0x34, - PACKET_BLOCK_CHANGE = 0x35, - PACKET_BLOCK_ACTION = 0x36, - PACKET_EXPLOSION = 0x3C, - PACKET_SOUND_EFFECT = 0x3e, - PACKET_SOUND_PARTICLE_EFFECT = 0x3d, - PACKET_CHANGE_GAME_STATE = 0x46, - PACKET_THUNDERBOLT = 0x47, - PACKET_WINDOW_OPEN = 0x64, - PACKET_WINDOW_CLOSE = 0x65, - PACKET_WINDOW_CLICK = 0x66, - PACKET_INVENTORY_SLOT = 0x67, - PACKET_INVENTORY_WHOLE = 0x68, - PACKET_WINDOW_PROPERTY = 0x69, - PACKET_CREATIVE_INVENTORY_ACTION = 0x6B, - PACKET_ENCHANT_ITEM = 0x6C, - PACKET_UPDATE_SIGN = 0x82, - PACKET_ITEM_DATA = 0x83, - PACKET_INCREMENT_STATISTIC = 0xC8, - PACKET_PLAYER_LIST_ITEM = 0xC9, - PACKET_PLAYER_ABILITIES = 0xca, - PACKET_PLUGIN_MESSAGE = 0xfa, - PACKET_PING = 0xfe, - PACKET_DISCONNECT = 0xff -} ; - - - - - -#define HANDLE_PACKET_READ(Proc, Type, Var) \ - Type Var; \ - { \ - if (!m_ReceivedData.Proc(Var)) \ - { \ - m_ReceivedData.CheckValid(); \ - return PARSE_INCOMPLETE; \ - } \ - m_ReceivedData.CheckValid(); \ - } - - - - -typedef unsigned char Byte; - - - - - -cProtocol125::cProtocol125(cClientHandle * a_Client) : - super(a_Client), - m_ReceivedData(32 KiB), - m_LastSentDimension(dimNotSet) -{ -} - - - - - -void cProtocol125::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ATTACH_ENTITY); - WriteInt(a_Entity.GetUniqueID()); - WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID()); - Flush(); -} - - - - - -void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) -{ - UNUSED(a_BlockType); - - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_BLOCK_ACTION); - WriteInt (a_BlockX); - WriteShort((short)a_BlockY); - WriteInt (a_BlockZ); - WriteChar (a_Byte1); - WriteChar (a_Byte2); - Flush(); -} - - - - - -void cProtocol125::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage) -{ - // Not supported in this protocol version -} - - - - - -void cProtocol125::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_BLOCK_CHANGE); - WriteInt (a_BlockX); - WriteByte((unsigned char)a_BlockY); - WriteInt (a_BlockZ); - WriteByte(a_BlockType); - WriteByte(a_BlockMeta); - Flush(); -} - - - - - -void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) -{ - cCSLock Lock(m_CSPacket); - if (a_Changes.size() == 1) - { - // Special packet for single-block changes - const sSetBlock & blk = a_Changes.front(); - SendBlockChange(a_ChunkX * cChunkDef::Width + blk.x, blk.y, a_ChunkZ * cChunkDef::Width + blk.z, blk.BlockType, blk.BlockMeta); - return; - } - - WriteByte (PACKET_MULTI_BLOCK); - WriteInt (a_ChunkX); - WriteInt (a_ChunkZ); - WriteShort((short)a_Changes.size()); - WriteUInt ((UInt32)(4 * a_Changes.size())); - for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) - { - UInt32 Coords = ((UInt32)itr->y) | ((UInt32)(itr->z << 8)) | ((UInt32)(itr->x << 12)); - UInt32 Blocks = ((UInt32)itr->BlockMeta) | ((UInt32)(itr->BlockType << 4)); - WriteUInt(Coords << 16 | Blocks); - } - Flush(); -} - - - - - -void cProtocol125::SendChat(const AString & a_Message) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_CHAT); - WriteString(a_Message); - Flush(); -} - - - - - -void cProtocol125::SendChat(const cCompositeChat & a_Message) -{ - // This version doesn't support composite messages, just extract each part's text and use it: - - // Send the message: - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_CHAT); - WriteString(a_Message.ExtractText()); - Flush(); -} - - - - - -void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) -{ - cCSLock Lock(m_CSPacket); - - // Send the pre-chunk: - SendPreChunk(a_ChunkX, a_ChunkZ, true); - - // Send the chunk data: - AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5, a_ChunkX, a_ChunkZ); - WriteByte(PACKET_MAP_CHUNK); - WriteInt (a_ChunkX); - WriteInt (a_ChunkZ); - SendData(Serialized.data(), Serialized.size()); - Flush(); -} - - - - - -void cProtocol125::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_COLLECT_PICKUP); - WriteInt (a_Entity.GetUniqueID()); - WriteInt (a_Player.GetUniqueID()); - Flush(); -} - - - - - -void cProtocol125::SendDestroyEntity(const cEntity & a_Entity) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_DESTROY_ENTITY); - WriteInt (a_Entity.GetUniqueID()); - Flush(); -} - - - - - -void cProtocol125::SendDisconnect(const AString & a_Reason) -{ - cCSLock Lock(m_CSPacket); - WriteByte ((unsigned char)PACKET_DISCONNECT); - WriteString(a_Reason); - Flush(); -} - - - - - -void cProtocol125::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - // This protocol version doesn't support this packet, sign editor is invoked by the client automatically - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); -} - - - - - -void cProtocol125::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_ENTITY_EFFECT); - WriteInt (a_Entity.GetUniqueID()); - WriteByte ((Byte)a_EffectID); - WriteByte ((Byte)a_Amplifier); - WriteShort(a_Duration); - Flush(); -} - - - - - -void cProtocol125::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_ENTITY_EQUIPMENT); - WriteInt (a_Entity.GetUniqueID()); - WriteShort(a_SlotNum); - WriteShort(a_Item.m_ItemType); - WriteShort(a_Item.m_ItemDamage); - Flush(); -} - - - - - -void cProtocol125::SendEntityHeadLook(const cEntity & a_Entity) -{ - ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ENT_HEAD_LOOK); - WriteInt (a_Entity.GetUniqueID()); - WriteChar((char)((a_Entity.GetHeadYaw() / 360.f) * 256)); - Flush(); -} - - - - - -void cProtocol125::SendEntityLook(const cEntity & a_Entity) -{ - ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ENT_LOOK); - WriteInt (a_Entity.GetUniqueID()); - WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256)); - Flush(); -} - - - - - -void cProtocol125::SendEntityMetadata(const cEntity & a_Entity) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_METADATA); - WriteInt (a_Entity.GetUniqueID()); - - WriteCommonMetadata(a_Entity); - if (a_Entity.IsMob()) - { - WriteMobMetadata(((const cMonster &)a_Entity)); - } - else - { - WriteEntityMetadata(a_Entity); - } - WriteByte(0x7f); - - Flush(); -} - - - - - -void cProtocol125::SendEntityProperties(const cEntity & a_Entity) -{ - // Not supported in this protocol version -} - - - - - -void cProtocol125::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) -{ - ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ENT_REL_MOVE); - WriteInt (a_Entity.GetUniqueID()); - WriteChar(a_RelX); - WriteChar(a_RelY); - WriteChar(a_RelZ); - Flush(); -} - - - - - -void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) -{ - ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ENT_REL_MOVE_LOOK); - WriteInt (a_Entity.GetUniqueID()); - WriteChar(a_RelX); - WriteChar(a_RelY); - WriteChar(a_RelZ); - WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256)); - Flush(); -} - - - - - -void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ENT_STATUS); - WriteInt (a_Entity.GetUniqueID()); - WriteChar(a_Status); - Flush(); -} - - - - - -void cProtocol125::SendEntityVelocity(const cEntity & a_Entity) -{ - ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ENTITY_VELOCITY); - WriteInt (a_Entity.GetUniqueID()); - WriteShort((short) (a_Entity.GetSpeedX() * 400)); // 400 = 8000 / 20 - WriteShort((short) (a_Entity.GetSpeedY() * 400)); - WriteShort((short) (a_Entity.GetSpeedZ() * 400)); - Flush(); -} - - - - - -void cProtocol125::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_EXPLOSION); - WriteDouble (a_BlockX); - WriteDouble (a_BlockY); - WriteDouble (a_BlockZ); - WriteFloat (a_Radius); - WriteInt ((Int32)a_BlocksAffected.size()); - int BlockX = (int)a_BlockX; - int BlockY = (int)a_BlockY; - int BlockZ = (int)a_BlockZ; - for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(); itr != a_BlocksAffected.end(); ++itr) - { - WriteByte((Byte)(itr->x - BlockX)); - WriteByte((Byte)(itr->y - BlockY)); - WriteByte((Byte)(itr->z - BlockZ)); - } - WriteFloat((float)a_PlayerMotion.x); - WriteFloat((float)a_PlayerMotion.y); - WriteFloat((float)a_PlayerMotion.z); - Flush(); -} - - - - - -void cProtocol125::SendGameMode(eGameMode a_GameMode) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_CHANGE_GAME_STATE); - WriteByte(3); - WriteChar((char)a_GameMode); - Flush(); -} - - - - - -void cProtocol125::SendHandshake(const AString & a_ConnectionHash) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_HANDSHAKE); - WriteString(a_ConnectionHash); - Flush(); -} - - - - - -void cProtocol125::SendHealth(void) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_UPDATE_HEALTH); - cPlayer * Player = m_Client->GetPlayer(); - WriteShort((short)Player->GetHealth()); - WriteShort((short)Player->GetFoodLevel()); - WriteFloat((float)Player->GetFoodSaturationLevel()); - Flush(); -} - - - - - -void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_INVENTORY_SLOT); - WriteChar (a_WindowID); - WriteShort(a_SlotNum); - WriteItem (a_Item); - Flush(); -} - - - - - -void cProtocol125::SendKeepAlive(int a_PingID) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_KEEP_ALIVE); - WriteInt (a_PingID); - Flush(); -} - - - - - -void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World) -{ - UNUSED(a_World); - cCSLock Lock(m_CSPacket); - - WriteByte (PACKET_LOGIN); - WriteInt (a_Player.GetUniqueID()); // EntityID of the player - WriteString(""); // Username, not used - WriteString("default"); // Level type - WriteInt ((int)a_Player.GetGameMode()); - WriteInt ((int)(a_World.GetDimension())); - WriteByte (2); // TODO: Difficulty - WriteByte (0); // Unused - WriteByte (60); // Client list width or something - Flush(); - m_LastSentDimension = a_World.GetDimension(); -} - - - - - -void cProtocol125::SendLoginSuccess(void) -{ - // Not supported in this protocol version -} - - - - - -void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale) -{ - cCSLock Lock(m_CSPacket); - - WriteByte (PACKET_ITEM_DATA); - WriteShort(E_ITEM_MAP); - WriteShort((short)a_ID); - WriteShort((short)(3 + a_Length)); - - WriteByte(0); - WriteChar((char)a_X); - WriteChar((char)a_Y); - - SendData((const char *)a_Colors, a_Length); - - Flush(); -} - - - - - -void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) -{ - cCSLock Lock(m_CSPacket); - - WriteByte (PACKET_ITEM_DATA); - WriteShort(E_ITEM_MAP); - WriteShort((short)a_ID); - WriteShort((short)(1 + (3 * a_Decorators.size()))); - - WriteByte(1); - - for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) - { - WriteByte((Byte)(it->GetType() << 4) | (it->GetRot() & 0xf)); - WriteByte((Byte)it->GetPixelX()); - WriteByte((Byte)it->GetPixelZ()); - } - - Flush(); -} - - - - - - -void cProtocol125::SendMapInfo(int a_ID, unsigned int a_Scale) -{ - // This protocol doesn't support such message - UNUSED(a_ID); - UNUSED(a_Scale); -} - - - - - -void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PICKUP_SPAWN); - WriteInt (a_Pickup.GetUniqueID()); - const cItem & Item = a_Pickup.GetItem(); - WriteShort (Item.m_ItemType); - WriteChar (Item.m_ItemCount); - WriteShort (Item.m_ItemDamage); - WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32)); - WriteByte ((char)(a_Pickup.GetSpeedX() * 8)); - WriteByte ((char)(a_Pickup.GetSpeedY() * 8)); - WriteByte ((char)(a_Pickup.GetSpeedZ() * 8)); - Flush(); -} - - - - - -void cProtocol125::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ANIMATION); - WriteInt (a_Entity.GetUniqueID()); - WriteChar(a_Animation); - Flush(); -} - - - - - -void cProtocol125::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) -{ - // Not supported by this protocol version -} - - - - - -void cProtocol125::SendPaintingSpawn(const cPainting & a_Painting) -{ - // Not implemented in this protocol version - UNUSED(a_Painting); -} - - - - - -void cProtocol125::SendPlayerListAddPlayer(const cPlayer & a_Player) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PLAYER_LIST_ITEM); - WriteString(a_Player.GetPlayerListName()); - WriteBool (true); - WriteShort (a_Player.GetClientHandle()->GetPing()); - Flush(); -} - - - - - -void cProtocol125::SendPlayerListRemovePlayer(const cPlayer & a_Player) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PLAYER_LIST_ITEM); - WriteString(a_Player.GetPlayerListName()); - WriteBool (false); - WriteShort (0); - Flush(); -} - - - - - -void cProtocol125::SendPlayerListUpdateGameMode(const cPlayer & a_Player) -{ - // Not implemented in this protocol version - UNUSED(a_Player); -} - - - - - -void cProtocol125::SendPlayerListUpdatePing(const cPlayer & a_Player) -{ - // It is a simple add player packet in this protocol. - SendPlayerListAddPlayer(a_Player); -} - - - - - -void cProtocol125::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) -{ - // Not implemented in this protocol version - UNUSED(a_Player); - UNUSED(a_CustomName); -} - - - - - -void cProtocol125::SendPlayerMaxSpeed(void) -{ - // Not supported by this protocol version -} - - - - - -void cProtocol125::SendPlayerMoveLook(void) -{ - cCSLock Lock(m_CSPacket); - - /* - LOGD("Sending PlayerMoveLook: {%0.2f, %0.2f, %0.2f}, stance %0.2f, OnGround: %d", - m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ(), m_Player->GetStance(), m_Player->IsOnGround() ? 1 : 0 - ); - */ - - WriteByte(PACKET_PLAYER_MOVE_LOOK); - cPlayer * Player = m_Client->GetPlayer(); - WriteDouble(Player->GetPosX()); - WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block - WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block - WriteDouble(Player->GetPosZ()); - WriteFloat ((float)(Player->GetYaw())); - WriteFloat ((float)(Player->GetPitch())); - WriteBool (Player->IsOnGround()); - Flush(); -} - - - - - -void cProtocol125::SendPlayerPosition(void) -{ - cCSLock Lock(m_CSPacket); - LOGD("Ignore send PlayerPos"); // PlayerPos is a C->S packet only now -} - - - - - -void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) -{ - const cItem & HeldItem = a_Player.GetEquippedItem(); - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PLAYER_SPAWN); - WriteInt (a_Player.GetUniqueID()); - if (a_Player.HasCustomName()) - { - WriteString(a_Player.GetCustomName()); - } - else - { - WriteString(a_Player.GetName()); - } - WriteInt ((int)(a_Player.GetPosX() * 32)); - WriteInt ((int)(a_Player.GetPosY() * 32)); - WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256)); - WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256)); - WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); - Flush(); -} - - - - - -void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString & a_Message) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_PLUGIN_MESSAGE); - WriteString(a_Channel); - WriteShort((short)a_Message.size()); - SendData(a_Message.data(), a_Message.size()); - Flush(); -} - - - - - -void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_REMOVE_ENTITY_EFFECT); - WriteInt (a_Entity.GetUniqueID()); - WriteChar((char)a_EffectID); - Flush(); -} - - - - - -void cProtocol125::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) -{ - cCSLock Lock(m_CSPacket); - if ((m_LastSentDimension == a_Dimension) && !a_ShouldIgnoreDimensionChecks) - { - // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death) - return; - } - cPlayer * Player = m_Client->GetPlayer(); - WriteByte (PACKET_RESPAWN); - WriteInt ((int)(a_Dimension)); - WriteByte (2); // TODO: Difficulty; 2 = Normal - WriteChar ((char)Player->GetGameMode()); - WriteShort (256); // Current world height - WriteString("default"); - Flush(); - m_LastSentDimension = a_Dimension; -} - - - - - -void cProtocol125::SendExperience(void) -{ - cCSLock Lock(m_CSPacket); - cPlayer * Player = m_Client->GetPlayer(); - WriteByte (PACKET_EXPERIENCE); - WriteFloat (Player->GetXpPercentage()); - WriteShort (Player->GetXpLevel()); - WriteShort (Player->GetCurrentXp()); - Flush(); -} - - - - - -void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SPAWN_EXPERIENCE_ORB); - WriteInt(a_ExpOrb.GetUniqueID()); - WriteInt((int) a_ExpOrb.GetPosX()); - WriteInt((int) a_ExpOrb.GetPosY()); - WriteInt((int) a_ExpOrb.GetPosZ()); - WriteShort((short)a_ExpOrb.GetReward()); - Flush(); -} - - - - - -void cProtocol125::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) -{ - // This protocol version doesn't support such message - UNUSED(a_Name); - UNUSED(a_DisplayName); - UNUSED(a_Mode); -} - - - - - -void cProtocol125::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) -{ - // Not needed in this protocol version -} - - - - - -void cProtocol125::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) -{ - // Not implemented in this protocol version -} - - - - - -void cProtocol125::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) -{ - // This protocol version implements falling blocks using the spawn object / vehicle packet: - SendSpawnObject(a_FallingBlock, 70, a_FallingBlock.GetBlockType(), 0, 0); -} - - - - - -void cProtocol125::SendSpawnMob(const cMonster & a_Mob) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_SPAWN_MOB); - WriteInt (a_Mob.GetUniqueID()); - WriteByte ((Byte)a_Mob.GetMobType()); - WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); - WriteByte (0); - WriteByte (0); - WriteByte (0); - - WriteCommonMetadata(a_Mob); - WriteMobMetadata(a_Mob); - WriteByte(0x7f); - - Flush(); -} - - - - - -void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) -{ - UNUSED(a_Yaw); - UNUSED(a_Pitch); - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SPAWN_OBJECT); - WriteInt (a_Entity.GetUniqueID()); - WriteChar(a_ObjectType); - WriteInt ((int)(a_Entity.GetPosX() * 32)); - WriteInt ((int)(a_Entity.GetPosY() * 32)); - WriteInt ((int)(a_Entity.GetPosZ() * 32)); - WriteByte(a_Pitch); - WriteByte(a_Yaw); - WriteInt (a_ObjectData); - if (a_ObjectData != 0) - { - WriteShort((short)(a_Entity.GetSpeedX() * 400)); - WriteShort((short)(a_Entity.GetSpeedY() * 400)); - WriteShort((short)(a_Entity.GetSpeedZ() * 400)); - } - Flush(); -} - - - - - -void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_SPAWN_OBJECT); - WriteInt (a_Vehicle.GetUniqueID()); - WriteChar (a_VehicleType); - WriteInt ((int)(a_Vehicle.GetPosX() * 32)); - WriteInt ((int)(a_Vehicle.GetPosY() * 32)); - WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); - WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); - WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256)); - WriteInt (a_VehicleSubType); - if (a_VehicleSubType != 0) - { - WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); - } - Flush(); -} - - - - - -void cProtocol125::SendStatistics(const cStatManager & a_Manager) -{ - /* NOTE: - Versions prior to minecraft 1.7 use an incremental statistic sync - method. The current setup does not allow us to implement that, because - of performance considerations. - */ -#if 0 - for (unsigned int i = 0; i < (unsigned int)statCount; ++i) - { - StatValue Value = m_Manager->GetValue((eStatistic) i); - - unsigned int StatID = cStatInfo::GetID((eStatistic) i); - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_INCREMENT_STATISTIC); - WriteInt(StatID); - WriteByte(Value); /* Can overflow! */ - Flush(); - } -#endif -} - - - - - -void cProtocol125::SendTabCompletionResults(const AStringVector & a_Results) -{ - // This protocol version doesn't support tab completion - UNUSED(a_Results); -} - - - - - -void cProtocol125::SendTeleportEntity(const cEntity & a_Entity) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_ENT_TELEPORT); - WriteInt (a_Entity.GetUniqueID()); - WriteInt ((int)(floor(a_Entity.GetPosX() * 32))); - WriteInt ((int)(floor(a_Entity.GetPosY() * 32))); - WriteInt ((int)(floor(a_Entity.GetPosZ() * 32))); - WriteChar ((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteChar ((char)((a_Entity.GetPitch() / 360.f) * 256)); - Flush(); -} - - - - - -void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_THUNDERBOLT); - WriteInt (0x7fffffff); // Entity ID of the thunderbolt; we use a constant one - WriteBool(true); // Unknown bool - WriteInt (a_BlockX * 32); - WriteInt (a_BlockY * 32); - WriteInt (a_BlockZ * 32); - Flush(); -} - - - - - -void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) -{ - // This protocol doesn't support a_DoDaylightCycle on false. - UNUSED(a_DoDaylightCycle); - - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_UPDATE_TIME); - // Use a_WorldAge for daycount, and a_TimeOfDay for the proper time of day: - WriteInt64((24000 * (a_WorldAge / 24000)) + (a_TimeOfDay % 24000)); - Flush(); -} - - - - - -void cProtocol125::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -{ - cCSLock Lock(m_CSPacket); - SendPreChunk(a_ChunkX, a_ChunkZ, false); -} - - - - - -void cProtocol125::SendUpdateSign( - int a_BlockX, int a_BlockY, int a_BlockZ, - const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 -) -{ - cCSLock Lock(m_CSPacket); - WriteByte ((unsigned char)PACKET_UPDATE_SIGN); - WriteInt (a_BlockX); - WriteShort ((short)a_BlockY); - WriteInt (a_BlockZ); - WriteString(a_Line1); - WriteString(a_Line2); - WriteString(a_Line3); - WriteString(a_Line4); - Flush(); -} - - - - - -void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_USE_BED); - WriteInt (a_Entity.GetUniqueID()); - WriteByte(0); // Unknown byte only 0 has been observed - WriteInt (a_BlockX); - WriteByte((Byte)a_BlockY); - WriteInt (a_BlockZ); - Flush(); -} - - - - - -void cProtocol125::SendWeather(eWeather a_Weather) -{ - cCSLock Lock(m_CSPacket); - switch (a_Weather) - { - case eWeather_Sunny: - { - WriteByte(PACKET_CHANGE_GAME_STATE); - WriteByte(2); // Stop rain - WriteByte(0); // Unused - Flush(); - break; - } - - case eWeather_Rain: - case eWeather_ThunderStorm: - { - WriteByte(PACKET_CHANGE_GAME_STATE); - WriteByte(1); // Begin rain - WriteByte(0); // Unused - Flush(); - break; - } - } -} - - - - - -void cProtocol125::SendWholeInventory(const cWindow & a_Window) -{ - cCSLock Lock(m_CSPacket); - cItems Slots; - a_Window.GetSlots(*(m_Client->GetPlayer()), Slots); - SendWindowSlots(a_Window.GetWindowID(), (int)Slots.size(), &(Slots[0])); -} - - - - - -void cProtocol125::SendWindowClose(const cWindow & a_Window) -{ - if (a_Window.GetWindowType() == cWindow::wtInventory) - { - // Do not send inventory-window-close - return; - } - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_WINDOW_CLOSE); - WriteChar(a_Window.GetWindowID()); - Flush(); -} - - - - - -void cProtocol125::SendWindowOpen(const cWindow & a_Window) -{ - if (a_Window.GetWindowType() < 0) - { - // Do not send for inventory windows - return; - } - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_WINDOW_OPEN); - WriteChar (a_Window.GetWindowID()); - WriteByte ((Byte)a_Window.GetWindowType()); - WriteString(a_Window.GetWindowTitle()); - WriteByte ((Byte)a_Window.GetNumNonInventorySlots()); - Flush(); -} - - - - - -void cProtocol125::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_WINDOW_PROPERTY); - WriteChar (a_Window.GetWindowID()); - WriteShort(a_Property); - WriteShort(a_Value); - Flush(); -} - - - - - -AString cProtocol125::GetAuthServerID(void) -{ - // http://wiki.vg/wiki/index.php?title=Session&oldid=2262 - // The server generates a random hash and that is used for all clients, unmodified - return cRoot::Get()->GetServer()->GetServerID(); -} - - - - - -void cProtocol125::SendData(const char * a_Data, size_t a_Size) -{ - m_Client->SendData(a_Data, a_Size); -} - - - - - -void cProtocol125::DataReceived(const char * a_Data, size_t a_Size) -{ - if (!m_ReceivedData.Write(a_Data, a_Size)) - { - // Too much data in the incoming queue, report to caller: - m_Client->PacketBufferFull(); - return; - } - - // Parse and handle all complete packets in m_ReceivedData: - while (m_ReceivedData.CanReadBytes(1)) - { - unsigned char PacketType; - m_ReceivedData.ReadByte(PacketType); - switch (ParsePacket(PacketType)) - { - case PARSE_UNKNOWN: - { - // An unknown packet has been received, notify the client and abort: - m_Client->PacketUnknown(PacketType); - return; - } - case PARSE_ERROR: - { - // An error occurred while parsing a known packet, notify the client and abort: - m_Client->PacketError(PacketType); - return; - } - case PARSE_INCOMPLETE: - { - // Incomplete packet, bail out and process with the next batch of data - m_ReceivedData.ResetRead(); - return; - } - default: - { - // Packet successfully parsed, commit the read data and try again one more packet - m_ReceivedData.CommitRead(); - break; - } - } - } -} - - - - - -int cProtocol125::ParsePacket(unsigned char a_PacketType) -{ - switch (a_PacketType) - { - default: return PARSE_UNKNOWN; - case PACKET_ANIMATION: return ParseArmAnim(); - case PACKET_BLOCK_DIG: return ParseBlockDig(); - case PACKET_BLOCK_PLACE: return ParseBlockPlace(); - case PACKET_CHAT: return ParseChat(); - case PACKET_CREATIVE_INVENTORY_ACTION: return ParseCreativeInventoryAction(); - case PACKET_DISCONNECT: return ParseDisconnect(); - case PACKET_HANDSHAKE: return ParseHandshake(); - case PACKET_KEEP_ALIVE: return ParseKeepAlive(); - case PACKET_LOGIN: return ParseLogin(); - case PACKET_PACKET_ENTITY_ACTION: return ParseEntityAction(); - case PACKET_PING: return ParsePing(); - case PACKET_PLAYER_ABILITIES: return ParsePlayerAbilities(); - case PACKET_PLAYER_LOOK: return ParsePlayerLook(); - case PACKET_PLAYER_MOVE_LOOK: return ParsePlayerMoveLook(); - case PACKET_PLAYER_ON_GROUND: return ParsePlayerOnGround(); - case PACKET_PLAYER_POS: return ParsePlayerPosition(); - case PACKET_PLUGIN_MESSAGE: return ParsePluginMessage(); - case PACKET_RESPAWN: return ParseRespawn(); - case PACKET_SLOT_SELECTED: return ParseSlotSelected(); - case PACKET_UPDATE_SIGN: return ParseUpdateSign(); - case PACKET_USE_ENTITY: return ParseUseEntity(); - case PACKET_ENCHANT_ITEM: return ParseEnchantItem(); - case PACKET_WINDOW_CLICK: return ParseWindowClick(); - case PACKET_WINDOW_CLOSE: return ParseWindowClose(); - } -} - - - - - -int cProtocol125::ParseArmAnim(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_PACKET_READ(ReadChar, char, Animation); - m_Client->HandleAnimation(Animation); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseBlockDig(void) -{ - HANDLE_PACKET_READ(ReadChar, char, Status); - HANDLE_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_PACKET_READ(ReadByte, Byte, PosY); - HANDLE_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_PACKET_READ(ReadChar, char, BlockFace); - m_Client->HandleLeftClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), Status); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseBlockPlace(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_PACKET_READ(ReadByte, Byte, PosY); - HANDLE_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_PACKET_READ(ReadChar, char, BlockFace); - - cItem HeldItem; - int res = ParseItem(HeldItem); - if (res < 0) - { - return res; - } - - // 1.2.5 didn't have any cursor position, so use 8, 8, 8, so that halfslabs and stairs work correctly and the special value is recognizable. - m_Client->HandleRightClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), 8, 8, 8, HeldItem); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseChat(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Message); - m_Client->HandleChat(Message); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseCreativeInventoryAction(void) -{ - HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); - cItem HeldItem; - int res = ParseItem(HeldItem); - if (res < 0) - { - return res; - } - m_Client->HandleCreativeInventory(SlotNum, HeldItem); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseDisconnect(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Reason); - m_Client->HandleDisconnect(Reason); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseEntityAction(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_PACKET_READ(ReadChar, char, ActionID); - - switch (ActionID) - { - case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch - case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch - case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed - case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting - case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting - } - - return PARSE_OK; -} - - - - - -int cProtocol125::ParseHandshake(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username); - - AStringVector UserData = StringSplit(Username, ";"); // "FakeTruth;localhost:25565" - if (UserData.empty()) - { - m_Client->Kick("Did not receive username"); - return PARSE_OK; - } - m_Username = UserData[0]; - - LOGD("HANDSHAKE %s", Username.c_str()); - - if (!m_Client->HandleHandshake( m_Username)) - { - return PARSE_OK; // Player is not allowed into the server - } - - SendHandshake(cRoot::Get()->GetServer()->GetServerID()); - LOGD("User \"%s\" was sent a handshake response", m_Username.c_str()); - - return PARSE_OK; -} - - - - - -int cProtocol125::ParseKeepAlive(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, KeepAliveID); - m_Client->HandleKeepAlive(KeepAliveID); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseLogin(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, ProtocolVersion); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType); - HANDLE_PACKET_READ(ReadBEInt, int, ServerMode); - HANDLE_PACKET_READ(ReadBEInt, int, Dimension); - HANDLE_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_PACKET_READ(ReadByte, Byte, WorldHeight); - HANDLE_PACKET_READ(ReadByte, Byte, MaxPlayers); - - if (ProtocolVersion < 29) - { - m_Client->Kick("Your client is outdated!"); - return PARSE_OK; - } - else if (ProtocolVersion > 29) - { - m_Client->Kick("Your client version is higher than the server!"); - return PARSE_OK; - } - - if (m_Username.compare(Username) != 0) - { - LOGWARNING("Login Username (\"%s\") does not match Handshake username (\"%s\") for client @ \"%s\", kicking", - Username.c_str(), - m_Username.c_str(), - m_Client->GetIPString().c_str() - ); - m_Client->Kick("Hacked client"); // Don't tell them why we don't want them - return PARSE_OK; - } - - m_Client->HandleLogin(ProtocolVersion, Username); - return PARSE_OK; -} - - - - - -int cProtocol125::ParsePing(void) -{ - // Packet has no more data - m_Client->HandlePing(); - return PARSE_OK; -} - - - - - - -int cProtocol125::ParsePlayerAbilities(void) -{ - HANDLE_PACKET_READ(ReadBool, bool, Invulnerable); - HANDLE_PACKET_READ(ReadBool, bool, IsFlying); - HANDLE_PACKET_READ(ReadBool, bool, CanFly); - HANDLE_PACKET_READ(ReadBool, bool, InstaMine); - // TODO: m_Client->HandlePlayerAbilities(...); - return PARSE_OK; -} - - - - - -int cProtocol125::ParsePlayerLook(void) -{ - HANDLE_PACKET_READ(ReadBEFloat, float, Rotation); - HANDLE_PACKET_READ(ReadBEFloat, float, Pitch); - HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); - m_Client->HandlePlayerLook(Rotation, Pitch, IsOnGround); - return PARSE_OK; -} - - - - - -int cProtocol125::ParsePlayerMoveLook(void) -{ - HANDLE_PACKET_READ(ReadBEDouble, double, PosX); - HANDLE_PACKET_READ(ReadBEDouble, double, PosY); - HANDLE_PACKET_READ(ReadBEDouble, double, Stance); - HANDLE_PACKET_READ(ReadBEDouble, double, PosZ); - HANDLE_PACKET_READ(ReadBEFloat, float, Rotation); - HANDLE_PACKET_READ(ReadBEFloat, float, Pitch); - HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); - // LOGD("Recv PML: {%0.2f, %0.2f, %0.2f}, Stance %0.2f, Gnd: %d", PosX, PosY, PosZ, Stance, IsOnGround ? 1 : 0); - m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, Stance, Rotation, Pitch, IsOnGround); - return PARSE_OK; -} - - - - - -int cProtocol125::ParsePlayerOnGround(void) -{ - HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); - // TODO: m_Client->HandleFlying(IsOnGround); - return PARSE_OK; -} - - - - - -int cProtocol125::ParsePlayerPosition(void) -{ - HANDLE_PACKET_READ(ReadBEDouble, double, PosX); - HANDLE_PACKET_READ(ReadBEDouble, double, PosY); - HANDLE_PACKET_READ(ReadBEDouble, double, Stance); - HANDLE_PACKET_READ(ReadBEDouble, double, PosZ); - HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); - m_Client->HandlePlayerPos(PosX, PosY, PosZ, Stance, IsOnGround); - return PARSE_OK; -} - - - - - -int cProtocol125::ParsePluginMessage(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ChannelName); - HANDLE_PACKET_READ(ReadBEShort, short, Length); - AString Data; - if (!m_ReceivedData.ReadString(Data, (size_t)Length)) - { - m_ReceivedData.CheckValid(); - return PARSE_INCOMPLETE; - } - m_ReceivedData.CheckValid(); - - // TODO: Process the data - LOGD("Received %d bytes of plugin data on channel \"%s\".", Length, ChannelName.c_str()); - - return PARSE_OK; -} - - - - - -int cProtocol125::ParseRespawn(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, Dimension); - HANDLE_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_PACKET_READ(ReadChar, char, CreativeMode); - HANDLE_PACKET_READ(ReadBEShort, short, WorldHeight); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType); - m_Client->HandleRespawn(); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseSlotSelected(void) -{ - HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); - m_Client->HandleSlotSelected(SlotNum); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseUpdateSign(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line1); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line2); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line3); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line4); - m_Client->HandleUpdateSign(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseUseEntity(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, SourceEntityID); - HANDLE_PACKET_READ(ReadBEInt, int, TargetEntityID); - HANDLE_PACKET_READ(ReadBool, bool, IsLeftClick); - m_Client->HandleUseEntity(TargetEntityID, IsLeftClick); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseEnchantItem(void) -{ - HANDLE_PACKET_READ(ReadByte, Byte, WindowID); - HANDLE_PACKET_READ(ReadByte, Byte, Enchantment); - - m_Client->HandleEnchantItem(WindowID, Enchantment); - - return PARSE_OK; -} - - - - - -int cProtocol125::ParseWindowClick(void) -{ - HANDLE_PACKET_READ(ReadChar, char, WindowID); - HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); - HANDLE_PACKET_READ(ReadBool, bool, IsRightClick); - HANDLE_PACKET_READ(ReadBEShort, short, TransactionID); - HANDLE_PACKET_READ(ReadBool, bool, IsShiftPressed); - cItem HeldItem; - int res = ParseItem(HeldItem); - if (res < 0) - { - return res; - } - - // Convert IsShiftPressed, IsRightClick, SlotNum and HeldItem into eClickAction used in the newer protocols: - eClickAction Action; - if (IsRightClick) - { - if (IsShiftPressed) - { - Action = caShiftRightClick; - } - else - { - if (SlotNum == -999) - { - Action = (HeldItem.IsEmpty()) ? caRightClickOutsideHoldNothing : caRightClickOutside; - } - else - { - Action = caRightClick; - } - } - } - else - { - // IsLeftClick - if (IsShiftPressed) - { - Action = caShiftLeftClick; - } - else - { - if (SlotNum == -999) - { - Action = (HeldItem.IsEmpty()) ? caLeftClickOutsideHoldNothing : caRightClickOutside; - } - else - { - Action = caLeftClick; - } - } - } - m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem); - return PARSE_OK; -} - - - - - -int cProtocol125::ParseWindowClose(void) -{ - HANDLE_PACKET_READ(ReadChar, char, WindowID); - m_Client->HandleWindowClose(WindowID); - return PARSE_OK; -} - - - - - -void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad) -{ - WriteByte(PACKET_PRE_CHUNK); - WriteInt (a_ChunkX); - WriteInt (a_ChunkZ); - WriteBool(a_ShouldLoad); - Flush(); -} - - - - - -void cProtocol125::SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items) -{ - WriteByte (PACKET_INVENTORY_WHOLE); - WriteChar (a_WindowID); - WriteShort((short)a_NumItems); - - for (int j = 0; j < a_NumItems; j++) - { - WriteItem(a_Items[j]); - } - Flush(); -} - - - - - -void cProtocol125::WriteItem(const cItem & a_Item) -{ - short ItemType = a_Item.m_ItemType; - ASSERT(ItemType >= -1); // Check validity of packets in debug runtime - if (ItemType <= 0) - { - // Fix, to make sure no invalid values are sent. - ItemType = -1; - } - - WriteShort(ItemType); - if (a_Item.IsEmpty()) - { - return; - } - - WriteChar (a_Item.m_ItemCount); - WriteShort(a_Item.m_ItemDamage); - - if (cItem::IsEnchantable(a_Item.m_ItemType)) - { - // TODO: Implement enchantments - WriteShort(-1); - } -} - - - - - -int cProtocol125::ParseItem(cItem & a_Item) -{ - HANDLE_PACKET_READ(ReadBEShort, short, ItemType); - - if (ItemType <= -1) - { - a_Item.Empty(); - return PARSE_OK; - } - a_Item.m_ItemType = ItemType; - - HANDLE_PACKET_READ(ReadChar, char, ItemCount); - HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage); - a_Item.m_ItemCount = ItemCount; - a_Item.m_ItemDamage = ItemDamage; - if (ItemCount <= 0) - { - a_Item.Empty(); - } - - if (!cItem::IsEnchantable(ItemType)) - { - return PARSE_OK; - } - - HANDLE_PACKET_READ(ReadBEShort, short, EnchantNumBytes); - - if (EnchantNumBytes <= 0) - { - return PARSE_OK; - } - - // TODO: Enchantment not implemented yet! - if (!m_ReceivedData.SkipRead((size_t)EnchantNumBytes)) - { - return PARSE_INCOMPLETE; - } - - return PARSE_OK; -} - - - - - -void cProtocol125::WriteCommonMetadata(const cEntity & a_Entity) -{ - Byte CommonMetadata = 0; - - if (a_Entity.IsOnFire()) - { - CommonMetadata |= 0x1; - } - if (a_Entity.IsCrouched()) - { - CommonMetadata |= 0x2; - } - if (a_Entity.IsRiding()) - { - CommonMetadata |= 0x4; - } - if (a_Entity.IsSprinting()) - { - CommonMetadata |= 0x8; - } - if (a_Entity.IsRclking()) - { - CommonMetadata |= 0x10; - } - if (a_Entity.IsInvisible()) - { - CommonMetadata |= 0x20; - } - - WriteByte(0x0); - WriteByte(CommonMetadata); -} - - - - - -void cProtocol125::WriteEntityMetadata(const cEntity & a_Entity) -{ - if (a_Entity.IsMinecart()) - { - WriteByte(0x51); - // No idea how Mojang makes their carts shakey shakey, so here is a complicated one-liner expression that does something similar - WriteInt( (((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * ((const cMinecart &)a_Entity).LastDamage()) * 4); - WriteByte(0x52); - WriteInt(1); // Shaking direction, doesn't seem to affect anything - WriteByte(0x73); - WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer - - if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace) - { - WriteByte(0x10); - WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0); // Fueled? - } - } - else if ((a_Entity.IsProjectile() && ((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow)) - { - WriteByte(0x10); - WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0); // Critical hitting arrow? - } -} - - - - - -void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) -{ - switch (a_Mob.GetMobType()) - { - case mtCreeper: - { - WriteByte(0x10); - WriteChar(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up? - WriteByte(0x11); - WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0); // Lightning-charged? - break; - } - case mtBat: - { - WriteByte(0x10); - WriteByte(((const cBat &)a_Mob).IsHanging() ? 1 : 0); // Upside down? - break; - } - case mtPig: - { - WriteByte(0x10); - WriteByte(((const cPig &)a_Mob).IsSaddled() ? 1 : 0); // Saddled? - break; - } - case mtVillager: - { - WriteByte(0x50); - WriteInt(((const cVillager &)a_Mob).GetVilType()); // What sort of TESTIFICATE? - break; - } - case mtZombie: - { - WriteByte(0xC); - WriteByte(((const cZombie &)a_Mob).IsBaby() ? 1 : 0); // Baby zombie? - WriteByte(0xD); - WriteByte(((const cZombie &)a_Mob).IsVillagerZombie() ? 1 : 0); // Converted zombie? - WriteByte(0xE); - WriteByte(((const cZombie &)a_Mob).IsConverting() ? 1 : 0); // Converted-but-converting-back zombllager? - break; - } - case mtGhast: - { - WriteByte(0x10); - WriteByte(((const cGhast &)a_Mob).IsCharging()); // About to spit a flameball? - break; - } - case mtWolf: - { - Byte WolfStatus = 0; - if (((const cWolf &)a_Mob).IsSitting()) - { - WolfStatus |= 0x1; - } - if (((const cWolf &)a_Mob).IsAngry()) - { - WolfStatus |= 0x2; - } - if (((const cWolf &)a_Mob).IsTame()) - { - WolfStatus |= 0x4; - } - WriteByte(0x10); - WriteByte(WolfStatus); - - WriteByte(0x72); - WriteFloat((float)(a_Mob.GetHealth())); // Tail health-o-meter (only shown when tamed, by the way) - WriteByte(0x13); - WriteByte(((const cWolf &)a_Mob).IsBegging() ? 1 : 0); // Ultra cute mode? - break; - } - case mtSheep: - { - // [1](1111) - // [] = Is sheared? () = Color, from 0 to 15 - - WriteByte(0x10); - Byte SheepMetadata = 0; - SheepMetadata = (Byte)((const cSheep &)a_Mob).GetFurColor(); - - if (((const cSheep &)a_Mob).IsSheared()) - { - SheepMetadata |= 0x16; - } - WriteByte(SheepMetadata); - break; - } - case mtEnderman: - { - WriteByte(0x10); - WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedBlock())); // Block that he stole from your house - WriteByte(0x11); - WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedMeta())); // Meta of block that he stole from your house - WriteByte(0x12); - WriteByte(((const cEnderman &)a_Mob).IsScreaming() ? 1 : 0); // Screaming at your face? - break; - } - case mtSkeleton: - { - WriteByte(0xD); - WriteByte(((const cSkeleton &)a_Mob).IsWither() ? 1 : 0); // It's a skeleton, but it's not - break; - } - case mtWitch: - { - WriteByte(0x15); - WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything - break; - } - case mtWither: - { - WriteByte(0x54); // Int at index 20 - WriteInt((Int32)((const cWither &)a_Mob).GetWitherInvulnerableTicks()); - WriteByte(0x66); // Float at index 6 - WriteFloat((float)(a_Mob.GetHealth())); - break; - } - case mtSlime: - case mtMagmaCube: - { - WriteByte(0x10); - if (a_Mob.GetMobType() == mtSlime) - { - WriteByte((Byte)((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME - } - else - { - WriteByte((Byte)((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME - } - break; - } - case mtHorse: - { - int Flags = 0; - if (((const cHorse &)a_Mob).IsTame()) - { - Flags |= 0x2; - } - if (((const cHorse &)a_Mob).IsSaddled()) - { - Flags |= 0x4; - } - if (((const cHorse &)a_Mob).IsChested()) - { - Flags |= 0x8; - } - if (((const cHorse &)a_Mob).IsBaby()) - { - Flags |= 0x10; // IsBred flag, according to wiki.vg - don't think it does anything in multiplayer - } - if (((const cHorse &)a_Mob).IsEating()) - { - Flags |= 0x20; - } - if (((const cHorse &)a_Mob).IsRearing()) - { - Flags |= 0x40; - } - if (((const cHorse &)a_Mob).IsMthOpen()) - { - Flags |= 0x80; - } - WriteByte(0x50); - WriteInt(Flags); - - WriteByte(0x13); - WriteByte((Byte)((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.) - - WriteByte(0x54); - int Appearance = 0; - Appearance = ((const cHorse &)a_Mob).GetHorseColor(); // Mask FF - Appearance |= ((const cHorse &)a_Mob).GetHorseStyle() * 256; // Mask FF00, so multiply by 256 - WriteInt(Appearance); - - WriteByte(0x56); - WriteInt(((const cHorse &)a_Mob).GetHorseArmour()); // Horshey armour - break; - } - default: - { - break; - } - } -} - - - - diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h deleted file mode 100644 index 3ea116c3b..000000000 --- a/src/Protocol/Protocol125.h +++ /dev/null @@ -1,185 +0,0 @@ - -// Protocol125.h - -// Interfaces to the cProtocol125 class representing the release 1.2.5 protocol (#29) - - - - - -#pragma once - -#include "Protocol.h" -#include "../ByteBuffer.h" -#include "../Entities/Painting.h" - - - - - -class cProtocol125 : - public cProtocol -{ - typedef cProtocol super; -public: - cProtocol125(cClientHandle * a_Client); - - /// Called when client sends some data: - virtual void DataReceived(const char * a_Data, size_t a_Size) override; - - /// Sending stuff to clients (alphabetically sorted): - virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; - virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; - virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; - virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; - virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; - virtual void SendChat (const AString & a_Message) override; - virtual void SendChat (const cCompositeChat & a_Message) override; - virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; - virtual void SendDestroyEntity (const cEntity & a_Entity) override; - virtual void SendDisconnect (const AString & a_Reason) override; - virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) - virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) override; - virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; - virtual void SendEntityHeadLook (const cEntity & a_Entity) override; - virtual void SendEntityLook (const cEntity & a_Entity) override; - virtual void SendEntityMetadata (const cEntity & a_Entity) override; - virtual void SendEntityProperties (const cEntity & a_Entity) override; - virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; - virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; - virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; - virtual void SendEntityVelocity (const cEntity & a_Entity) override; - virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override; - virtual void SendGameMode (eGameMode a_GameMode) override; - virtual void SendHealth (void) override; - virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; - virtual void SendKeepAlive (int a_PingID) override; - virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; - virtual void SendLoginSuccess (void) override; - virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale) override; - virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) override; - virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; - virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) override; - virtual void SendPaintingSpawn (const cPainting & a_Painting) override; - virtual void SendPickupSpawn (const cPickup & a_Pickup) override; - virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message - virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; - virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override; - virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) override; - virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override; - virtual void SendPlayerListUpdatePing (const cPlayer & a_Player) override; - virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override; - virtual void SendPlayerMaxSpeed (void) override; - virtual void SendPlayerMoveLook (void) override; - virtual void SendPlayerPosition (void) override; - virtual void SendPlayerSpawn (const cPlayer & a_Player) override; - virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; - virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override; - virtual void SendExperience (void) override; - virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; - virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; - virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message - virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message - virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; - virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; - virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; - virtual void SendSpawnMob (const cMonster & a_Mob) override; - virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; - virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; - virtual void SendStatistics (const cStatManager & a_Manager) override; - virtual void SendTabCompletionResults (const AStringVector & a_Results) override; - virtual void SendTeleportEntity (const cEntity & a_Entity) override; - virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; - virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override {} - virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; - virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual void SendWeather (eWeather a_Weather) override; - virtual void SendWholeInventory (const cWindow & a_Window) override; - virtual void SendWindowClose (const cWindow & a_Window) override; - virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; - - virtual AString GetAuthServerID(void) override; - -protected: - /// Results of packet-parsing: - enum eParseResult - { - PARSE_OK = 1, - PARSE_ERROR = -1, - PARSE_UNKNOWN = -2, - PARSE_INCOMPLETE = -3, - } ; - - cByteBuffer m_ReceivedData; ///< Buffer for the received data - - AString m_Username; ///< Stored in ParseHandshake(), compared to Login username - - /** The dimension that was last sent to a player in a Respawn or Login packet. - Used to avoid Respawning into the same dimension, which confuses the client. */ - eDimension m_LastSentDimension; - - virtual void SendData(const char * a_Data, size_t a_Size) override; - - /// Sends the Handshake packet - void SendHandshake(const AString & a_ConnectionHash); - - /// Parse the packet of the specified type from m_ReceivedData (switch into ParseXYZ()) - virtual int ParsePacket(unsigned char a_PacketType); - - // Specific packet parsers: - virtual int ParseArmAnim (void); - virtual int ParseBlockDig (void); - virtual int ParseBlockPlace (void); - virtual int ParseChat (void); - virtual int ParseCreativeInventoryAction(void); - virtual int ParseDisconnect (void); - virtual int ParseEntityAction (void); - virtual int ParseHandshake (void); - virtual int ParseKeepAlive (void); - virtual int ParseLogin (void); - virtual int ParsePing (void); - virtual int ParsePlayerAbilities (void); - virtual int ParsePlayerLook (void); - virtual int ParsePlayerMoveLook (void); - virtual int ParsePlayerOnGround (void); - virtual int ParsePlayerPosition (void); - virtual int ParsePluginMessage (void); - virtual int ParseRespawn (void); - virtual int ParseSlotSelected (void); - virtual int ParseUpdateSign (void); - virtual int ParseUseEntity (void); - virtual int ParseEnchantItem (void); - virtual int ParseWindowClick (void); - virtual int ParseWindowClose (void); - - // Utility functions: - /// Writes a "pre-chunk" packet - void SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad); - - /// Writes a "set window items" packet with the specified params - void SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items); - - /// Writes one item, "slot" as the protocol wiki calls it - virtual void WriteItem(const cItem & a_Item); - - /// Parses one item, "slot" as the protocol wiki calls it, from m_ReceivedData; returns the usual ParsePacket() codes - virtual int ParseItem(cItem & a_Item); - - /// Writes the COMMON entity metadata - void WriteCommonMetadata(const cEntity & a_Entity); - - /// Writes normal entity metadata - void WriteEntityMetadata(const cEntity & a_Entity); - - /// Writes mobile entity metadata - void WriteMobMetadata(const cMonster & a_Mob); -} ; - - - - diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp deleted file mode 100644 index 63a15c082..000000000 --- a/src/Protocol/Protocol132.cpp +++ /dev/null @@ -1,880 +0,0 @@ - -// Protocol132.cpp - -// Implements the cProtocol132 class representing the release 1.3.2 protocol (#39) - -#include "Globals.h" -#include "ChunkDataSerializer.h" -#include "Protocol132.h" -#include "../Root.h" -#include "../Server.h" -#include "../World.h" -#include "../ClientHandle.h" -#include "../Item.h" -#include "../Entities/Player.h" -#include "../Mobs/Monster.h" -#include "../UI/Window.h" -#include "../Entities/Pickup.h" -#include "../WorldStorage/FastNBT.h" -#include "../WorldStorage/EnchantmentSerializer.h" -#include "../StringCompression.h" -#include "PolarSSL++/Sha1Checksum.h" - - - - - -#define HANDLE_PACKET_READ(Proc, Type, Var) \ - Type Var; \ - { \ - if (!m_ReceivedData.Proc(Var)) \ - { \ - m_ReceivedData.CheckValid(); \ - return PARSE_INCOMPLETE; \ - } \ - m_ReceivedData.CheckValid(); \ - } - - - - - -const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows... - - - - - -enum -{ - PACKET_KEEP_ALIVE = 0x00, - PACKET_LOGIN = 0x01, - PACKET_ENTITY_EQUIPMENT = 0x05, - PACKET_COMPASS = 0x06, - PACKET_PLAYER_SPAWN = 0x14, - PACKET_COLLECT_PICKUP = 0x16, - PACKET_SPAWN_MOB = 0x18, - PACKET_DESTROY_ENTITIES = 0x1d, - PACKET_CHUNK_DATA = 0x33, - PACKET_BLOCK_CHANGE = 0x35, - PACKET_BLOCK_ACTION = 0x36, - PACKET_BLOCK_BREAK_ANIM = 0x37, - PACKET_SOUND_EFFECT = 0x3e, - PACKET_SOUND_PARTICLE_EFFECT = 0x3d, - PACKET_TAB_COMPLETION = 0xcb, - PACKET_LOCALE_VIEW_DISTANCE = 0xcc, - PACKET_CLIENT_STATUSES = 0xcd, - PACKET_ENCRYPTION_KEY_RESP = 0xfc, -} ; - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cProtocol132: - -cProtocol132::cProtocol132(cClientHandle * a_Client) : - super(a_Client), - m_IsEncrypted(false) -{ -} - - - - - -cProtocol132::~cProtocol132() -{ - if (!m_DataToSend.empty()) - { - LOGD("There are " SIZE_T_FMT " unsent bytes while deleting cProtocol132", m_DataToSend.size()); - } -} - - - - - -void cProtocol132::DataReceived(const char * a_Data, size_t a_Size) -{ - if (m_IsEncrypted) - { - Byte Decrypted[512]; - while (a_Size > 0) - { - size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; - m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes); - super::DataReceived((const char *)Decrypted, NumBytes); - a_Size -= NumBytes; - a_Data += NumBytes; - } - } - else - { - super::DataReceived(a_Data, a_Size); - } -} - - - - - -void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_BLOCK_ACTION); - WriteInt (a_BlockX); - WriteShort((short)a_BlockY); - WriteInt (a_BlockZ); - WriteChar (a_Byte1); - WriteChar (a_Byte2); - WriteShort(a_BlockType); - Flush(); -} - - - - - -void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_BLOCK_BREAK_ANIM); - WriteInt (a_entityID); - WriteInt (a_BlockX); - WriteInt (a_BlockY); - WriteInt (a_BlockZ); - WriteChar (stage); - Flush(); -} - - - - - -void cProtocol132::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_BLOCK_CHANGE); - WriteInt (a_BlockX); - WriteByte ((unsigned char)a_BlockY); - WriteInt (a_BlockZ); - WriteShort(a_BlockType); - WriteByte (a_BlockMeta); - Flush(); -} - - - - - -void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) -{ - cCSLock Lock(m_CSPacket); - - // Pre-chunk not used in 1.3.2. Finally. - - // Send the chunk data: - AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2, a_ChunkX, a_ChunkZ); - WriteByte(PACKET_CHUNK_DATA); - WriteInt (a_ChunkX); - WriteInt (a_ChunkZ); - SendData(Serialized.data(), Serialized.size()); - Flush(); -} - - - - - -void cProtocol132::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_COLLECT_PICKUP); - WriteInt (a_Entity.GetUniqueID()); - WriteInt (a_Player.GetUniqueID()); - Flush(); -} - - - - - -void cProtocol132::SendDestroyEntity(const cEntity & a_Entity) -{ - if (a_Entity.GetUniqueID() == m_Client->GetPlayer()->GetUniqueID()) - { - // Do not send "destroy self" to the client, the client would crash (FS #254) - return; - } - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_DESTROY_ENTITIES); - WriteByte(1); // entity count - WriteInt (a_Entity.GetUniqueID()); - Flush(); -} - - - - - -void cProtocol132::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_ENTITY_EQUIPMENT); - WriteInt (a_Entity.GetUniqueID()); - WriteShort(a_SlotNum); - WriteItem (a_Item); - Flush(); -} - - - - - -void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_LOGIN); - WriteInt (a_Player.GetUniqueID()); // EntityID of the player - WriteString("default"); // Level type - WriteByte ((Byte)a_Player.GetGameMode()); - WriteByte ((Byte)(a_World.GetDimension())); - WriteByte (2); // TODO: Difficulty - WriteByte (0); // Unused, used to be world height - WriteByte (8); // Client list width or something - Flush(); - m_LastSentDimension = a_World.GetDimension(); - SendCompass(a_World); -} - - - - - -void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player) -{ - const cItem & HeldItem = a_Player.GetEquippedItem(); - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PLAYER_SPAWN); - WriteInt (a_Player.GetUniqueID()); - if (a_Player.HasCustomName()) - { - WriteString(a_Player.GetCustomName()); - } - else - { - WriteString(a_Player.GetName()); - } - WriteInt ((int)(a_Player.GetPosX() * 32)); - WriteInt ((int)(a_Player.GetPosY() * 32)); - WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256)); - WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256)); - WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); - // Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata: - WriteByte (0); // Index 0, byte (flags) - WriteByte (0); // Flags, empty - WriteByte (0x7f); // End of metadata - Flush(); -} - - - - - -void cProtocol132::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_SOUND_EFFECT); - WriteString (a_SoundName); - WriteInt ((int)(a_X * 8.0)); - WriteInt ((int)(a_Y * 8.0)); - WriteInt ((int)(a_Z * 8.0)); - WriteFloat (a_Volume); - WriteChar ((char)(a_Pitch * 63.0f)); - Flush(); -} - - - - - -void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SOUND_PARTICLE_EFFECT); - WriteInt (a_EffectID); - WriteInt (a_SrcX); - WriteByte((Byte)a_SrcY); - WriteInt (a_SrcZ); - WriteInt (a_Data); - Flush(); -} - - - - - -void cProtocol132::SendSpawnMob(const cMonster & a_Mob) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_SPAWN_MOB); - WriteInt (a_Mob.GetUniqueID()); - WriteByte ((Byte)a_Mob.GetMobType()); - WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); - WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256)); - WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256)); - WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256)); - WriteShort ((short)(a_Mob.GetSpeedX() * 400)); - WriteShort ((short)(a_Mob.GetSpeedY() * 400)); - WriteShort ((short)(a_Mob.GetSpeedZ() * 400)); - - WriteCommonMetadata(a_Mob); - WriteMobMetadata(a_Mob); - WriteByte(0x7f); - - Flush(); -} - - - - - -void cProtocol132::SendTabCompletionResults(const AStringVector & a_Results) -{ - if (a_Results.empty()) - { - // No results to send - return; - } - - AString Serialized(a_Results[0]); - for (AStringVector::const_iterator itr = a_Results.begin() + 1, end = a_Results.end(); itr != end; ++itr) - { - Serialized.push_back(0); - Serialized.append(*itr); - } // for itr - a_Results[] - - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_TAB_COMPLETION); - WriteString(Serialized); - Flush(); -} - - - - - -void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -{ - // Unloading the chunk is done by sending a "map chunk" packet - // with IncludeInitialize set to true and primary bitmap set to 0: - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_CHUNK_DATA); - WriteInt (a_ChunkX); - WriteInt (a_ChunkZ); - WriteBool(true); // IncludeInitialize - WriteShort(0); // Primary bitmap - WriteShort(0); // Add bitmap - WriteInt(0); - Flush(); -} - - - - - -void cProtocol132::SendWholeInventory(const cWindow & a_Window) -{ - // 1.3.2 requires player inventory slots to be sent as SetSlot packets, - // otherwise it sometimes fails to update the window - - // Send the entire window: - super::SendWholeInventory(a_Window); - - // Send the player inventory and hotbar: - cPlayer * Player = m_Client->GetPlayer(); - const cInventory & Inventory = Player->GetInventory(); - int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots - char WindowID = a_Window.GetWindowID(); - for (short i = 0; i < cInventory::invInventoryCount; i++) - { - SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i)); - } // for i - Inventory[] - BaseOffset += cInventory::invInventoryCount; - for (short i = 0; i < cInventory::invHotbarCount; i++) - { - SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i)); - } // for i - Hotbar[] - - // Send even the item being dragged: - SendInventorySlot(-1, -1, Player->GetDraggingItem()); -} - - - - - -AString cProtocol132::GetAuthServerID(void) -{ - // http://wiki.vg/wiki/index.php?title=Session&oldid=2615 - // Server uses SHA1 to mix ServerID, Client secret and server public key together - // The mixing is done in StartEncryption, the result is in m_AuthServerID - - return m_AuthServerID; -} - - - - - -int cProtocol132::ParsePacket(unsigned char a_PacketType) -{ - switch (a_PacketType) - { - default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125 - case PACKET_CLIENT_STATUSES: return ParseClientStatuses(); - case PACKET_ENCRYPTION_KEY_RESP: return ParseEncryptionKeyResponse(); - case PACKET_LOCALE_VIEW_DISTANCE: return ParseLocaleViewDistance(); - case PACKET_TAB_COMPLETION: return ParseTabCompletion(); - } -} - - - - - -int cProtocol132::ParseBlockPlace(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_PACKET_READ(ReadByte, Byte, PosY); - HANDLE_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_PACKET_READ(ReadChar, char, BlockFace); - - cItem HeldItem; - int res = ParseItem(HeldItem); - if (res < 0) - { - return res; - } - - HANDLE_PACKET_READ(ReadChar, char, CursorX); - HANDLE_PACKET_READ(ReadChar, char, CursorY); - HANDLE_PACKET_READ(ReadChar, char, CursorZ); - - m_Client->HandleRightClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), CursorX, CursorY, CursorZ, HeldItem); - return PARSE_OK; -} - - - - - -int cProtocol132::ParseHandshake(void) -{ - HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ServerHost); - HANDLE_PACKET_READ(ReadBEInt, int, ServerPort); - m_Username = Username; - - if (!m_Client->HandleHandshake( m_Username)) - { - return PARSE_OK; // Player is not allowed into the server - } - - // Send a 0xfd Encryption Key Request http://wiki.vg/Protocol#0xFD - SendEncryptionKeyRequest(); - - return PARSE_OK; -} - - - - - -int cProtocol132::ParseClientStatuses(void) -{ - HANDLE_PACKET_READ(ReadByte, Byte, Status); - if ((Status & 1) == 0) - { - m_Client->HandleLogin(39, m_Username); - } - else - { - m_Client->HandleRespawn(); - } - return PARSE_OK; -} - - - - - -int cProtocol132::ParseEncryptionKeyResponse(void) -{ - // Read the encryption key: - HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength); - if (EncKeyLength > MAX_ENC_LEN) - { - LOGD("Too long encryption key"); - m_Client->Kick("Hacked client"); - return PARSE_OK; - } - AString EncKey; - if (!m_ReceivedData.ReadString(EncKey, (size_t)EncKeyLength)) - { - return PARSE_INCOMPLETE; - } - - // Read the encryption nonce: - HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength); - AString EncNonce; - if (!m_ReceivedData.ReadString(EncNonce, (size_t)EncNonceLength)) - { - return PARSE_INCOMPLETE; - } - if (EncNonceLength > MAX_ENC_LEN) - { - LOGD("Too long encryption nonce"); - m_Client->Kick("Hacked client"); - return PARSE_OK; - } - - HandleEncryptionKeyResponse(EncKey, EncNonce); - return PARSE_OK; -} - - - - - -int cProtocol132::ParseLocaleViewDistance(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale); - HANDLE_PACKET_READ(ReadChar, char, ViewDistance); - HANDLE_PACKET_READ(ReadChar, char, ChatFlags); - HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty); - m_Client->SetLocale(Locale); - // TODO: m_Client->HandleViewDistance(ViewDistance); - // TODO: m_Client->HandleChatFlags(ChatFlags); - // Ignoring client difficulty - return PARSE_OK; -} - - - - - -int cProtocol132::ParseLogin(void) -{ - // Login packet not used in 1.3.2 - return PARSE_ERROR; -} - - - - - -int cProtocol132::ParsePlayerAbilities(void) -{ - HANDLE_PACKET_READ(ReadBool, bool, Flags); - HANDLE_PACKET_READ(ReadChar, char, FlyingSpeed); - HANDLE_PACKET_READ(ReadChar, char, WalkingSpeed); - // TODO: m_Client->HandlePlayerAbilities(...); - return PARSE_OK; -} - - - - - -int cProtocol132::ParseTabCompletion(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Text); - m_Client->HandleTabCompletion(Text); - return PARSE_OK; -} - - - - - -void cProtocol132::SendData(const char * a_Data, size_t a_Size) -{ - m_DataToSend.append(a_Data, a_Size); -} - - - - - -void cProtocol132::Flush(void) -{ - ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly? - - if (m_DataToSend.empty()) - { - LOGD("Flushing empty"); - return; - } - const char * Data = m_DataToSend.data(); - size_t Size = m_DataToSend.size(); - if (m_IsEncrypted) - { - Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) - while (Size > 0) - { - size_t NumBytes = (Size > sizeof(Encrypted)) ? sizeof(Encrypted) : Size; - m_Encryptor.ProcessData(Encrypted, (Byte *)Data, NumBytes); - super::SendData((const char *)Encrypted, NumBytes); - Size -= NumBytes; - Data += NumBytes; - } - } - else - { - super::SendData(Data, Size); - } - m_DataToSend.clear(); -} - - - - - -void cProtocol132::WriteItem(const cItem & a_Item) -{ - short ItemType = a_Item.m_ItemType; - ASSERT(ItemType >= -1); // Check validity of packets in debug runtime - if (ItemType <= 0) - { - // Fix, to make sure no invalid values are sent. - ItemType = -1; - } - - if (a_Item.IsEmpty()) - { - WriteShort(-1); - return; - } - - WriteShort(ItemType); - WriteChar (a_Item.m_ItemCount); - WriteShort(a_Item.m_ItemDamage); - - if (a_Item.m_Enchantments.IsEmpty()) - { - WriteShort(-1); - return; - } - - // Send the enchantments: - cFastNBTWriter Writer; - const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); - Writer.Finish(); - AString Compressed; - CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort((short)Compressed.size()); - SendData(Compressed.data(), Compressed.size()); -} - - - - - -int cProtocol132::ParseItem(cItem & a_Item) -{ - HANDLE_PACKET_READ(ReadBEShort, short, ItemType); - - if (ItemType <= -1) - { - a_Item.Empty(); - return PARSE_OK; - } - a_Item.m_ItemType = ItemType; - - HANDLE_PACKET_READ(ReadChar, char, ItemCount); - HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage); - a_Item.m_ItemCount = ItemCount; - a_Item.m_ItemDamage = ItemDamage; - if (ItemCount <= 0) - { - a_Item.Empty(); - } - - HANDLE_PACKET_READ(ReadBEShort, short, MetadataLength); - if (MetadataLength <= 0) - { - return PARSE_OK; - } - - // Read the metadata - AString Metadata; - Metadata.resize((size_t)MetadataLength); - if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), (size_t)MetadataLength)) - { - return PARSE_INCOMPLETE; - } - - return ParseItemMetadata(a_Item, Metadata); -} - - - - - -int cProtocol132::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) -{ - // Uncompress the GZIPped data: - AString Uncompressed; - if (UncompressStringGZIP(a_Metadata.data(), a_Metadata.size(), Uncompressed) != Z_OK) - { - AString HexDump; - CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16); - LOG("Cannot unGZIP item metadata:\n%s", HexDump.c_str()); - return PARSE_ERROR; - } - - // Parse into NBT: - cParsedNBT NBT(Uncompressed.data(), Uncompressed.size()); - if (!NBT.IsValid()) - { - AString HexDump; - CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16); - LOG("Cannot parse NBT item metadata:\n%s", HexDump.c_str()); - return PARSE_ERROR; - } - - // Load enchantments from the NBT: - for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag)) - { - if ( - (NBT.GetType(tag) == TAG_List) && - ( - (NBT.GetName(tag) == "ench") || - (NBT.GetName(tag) == "StoredEnchantments") - ) - ) - { - EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); - } - } - - return PARSE_OK; -} - - - - - -void cProtocol132::SendCompass(const cWorld & a_World) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_COMPASS); - WriteInt((int)(a_World.GetSpawnX())); - WriteInt((int)(a_World.GetSpawnY())); - WriteInt((int)(a_World.GetSpawnZ())); - Flush(); -} - - - - - -void cProtocol132::SendEncryptionKeyRequest(void) -{ - cCSLock Lock(m_CSPacket); - cServer * Server = cRoot::Get()->GetServer(); - WriteByte(0xfd); - WriteString(Server->GetServerID()); - const AString & PublicKeyDER = Server->GetPublicKeyDER(); - WriteShort((short)(PublicKeyDER.size())); - SendData(PublicKeyDER.data(), PublicKeyDER.size()); - WriteShort(4); - WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) - Flush(); -} - - - - - -void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce) -{ - // Decrypt EncNonce using privkey - cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); - - Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; - int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce)); - if (res != 4) - { - LOGD("Bad nonce length"); - m_Client->Kick("Hacked client"); - return; - } - if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this) - { - LOGD("Bad nonce value"); - m_Client->Kick("Hacked client"); - return; - } - - // Decrypt the symmetric encryption key using privkey: - Byte DecryptedKey[MAX_ENC_LEN]; - res = rsaDecryptor.Decrypt((const Byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey, sizeof(DecryptedKey)); - if (res != 16) - { - LOGD("Bad key length"); - m_Client->Kick("Hacked client"); - return; - } - - { - // Send encryption key response: - cCSLock Lock(m_CSPacket); - WriteByte(0xfc); - WriteShort(0); - WriteShort(0); - Flush(); - } - - #ifdef _DEBUG - AString DecryptedKeyHex; - CreateHexDump(DecryptedKeyHex, DecryptedKey, res, 16); - LOGD("Received encryption key, %d bytes:\n%s", res, DecryptedKeyHex.c_str()); - #endif - - StartEncryption(DecryptedKey); - return; -} - - - - - -void cProtocol132::StartEncryption(const Byte * a_Key) -{ - m_Encryptor.Init(a_Key, a_Key); - m_Decryptor.Init(a_Key, a_Key); - m_IsEncrypted = true; - - // Prepare the m_AuthServerID: - cSha1Checksum Checksum; - cServer * Server = cRoot::Get()->GetServer(); - AString ServerID = Server->GetServerID(); - Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); - Checksum.Update(a_Key, 16); - Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size()); - Byte Digest[20]; - Checksum.Finalize(Digest); - cSha1Checksum::DigestToJava(Digest, m_AuthServerID); -} - - - - diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h deleted file mode 100644 index 1124a7253..000000000 --- a/src/Protocol/Protocol132.h +++ /dev/null @@ -1,115 +0,0 @@ - -// Protocol132.h - -// Interfaces to the cProtocol132 class representing the release 1.3.2 protocol (#39) - - - - - -#pragma once - -#include "Protocol125.h" - -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4127) - #pragma warning(disable:4189) - #pragma warning(disable:4231) - #pragma warning(disable:4244) - #pragma warning(disable:4702) -#endif - -#ifdef _MSC_VER - #pragma warning(pop) -#endif - -#include "PolarSSL++/AesCfb128Decryptor.h" -#include "PolarSSL++/AesCfb128Encryptor.h" - - - - - -class cProtocol132 : - public cProtocol125 -{ - typedef cProtocol125 super; -public: - - cProtocol132(cClientHandle * a_Client); - virtual ~cProtocol132(); - - /// Called when client sends some data: - virtual void DataReceived(const char * a_Data, size_t a_Size) override; - - // Sending commands (alphabetically sorted): - virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; - virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; - virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; - virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; - virtual void SendDestroyEntity (const cEntity & a_Entity) override; - virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; - virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; - virtual void SendPlayerSpawn (const cPlayer & a_Player) override; - virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; - virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; - virtual void SendSpawnMob (const cMonster & a_Mob) override; - virtual void SendTabCompletionResults(const AStringVector & a_Results) override; - virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendWholeInventory (const cWindow & a_Window) override; - - virtual AString GetAuthServerID(void) override; - - /// Handling of the additional packets: - virtual int ParsePacket(unsigned char a_PacketType) override; - - // Modified packets: - virtual int ParseBlockPlace (void) override; - virtual int ParseHandshake (void) override; - virtual int ParseLogin (void) override; - virtual int ParsePlayerAbilities(void) override; - - // New packets: - virtual int ParseClientStatuses (void); - virtual int ParseEncryptionKeyResponse(void); - virtual int ParseLocaleViewDistance (void); - virtual int ParseTabCompletion (void); - -protected: - bool m_IsEncrypted; - - cAesCfb128Decryptor m_Decryptor; - cAesCfb128Encryptor m_Encryptor; - - AString m_DataToSend; - - /// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID() - AString m_AuthServerID; - - virtual void SendData(const char * a_Data, size_t a_Size) override; - - // DEBUG: - virtual void Flush(void) override; - - // Items in slots are sent differently - virtual void WriteItem(const cItem & a_Item) override; - virtual int ParseItem(cItem & a_Item) override; - - /// Parses the metadata that may come with the item. - int ParseItemMetadata(cItem & a_Item, const AString & a_Metadata); - - virtual void SendCompass(const cWorld & a_World); - virtual void SendEncryptionKeyRequest(void); - - /// Decrypts the key and nonce, checks nonce, starts the symmetric encryption - void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce); - - /// Starts the symmetric encryption with the specified key; also sets m_AuthServerID - void StartEncryption(const Byte * a_Key); -} ; - - - - diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp deleted file mode 100644 index d33314a2f..000000000 --- a/src/Protocol/Protocol14x.cpp +++ /dev/null @@ -1,265 +0,0 @@ - -// Protocol14x.cpp - -/* -Implements the 1.4.x protocol classes representing these protocols: -- cProtocol142: - - release 1.4.2 protocol (#47) - - release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA) - - release 1.4.5 protocol (same as 1.4.4) -- cProtocol146: - - release 1.4.6 protocol (#51) -*/ - -#include "Globals.h" -#include "Protocol14x.h" -#include "../Root.h" -#include "../Server.h" -#include "../ClientHandle.h" -#include "../Item.h" -#include "ChunkDataSerializer.h" -#include "../Entities/Player.h" -#include "../Mobs/Monster.h" -#include "../UI/Window.h" -#include "../Entities/Pickup.h" -#include "../Entities/FallingBlock.h" - -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4127) - #pragma warning(disable:4244) - #pragma warning(disable:4231) - #pragma warning(disable:4189) - #pragma warning(disable:4702) -#endif - -#ifdef _MSC_VER - #pragma warning(pop) -#endif - - -#define HANDLE_PACKET_READ(Proc, Type, Var) \ - Type Var; \ - { \ - if (!m_ReceivedData.Proc(Var)) \ - { \ - m_ReceivedData.CheckValid(); \ - return PARSE_INCOMPLETE; \ - } \ - m_ReceivedData.CheckValid(); \ - } - - - - - -enum -{ - PACKET_UPDATE_TIME = 0x04, - PACKET_PICKUP_SPAWN = 0x15, - PACKET_SPAWN_OBJECT = 0x17, - PACKET_ENTITY_METADATA = 0x28, - PACKET_SOUND_PARTICLE_EFFECT = 0x3d -} ; - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cProtocol142: - -cProtocol142::cProtocol142(cClientHandle * a_Client) : - super(a_Client) -{ -} - - - - - -int cProtocol142::ParseLocaleViewDistance(void) -{ - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale); - HANDLE_PACKET_READ(ReadChar, char, ViewDistance); - HANDLE_PACKET_READ(ReadChar, char, ChatFlags); - HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty); - HANDLE_PACKET_READ(ReadChar, char, ShouldShowCape); // <-- new in 1.4.2 - m_Client->SetLocale(Locale); - // TODO: m_Client->HandleViewDistance(ViewDistance); - // TODO: m_Client->HandleChatFlags(ChatFlags); - // Ignoring client difficulty - return PARSE_OK; -} - - - - - -void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PICKUP_SPAWN); - WriteInt (a_Pickup.GetUniqueID()); - WriteItem (a_Pickup.GetItem()); - WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32)); - WriteChar((char)(a_Pickup.GetSpeedX() * 8)); - WriteChar((char)(a_Pickup.GetSpeedY() * 8)); - WriteChar((char)(a_Pickup.GetSpeedZ() * 8)); - Flush(); -} - - - - - -void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SOUND_PARTICLE_EFFECT); - WriteInt (a_EffectID); - WriteInt (a_SrcX); - WriteByte((Byte)a_SrcY); - WriteInt (a_SrcZ); - WriteInt (a_Data); - WriteBool(0); - Flush(); -} - - - - - -void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_UPDATE_TIME); - WriteInt64(a_WorldAge); - WriteInt64(a_TimeOfDay); - Flush(); -} - - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cProtocol146: - -cProtocol146::cProtocol146(cClientHandle * a_Client) : - super(a_Client) -{ -} - - - - - -void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup) -{ - ASSERT(!a_Pickup.GetItem().IsEmpty()); - - cCSLock Lock(m_CSPacket); - - // Send a SPAWN_OBJECT packet for the base entity: - WriteByte(PACKET_SPAWN_OBJECT); - WriteInt (a_Pickup.GetUniqueID()); - WriteByte(0x02); - WriteInt ((int)(a_Pickup.GetPosX() * 32)); - WriteInt ((int)(a_Pickup.GetPosY() * 32)); - WriteInt ((int)(a_Pickup.GetPosZ() * 32)); - WriteInt (1); - WriteShort((short)(a_Pickup.GetSpeedX() * 32)); - WriteShort((short)(a_Pickup.GetSpeedY() * 32)); - WriteShort((short)(a_Pickup.GetSpeedZ() * 32)); - WriteByte(0); - WriteByte(0); - - // Send a ENTITY_METADATA packet with the slot info: - WriteByte(PACKET_ENTITY_METADATA); - WriteInt(a_Pickup.GetUniqueID()); - WriteByte(0xaa); // a slot value at index 10 - WriteItem(a_Pickup.GetItem()); - WriteByte(0x7f); // End of metadata - Flush(); -} - - - - - -void cProtocol146::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) -{ - // Send a spawn object / vehicle packet - cCSLock Lock(m_CSPacket); - - WriteByte(PACKET_SPAWN_OBJECT); - WriteInt (a_FallingBlock.GetUniqueID()); - WriteByte(70); - WriteInt ((int)(a_FallingBlock.GetPosX() * 32)); - WriteInt ((int)(a_FallingBlock.GetPosY() * 32)); - WriteInt ((int)(a_FallingBlock.GetPosZ() * 32)); - WriteByte (0); // Pitch - WriteByte (0); // Yaw - WriteInt (a_FallingBlock.GetBlockType()); // data indicator = blocktype - WriteShort((short)(a_FallingBlock.GetSpeedX() * 400)); - WriteShort((short)(a_FallingBlock.GetSpeedY() * 400)); - WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400)); - Flush(); -} - - - - - -void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SPAWN_OBJECT); - WriteInt (a_Entity.GetUniqueID()); - WriteChar(a_ObjectType); - WriteInt ((int)(a_Entity.GetPosX() * 32)); - WriteInt ((int)(a_Entity.GetPosY() * 32)); - WriteInt ((int)(a_Entity.GetPosZ() * 32)); - WriteByte(a_Pitch); - WriteByte(a_Yaw); - WriteInt (a_ObjectData); - if (a_ObjectData != 0) - { - WriteShort((short)(a_Entity.GetSpeedX() * 400)); - WriteShort((short)(a_Entity.GetSpeedY() * 400)); - WriteShort((short)(a_Entity.GetSpeedZ() * 400)); - } - Flush(); -} - - - - - -void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_SPAWN_OBJECT); - WriteInt (a_Vehicle.GetUniqueID()); - WriteChar (a_VehicleType); - WriteInt ((int)(a_Vehicle.GetPosX() * 32)); - WriteInt ((int)(a_Vehicle.GetPosY() * 32)); - WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); - WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); - WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256)); - WriteInt (a_VehicleSubType); - if (a_VehicleSubType != 0) - { - WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); - } - Flush(); -} - - - - - diff --git a/src/Protocol/Protocol14x.h b/src/Protocol/Protocol14x.h deleted file mode 100644 index 227cc8cc7..000000000 --- a/src/Protocol/Protocol14x.h +++ /dev/null @@ -1,63 +0,0 @@ - -// Protocol14x.h - -/* -Interfaces to the 1.4.x protocol classes representing these protocols: -- cProtocol142: - - release 1.4.2 protocol (#47) - - release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA) - - release 1.4.5 protocol (same as 1.4.4) -- cProtocol146: - - release 1.4.6 protocol (#51) -*/ - - - - - -#pragma once - -#include "Protocol132.h" - - - - - -class cProtocol142 : - public cProtocol132 -{ - typedef cProtocol132 super; - -public: - cProtocol142(cClientHandle * a_Client); - - // Sending commands (alphabetically sorted): - virtual void SendPickupSpawn (const cPickup & a_Pickup) override; - virtual void SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; - - // Specific packet parsers: - virtual int ParseLocaleViewDistance(void) override; -} ; - - - - - -class cProtocol146 : - public cProtocol142 -{ - typedef cProtocol142 super; - -public: - cProtocol146(cClientHandle * a_Client); - - virtual void SendPickupSpawn (const cPickup & a_Pickup) override; - virtual void SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) override; - virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; - virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; -} ; - - - - diff --git a/src/Protocol/Protocol15x.cpp b/src/Protocol/Protocol15x.cpp deleted file mode 100644 index 089296fdf..000000000 --- a/src/Protocol/Protocol15x.cpp +++ /dev/null @@ -1,209 +0,0 @@ - -// Protocol15x.cpp - -/* -Implements the 1.5.x protocol classes: - - cProtocol150 - - release 1.5 protocol (#60) - - release 1.5.2 protocol (#61, no relevant changes found) -*/ - -#include "Globals.h" -#include "Protocol15x.h" -#include "../ClientHandle.h" -#include "../Item.h" -#include "../UI/Window.h" - - - - - -#define HANDLE_PACKET_READ(Proc, Type, Var) \ - Type Var; \ - { \ - if (!m_ReceivedData.Proc(Var)) \ - { \ - m_ReceivedData.CheckValid(); \ - return PARSE_INCOMPLETE; \ - } \ - m_ReceivedData.CheckValid(); \ - } - - - - - -enum -{ - PACKET_WINDOW_OPEN = 0x64, - PACKET_PARTICLE_EFFECT = 0x3F, - PACKET_SCOREBOARD_OBJECTIVE = 0xCE, - PACKET_SCORE_UPDATE = 0xCF, - PACKET_DISPLAY_OBJECTIVE = 0xD0 -} ; - - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cProtocol150: - -cProtocol150::cProtocol150(cClientHandle * a_Client) : - super(a_Client) -{ -} - - - - - -void cProtocol150::SendWindowOpen(const cWindow & a_Window) -{ - if (a_Window.GetWindowType() < 0) - { - // Do not send for inventory windows - return; - } - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_WINDOW_OPEN); - WriteByte (a_Window.GetWindowID()); - WriteByte (a_Window.GetWindowType()); - WriteString(a_Window.GetWindowTitle()); - WriteByte (a_Window.GetNumNonInventorySlots()); - WriteByte (1); // Use title - Flush(); -} - - - - - -void cProtocol150::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_PARTICLE_EFFECT); - WriteString(a_ParticleName); - WriteFloat(a_SrcX); - WriteFloat(a_SrcY); - WriteFloat(a_SrcZ); - WriteFloat(a_OffsetX); - WriteFloat(a_OffsetY); - WriteFloat(a_OffsetZ); - WriteFloat(a_ParticleData); - WriteInt(a_ParticleAmount); - Flush(); -} - - - - - -void cProtocol150::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SCOREBOARD_OBJECTIVE); - WriteString(a_Name); - WriteString(a_DisplayName); - WriteByte(a_Mode); - Flush(); -} - - - - - -void cProtocol150::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SCORE_UPDATE); - WriteString(a_Player); - WriteByte(a_Mode); - - if (a_Mode != 1) - { - WriteString(a_Objective); - WriteInt((int) a_Score); - } - - Flush(); -} - - - - - -void cProtocol150::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_DISPLAY_OBJECTIVE); - WriteByte((int) a_Display); - WriteString(a_Objective); - Flush(); -} - - - - - -int cProtocol150::ParseWindowClick(void) -{ - HANDLE_PACKET_READ(ReadChar, char, WindowID); - HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); - HANDLE_PACKET_READ(ReadByte, Byte, Button); - HANDLE_PACKET_READ(ReadBEShort, short, TransactionID); - HANDLE_PACKET_READ(ReadByte, Byte, Mode); - cItem HeldItem; - int res = ParseItem(HeldItem); - if (res < 0) - { - return res; - } - - // Convert Button, Mode, SlotNum and HeldItem into eClickAction: - eClickAction Action = caUnknown; - switch ((Mode << 8) | Button) - { - case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break; - case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break; - case 0x0100: Action = caShiftLeftClick; break; - case 0x0101: Action = caShiftRightClick; break; - case 0x0200: Action = caNumber1; break; - case 0x0201: Action = caNumber2; break; - case 0x0202: Action = caNumber3; break; - case 0x0203: Action = caNumber4; break; - case 0x0204: Action = caNumber5; break; - case 0x0205: Action = caNumber6; break; - case 0x0206: Action = caNumber7; break; - case 0x0207: Action = caNumber8; break; - case 0x0208: Action = caNumber9; break; - case 0x0300: Action = caMiddleClick; break; - case 0x0400: Action = (SlotNum == -999) ? caLeftClickOutsideHoldNothing : caDropKey; break; - case 0x0401: Action = (SlotNum == -999) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break; - case 0x0500: Action = (SlotNum == -999) ? caLeftPaintBegin : caUnknown; break; - case 0x0501: Action = (SlotNum != -999) ? caLeftPaintProgress : caUnknown; break; - case 0x0502: Action = (SlotNum == -999) ? caLeftPaintEnd : caUnknown; break; - case 0x0504: Action = (SlotNum == -999) ? caRightPaintBegin : caUnknown; break; - case 0x0505: Action = (SlotNum != -999) ? caRightPaintProgress : caUnknown; break; - case 0x0506: Action = (SlotNum == -999) ? caRightPaintEnd : caUnknown; break; - case 0x0600: Action = caDblClick; break; - } - - if (Action == caUnknown) - { - LOGWARNING("Received an unknown click action combination: Mode = %d, Button = %d, Slot = %d, HeldItem = %s. Ignoring packet.", - Mode, Button, SlotNum, ItemToFullString(HeldItem).c_str() - ); - ASSERT(!"Unknown click action"); - return PARSE_OK; - } - - m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem); - return PARSE_OK; -} - - - - - diff --git a/src/Protocol/Protocol15x.h b/src/Protocol/Protocol15x.h deleted file mode 100644 index 968d5ebcf..000000000 --- a/src/Protocol/Protocol15x.h +++ /dev/null @@ -1,42 +0,0 @@ - -// Protocol15x.h - -/* -Declares the 1.5.x protocol classes: - - cProtocol150 - - release 1.5 and 1.5.1 protocol (#60) - - release 1.5.2 protocol (#61; no relevant changes found) -*/ - - - - - -#pragma once - -#include "Protocol14x.h" - - - - - -class cProtocol150 : - public cProtocol146 -{ - typedef cProtocol146 super; - -public: - cProtocol150(cClientHandle * a_Client); - - virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) override; - virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; - virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; - virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; - - virtual int ParseWindowClick(void); -} ; - - - - diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp deleted file mode 100644 index 0d354a030..000000000 --- a/src/Protocol/Protocol16x.cpp +++ /dev/null @@ -1,312 +0,0 @@ - -// Protocol16x.cpp - -/* -Implements the 1.6.x protocol classes: - - cProtocol161 - - release 1.6.1 protocol (#73) - - cProtocol162 - - release 1.6.2 protocol (#74) - - release 1.6.3 protocol (#77) - no relevant changes - - release 1.6.4 protocol (#78) - no relevant changes -(others may be added later in the future for the 1.6 release series) -*/ - -#include "Globals.h" -#include "Protocol16x.h" -#include "../ClientHandle.h" -#include "../Entities/Entity.h" -#include "../Entities/Player.h" -#include "../UI/Window.h" -#include "../CompositeChat.h" - - - - - -#define HANDLE_PACKET_READ(Proc, Type, Var) \ - Type Var; \ - { \ - if (!m_ReceivedData.Proc(Var)) \ - { \ - m_ReceivedData.CheckValid(); \ - return PARSE_INCOMPLETE; \ - } \ - m_ReceivedData.CheckValid(); \ - } - - - - - -enum -{ - PACKET_CHAT = 0x03, - PACKET_UPDATE_HEALTH = 0x08, - PACKET_STEER_VEHICLE = 0x1b, - PACKET_ATTACH_ENTITY = 0x27, - PACKET_ENTITY_PROPERTIES = 0x2c, - PACKET_WINDOW_OPEN = 0x64, - PACKET_TILE_EDITOR_OPEN = 0x85, - PACKET_PLAYER_ABILITIES = 0xca, -} ; - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cProtocol161: - -cProtocol161::cProtocol161(cClientHandle * a_Client) : - super(a_Client) -{ -} - - - - - -void cProtocol161::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_ATTACH_ENTITY); - WriteInt(a_Entity.GetUniqueID()); - WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID()); - WriteBool(false); // TODO: "Should use leash?" -> no - Flush(); -} - - - - - -void cProtocol161::SendChat(const AString & a_Message) -{ - super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); -} - - - - - -void cProtocol161::SendChat(const cCompositeChat & a_Message) -{ - // This protocol version doesn't support composite messages to the full - // Just extract each part's text and use it: - - super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message.ExtractText()).c_str())); -} - - - - - -void cProtocol161::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - cCSLock Lock(m_CSPacket); - WriteByte(PACKET_TILE_EDITOR_OPEN); - WriteByte(0); - WriteInt(a_BlockX); - WriteInt(a_BlockY); - WriteInt(a_BlockZ); - Flush(); -} - - - - - -void cProtocol161::SendGameMode(eGameMode a_GameMode) -{ - super::SendGameMode(a_GameMode); - SendPlayerMaxSpeed(); -} - - - - - -void cProtocol161::SendHealth(void) -{ - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_UPDATE_HEALTH); - cPlayer * Player = m_Client->GetPlayer(); - WriteFloat((float)Player->GetHealth()); - WriteShort((short)Player->GetFoodLevel()); - WriteFloat((float)Player->GetFoodSaturationLevel()); - Flush(); -} - - - - - -void cProtocol161::SendPlayerMaxSpeed(void) -{ - cCSLock Lock(m_CSPacket); - cPlayer * Player = m_Client->GetPlayer(); - WriteByte(PACKET_ENTITY_PROPERTIES); - WriteInt(Player->GetUniqueID()); - WriteInt(1); - WriteString("generic.movementSpeed"); - WriteDouble(0.1 * Player->GetMaxSpeed()); - Flush(); -} - - - - - -void cProtocol161::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) -{ - // Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast - super::SendRespawn(a_Dimension, a_ShouldIgnoreDimensionChecks); - SendPlayerMaxSpeed(); -} - - - - - -void cProtocol161::SendWindowOpen(const cWindow & a_Window) -{ - if (a_Window.GetWindowType() < 0) - { - // Do not send for inventory windows - return; - } - cCSLock Lock(m_CSPacket); - WriteByte (PACKET_WINDOW_OPEN); - WriteChar (a_Window.GetWindowID()); - WriteByte ((Byte)a_Window.GetWindowType()); - WriteString(a_Window.GetWindowTitle()); - WriteByte ((Byte)a_Window.GetNumNonInventorySlots()); - WriteByte (1); // Use title - if (a_Window.GetWindowType() == cWindow::wtAnimalChest) - { - WriteInt(0); // TODO: The animal's EntityID - } - Flush(); -} - - - - - -int cProtocol161::ParseEntityAction(void) -{ - HANDLE_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_PACKET_READ(ReadChar, char, ActionID); - HANDLE_PACKET_READ(ReadBEInt, int, UnknownHorseVal); - - switch (ActionID) - { - case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch - case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch - case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed - case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting - case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting - } - - return PARSE_OK; -} - - - - - -int cProtocol161::ParseLogin(void) -{ - // The login packet is sent by Forge clients only - // Only parse the packet, do no extra processing - // Note that the types and the names have been only guessed and are not verified at all! - HANDLE_PACKET_READ(ReadBEInt, int, Int1); - HANDLE_PACKET_READ(ReadBEUTF16String16, AString, String1); - HANDLE_PACKET_READ(ReadChar, char, Char1); - HANDLE_PACKET_READ(ReadChar, char, Char2); - HANDLE_PACKET_READ(ReadChar, char, Char3); - HANDLE_PACKET_READ(ReadByte, Byte, Byte1); - HANDLE_PACKET_READ(ReadByte, Byte, Byte2); - return PARSE_OK; -} - - - - - -int cProtocol161::ParsePlayerAbilities(void) -{ - HANDLE_PACKET_READ(ReadByte, Byte, Flags); - HANDLE_PACKET_READ(ReadBEFloat, float, FlyingSpeed); - HANDLE_PACKET_READ(ReadBEFloat, float, WalkingSpeed); - // TODO: m_Client->HandlePlayerAbilities(...); - return PARSE_OK; -} - - - - - -int cProtocol161::ParseSteerVehicle(void) -{ - HANDLE_PACKET_READ(ReadBEFloat, float, Sideways); - HANDLE_PACKET_READ(ReadBEFloat, float, Forward); - HANDLE_PACKET_READ(ReadBool, bool, Jump); - HANDLE_PACKET_READ(ReadBool, bool, Unmount); - if (Unmount) - { - m_Client->HandleUnmount(); - } - else - { - m_Client->HandleSteerVehicle(Forward, Sideways); - } - return PARSE_OK; -} - - - - - -int cProtocol161::ParsePacket(unsigned char a_PacketType) -{ - switch (a_PacketType) - { - case PACKET_STEER_VEHICLE: return ParseSteerVehicle(); - default: return super::ParsePacket(a_PacketType); - } -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cProtocol162: - -cProtocol162::cProtocol162(cClientHandle * a_Client) : - super(a_Client) -{ -} - - - - - -void cProtocol162::SendPlayerMaxSpeed(void) -{ - cCSLock Lock(m_CSPacket); - cPlayer * Player = m_Client->GetPlayer(); - WriteByte(PACKET_ENTITY_PROPERTIES); - WriteInt(Player->GetUniqueID()); - WriteInt(1); - WriteString("generic.movementSpeed"); - WriteDouble(0.1 * Player->GetMaxSpeed()); - WriteShort(0); - Flush(); -} - - - - diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h deleted file mode 100644 index add761d1e..000000000 --- a/src/Protocol/Protocol16x.h +++ /dev/null @@ -1,78 +0,0 @@ - -// Protocol16x.h - -/* -Declares the 1.6.x protocol classes: - - cProtocol161 - - release 1.6.1 protocol (#73) - - cProtocol162 - - release 1.6.2 protocol (#74) - - release 1.6.3 protocol (#77) - no relevant changes - - release 1.6.4 protocol (#78) - no relevant changes -(others may be added later in the future for the 1.6 release series) -*/ - - - - - -#pragma once - -#include "Protocol15x.h" - - - - - -class cProtocol161 : - public cProtocol150 -{ - typedef cProtocol150 super; - -public: - cProtocol161(cClientHandle * a_Client); - -protected: - - // cProtocol150 overrides: - virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; - virtual void SendChat (const AString & a_Message) override; - virtual void SendChat (const cCompositeChat & a_Message) override; - virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) - virtual void SendGameMode (eGameMode a_GameMode) override; - virtual void SendHealth (void) override; - virtual void SendPlayerMaxSpeed(void) override; - virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override; - virtual void SendWindowOpen (const cWindow & a_Window) override; - - virtual int ParseEntityAction (void) override; - virtual int ParseLogin (void) override; - virtual int ParsePlayerAbilities(void) override; - - // New packets: - virtual int ParseSteerVehicle(void); - - // Enable new packets' handling - virtual int ParsePacket(unsigned char a_PacketType) override; -} ; - - - - - -class cProtocol162 : - public cProtocol161 -{ - typedef cProtocol161 super; - -public: - cProtocol162(cClientHandle * a_Client); - -protected: - // cProtocol161 overrides: - virtual void SendPlayerMaxSpeed(void) override; -} ; - - - - diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 95abcd146..9067131b2 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -121,7 +121,7 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd { static int sCounter = 0; cFile::CreateFolder("CommLogs"); - AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(NULL), sCounter++, a_Client->GetIPString().c_str()); + AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(nullptr), sCounter++, a_Client->GetIPString().c_str()); m_CommLogFile.Open(FileName, cFile::fmWrite); } } @@ -160,7 +160,7 @@ void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_ cPacketizer Pkt(*this, 0x1b); // Attach Entity packet Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0); + Pkt.WriteInt((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0); Pkt.WriteBool(false); } @@ -255,7 +255,7 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message) ASSERT(m_State == 3); // In game mode? cWorld * World = m_Client->GetPlayer()->GetWorld(); - bool ShouldUseChatPrefixes = (World == NULL) ? false : World->ShouldUseChatPrefixes(); + bool ShouldUseChatPrefixes = (World == nullptr) ? false : World->ShouldUseChatPrefixes(); // Send the message to the client: cPacketizer Pkt(*this, 0x02); @@ -1440,7 +1440,7 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window) -void cProtocol172::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) +void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) { ASSERT(m_State == 3); // In game mode? @@ -1902,6 +1902,7 @@ void cProtocol172::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ShowCape); m_Client->SetLocale(Locale); + m_Client->SetViewDistance(ViewDistance); // TODO: Do anything with the other values. } @@ -2065,6 +2066,22 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); HANDLE_READ(a_ByteBuffer, ReadBEShort, short, Length); + if (Length + 1 != (int)a_ByteBuffer.GetReadableSpace()) + { + LOGD("Invalid plugin message packet, payload length doesn't match packet length (exp %d, got %d)", + (int)a_ByteBuffer.GetReadableSpace() - 1, Length + ); + return; + } + + // If the plugin channel is recognized vanilla, handle it directly: + if (Channel.substr(0, 3) == "MC|") + { + HandleVanillaPluginMessage(a_ByteBuffer, Channel, Length); + return; + } + + // Read the plugin message and relay to clienthandle: AString Data; if (!a_ByteBuffer.ReadString(Data, Length)) { @@ -2218,14 +2235,76 @@ void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) -void cProtocol172::WritePacket(cByteBuffer & a_Packet) +void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength) { - cCSLock Lock(m_CSPacket); - AString Pkt; - a_Packet.ReadAll(Pkt); - WriteVarInt((UInt32)Pkt.size()); - SendData(Pkt.data(), Pkt.size()); - Flush(); + if (a_Channel == "MC|AdvCdm") + { + HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode); + switch (Mode) + { + case 0x00: + { + // Block-based commandblock update: + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); + break; + } + + // TODO: Entity-based commandblock update + + default: + { + m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %d", Mode), mtFailure); + LOG("Unhandled MC|AdvCdm packet mode."); + return; + } + } // switch (Mode) + return; + } + else if (a_Channel == "MC|Brand") + { + // Read the client's brand: + AString Brand; + if (a_ByteBuffer.ReadString(Brand, a_PayloadLength)) + { + m_Client->SetClientBrand(Brand); + } + + // Send back our brand: + SendPluginMessage("MC|Brand", "MCServer"); + return; + } + else if (a_Channel == "MC|Beacon") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2); + m_Client->HandleBeaconSelection(Effect1, Effect2); + return; + } + else if (a_Channel == "MC|ItemName") + { + AString ItemName; + if (a_ByteBuffer.ReadString(ItemName, a_PayloadLength)) + { + m_Client->HandleAnvilItemName(ItemName); + } + return; + } + else if (a_Channel == "MC|TrSel") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum); + m_Client->HandleNPCTrade(SlotNum); + return; + } + LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str()); + + // Read the payload and send it through to the clienthandle: + AString Message; + VERIFY(a_ByteBuffer.ReadString(Message, a_PayloadLength)); + m_Client->HandlePluginMessage(a_Channel, Message); } @@ -2738,7 +2817,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteByte(0xA2); WriteItem(Frame.GetItem()); WriteByte(0x3); - WriteByte(Frame.GetRotation() / 2); + WriteByte(Frame.GetItemRotation() / 2); break; } default: break; diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 8f537f5d7..f939bfb5e 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -134,7 +134,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) override; virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; + virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; virtual AString GetAuthServerID(void) override { return m_AuthServerID; } @@ -295,10 +295,10 @@ protected: void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); + /** Parses Vanilla plugin messages into specific ClientHandle calls. + The message payload is still in the bytebuffer, to be read by this function. */ + void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength); - /** Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. */ - void WritePacket(cByteBuffer & a_Packet); - /** Sends the data to the client, encrypting them if needed. */ virtual void SendData(const char * a_Data, size_t a_Size) override; diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index a2dbb7a1f..8170a494f 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -107,7 +107,7 @@ cProtocol180::cProtocol180(cClientHandle * a_Client, const AString & a_ServerAdd { static int sCounter = 0; cFile::CreateFolder("CommLogs"); - AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(NULL), sCounter++, a_Client->GetIPString().c_str()); + AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(nullptr), sCounter++, a_Client->GetIPString().c_str()); m_CommLogFile.Open(FileName, cFile::fmWrite); } } @@ -146,7 +146,7 @@ void cProtocol180::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_ cPacketizer Pkt(*this, 0x1b); // Attach Entity packet Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0); + Pkt.WriteInt((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0); Pkt.WriteBool(false); } @@ -234,7 +234,7 @@ void cProtocol180::SendChat(const cCompositeChat & a_Message) ASSERT(m_State == 3); // In game mode? cWorld * World = m_Client->GetPlayer()->GetWorld(); - bool ShouldUseChatPrefixes = (World == NULL) ? false : World->ShouldUseChatPrefixes(); + bool ShouldUseChatPrefixes = (World == nullptr) ? false : World->ShouldUseChatPrefixes(); // Send the message to the client: cPacketizer Pkt(*this, 0x02); @@ -989,7 +989,6 @@ void cProtocol180::SendPluginMessage(const AString & a_Channel, const AString & cPacketizer Pkt(*this, 0x3f); Pkt.WriteString(a_Channel); - Pkt.WriteVarInt((UInt32)a_Message.size()); Pkt.WriteBuf(a_Message.data(), a_Message.size()); } @@ -1501,7 +1500,7 @@ void cProtocol180::SendWindowOpen(const cWindow & a_Window) -void cProtocol180::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) +void cProtocol180::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) { ASSERT(m_State == 3); // In game mode? @@ -1714,6 +1713,11 @@ void cProtocol180::AddReceivedData(const char * a_Data, size_t a_Size) { UInt32 NumBytesRead = m_ReceivedData.GetReadableSpace(); m_ReceivedData.ReadVarInt(CompressedSize); + if (CompressedSize > PacketLen) + { + m_Client->Kick("Bad compression"); + return; + } if (CompressedSize > 0) { // Decompress the data: @@ -2156,6 +2160,7 @@ void cProtocol180::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadChar, char, SkinFlags); m_Client->SetLocale(Locale); + m_Client->SetViewDistance(ViewDistance); // TODO: Handle other values } @@ -2316,9 +2321,17 @@ void cProtocol180::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); - HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, DataLen); + + // If the plugin channel is recognized vanilla, handle it directly: + if (Channel.substr(0, 3) == "MC|") + { + HandleVanillaPluginMessage(a_ByteBuffer, Channel); + return; + } + + // Read the plugin message and relay to clienthandle: AString Data; - a_ByteBuffer.ReadString(Data, DataLen); + VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds m_Client->HandlePluginMessage(Channel, Data); } @@ -2507,14 +2520,65 @@ void cProtocol180::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) -void cProtocol180::WritePacket(cByteBuffer & a_Packet) +void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel) { - cCSLock Lock(m_CSPacket); - AString Pkt; - a_Packet.ReadAll(Pkt); - WriteVarInt((UInt32)Pkt.size()); - SendData(Pkt.data(), Pkt.size()); - Flush(); + if (a_Channel == "MC|AdvCdm") + { + HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode) + switch (Mode) + { + case 0x00: + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); + break; + } + + default: + { + m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %d", Mode), mtFailure); + LOG("Unhandled MC|AdvCdm packet mode."); + return; + } + } // switch (Mode) + return; + } + else if (a_Channel == "MC|Brand") + { + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); + m_Client->SetClientBrand(Brand); + // Send back our brand, including the length: + SendPluginMessage("MC|Brand", "\x08MCServer"); + return; + } + else if (a_Channel == "MC|Beacon") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2); + m_Client->HandleBeaconSelection(Effect1, Effect2); + return; + } + else if (a_Channel == "MC|ItemName") + { + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, ItemName); + m_Client->HandleAnvilItemName(ItemName); + return; + } + else if (a_Channel == "MC|TrSel") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum); + m_Client->HandleNPCTrade(SlotNum); + return; + } + LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str()); + + // Read the payload and send it through to the clienthandle: + AString Message; + VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1)); + m_Client->HandlePluginMessage(a_Channel, Message); } @@ -3046,7 +3110,7 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteByte(0xA8); WriteItem(Frame.GetItem()); WriteByte(0x09); - WriteByte(Frame.GetRotation()); + WriteByte(Frame.GetItemRotation()); break; } default: break; diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h index 554edecc8..92d9825ef 100644 --- a/src/Protocol/Protocol18x.h +++ b/src/Protocol/Protocol18x.h @@ -133,7 +133,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) override; virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; + virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; virtual AString GetAuthServerID(void) override { return m_AuthServerID; } @@ -312,10 +312,11 @@ protected: void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); + /** Parses Vanilla plugin messages into specific ClientHandle calls. + The message payload is still in the bytebuffer, the handler reads it specifically for each handled channel */ + void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel); + - /** Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. */ - void WritePacket(cByteBuffer & a_Packet); - /** Sends the data to the client, encrypting them if needed. */ virtual void SendData(const char * a_Data, size_t a_Size) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index fe53aede1..af9e0d1bc 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -7,11 +7,6 @@ #include "Globals.h" #include "ProtocolRecognizer.h" -#include "Protocol125.h" -#include "Protocol132.h" -#include "Protocol14x.h" -#include "Protocol15x.h" -#include "Protocol16x.h" #include "Protocol17x.h" #include "Protocol18x.h" #include "../ClientHandle.h" @@ -27,7 +22,7 @@ cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) : super(a_Client), - m_Protocol(NULL), + m_Protocol(nullptr), m_Buffer(8192) // We need a larger buffer to support BungeeCord - it sends one huge packet at the start { } @@ -39,7 +34,7 @@ cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) : cProtocolRecognizer::~cProtocolRecognizer() { delete m_Protocol; - m_Protocol = NULL; + m_Protocol = nullptr; } @@ -50,17 +45,6 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) { switch (a_ProtocolVersion) { - case PROTO_VERSION_1_2_5: return "1.2.5"; - case PROTO_VERSION_1_3_2: return "1.3.2"; - // case PROTO_VERSION_1_4_2: return "1.4.2"; - case PROTO_VERSION_1_4_4: return "1.4.4"; - case PROTO_VERSION_1_4_6: return "1.4.6"; - case PROTO_VERSION_1_5_0: return "1.5"; - case PROTO_VERSION_1_5_2: return "1.5.2"; - case PROTO_VERSION_1_6_1: return "1.6.1"; - case PROTO_VERSION_1_6_2: return "1.6.2"; - case PROTO_VERSION_1_6_3: return "1.6.3"; - case PROTO_VERSION_1_6_4: return "1.6.4"; case PROTO_VERSION_1_7_2: return "1.7.2"; case PROTO_VERSION_1_7_6: return "1.7.6"; case PROTO_VERSION_1_8_0: return "1.8"; @@ -75,7 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size) { - if (m_Protocol == NULL) + if (m_Protocol == nullptr) { if (!m_Buffer.Write(a_Data, a_Size)) { @@ -106,7 +90,7 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size) void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendAttachEntity(a_Entity, a_Vehicle); } @@ -116,7 +100,7 @@ void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEnti void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType); } @@ -126,7 +110,7 @@ void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_Bloc void cProtocolRecognizer::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendBlockBreakAnim(a_entityID, a_BlockX, a_BlockY, a_BlockZ, stage); } @@ -136,7 +120,7 @@ void cProtocolRecognizer::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a void cProtocolRecognizer::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } @@ -146,7 +130,7 @@ void cProtocolRecognizer::SendBlockChange(int a_BlockX, int a_BlockY, int a_Bloc void cProtocolRecognizer::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes); } @@ -156,7 +140,7 @@ void cProtocolRecognizer::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSe void cProtocolRecognizer::SendChat(const AString & a_Message) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendChat(a_Message); } @@ -166,7 +150,7 @@ void cProtocolRecognizer::SendChat(const AString & a_Message) void cProtocolRecognizer::SendChat(const cCompositeChat & a_Message) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendChat(a_Message); } @@ -176,7 +160,7 @@ void cProtocolRecognizer::SendChat(const cCompositeChat & a_Message) void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); } @@ -186,7 +170,7 @@ void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSe void cProtocolRecognizer::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendCollectEntity(a_Entity, a_Player); } @@ -196,7 +180,7 @@ void cProtocolRecognizer::SendCollectEntity(const cEntity & a_Entity, const cPla void cProtocolRecognizer::SendDestroyEntity(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendDestroyEntity(a_Entity); } @@ -206,15 +190,20 @@ void cProtocolRecognizer::SendDestroyEntity(const cEntity & a_Entity) void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) { - if (m_Protocol != NULL) + if (m_Protocol != nullptr) { m_Protocol->SendDisconnect(a_Reason); } else { // This is used when the client sends a server-ping, respond with the default packet: - WriteByte (0xff); // PACKET_DISCONNECT - WriteString(a_Reason); + static const int Packet = 0xff; // PACKET_DISCONNECT + SendData((const char *)&Packet, 1); // WriteByte() + + AString UTF16 = UTF8ToRawBEUTF16(a_Reason.c_str(), a_Reason.length()); + static const u_short Size = htons((u_short)(UTF16.size() / 2)); + SendData((const char *)&Size, 2); // WriteShort() + SendData(UTF16.data(), UTF16.size()); // WriteString() } } @@ -223,7 +212,7 @@ void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) void cProtocolRecognizer::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEditSign(a_BlockX, a_BlockY, a_BlockZ); } @@ -233,7 +222,7 @@ void cProtocolRecognizer::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) void cProtocolRecognizer::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityEffect(a_Entity, a_EffectID, a_Amplifier, a_Duration); } @@ -243,7 +232,7 @@ void cProtocolRecognizer::SendEntityEffect(const cEntity & a_Entity, int a_Effec void cProtocolRecognizer::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityEquipment(a_Entity, a_SlotNum, a_Item); } @@ -253,7 +242,7 @@ void cProtocolRecognizer::SendEntityEquipment(const cEntity & a_Entity, short a_ void cProtocolRecognizer::SendEntityHeadLook(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityHeadLook(a_Entity); } @@ -263,7 +252,7 @@ void cProtocolRecognizer::SendEntityHeadLook(const cEntity & a_Entity) void cProtocolRecognizer::SendEntityLook(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityLook(a_Entity); } @@ -273,7 +262,7 @@ void cProtocolRecognizer::SendEntityLook(const cEntity & a_Entity) void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityMetadata(a_Entity); } @@ -283,7 +272,7 @@ void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity) void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityProperties(a_Entity); } @@ -293,7 +282,7 @@ void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity) void cProtocolRecognizer::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityRelMove(a_Entity, a_RelX, a_RelY, a_RelZ); } @@ -303,7 +292,7 @@ void cProtocolRecognizer::SendEntityRelMove(const cEntity & a_Entity, char a_Rel void cProtocolRecognizer::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityRelMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ); } @@ -313,7 +302,7 @@ void cProtocolRecognizer::SendEntityRelMoveLook(const cEntity & a_Entity, char a void cProtocolRecognizer::SendEntityStatus(const cEntity & a_Entity, char a_Status) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityStatus(a_Entity, a_Status); } @@ -323,7 +312,7 @@ void cProtocolRecognizer::SendEntityStatus(const cEntity & a_Entity, char a_Stat void cProtocolRecognizer::SendEntityVelocity(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityVelocity(a_Entity); } @@ -333,7 +322,7 @@ void cProtocolRecognizer::SendEntityVelocity(const cEntity & a_Entity) void cProtocolRecognizer::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion); } @@ -343,7 +332,7 @@ void cProtocolRecognizer::SendExplosion(double a_BlockX, double a_BlockY, double void cProtocolRecognizer::SendGameMode(eGameMode a_GameMode) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendGameMode(a_GameMode); } @@ -353,7 +342,7 @@ void cProtocolRecognizer::SendGameMode(eGameMode a_GameMode) void cProtocolRecognizer::SendHealth(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendHealth(); } @@ -361,9 +350,9 @@ void cProtocolRecognizer::SendHealth(void) -void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) +void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendWindowProperty(a_Window, a_Property, a_Value); } @@ -373,7 +362,7 @@ void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, int a_Pro void cProtocolRecognizer::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item); } @@ -383,7 +372,7 @@ void cProtocolRecognizer::SendInventorySlot(char a_WindowID, short a_SlotNum, co void cProtocolRecognizer::SendKeepAlive(int a_PingID) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendKeepAlive(a_PingID); } @@ -393,7 +382,7 @@ void cProtocolRecognizer::SendKeepAlive(int a_PingID) void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendLogin(a_Player, a_World); } @@ -403,7 +392,7 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W void cProtocolRecognizer::SendLoginSuccess(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendLoginSuccess(); } @@ -413,7 +402,7 @@ void cProtocolRecognizer::SendLoginSuccess(void) void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length, m_Scale); } @@ -423,7 +412,7 @@ void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * void cProtocolRecognizer::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendMapDecorators(a_ID, a_Decorators, m_Scale); } @@ -433,7 +422,7 @@ void cProtocolRecognizer::SendMapDecorators(int a_ID, const cMapDecoratorList & void cProtocolRecognizer::SendMapInfo(int a_ID, unsigned int a_Scale) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendMapInfo(a_ID, a_Scale); } @@ -443,7 +432,7 @@ void cProtocolRecognizer::SendMapInfo(int a_ID, unsigned int a_Scale) void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmount); } @@ -461,7 +450,7 @@ void cProtocolRecognizer::SendPaintingSpawn(const cPainting & a_Painting) void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPickupSpawn(a_Pickup); } @@ -471,7 +460,7 @@ void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup) void cProtocolRecognizer::SendPlayerAbilities(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerAbilities(); } @@ -481,7 +470,7 @@ void cProtocolRecognizer::SendPlayerAbilities(void) void cProtocolRecognizer::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendEntityAnimation(a_Entity, a_Animation); } @@ -491,7 +480,7 @@ void cProtocolRecognizer::SendEntityAnimation(const cEntity & a_Entity, char a_A void cProtocolRecognizer::SendPlayerListAddPlayer(const cPlayer & a_Player) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerListAddPlayer(a_Player); } @@ -501,7 +490,7 @@ void cProtocolRecognizer::SendPlayerListAddPlayer(const cPlayer & a_Player) void cProtocolRecognizer::SendPlayerListRemovePlayer(const cPlayer & a_Player) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerListRemovePlayer(a_Player); } @@ -511,7 +500,7 @@ void cProtocolRecognizer::SendPlayerListRemovePlayer(const cPlayer & a_Player) void cProtocolRecognizer::SendPlayerListUpdateGameMode(const cPlayer & a_Player) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerListUpdateGameMode(a_Player); } @@ -521,7 +510,7 @@ void cProtocolRecognizer::SendPlayerListUpdateGameMode(const cPlayer & a_Player) void cProtocolRecognizer::SendPlayerListUpdatePing(const cPlayer & a_Player) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerListUpdatePing(a_Player); } @@ -531,7 +520,7 @@ void cProtocolRecognizer::SendPlayerListUpdatePing(const cPlayer & a_Player) void cProtocolRecognizer::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerListUpdateDisplayName(a_Player, a_CustomName); } @@ -541,7 +530,7 @@ void cProtocolRecognizer::SendPlayerListUpdateDisplayName(const cPlayer & a_Play void cProtocolRecognizer::SendPlayerMaxSpeed(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerMaxSpeed(); } @@ -551,7 +540,7 @@ void cProtocolRecognizer::SendPlayerMaxSpeed(void) void cProtocolRecognizer::SendPlayerMoveLook(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerMoveLook(); } @@ -561,7 +550,7 @@ void cProtocolRecognizer::SendPlayerMoveLook(void) void cProtocolRecognizer::SendPlayerPosition(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerPosition(); } @@ -571,7 +560,7 @@ void cProtocolRecognizer::SendPlayerPosition(void) void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPlayerSpawn(a_Player); } @@ -581,7 +570,7 @@ void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player) void cProtocolRecognizer::SendPluginMessage(const AString & a_Channel, const AString & a_Message) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendPluginMessage(a_Channel, a_Message); } @@ -591,7 +580,7 @@ void cProtocolRecognizer::SendPluginMessage(const AString & a_Channel, const ASt void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendRemoveEntityEffect(a_Entity, a_EffectID); } @@ -601,7 +590,7 @@ void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a void cProtocolRecognizer::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendRespawn(a_Dimension, a_ShouldIgnoreDimensionChecks); } @@ -611,7 +600,7 @@ void cProtocolRecognizer::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnor void cProtocolRecognizer::SendExperience(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendExperience(); } @@ -621,7 +610,7 @@ void cProtocolRecognizer::SendExperience(void) void cProtocolRecognizer::SendExperienceOrb(const cExpOrb & a_ExpOrb) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendExperienceOrb(a_ExpOrb); } @@ -631,7 +620,7 @@ void cProtocolRecognizer::SendExperienceOrb(const cExpOrb & a_ExpOrb) void cProtocolRecognizer::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode); } @@ -641,7 +630,7 @@ void cProtocolRecognizer::SendScoreboardObjective(const AString & a_Name, const void cProtocolRecognizer::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendScoreUpdate(a_Objective, a_Player, a_Score, a_Mode); } @@ -651,7 +640,7 @@ void cProtocolRecognizer::SendScoreUpdate(const AString & a_Objective, const ASt void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendDisplayObjective(a_Objective, a_Display); } @@ -661,7 +650,7 @@ void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cSco void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch); } @@ -671,7 +660,7 @@ void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, double a_ void cProtocolRecognizer::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendSoundParticleEffect(a_EffectID, a_SrcX, a_SrcY, a_SrcZ, a_Data); } @@ -681,7 +670,7 @@ void cProtocolRecognizer::SendSoundParticleEffect(int a_EffectID, int a_SrcX, in void cProtocolRecognizer::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendSpawnFallingBlock(a_FallingBlock); } @@ -691,7 +680,7 @@ void cProtocolRecognizer::SendSpawnFallingBlock(const cFallingBlock & a_FallingB void cProtocolRecognizer::SendSpawnMob(const cMonster & a_Mob) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendSpawnMob(a_Mob); } @@ -701,7 +690,7 @@ void cProtocolRecognizer::SendSpawnMob(const cMonster & a_Mob) void cProtocolRecognizer::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendSpawnObject(a_Entity, a_ObjectType, a_ObjectData, a_Yaw, a_Pitch); } @@ -711,7 +700,7 @@ void cProtocolRecognizer::SendSpawnObject(const cEntity & a_Entity, char a_Objec void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType, a_VehicleSubType); } @@ -721,7 +710,7 @@ void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_Veh void cProtocolRecognizer::SendStatistics(const cStatManager & a_Manager) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendStatistics(a_Manager); } @@ -731,7 +720,7 @@ void cProtocolRecognizer::SendStatistics(const cStatManager & a_Manager) void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Results) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendTabCompletionResults(a_Results); } @@ -741,7 +730,7 @@ void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Resul void cProtocolRecognizer::SendTeleportEntity(const cEntity & a_Entity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendTeleportEntity(a_Entity); } @@ -751,7 +740,7 @@ void cProtocolRecognizer::SendTeleportEntity(const cEntity & a_Entity) void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ); } @@ -761,7 +750,7 @@ void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_Bloc void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay, a_DoDaylightCycle); } @@ -771,7 +760,7 @@ void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bo void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ); } @@ -781,7 +770,7 @@ void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) void cProtocolRecognizer::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendUpdateBlockEntity(a_BlockEntity); } @@ -791,7 +780,7 @@ void cProtocolRecognizer::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) void cProtocolRecognizer::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendUpdateSign(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); } @@ -801,7 +790,7 @@ void cProtocolRecognizer::SendUpdateSign(int a_BlockX, int a_BlockY, int a_Block void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendUseBed(a_Entity, a_BlockX, a_BlockY, a_BlockZ); } @@ -811,7 +800,7 @@ void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int void cProtocolRecognizer::SendWeather(eWeather a_Weather) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendWeather(a_Weather); } @@ -821,7 +810,7 @@ void cProtocolRecognizer::SendWeather(eWeather a_Weather) void cProtocolRecognizer::SendWholeInventory(const cWindow & a_Window) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendWholeInventory(a_Window); } @@ -831,7 +820,7 @@ void cProtocolRecognizer::SendWholeInventory(const cWindow & a_Window) void cProtocolRecognizer::SendWindowClose(const cWindow & a_Window) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendWindowClose(a_Window); } @@ -841,7 +830,7 @@ void cProtocolRecognizer::SendWindowClose(const cWindow & a_Window) void cProtocolRecognizer::SendWindowOpen(const cWindow & a_Window) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); m_Protocol->SendWindowOpen(a_Window); } @@ -851,7 +840,7 @@ void cProtocolRecognizer::SendWindowOpen(const cWindow & a_Window) AString cProtocolRecognizer::GetAuthServerID(void) { - ASSERT(m_Protocol != NULL); + ASSERT(m_Protocol != nullptr); return m_Protocol->GetAuthServerID(); } @@ -873,51 +862,8 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) { // NOTE: If a new protocol is added or an old one is removed, adjust MCS_CLIENT_VERSIONS and // MCS_PROTOCOL_VERSIONS macros in the header file, as well as PROTO_VERSION_LATEST macro - - // The first packet should be a Handshake, 0x02: - unsigned char PacketType; - if (!m_Buffer.ReadByte(PacketType)) - { - return false; - } - switch (PacketType) - { - case 0x02: return TryRecognizeLengthlessProtocol(); // Handshake, continue recognizing - case 0xfe: - { - // This may be either a packet length or the length-less Ping packet - Byte NextByte; - if (!m_Buffer.ReadByte(NextByte)) - { - // Not enough data for either protocol - // This could actually happen with the 1.2 / 1.3 client, but their support is fading out anyway - return false; - } - if (NextByte != 0x01) - { - // This is definitely NOT a length-less Ping packet, handle as lengthed protocol: - break; - } - if (!m_Buffer.ReadByte(NextByte)) - { - // There is no more data. Although this *could* mean TCP fragmentation, it is highly unlikely - // and rather this is a 1.4 client sending a regular Ping packet (without the following Plugin message) - SendLengthlessServerPing(); - return false; - } - if (NextByte == 0xfa) - { - // Definitely a length-less Ping followed by a Plugin message - SendLengthlessServerPing(); - return false; - } - // Definitely a lengthed Initial handshake, handle below: - break; - } - } // switch (PacketType) - // This must be a lengthed protocol, try if it has the entire initial handshake packet: - m_Buffer.ResetRead(); + // Lengthed protocol, try if it has the entire initial handshake packet: UInt32 PacketLen; UInt32 ReadSoFar = (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.ReadVarInt(PacketLen)) @@ -938,61 +884,6 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) -bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) -{ - // The comm started with 0x02, which is a Handshake packet in the length-less protocol family - // 1.3.2 starts with 0x02 0x39 <name-length-short> - // 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :) - char ch; - if (!m_Buffer.ReadChar(ch)) - { - return false; - } - switch (ch) - { - case PROTO_VERSION_1_3_2: - { - m_Protocol = new cProtocol132(m_Client); - return true; - } - case PROTO_VERSION_1_4_2: - case PROTO_VERSION_1_4_4: - { - m_Protocol = new cProtocol142(m_Client); - return true; - } - case PROTO_VERSION_1_4_6: - { - m_Protocol = new cProtocol146(m_Client); - return true; - } - case PROTO_VERSION_1_5_0: - case PROTO_VERSION_1_5_2: - { - m_Protocol = new cProtocol150(m_Client); - return true; - } - case PROTO_VERSION_1_6_1: - { - m_Protocol = new cProtocol161(m_Client); - return true; - } - case PROTO_VERSION_1_6_2: - case PROTO_VERSION_1_6_3: - case PROTO_VERSION_1_6_4: - { - m_Protocol = new cProtocol162(m_Client); - return true; - } - } - m_Protocol = new cProtocol125(m_Client); - return true; -} - - - - - bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining) { UInt32 PacketType; @@ -1014,6 +905,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema { return false; } + m_Client->SetProtocolVersion(ProtocolVersion); switch (ProtocolVersion) { case PROTO_VERSION_1_7_2: @@ -1090,80 +982,3 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema - -void cProtocolRecognizer::SendLengthlessServerPing(void) -{ - AString Reply; - cServer * Server = cRoot::Get()->GetServer(); - - AString ServerDescription = Server->GetDescription(); - int NumPlayers = Server->GetNumPlayers(); - int MaxPlayers = Server->GetMaxPlayers(); - AString Favicon = Server->GetFaviconData(); - cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); - - switch (cRoot::Get()->GetPrimaryServerVersion()) - { - case PROTO_VERSION_1_2_5: - case PROTO_VERSION_1_3_2: - { - // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29 - Printf(Reply, "%s%s%i%s%i", - ServerDescription.c_str(), - cChatColor::Delimiter, - NumPlayers, - cChatColor::Delimiter, - MaxPlayers - ); - break; - } - - case PROTO_VERSION_1_4_2: - case PROTO_VERSION_1_4_4: - case PROTO_VERSION_1_4_6: - case PROTO_VERSION_1_5_0: - case PROTO_VERSION_1_5_2: - case PROTO_VERSION_1_6_1: - case PROTO_VERSION_1_6_2: - case PROTO_VERSION_1_6_3: - case PROTO_VERSION_1_6_4: - { - // The server list ping now has 1 more byte of "magic". Mojang just loves to complicate stuff. - // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29 - // _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit. - // Who cares? We're disconnecting anyway. - m_Buffer.ResetRead(); - if (m_Buffer.CanReadBytes(2)) - { - Byte val; - m_Buffer.ReadByte(val); // Packet type - Serverlist ping - m_Buffer.ReadByte(val); // 0x01 magic value - ASSERT(val == 0x01); - } - - AString ProtocolVersionNum; - Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion()); - AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->GetPrimaryServerVersion())); - - // Cannot use Printf() because of in-string NUL bytes. - Reply = cChatColor::Delimiter; - Reply.append("1"); - Reply.push_back(0); - Reply.append(ProtocolVersionNum); - Reply.push_back(0); - Reply.append(ProtocolVersionTxt); - Reply.push_back(0); - Reply.append(ServerDescription); - Reply.push_back(0); - Reply.append(Printf("%d", NumPlayers)); - Reply.push_back(0); - Reply.append(Printf("%d", MaxPlayers)); - break; - } - } // switch (m_PrimaryServerVersion) - m_Client->Kick(Reply); -} - - - - diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index e4419f6ae..dcf653e75 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -18,8 +18,8 @@ // Adjust these if a new protocol is added or an old one is removed: -#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9, 1.7.10, 1.8" -#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4, 5" +#define MCS_CLIENT_VERSIONS "1.7.x, 1.8" +#define MCS_PROTOCOL_VERSIONS "4, 5, 47" @@ -33,22 +33,6 @@ class cProtocolRecognizer : public: enum { - PROTO_VERSION_1_2_5 = 29, - PROTO_VERSION_1_3_2 = 39, - PROTO_VERSION_1_4_2 = 47, - PROTO_VERSION_1_4_4 = 49, - PROTO_VERSION_1_4_6 = 51, - PROTO_VERSION_1_5_0 = 60, - PROTO_VERSION_1_5_2 = 61, - PROTO_VERSION_1_6_1 = 73, - PROTO_VERSION_1_6_2 = 74, - PROTO_VERSION_1_6_3 = 77, - PROTO_VERSION_1_6_4 = 78, - - PROTO_VERSION_NEXT, - PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion - - // These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols PROTO_VERSION_1_7_2 = 4, PROTO_VERSION_1_7_6 = 5, PROTO_VERSION_1_8_0 = 47, @@ -137,7 +121,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) override; virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; + virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; virtual AString GetAuthServerID(void) override; @@ -150,23 +134,11 @@ protected: /// Tries to recognize protocol based on m_Buffer contents; returns true if recognized bool TryRecognizeProtocol(void); - /** Tries to recognize a protocol in the length-less family, based on m_Buffer; returns true if recognized. - Handles protocols before release 1.7, that didn't include packet lengths, and started with a 0x02 handshake packet - Note that length-less server ping is handled directly in TryRecognizeProtocol(), this function is called only - when the 0x02 Handshake packet has been received - */ - bool TryRecognizeLengthlessProtocol(void); - - /** Tries to recognize a protocol in the leghted family (1.7+), based on m_Buffer; returns true if recognized. + /** Tries to recognize a protocol in the lengthed family (1.7+), based on m_Buffer; returns true if recognized. The packet length and type have already been read, type is 0 The number of bytes remaining in the packet is passed as a_PacketLengthRemaining **/ bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining); - - /** Called when the recognizer gets a length-less protocol's server ping packet - Responds with server stats and destroys the client. - */ - void SendLengthlessServerPing(void); } ; diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index 141c67d1b..49ca4fc61 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -4,7 +4,7 @@ // Implements the cRCONServer class representing the RCON server #include "Globals.h" -#include "inifile/iniFile.h" +#include "IniFile.h" #include "RCONServer.h" #include "Server.h" #include "Root.h" @@ -242,7 +242,7 @@ bool cRCONServer::cConnection::ProcessPacket(int a_RequestID, int a_PacketType, if (strncmp(a_Payload, m_RCONServer.m_Password.c_str(), a_PayloadLength) != 0) { LOGINFO("RCON: Invalid password from client %s, dropping connection.", m_IPAddress.c_str()); - SendResponse(-1, RCON_PACKET_RESPONSE, 0, NULL); + SendResponse(-1, RCON_PACKET_RESPONSE, 0, nullptr); return false; } m_IsAuthenticated = true; @@ -250,7 +250,7 @@ bool cRCONServer::cConnection::ProcessPacket(int a_RequestID, int a_PacketType, LOGD("RCON: Client at %s has successfully authenticated", m_IPAddress.c_str()); // Send OK response: - SendResponse(a_RequestID, RCON_PACKET_RESPONSE, 0, NULL); + SendResponse(a_RequestID, RCON_PACKET_RESPONSE, 0, nullptr); return true; } @@ -268,7 +268,7 @@ bool cRCONServer::cConnection::ProcessPacket(int a_RequestID, int a_PacketType, cRoot::Get()->ExecuteConsoleCommand(cmd, *(new cRCONCommandOutput(*this, a_RequestID))); // Send an empty response: - SendResponse(a_RequestID, RCON_PACKET_RESPONSE, 0, NULL); + SendResponse(a_RequestID, RCON_PACKET_RESPONSE, 0, nullptr); return true; } } @@ -310,7 +310,7 @@ void cRCONServer::cConnection::IntToBuffer(int a_Value, char * a_Buffer) /// Sends a RCON packet back to the client void cRCONServer::cConnection::SendResponse(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload) { - ASSERT((a_PayloadLength == 0) || (a_Payload != NULL)); // Either zero data to send, or a valid payload ptr + ASSERT((a_PayloadLength == 0) || (a_Payload != nullptr)); // Either zero data to send, or a valid payload ptr char Buffer[4]; int Length = a_PayloadLength + 10; diff --git a/src/RankManager.cpp b/src/RankManager.cpp index e5896f8f3..451de88e7 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -5,7 +5,7 @@ #include "Globals.h" #include "RankManager.h" -#include "inifile/iniFile.h" +#include "IniFile.h" #include "Protocol/MojangAPI.h" #include "ClientHandle.h" @@ -384,7 +384,7 @@ protected: cRankManager::cRankManager(void) : m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), m_IsInitialized(false), - m_MojangAPI(NULL) + m_MojangAPI(nullptr) { } @@ -394,9 +394,9 @@ cRankManager::cRankManager(void) : cRankManager::~cRankManager() { - if (m_MojangAPI != NULL) + if (m_MojangAPI != nullptr) { - m_MojangAPI->SetRankManager(NULL); + m_MojangAPI->SetRankManager(nullptr); } } @@ -496,6 +496,33 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) +AString cRankManager::GetPlayerName(const AString & a_PlayerUUID) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + // Prepare the DB statement: + SQLite::Statement stmt(m_DB, "SELECT PlayerName FROM PlayerRank WHERE PlayerUUID = ?"); + stmt.bind(1, a_PlayerUUID); + + if (stmt.executeStep()) + { + return stmt.getColumn(0).getText(); + } + } + catch (SQLite::Exception & ex) + { + LOGWARNING("%s: Cannot get player name: %s", __FUNCTION__, ex.what()); + } + return AString(); +} + + + + + AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) { ASSERT(m_IsInitialized); @@ -636,6 +663,32 @@ AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) +AStringVector cRankManager::GetAllPlayerUUIDs(void) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + AStringVector res; + try + { + SQLite::Statement stmt(m_DB, "SELECT PlayerUUID FROM PlayerRank ORDER BY PlayerName COLLATE NOCASE"); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get players from DB: %s", __FUNCTION__, ex.what()); + } + return res; +} + + + + + + AStringVector cRankManager::GetAllRanks(void) { ASSERT(m_IsInitialized); @@ -1764,6 +1817,54 @@ bool cRankManager::SetDefaultRank(const AString & a_RankName) +void cRankManager::ClearPlayerRanks(void) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank"); + stmt.exec(); + } + catch (SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to remove/clear all players: %s", __FUNCTION__, ex.what()); + } +} + + + + + +bool cRankManager::UpdatePlayerName(const AString & a_PlayerUUID, const AString & a_NewPlayerName) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?"); + stmt.bind(1, a_NewPlayerName); + stmt.bind(2, a_PlayerUUID); + if (stmt.exec() > 0) + { + // The player name was changed, returns true + return true; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to update player name from UUID %s: %s", __FUNCTION__, a_PlayerUUID.c_str(), ex.what()); + } + return false; +} + + + + + + bool cRankManager::AreDBTablesEmpty(void) { return ( diff --git a/src/RankManager.h b/src/RankManager.h index f364bba6a..5dff634b5 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -60,6 +60,10 @@ public: If the player has no rank assigned, returns an empty string (NOT the default rank). */ AString GetPlayerRankName(const AString & a_PlayerUUID); + /** Returns the last name that the specified player has. + An empty string is returned if the player isn't in the database. */ + AString GetPlayerName(const AString & a_PlayerUUID); + /** Returns the names of Groups that the specified player has assigned to them. */ AStringVector GetPlayerGroups(const AString & a_PlayerUUID); @@ -79,6 +83,9 @@ public: Returns an empty vector if the rank doesn't exist. Any non-existent groups are ignored. */ AStringVector GetRankPermissions(const AString & a_RankName); + /** Returns the short uuids of all defined players. The returned players are ordered by their name (NOT their UUIDs). */ + AStringVector GetAllPlayerUUIDs(void); + /** Returns the names of all defined ranks. */ AStringVector GetAllRanks(void); @@ -211,6 +218,13 @@ public: /** Returns the name of the default rank. */ const AString & GetDefaultRank(void) const { return m_DefaultRank; } + /** Removes all player ranks from the database. Note that this doesn't change the cPlayer instances + for the already connected players, you need to update all the instances manually. */ + void ClearPlayerRanks(void); + + /** Updates the playername that is saved with this uuid. Returns false if a error occurred */ + bool UpdatePlayerName(const AString & a_PlayerUUID, const AString & a_NewPlayerName); + protected: /** The database storage for all the data. Protected by m_CS. */ @@ -226,7 +240,7 @@ protected: bool m_IsInitialized; /** The MojangAPI instance that is used for translating playernames to UUIDs. - Set in Initialize(), may be NULL. */ + Set in Initialize(), may be nullptr. */ cMojangAPI * m_MojangAPI; diff --git a/src/Root.cpp b/src/Root.cpp index 966a9b4ba..55e1c1156 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -19,11 +19,10 @@ #include "OSSupport/Timer.h" #include "LoggerListeners.h" #include "BuildInfo.h" - -#include "inifile/iniFile.h" +#include "IniFile.h" #ifdef _WIN32 - #include "conio.h" + #include <conio.h> #include <psapi.h> #elif defined(__linux__) #include <fstream> @@ -35,22 +34,21 @@ -cRoot* cRoot::s_Root = NULL; +cRoot* cRoot::s_Root = nullptr; cRoot::cRoot(void) : - m_PrimaryServerVersion(cProtocolRecognizer::PROTO_VERSION_LATEST), - m_pDefaultWorld(NULL), - m_InputThread(NULL), - m_Server(NULL), - m_MonsterConfig(NULL), - m_CraftingRecipes(NULL), - m_FurnaceRecipe(NULL), - m_WebAdmin(NULL), - m_PluginManager(NULL), + m_pDefaultWorld(nullptr), + m_InputThread(nullptr), + m_Server(nullptr), + m_MonsterConfig(nullptr), + m_CraftingRecipes(nullptr), + m_FurnaceRecipe(nullptr), + m_WebAdmin(nullptr), + m_PluginManager(nullptr), m_bStop(false), m_bRestart(false) { @@ -142,20 +140,10 @@ void cRoot::Start(void) IniFile.AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help"); } - m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0); - if (m_PrimaryServerVersion == 0) - { - m_PrimaryServerVersion = cProtocolRecognizer::PROTO_VERSION_LATEST; - } - else - { - // Make a note in the log that the primary server version is explicitly set in the ini file - LOGINFO("Primary server version set explicitly to %d.", m_PrimaryServerVersion); - } - LOG("Starting server..."); - m_MojangAPI.Start(IniFile); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init - if (!m_Server->InitServer(IniFile)) + bool ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); + m_MojangAPI.Start(IniFile, ShouldAuthenticate); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init + if (!m_Server->InitServer(IniFile, ShouldAuthenticate)) { IniFile.WriteFile("settings.ini"); LOGERROR("Failure starting server, aborting..."); @@ -166,7 +154,8 @@ void cRoot::Start(void) m_WebAdmin->Init(); LOGD("Loading settings..."); - m_RankManager.Initialize(m_MojangAPI); + m_RankManager = new cRankManager(); + m_RankManager->Initialize(m_MojangAPI); m_CraftingRecipes = new cCraftingRecipes; m_FurnaceRecipe = new cFurnaceRecipe(); @@ -225,7 +214,7 @@ void cRoot::Start(void) } #if !defined(ANDROID_NDK) - delete m_InputThread; m_InputThread = NULL; + delete m_InputThread; m_InputThread = nullptr; #endif // Stop the server: @@ -240,21 +229,21 @@ void cRoot::Start(void) m_Authenticator.Stop(); LOGD("Freeing MonsterConfig..."); - delete m_MonsterConfig; m_MonsterConfig = NULL; - delete m_WebAdmin; m_WebAdmin = NULL; + delete m_MonsterConfig; m_MonsterConfig = nullptr; + delete m_WebAdmin; m_WebAdmin = nullptr; LOGD("Unloading recipes..."); - delete m_FurnaceRecipe; m_FurnaceRecipe = NULL; - delete m_CraftingRecipes; m_CraftingRecipes = NULL; + delete m_FurnaceRecipe; m_FurnaceRecipe = nullptr; + delete m_CraftingRecipes; m_CraftingRecipes = nullptr; LOGD("Unloading worlds..."); UnloadWorlds(); LOGD("Stopping plugin manager..."); - delete m_PluginManager; m_PluginManager = NULL; + delete m_PluginManager; m_PluginManager = nullptr; cItemHandler::Deinit(); LOG("Cleaning up..."); - delete m_Server; m_Server = NULL; + delete m_Server; m_Server = nullptr; LOG("Shutdown successful!"); } @@ -329,7 +318,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile) cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) { cWorld * World = m_WorldsByName[a_WorldName]; - if (World != NULL) + if (World != nullptr) { return World; } @@ -374,7 +363,7 @@ void cRoot::StopWorlds(void) void cRoot::UnloadWorlds(void) { - m_pDefaultWorld = NULL; + m_pDefaultWorld = nullptr; for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr) { delete itr->second; @@ -407,7 +396,7 @@ cWorld * cRoot::GetWorld(const AString & a_WorldName, bool a_SearchForFolder) { return CreateAndInitializeWorld(a_WorldName); } - return NULL; + return nullptr; } @@ -419,7 +408,7 @@ bool cRoot::ForEachWorld(cWorldListCallback & a_Callback) for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2) { ++itr2; - if (itr->second != NULL) + if (itr->second != nullptr) { if (a_Callback.Item(itr->second)) { @@ -554,7 +543,7 @@ void cRoot::BroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix) { for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr) { - itr->second->BroadcastChat(a_Message, NULL, a_ChatPrefix); + itr->second->BroadcastChat(a_Message, nullptr, a_ChatPrefix); } // for itr - m_WorldsByName[] } @@ -624,7 +613,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac m_BestRating(0), m_NameLength(a_PlayerName.length()), m_PlayerName(a_PlayerName), - m_BestMatch(NULL), + m_BestMatch(nullptr), m_NumMatches(0) {} @@ -644,6 +633,22 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac +bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback) +{ + for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end();itr++) + { + if (itr->second->DoWithPlayerByUUID(a_PlayerUUID, a_Callback)) + { + return true; + } + } + return false; +} + + + + + AString cRoot::GetProtocolVersionTextFromInt(int a_ProtocolVersion) { return cProtocolRecognizer::GetVersionTextFromInt(a_ProtocolVersion); diff --git a/src/Root.h b/src/Root.h index 9bc975889..ec6b83fcc 100644 --- a/src/Root.h +++ b/src/Root.h @@ -41,11 +41,12 @@ namespace Json class cRoot { public: - static bool m_TerminateEventRaised; - static cRoot * Get() { return s_Root; } // tolua_end + static bool m_TerminateEventRaised; + + cRoot(void); ~cRoot(); @@ -73,9 +74,6 @@ public: /// Writes chunkstats, for each world and totals, to the output callback void LogChunkStats(cCommandOutputCallback & a_Output); - int GetPrimaryServerVersion(void) const { return m_PrimaryServerVersion; } // tolua_export - void SetPrimaryServerVersion(int a_Version) { m_PrimaryServerVersion = a_Version; } // tolua_export - cMonsterConfig * GetMonsterConfig(void) { return m_MonsterConfig; } cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export @@ -88,7 +86,7 @@ public: cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } - cRankManager & GetRankManager (void) { return m_RankManager; } + cRankManager * GetRankManager (void) { return m_RankManager; } /** Queues a console command for execution through the cServer class. The command will be executed in the tick thread @@ -128,19 +126,22 @@ public: /// Finds a player from a partial or complete player name and calls the callback - case-insensitive bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + /** Finds the player over his uuid and calls the callback */ + bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + // tolua_begin /// Sends a chat message to all connected clients (in all worlds) void BroadcastChat (const AString & a_Message, eMessageType a_ChatPrefix = mtCustom); - void BroadcastChatInfo (const AString & a_Message) { BroadcastChat(a_Message, mtInformation); } + void BroadcastChat (const cCompositeChat & a_Message); + void BroadcastChatDeath (const AString & a_Message) { BroadcastChat(a_Message, mtDeath); } void BroadcastChatFailure(const AString & a_Message) { BroadcastChat(a_Message, mtFailure); } - void BroadcastChatSuccess(const AString & a_Message) { BroadcastChat(a_Message, mtSuccess); } - void BroadcastChatWarning(const AString & a_Message) { BroadcastChat(a_Message, mtWarning); } void BroadcastChatFatal (const AString & a_Message) { BroadcastChat(a_Message, mtFailure); } + void BroadcastChatInfo (const AString & a_Message) { BroadcastChat(a_Message, mtInformation); } void BroadcastChatJoin (const AString & a_Message) { BroadcastChat(a_Message, mtJoin); } void BroadcastChatLeave (const AString & a_Message) { BroadcastChat(a_Message, mtLeave); } - void BroadcastChatDeath (const AString & a_Message) { BroadcastChat(a_Message, mtDeath); } - void BroadcastChat (const cCompositeChat & a_Message); + void BroadcastChatSuccess(const AString & a_Message) { BroadcastChat(a_Message, mtSuccess); } + void BroadcastChatWarning(const AString & a_Message) { BroadcastChat(a_Message, mtWarning); } /// Returns the textual description of the protocol version: 49 -> "1.4.4". Provided specifically for Lua API static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum); @@ -169,9 +170,6 @@ private: typedef std::map<AString, cWorld *> WorldMap; typedef std::vector<cCommand> cCommandQueue; - - /// The version of the protocol that is primary for the server (reported in the server list). All versions are still supported. - int m_PrimaryServerVersion; cWorld * m_pDefaultWorld; WorldMap m_WorldsByName; @@ -190,7 +188,7 @@ private: cPluginManager * m_PluginManager; cAuthenticator m_Authenticator; cMojangAPI m_MojangAPI; - cRankManager m_RankManager; + cRankManager * m_RankManager; cHTTPServer m_HTTPServer; bool m_bStop; diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index def952029..adce8b549 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -278,7 +278,7 @@ cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World) { for (int i = 0; i < (int) dsCount; ++i) { - m_Display[i] = NULL; + m_Display[i] = nullptr; } } @@ -294,14 +294,14 @@ cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString if (Status.second) { - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); m_World->BroadcastScoreboardObjective(a_Name, a_DisplayName, 0); return &Status.first->second; } else { - return NULL; + return nullptr; } } @@ -320,14 +320,14 @@ bool cScoreboard::RemoveObjective(const AString & a_Name) return false; } - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1); for (unsigned int i = 0; i < (unsigned int) dsCount; ++i) { if (m_Display[i] == &it->second) { - SetDisplay(NULL, (eDisplaySlot) i); + SetDisplay(nullptr, (eDisplaySlot) i); } } @@ -348,7 +348,7 @@ cObjective * cScoreboard::GetObjective(const AString & a_Name) if (it == m_Objectives.end()) { - return NULL; + return nullptr; } else { @@ -369,7 +369,7 @@ cTeam * cScoreboard::RegisterTeam( std::pair<cTeamMap::iterator, bool> Status = m_Teams.insert(cNamedTeam(a_Name, Team)); - return Status.second ? &Status.first->second : NULL; + return Status.second ? &Status.first->second : nullptr; } @@ -404,7 +404,7 @@ cTeam * cScoreboard::GetTeam(const AString & a_Name) if (it == m_Teams.end()) { - return NULL; + return nullptr; } else { @@ -428,7 +428,7 @@ cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name) } } - return NULL; + return nullptr; } @@ -452,7 +452,7 @@ void cScoreboard::SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot) { m_Display[a_Slot] = a_Objective; - ASSERT(m_World != NULL); + ASSERT(m_World != nullptr); m_World->BroadcastDisplayObjective(a_Objective ? a_Objective->GetName() : "", a_Slot); } diff --git a/src/Scoreboard.h b/src/Scoreboard.h index f53b8c803..dd4073c89 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -226,22 +226,22 @@ public: // tolua_begin - /** Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision */ + /** Registers a new scoreboard objective, returns the cObjective instance, nullptr on name collision */ cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type); /** Removes a registered objective, returns true if operation was successful */ bool RemoveObjective(const AString & a_Name); - /** Retrieves the objective with the specified name, NULL if not found */ + /** Retrieves the objective with the specified name, nullptr if not found */ cObjective * GetObjective(const AString & a_Name); - /** Registers a new team, returns the cTeam instance, NULL on name collision */ + /** Registers a new team, returns the cTeam instance, nullptr on name collision */ cTeam * RegisterTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix); /** Removes a registered team, returns true if operation was successful */ bool RemoveTeam(const AString & a_Name); - /** Retrieves the team with the specified name, NULL if not found */ + /** Retrieves the team with the specified name, nullptr if not found */ cTeam * GetTeam(const AString & a_Name); void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot); diff --git a/src/Server.cpp b/src/Server.cpp index 969ffd693..bbb5ecff3 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -22,7 +22,7 @@ #include "MersenneTwister.h" -#include "inifile/iniFile.h" +#include "IniFile.h" #include "Vector3.h" #include <fstream> @@ -196,7 +196,7 @@ void cServer::PlayerDestroying(const cPlayer * a_Player) -bool cServer::InitServer(cIniFile & a_SettingsIni) +bool cServer::InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth) { m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!"); m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100); @@ -247,7 +247,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni) m_bIsConnected = true; m_ServerID = "-"; - m_ShouldAuthenticate = a_SettingsIni.GetValueSetB("Authentication", "Authenticate", true); + m_ShouldAuthenticate = a_ShouldAuth; if (m_ShouldAuthenticate) { MTRand mtrand1; @@ -338,7 +338,7 @@ void cServer::OnConnectionAccepted(cSocket & a_Socket) LOGERROR("Client \"%s\" cannot be handled, server probably unstable", ClientIP.c_str()); a_Socket.CloseSocket(); delete NewHandle; - NewHandle = NULL; + NewHandle = nullptr; return; } @@ -450,7 +450,7 @@ bool cServer::Start(void) bool cServer::Command(cClientHandle & a_Client, AString & a_Cmd) { - return cRoot::Get()->GetPluginManager()->CallHookChat(a_Client.GetPlayer(), a_Cmd); + return cRoot::Get()->GetPluginManager()->CallHookChat(*(a_Client.GetPlayer()), a_Cmd); } @@ -491,6 +491,17 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac { if (split.size() > 1) { + cPluginManager::PluginMap map = cPluginManager::Get()->GetAllPlugins(); + + for (auto plugin_entry : map) + { + if (plugin_entry.first == split[1]) + { + a_Output.Out("Error! Plugin is already loaded!"); + a_Output.Finished(); + return; + } + } a_Output.Out(cPluginManager::Get()->LoadPlugin(split[1]) ? "Plugin loaded" : "Error occurred loading plugin"); } else @@ -626,17 +637,17 @@ void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & void cServer::BindBuiltInConsoleCommands(void) { cPluginManager * PlgMgr = cPluginManager::Get(); - PlgMgr->BindConsoleCommand("help", NULL, " - Shows the available commands"); - PlgMgr->BindConsoleCommand("reload", NULL, " - Reloads all plugins"); - PlgMgr->BindConsoleCommand("restart", NULL, " - Restarts the server cleanly"); - PlgMgr->BindConsoleCommand("stop", NULL, " - Stops the server cleanly"); - PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics"); - PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin"); - PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin"); - PlgMgr->BindConsoleCommand("destroyentities", NULL, " - Destroys all entities in all worlds"); + PlgMgr->BindConsoleCommand("help", nullptr, " - Shows the available commands"); + PlgMgr->BindConsoleCommand("reload", nullptr, " - Reloads all plugins"); + PlgMgr->BindConsoleCommand("restart", nullptr, " - Restarts the server cleanly"); + PlgMgr->BindConsoleCommand("stop", nullptr, " - Stops the server cleanly"); + PlgMgr->BindConsoleCommand("chunkstats", nullptr, " - Displays detailed chunk memory statistics"); + PlgMgr->BindConsoleCommand("load <pluginname>", nullptr, " - Adds and enables the specified plugin"); + PlgMgr->BindConsoleCommand("unload <pluginname>", nullptr, " - Disables the specified plugin"); + PlgMgr->BindConsoleCommand("destroyentities", nullptr, " - Destroys all entities in all worlds"); #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml"); + PlgMgr->BindConsoleCommand("dumpmem", nullptr, " - Dumps all used memory blocks together with their callstacks into memdump.xml"); #endif } @@ -705,7 +716,7 @@ void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const ASt cServer::cNotifyWriteThread::cNotifyWriteThread(void) : super("ClientPacketThread"), - m_Server(NULL) + m_Server(nullptr) { } diff --git a/src/Server.h b/src/Server.h index 6d659fa40..022794bbc 100644 --- a/src/Server.h +++ b/src/Server.h @@ -56,7 +56,7 @@ class cServer // tolua_export public: // tolua_export virtual ~cServer() {} - bool InitServer(cIniFile & a_SettingsIni); + bool InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth); // tolua_begin diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index 707dfb9e8..e335176a8 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -42,15 +42,15 @@ cSetChunkData::cSetChunkData( m_ShouldMarkDirty(a_ShouldMarkDirty) { // Check the params' validity: - ASSERT(a_BlockTypes != NULL); - ASSERT(a_BlockMetas != NULL); + ASSERT(a_BlockTypes != nullptr); + ASSERT(a_BlockMetas != nullptr); // Copy block types and metas: memcpy(m_BlockTypes, a_BlockTypes, sizeof(cChunkDef::BlockTypes)); memcpy(m_BlockMetas, a_BlockMetas, sizeof(cChunkDef::BlockNibbles)); // Copy lights, if both given: - if ((a_BlockLight != NULL) && (a_SkyLight != NULL)) + if ((a_BlockLight != nullptr) && (a_SkyLight != nullptr)) { memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); memcpy(m_SkyLight, a_SkyLight, sizeof(m_SkyLight)); @@ -62,7 +62,7 @@ cSetChunkData::cSetChunkData( } // Copy the heightmap, if available: - if (a_HeightMap != NULL) + if (a_HeightMap != nullptr) { memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap)); m_IsHeightMapValid = true; @@ -73,7 +73,7 @@ cSetChunkData::cSetChunkData( } // Copy biomes, if available: - if (a_Biomes != NULL) + if (a_Biomes != nullptr) { memcpy(m_Biomes, a_Biomes, sizeof(m_Biomes)); m_AreBiomesValid = true; diff --git a/src/SetChunkData.h b/src/SetChunkData.h index 03e9ef4d9..1eeb75ca9 100644 --- a/src/SetChunkData.h +++ b/src/SetChunkData.h @@ -27,7 +27,7 @@ public: Will move the entity and blockentity lists into the internal storage, and empty the a_Entities and a_BlockEntities lists. a_BlockTypes and a_BlockMetas must always be valid. - If either of the light arrays are NULL, the chunk data will be marked as not having any light at all and + If either of the light arrays are nullptr, the chunk data will be marked as not having any light at all and will be scheduled for re-lighting once it is set into the chunkmap. If a_Biomes is not valid, the internal flag is set and the world will calculate the biomes using the chunk generator when setting the chunk data. diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index 59ea51aa0..dc8dffe2d 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -55,7 +55,7 @@ cDelayedFluidSimulatorChunkData::cDelayedFluidSimulatorChunkData(int a_TickDelay cDelayedFluidSimulatorChunkData::~cDelayedFluidSimulatorChunkData() { delete[] m_Slots; - m_Slots = NULL; + m_Slots = nullptr; } @@ -86,7 +86,7 @@ void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, return; } - if ((a_Chunk == NULL) || !a_Chunk->IsValid()) + if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 7ae84af7b..75ebefcf7 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -220,7 +220,7 @@ bool cFireSimulator::DoesBurnForever(BLOCKTYPE a_BlockType) void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if ((a_Chunk == NULL) || !a_Chunk->IsValid()) + if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } @@ -333,7 +333,7 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int int a_PosX = x + a_Chunk->GetPosX() * cChunkDef::Width; int a_PosZ = z + a_Chunk->GetPosZ() * cChunkDef::Width; - if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(&m_World, a_PosX, y, a_PosZ, ssFireSpread)) + if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, a_PosX, y, a_PosZ, ssFireSpread)) { return; } @@ -359,7 +359,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel int Z = a_RelZ + gNeighborCoords[i].z; cChunkPtr Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(X, Z); - if (Neighbour == NULL) + if (Neighbour == nullptr) { continue; } @@ -382,7 +382,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel } bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance); - if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(&m_World, AbsX, Y, AbsZ, ssFireSpread)) + if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, AbsX, Y, AbsZ, ssFireSpread)) { Neighbour->SetBlock(X, Y, Z, E_BLOCK_FIRE, 0); } diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index b839aa746..e95ef216d 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -220,7 +220,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i ASSERT(a_NewMeta > 0); // Source blocks aren't spread a_NearChunk = a_NearChunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((a_NearChunk == NULL) || (!a_NearChunk->IsValid())) + if ((a_NearChunk == nullptr) || (!a_NearChunk->IsValid())) { // Chunk not available return; @@ -297,7 +297,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i ChunkInterface, m_World, PluginInterface, - NULL, + nullptr, BlockX, a_RelY, BlockZ diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp index 58501326f..9c8453d04 100644 --- a/src/Simulator/FluidSimulator.cpp +++ b/src/Simulator/FluidSimulator.cpp @@ -178,7 +178,7 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a } delete Pos; - Pos = NULL; + Pos = nullptr; } if (LowestPoint == m_World.GetBlockMeta(a_X, a_Y, a_Z)) diff --git a/src/Simulator/FluidSimulator.h b/src/Simulator/FluidSimulator.h index 0877a7bf1..d65a8e78b 100644 --- a/src/Simulator/FluidSimulator.h +++ b/src/Simulator/FluidSimulator.h @@ -51,7 +51,7 @@ public: virtual Direction GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over = true); /// Creates a ChunkData object for the simulator to use. The simulator returns the correct object type. - virtual cFluidSimulatorData * CreateChunkData(void) { return NULL; } + virtual cFluidSimulatorData * CreateChunkData(void) { return nullptr; } bool IsFluidBlock (BLOCKTYPE a_BlockType) const { return (a_BlockType == m_FluidBlock); } bool IsStationaryFluidBlock(BLOCKTYPE a_BlockType) const { return (a_BlockType == m_StationaryFluidBlock); } diff --git a/src/Simulator/IncrementalRedstoneSimulator.inc b/src/Simulator/IncrementalRedstoneSimulator.inc index 6fda9824c..2d03584e2 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.inc +++ b/src/Simulator/IncrementalRedstoneSimulator.inc @@ -27,6 +27,11 @@ public: { } ~cIncrementalRedstoneSimulator(); + + virtual cRedstoneSimulatorChunkData * CreateChunkData() override + { + return new cIncrementalRedstoneSimulatorChunkData; + } virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, ChunkType * a_Chunk) override; @@ -77,7 +82,7 @@ private: }; class cIncrementalRedstoneSimulatorChunkData : - cRedstoneSimulatorChunkData + public cRedstoneSimulatorChunkData { public: /// Per-chunk data for the simulator, specified individual chunks to simulate @@ -408,7 +413,12 @@ void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid // Checking only when a block is changed, as opposed to every tick, also improves performance - PoweredBlocksList & PoweredBlocks = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks; + cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData * SimulatorChunkData = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData()); + if (SimulatorChunkData == NULL) + { + return; + } + PoweredBlocksList & PoweredBlocks = SimulatorChunkData->m_PoweredBlocks; for (typename PoweredBlocksList::iterator itr = PoweredBlocks.begin(); itr != PoweredBlocks.end();) { if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) @@ -554,6 +564,11 @@ template <class ChunkType, class WorldType, template <BLOCKTYPE block> class Get void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, ChunkType * a_Chunk) { m_RedstoneSimulatorChunkData = (cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + if (m_RedstoneSimulatorChunkData == NULL) + { + m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData(); + a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData); + } if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty()) { return; @@ -1986,7 +2001,6 @@ bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, // Check if western(left) neighbor is a powered on repeater who is facing us if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) { - NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX -1, a_RelBlockY, a_RelBlockZ) & 0x3; if ((OtherRepeaterDir & 0x03) == 0x1) { return true; diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h index 88e141e85..832b26dfc 100644 --- a/src/Simulator/NoopRedstoneSimulator.h +++ b/src/Simulator/NoopRedstoneSimulator.h @@ -36,5 +36,10 @@ public: UNUSED(a_BlockZ); UNUSED(a_Chunk); } + + virtual cRedstoneSimulatorChunkData * CreateChunkData() override + { + return nullptr; + } } ; diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index f6d36f869..6104d39b4 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -24,5 +24,7 @@ public: super(a_World) { } + + virtual cRedstoneSimulatorChunkData * CreateChunkData() = 0; } ; diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index e8887ce59..dfbd3e458 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -7,7 +7,7 @@ #include "../Defines.h" #include "../Entities/FallingBlock.h" #include "../Chunk.h" -#include "inifile/iniFile.h" +#include "../IniFile.h" @@ -94,7 +94,7 @@ bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if ((a_Chunk == NULL) || !a_Chunk->IsValid()) + if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } @@ -160,6 +160,7 @@ bool cSandSimulator::CanContinueFallThrough(BLOCKTYPE a_BlockType) case E_BLOCK_FIRE: case E_BLOCK_FLOWER_POT: case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: + case E_BLOCK_IRON_TRAPDOOR: case E_BLOCK_LAVA: case E_BLOCK_LEVER: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp index d26702166..29a1132ad 100644 --- a/src/Simulator/Simulator.cpp +++ b/src/Simulator/Simulator.cpp @@ -8,6 +8,11 @@ #include "Simulator.inc" -#pragma clang diagnostic ignored "-Wweak-template-vtables" +#ifdef __clang__ + #pragma clang diagnostic ignored "-Wweak-template-vtables" +#endif // __clang__ + template class cSimulator<cChunk, cWorld>; + + diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 484cac334..119742346 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -22,7 +22,7 @@ cVaporizeFluidSimulator::cVaporizeFluidSimulator(cWorld & a_World, BLOCKTYPE a_F void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if (a_Chunk == NULL) + if (a_Chunk == nullptr) { return; } diff --git a/src/StackWalker.h b/src/StackWalker.h index bf47d3726..a609f6840 100644 --- a/src/StackWalker.h +++ b/src/StackWalker.h @@ -88,7 +88,7 @@ public: StackWalker( int options = OptionsAll, // 'int' is by design, to combine the enum-flags - LPCSTR szSymPath = NULL, + LPCSTR szSymPath = nullptr, DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess() ); @@ -108,9 +108,9 @@ public: BOOL ShowCallstack( HANDLE hThread = GetCurrentThread(), - const CONTEXT *context = NULL, - PReadProcessMemoryRoutine readMemoryFunction = NULL, - LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback + const CONTEXT *context = nullptr, + PReadProcessMemoryRoutine readMemoryFunction = nullptr, + LPVOID pUserData = nullptr // optional to identify some data in the 'readMemoryFunction'-callback ); #if _MSC_VER >= 1300 @@ -180,11 +180,11 @@ protected: #define GET_CURRENT_CONTEXT(c, contextFlags) \ do { \ memset(&c, 0, sizeof(CONTEXT)); \ - EXCEPTION_POINTERS *pExp = NULL; \ + EXCEPTION_POINTERS *pExp = nullptr; \ __try { \ throw 0; \ } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ - if (pExp != NULL) \ + if (pExp != nullptr) \ memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ c.ContextFlags = contextFlags; \ } while(0); diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 73147eebc..34f2da682 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -20,7 +20,7 @@ AString & AppendVPrintf(AString & str, const char * format, va_list args) { - ASSERT(format != NULL); + ASSERT(format != nullptr); char buffer[2048]; size_t len; @@ -441,10 +441,10 @@ static bool isLegalUTF8(const unsigned char * source, int length) -AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16) +AString UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length) { - a_UTF16.clear(); - a_UTF16.reserve(a_UTF8Length * 3); + AString UTF16; + UTF16.reserve(a_UTF8Length * 3); const unsigned char * source = (const unsigned char*)a_UTF8; const unsigned char * sourceEnd = source + a_UTF8Length; @@ -458,12 +458,12 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { - return a_UTF16; + return UTF16; } // Do this check whether lenient or strict if (!isLegalUTF8(source, extraBytesToRead + 1)) { - return a_UTF16; + return UTF16; } // The cases all fall through. See "Note A" below. @@ -487,13 +487,13 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a ch = ' '; } unsigned short v = htons((unsigned short)ch); - a_UTF16.append((const char *)&v, 2); + UTF16.append((const char *)&v, 2); } else if (ch > UNI_MAX_UTF16) { // Invalid value, replace with a space unsigned short v = htons(' '); - a_UTF16.append((const char *)&v, 2); + UTF16.append((const char *)&v, 2); } else { @@ -501,11 +501,11 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a ch -= halfBase; unsigned short v1 = htons((ch >> halfShift) + UNI_SUR_HIGH_START); unsigned short v2 = htons((ch & halfMask) + UNI_SUR_LOW_START); - a_UTF16.append((const char *)&v1, 2); - a_UTF16.append((const char *)&v2, 2); + UTF16.append((const char *)&v1, 2); + UTF16.append((const char *)&v2, 2); } } - return a_UTF16; + return UTF16; } /* @@ -562,7 +562,7 @@ AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, siz #else int Count = sprintf(line, "%08x:", (unsigned)i); #endif - // Remove the terminating NULL / leftover garbage in line, after the sprintf-ed value + // Remove the terminating nullptr / leftover garbage in line, after the sprintf-ed value memset(line + Count, 32, sizeof(line) - Count); p = line + 10; q = p + 2 + a_BytesPerLine * 3 + 1; diff --git a/src/StringUtils.h b/src/StringUtils.h index a76894d05..159e8ecac 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -66,8 +66,8 @@ extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AS /// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8); -/// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16 -extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16); +/// Converts a UTF-8 string into a UTF-16 BE string; returns a ref to a_UTF16 +extern AString UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length); /// Creates a nicely formatted HEX dump of the given memory block. Max a_BytesPerLine is 120 extern AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, size_t a_BytesPerLine); diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index b4facb2d3..9113ec343 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -10,6 +10,7 @@ #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/EnderChestEntity.h" #include "../BlockEntities/FurnaceEntity.h" +#include "../Entities/Minecart.h" #include "../Items/ItemHandler.h" #include "Window.h" #include "../CraftingRecipes.h" @@ -47,9 +48,9 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); bool bAsync = false; - if (GetSlot(a_SlotNum, a_Player) == NULL) + if (GetSlot(a_SlotNum, a_Player) == nullptr) { - LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum); return; } @@ -713,7 +714,7 @@ void cSlotAreaCrafting::UpdateRecipe(cPlayer & a_Player) { cCraftingGrid Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize); cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); - cRoot::Get()->GetCraftingRecipes()->GetRecipe(&a_Player, Grid, Recipe); + cRoot::Get()->GetCraftingRecipes()->GetRecipe(a_Player, Grid, Recipe); SetSlot(0, a_Player, Recipe.GetResult()); m_ParentWindow.SendSlot(a_Player, this, 0); } @@ -735,7 +736,7 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player) // Not found. Add a new one: cCraftingGrid Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize); cCraftingRecipe Recipe(Grid); - cRoot::Get()->GetCraftingRecipes()->GetRecipe(&a_Player, Grid, Recipe); + cRoot::Get()->GetCraftingRecipes()->GetRecipe(a_Player, Grid, Recipe); m_Recipes.push_back(std::make_pair(a_Player.GetUniqueID(), Recipe)); return m_Recipes.back().second; } @@ -790,9 +791,9 @@ void cSlotAreaAnvil::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_C } bool bAsync = false; - if (GetSlot(a_SlotNum, a_Player) == NULL) + if (GetSlot(a_SlotNum, a_Player) == nullptr) { - LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum); return; } @@ -979,7 +980,7 @@ void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player) m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player); m_MaximumCost = 0; - ((cAnvilWindow*)&m_ParentWindow)->SetRepairedItemName("", NULL); + ((cAnvilWindow*)&m_ParentWindow)->SetRepairedItemName("", nullptr); int PosX, PosY, PosZ; ((cAnvilWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); @@ -1237,9 +1238,9 @@ void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); bool bAsync = false; - if (GetSlot(a_SlotNum, a_Player) == NULL) + if (GetSlot(a_SlotNum, a_Player) == nullptr) { - LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum); return; } @@ -1407,9 +1408,9 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); bool bAsync = false; - if (GetSlot(a_SlotNum, a_Player) == NULL) + if (GetSlot(a_SlotNum, a_Player) == nullptr) { - LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum); return; } @@ -1708,19 +1709,19 @@ cSlotAreaFurnace::~cSlotAreaFurnace() void cSlotAreaFurnace::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) { - if (m_Furnace == NULL) + if (m_Furnace == nullptr) { - LOGERROR("cSlotAreaFurnace::Clicked(): m_Furnace == NULL"); - ASSERT(!"cSlotAreaFurnace::Clicked(): m_Furnace == NULL"); + LOGERROR("cSlotAreaFurnace::Clicked(): m_Furnace == nullptr"); + ASSERT(!"cSlotAreaFurnace::Clicked(): m_Furnace == nullptr"); return; } if (a_SlotNum == 2) { bool bAsync = false; - if (GetSlot(a_SlotNum, a_Player) == NULL) + if (GetSlot(a_SlotNum, a_Player) == nullptr) { - LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum); return; } @@ -1920,6 +1921,40 @@ void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Playe //////////////////////////////////////////////////////////////////////////////// +// cSlotAreaMinecartWithChest: + +cSlotAreaMinecartWithChest::cSlotAreaMinecartWithChest(cMinecartWithChest * a_Chest, cWindow & a_ParentWindow) : + cSlotArea(27, a_ParentWindow), + m_Chest(a_Chest) +{ +} + + + + + +const cItem * cSlotAreaMinecartWithChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const +{ + // a_SlotNum ranges from 0 to 26, use that to index the minecart chest entity's inventory directly: + UNUSED(a_Player); + return &(m_Chest->GetSlot(a_SlotNum)); +} + + + + + +void cSlotAreaMinecartWithChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) +{ + UNUSED(a_Player); + m_Chest->SetSlot(a_SlotNum, a_Item); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// // cSlotAreaInventoryBase: cSlotAreaInventoryBase::cSlotAreaInventoryBase(int a_NumSlots, int a_SlotOffset, cWindow & a_ParentWindow) : @@ -2036,9 +2071,9 @@ void cSlotAreaArmor::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_C } bool bAsync = false; - if (GetSlot(a_SlotNum, a_Player) == NULL) + if (GetSlot(a_SlotNum, a_Player) == nullptr) { - LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum); return; } @@ -2188,15 +2223,15 @@ const cItem * cSlotAreaTemporary::GetSlot(int a_SlotNum, cPlayer & a_Player) con LOGERROR("cSlotAreaTemporary: player \"%s\" not found for slot %d!", a_Player.GetName().c_str(), a_SlotNum); ASSERT(!"cSlotAreaTemporary: player not found!"); - // Player not found, this should not happen, ever! Return NULL, but things may break by this. - return NULL; + // Player not found, this should not happen, ever! Return nullptr, but things may break by this. + return nullptr; } if (a_SlotNum >= (int)(itr->second.size())) { LOGERROR("cSlotAreaTemporary: asking for more slots than actually stored!"); ASSERT(!"cSlotAreaTemporary: asking for more slots than actually stored!"); - return NULL; + return nullptr; } return &(itr->second[a_SlotNum]); @@ -2285,7 +2320,7 @@ cItem * cSlotAreaTemporary::GetPlayerSlots(cPlayer & a_Player) cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID()); if (itr == m_Items.end()) { - return NULL; + return nullptr; } return &(itr->second[0]); } diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 6bbc87b76..1eeeb9836 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -20,6 +20,7 @@ class cChestEntity; class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; +class cMinecartWithChest; class cCraftingRecipe; class cEnchantingWindow; class cWorld; @@ -448,10 +449,27 @@ protected: // cItemGrid::cListener overrides: virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; - /// Called after an item has been smelted to handle statistics e.t.c. + /// Called after an item has been smelted to handle statistics etc. void HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player); } ; + +class cSlotAreaMinecartWithChest : + public cSlotArea +{ +public: + cSlotAreaMinecartWithChest(cMinecartWithChest * a_ChestCart, cWindow & a_ParentWindow); + + virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override; + virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; + +protected: + cMinecartWithChest * m_Chest; +}; + + + + diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 1b7b07f77..1598dd3e7 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -14,6 +14,7 @@ #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/EnderChestEntity.h" #include "../BlockEntities/HopperEntity.h" +#include "../Entities/Minecart.h" #include "../Root.h" #include "../Bindings/PluginManager.h" @@ -32,7 +33,7 @@ cWindow::cWindow(WindowType a_WindowType, const AString & a_WindowTitle) : m_WindowTitle(a_WindowTitle), m_IsDestroyed(false), m_ShouldDistributeToHotbarFirst(true), - m_Owner(NULL) + m_Owner(nullptr) { if (a_WindowType == wtInventory) { @@ -104,10 +105,10 @@ const cItem * cWindow::GetSlot(cPlayer & a_Player, int a_SlotNum) const // Return the item at the specified slot for the specified player int LocalSlotNum = 0; const cSlotArea * Area = GetSlotArea(a_SlotNum, LocalSlotNum); - if (Area == NULL) + if (Area == nullptr) { - LOGWARNING("%s: requesting item from an invalid SlotArea (SlotNum %d), returning NULL.", __FUNCTION__, a_SlotNum); - return NULL; + LOGWARNING("%s: requesting item from an invalid SlotArea (SlotNum %d), returning nullptr.", __FUNCTION__, a_SlotNum); + return nullptr; } return Area->GetSlot(LocalSlotNum, a_Player); } @@ -121,7 +122,7 @@ void cWindow::SetSlot(cPlayer & a_Player, int a_SlotNum, const cItem & a_Item) // Set the item to the specified slot for the specified player int LocalSlotNum = 0; cSlotArea * Area = GetSlotArea(a_SlotNum, LocalSlotNum); - if (Area == NULL) + if (Area == nullptr) { LOGWARNING("%s: requesting write to an invalid SlotArea (SlotNum %d), ignoring.", __FUNCTION__, a_SlotNum); return; @@ -176,7 +177,7 @@ void cWindow::GetSlots(cPlayer & a_Player, cItems & a_Slots) const for (int i = 0; i < NumSlots; i++) { const cItem * Item = (*itr)->GetSlot(i, a_Player); - if (Item == NULL) + if (Item == nullptr) { a_Slots.push_back(cItem()); } @@ -310,7 +311,7 @@ bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) } cClientHandle * ClientHandle = a_Player.GetClientHandle(); - if (ClientHandle != NULL) + if (ClientHandle != nullptr) { ClientHandle->SendWindowClose(*this); } @@ -344,7 +345,7 @@ bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) void cWindow::OwnerDestroyed() { - m_Owner = NULL; + m_Owner = nullptr; // Close window for each player. Note that the last one needs special handling while (m_OpenedBy.size() > 1) { @@ -510,10 +511,10 @@ void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_Relativ void cWindow::Destroy(void) { - if (m_Owner != NULL) + if (m_Owner != nullptr) { m_Owner->CloseWindow(); - m_Owner = NULL; + m_Owner = nullptr; } m_IsDestroyed = true; } @@ -528,7 +529,7 @@ cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) { LOGWARNING("%s: requesting an invalid SlotNum: %d out of %d slots", __FUNCTION__, a_GlobalSlotNum, GetNumSlots() - 1); ASSERT(!"Invalid SlotNum"); - return NULL; + return nullptr; } // Iterate through all the SlotAreas, find the correct one @@ -546,7 +547,7 @@ cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) // We shouldn't be here - the check at the beginnning should prevent this. Log and assert LOGWARNING("%s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d", __FUNCTION__, GetNumSlots(), LocalSlotNum); ASSERT(!"Invalid GetNumSlots"); - return NULL; + return nullptr; } @@ -559,7 +560,7 @@ const cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum { LOGWARNING("%s: requesting an invalid SlotNum: %d out of %d slots", __FUNCTION__, a_GlobalSlotNum, GetNumSlots() - 1); ASSERT(!"Invalid SlotNum"); - return NULL; + return nullptr; } // Iterate through all the SlotAreas, find the correct one @@ -577,7 +578,7 @@ const cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum // We shouldn't be here - the check at the beginnning should prevent this. Log and assert LOGWARNING("%s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d", __FUNCTION__, GetNumSlots(), LocalSlotNum); ASSERT(!"Invalid GetNumSlots"); - return NULL; + return nullptr; } @@ -668,7 +669,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int { int LocalSlotNum = 0; cSlotArea * Area = GetSlotArea(*itr, LocalSlotNum); - if (Area == NULL) + if (Area == nullptr) { LOGWARNING("%s: Bad SlotArea for slot %d", __FUNCTION__, *itr); continue; @@ -757,20 +758,7 @@ void cWindow::BroadcastWholeWindow(void) -void cWindow::BroadcastProgress(int a_Progressbar, int a_Value) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) - { - (*itr)->GetClientHandle()->SendWindowProperty(*this, a_Progressbar, a_Value); - } // for itr - m_OpenedBy[] -} - - - - - -void cWindow::SetProperty(int a_Property, int a_Value) +void cWindow::SetProperty(short a_Property, short a_Value) { cCSLock Lock(m_CS); for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) @@ -783,7 +771,7 @@ void cWindow::SetProperty(int a_Property, int a_Value) -void cWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) +void cWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player) { a_Player.GetClientHandle()->SendWindowProperty(*this, a_Property, a_Value); } @@ -848,7 +836,7 @@ void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Playe { m_RepairedItemName = a_Name; - if (a_Player != NULL) + if (a_Player != nullptr) { m_AnvilSlotArea->UpdateResult(*a_Player); } @@ -918,7 +906,7 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : -void cEnchantingWindow::SetProperty(int a_Property, int a_Value) +void cEnchantingWindow::SetProperty(short a_Property, short a_Value) { if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) { @@ -934,7 +922,7 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value) -void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) +void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player) { if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) { @@ -950,7 +938,7 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Pla -int cEnchantingWindow::GetPropertyValue(int a_Property) +short cEnchantingWindow::GetPropertyValue(short a_Property) { if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) { @@ -975,7 +963,7 @@ cChestWindow::cChestWindow(cChestEntity * a_Chest) : m_BlockY(a_Chest->GetPosY()), m_BlockZ(a_Chest->GetPosZ()), m_PrimaryChest(a_Chest), - m_SecondaryChest(NULL) + m_SecondaryChest(nullptr) { m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); @@ -1026,7 +1014,7 @@ void cChestWindow::OpenedByPlayer(cPlayer & a_Player) cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); - if (m_SecondaryChest != NULL) + if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1); cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); @@ -1048,7 +1036,7 @@ bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); - if (m_SecondaryChest != NULL) + if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1); cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); @@ -1076,6 +1064,34 @@ cChestWindow::~cChestWindow() //////////////////////////////////////////////////////////////////////////////// +// cMinecartWithChestWindow: + +cMinecartWithChestWindow::cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart) : + cWindow(wtChest, "Minecart with Chest"), + m_ChestCart(a_ChestCart) +{ + m_ShouldDistributeToHotbarFirst = false; + m_SlotAreas.push_back(new cSlotAreaMinecartWithChest(a_ChestCart, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); + + a_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestopen", a_ChestCart->GetPosX(), a_ChestCart->GetPosY(), a_ChestCart->GetPosZ(), 1, 1); +} + + + + + +cMinecartWithChestWindow::~cMinecartWithChestWindow() +{ + m_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestclosed", m_ChestCart->GetPosX(), m_ChestCart->GetPosY(), m_ChestCart->GetPosZ(), 1, 1); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// // cDropSpenserWindow: cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : @@ -1101,6 +1117,7 @@ cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) : m_BlockY(a_EnderChest->GetPosY()), m_BlockZ(a_EnderChest->GetPosZ()) { + m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); diff --git a/src/UI/Window.h b/src/UI/Window.h index bc5becf11..e62176d50 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -23,6 +23,7 @@ class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cHopperEntity; +class cMinecartWithChest; class cBeaconEntity; class cSlotArea; class cSlotAreaAnvil; @@ -89,7 +90,7 @@ public: // tolua_begin - /// Returns the item at the specified slot for the specified player. Returns NULL if invalid SlotNum requested + /// Returns the item at the specified slot for the specified player. Returns nullptr if invalid SlotNum requested const cItem * GetSlot(cPlayer & a_Player, int a_SlotNum) const; /// Sets the item to the specified slot for the specified player @@ -129,9 +130,6 @@ public: /// Sends the contents of the whole window to all clients of this window. void BroadcastWholeWindow(void); - - /// Sends the progressbar to all clients of this window (same as SetProperty) - void BroadcastProgress(int a_Progressbar, int a_Value); // tolua_begin @@ -139,10 +137,10 @@ public: void SetWindowTitle(const AString & a_WindowTitle) { m_WindowTitle = a_WindowTitle; } /// Sends the UpdateWindowProperty (0x69) packet to all clients of the window - virtual void SetProperty(int a_Property, int a_Value); + virtual void SetProperty(short a_Property, short a_Value); /// Sends the UpdateWindowPropert(0x69) packet to the specified player - virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player); + virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player); // tolua_end @@ -191,13 +189,13 @@ protected: /** Returns the correct slot area for the specified window-global SlotNum Also returns the area-local SlotNum corresponding to the GlobalSlotNum - If the global SlotNum is out of range, returns NULL + If the global SlotNum is out of range, returns nullptr */ cSlotArea * GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum); /** Returns the correct slot area for the specified window-global SlotNum Also returns the area-local SlotNum corresponding to the GlobalSlotNum - If the global SlotNum is out of range, returns NULL. + If the global SlotNum is out of range, returns nullptr. Const version. */ const cSlotArea * GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) const; @@ -286,16 +284,16 @@ class cEnchantingWindow : typedef cWindow super; public: cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); - virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player) override; - virtual void SetProperty(int a_Property, int a_Value) override; + virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player) override; + virtual void SetProperty(short a_Property, short a_Value) override; /** Return the Value of a Property */ - int GetPropertyValue(int a_Property); + short GetPropertyValue(short a_Property); cSlotArea * m_SlotArea; protected: - int m_PropertyValue[3]; + short m_PropertyValue[3]; int m_BlockX, m_BlockY, m_BlockZ; }; @@ -361,6 +359,20 @@ protected: +class cMinecartWithChestWindow : + public cWindow +{ +public: + cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart); + ~cMinecartWithChestWindow(); +private: + cMinecartWithChest * m_ChestCart; +}; + + + + + class cEnderChestWindow : public cWindow { diff --git a/src/UI/WindowOwner.h b/src/UI/WindowOwner.h index 7a7941e37..4dc3cf080 100644 --- a/src/UI/WindowOwner.h +++ b/src/UI/WindowOwner.h @@ -1,4 +1,3 @@ - #pragma once #include "../BlockEntities/BlockEntity.h" @@ -16,12 +15,6 @@ for entities / players in motion to close their windows when they get too far aw -// class cWindow; - - - - - /** Base class for the window owning */ @@ -29,19 +22,19 @@ class cWindowOwner { public: cWindowOwner() : - m_Window(NULL) + m_Window(nullptr) { } - + virtual ~cWindowOwner() { } - + void CloseWindow(void) { - m_Window = NULL; + m_Window = nullptr; } - + void OpenWindow(cWindow * a_Window) { m_Window = a_Window; @@ -54,11 +47,11 @@ public: } /// Returns the block position at which the element owning the window is - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) = 0; - + virtual Vector3i GetBlockPos(void) = 0; + private: cWindow * m_Window; -} ; +}; @@ -71,26 +64,19 @@ class cBlockEntityWindowOwner : public cWindowOwner { public: - cBlockEntityWindowOwner(void) : - m_BlockEntity(NULL) - { - } - - void SetBlockEntity(cBlockEntity * a_BlockEntity) + cBlockEntityWindowOwner(cBlockEntity * a_BlockEntity) : + m_BlockEntity(a_BlockEntity) { - m_BlockEntity = a_BlockEntity; } - - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override + + virtual Vector3i GetBlockPos(void) override { - a_BlockX = m_BlockEntity->GetPosX(); - a_BlockY = m_BlockEntity->GetPosY(); - a_BlockZ = m_BlockEntity->GetPosZ(); + return Vector3i(m_BlockEntity->GetPosX(), m_BlockEntity->GetPosY(), m_BlockEntity->GetPosZ()); } - + private: cBlockEntity * m_BlockEntity; -} ; +}; @@ -103,26 +89,19 @@ class cEntityWindowOwner : public cWindowOwner { public: - cEntityWindowOwner(void) : - m_Entity(NULL) - { - } - - void SetEntity(cEntity * a_Entity) + cEntityWindowOwner(cEntity * a_Entity) : + m_Entity(a_Entity) { - m_Entity = a_Entity; } - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override + virtual Vector3i GetBlockPos(void) override { - a_BlockX = (int)floor(m_Entity->GetPosX() + 0.5); - a_BlockY = (int)floor(m_Entity->GetPosY() + 0.5); - a_BlockZ = (int)floor(m_Entity->GetPosZ() + 0.5); + return m_Entity->GetPosition().Floor(); } - + private: cEntity * m_Entity; -} ; +}; diff --git a/src/Vector3.h b/src/Vector3.h index 1dcb38f64..1854e42e3 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -3,8 +3,6 @@ -#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC) -#include <math.h> #include <list> #include <vector> @@ -29,9 +27,9 @@ public: // Hardcoded copy constructors (tolua++ does not support function templates .. yet) - Vector3(const Vector3<float> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {} - Vector3(const Vector3<double> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {} - Vector3(const Vector3<int> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {} + Vector3(const Vector3<float> & a_Rhs) : x(static_cast<T>(a_Rhs.x)), y(static_cast<T>(a_Rhs.y)), z(static_cast<T>(a_Rhs.z)) {} + Vector3(const Vector3<double> & a_Rhs) : x(static_cast<T>(a_Rhs.x)), y(static_cast<T>(a_Rhs.y)), z(static_cast<T>(a_Rhs.z)) {} + Vector3(const Vector3<int> & a_Rhs) : x(static_cast<T>(a_Rhs.x)), y(static_cast<T>(a_Rhs.y)), z(static_cast<T>(a_Rhs.z)) {} // tolua_end @@ -53,9 +51,9 @@ public: { double Len = 1.0 / Length(); - x = (T)(x * Len); - y = (T)(y * Len); - z = (T)(z * Len); + x = static_cast<T>(x * Len); + y = static_cast<T>(y * Len); + z = static_cast<T>(z * Len); } inline Vector3<T> NormalizeCopy(void) const @@ -63,9 +61,9 @@ public: double Len = 1.0 / Length(); return Vector3<T>( - (T)(x * Len), - (T)(y * Len), - (T)(z * Len) + static_cast<T>(x * Len), + static_cast<T>(y * Len), + static_cast<T>(z * Len) ); } @@ -74,15 +72,15 @@ public: double Len = 1.0 / Length(); a_Rhs.Set( - (T)(x * Len), - (T)(y * Len), - (T)(z * Len) + static_cast<T>(x * Len), + static_cast<T>(y * Len), + static_cast<T>(z * Len) ); } inline double Length(void) const { - return sqrt((double)(x * x + y * y + z * z)); + return sqrt(static_cast<double>(x * x + y * y + z * z)); } inline double SqrLength(void) const @@ -138,9 +136,9 @@ public: inline Vector3<int> Floor(void) const { return Vector3<int>( - (int)floor(x), - (int)floor(y), - (int)floor(z) + FloorC(x), + FloorC(y), + FloorC(z) ); } diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index db2ace386..dbf600c25 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -224,7 +224,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque // Retrieve the request data: cWebadminRequestData * Data = (cWebadminRequestData *)(a_Request.GetUserData()); - if (Data == NULL) + if (Data == nullptr) { a_Connection.SendStatusAndReason(500, "Bad UserData"); return; @@ -483,7 +483,7 @@ AString cWebAdmin::GetDefaultPage(void) const cPluginManager::PluginMap & List = PM->GetAllPlugins(); for (cPluginManager::PluginMap::const_iterator itr = List.begin(); itr != List.end(); ++itr) { - if (itr->second == NULL) + if (itr->second == nullptr) { continue; } @@ -494,7 +494,7 @@ AString cWebAdmin::GetDefaultPage(void) cPlayerAccum PlayerAccum; cWorld * World = cRoot::Get()->GetDefaultWorld(); // TODO - Create a list of worlds and players - if (World != NULL) + if (World != nullptr) { World->ForEachPlayer(PlayerAccum); Content.append(PlayerAccum.m_Contents); @@ -625,7 +625,7 @@ void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_R { UNUSED(a_Connection); cRequestData * Data = (cRequestData *)(a_Request.GetUserData()); - if (Data == NULL) + if (Data == nullptr) { return; } @@ -659,7 +659,7 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & // Delete any request data assigned to the request: cRequestData * Data = (cRequestData *)(a_Request.GetUserData()); delete Data; - Data = NULL; + Data = nullptr; } diff --git a/src/WebAdmin.h b/src/WebAdmin.h index 94b95dbcf..a85fb1f0c 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -7,7 +7,7 @@ #include "OSSupport/Socket.h" #include "Bindings/LuaState.h" -#include "inifile/iniFile.h" +#include "IniFile.h" #include "HTTPServer/HTTPServer.h" #include "HTTPServer/HTTPFormParser.h" diff --git a/src/World.cpp b/src/World.cpp index 61c061867..df1a97460 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -8,7 +8,7 @@ #include "Server.h" #include "Item.h" #include "Root.h" -#include "inifile/iniFile.h" +#include "IniFile.h" #include "ChunkMap.h" #include "Generating/ChunkDesc.h" #include "OSSupport/Timer.h" @@ -256,14 +256,14 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_IsDeepSnowEnabled(false), m_ShouldLavaSpawnFire(true), m_VillagersShouldHarvestCrops(true), - m_SimulatorManager(NULL), - m_SandSimulator(NULL), - m_WaterSimulator(NULL), - m_LavaSimulator(NULL), - m_FireSimulator(NULL), - m_RedstoneSimulator(NULL), + m_SimulatorManager(), + m_SandSimulator(), + m_WaterSimulator(nullptr), + m_LavaSimulator(nullptr), + m_FireSimulator(), + m_RedstoneSimulator(nullptr), m_MaxPlayers(10), - m_ChunkMap(NULL), + m_ChunkMap(), m_bAnimals(true), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) @@ -283,6 +283,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_bCommandBlocksEnabled(true), m_bUseChatPrefixes(false), m_TNTShrapnelLevel(slNone), + m_MaxViewDistance(12), m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), @@ -303,12 +304,9 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin cWorld::~cWorld() { - delete m_SimulatorManager; m_SimulatorManager = NULL; - delete m_SandSimulator; m_SandSimulator = NULL; - delete m_WaterSimulator; m_WaterSimulator = NULL; - delete m_LavaSimulator; m_LavaSimulator = NULL; - delete m_FireSimulator; m_FireSimulator = NULL; - delete m_RedstoneSimulator; m_RedstoneSimulator = NULL; + delete m_WaterSimulator; m_WaterSimulator = nullptr; + delete m_LavaSimulator; m_LavaSimulator = nullptr; + delete m_RedstoneSimulator; m_RedstoneSimulator = nullptr; UnloadUnusedChunks(); @@ -319,8 +317,6 @@ cWorld::~cWorld() Serializer.Save(); m_MapManager.SaveMapData(); - - delete m_ChunkMap; } @@ -566,6 +562,8 @@ void cWorld::Start(void) m_BroadcastDeathMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastDeathMessages", true); m_BroadcastAchievementMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastAchievementMessages", true); + SetMaxViewDistance(IniFile.GetValueSetI("SpawnPosition", "MaxViewDistance", 12)); + // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); m_IsSpawnExplicitlySet = @@ -631,7 +629,7 @@ void cWorld::Start(void) InitialiseAndLoadMobSpawningValues(IniFile); SetTimeOfDay(IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay)); - m_ChunkMap = new cChunkMap(this); + m_ChunkMap = make_unique<cChunkMap>(this); m_LastSave = 0; m_LastUnload = 0; @@ -641,16 +639,16 @@ void cWorld::Start(void) m_BlockTickQueueCopy.reserve(1000); // Simulators: - m_SimulatorManager = new cSimulatorManager(*this); + m_SimulatorManager = make_unique<cSimulatorManager>(*this); m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); - m_SandSimulator = new cSandSimulator(*this, IniFile); - m_FireSimulator = new cFireSimulator(*this, IniFile); + m_SandSimulator = make_unique<cSandSimulator>(*this, IniFile); + m_FireSimulator = make_unique<cFireSimulator>(*this, IniFile); m_RedstoneSimulator = InitializeRedstoneSimulator(IniFile); // Water, Lava and Redstone simulators get registered in their initialize function. - m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1); - m_SimulatorManager->RegisterSimulator(m_FireSimulator, 1); + m_SimulatorManager->RegisterSimulator(m_SandSimulator.get(), 1); + m_SimulatorManager->RegisterSimulator(m_FireSimulator.get(), 1); m_Lighting.Start(this); m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor); @@ -1059,7 +1057,6 @@ void cWorld::TickQueuedTasks(void) for (cTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) { (*itr)->Run(*this); - delete *itr; } // for itr - m_Tasks[] } @@ -1069,14 +1066,28 @@ void cWorld::TickQueuedTasks(void) void cWorld::TickScheduledTasks(void) { - // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks + // Move the tasks to be executed to a seperate vector to avoid deadlocks on accessing m_Tasks cScheduledTasks Tasks; { cCSLock Lock(m_CSScheduledTasks); - while (!m_ScheduledTasks.empty() && (m_ScheduledTasks.front()->m_TargetTick < m_WorldAge)) + auto WorldAge = m_WorldAge; + + // Move all the due tasks from m_ScheduledTasks into Tasks: + for (auto itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end();) // Cannot use range-basd for, we're modifying the container { - Tasks.push_back(m_ScheduledTasks.front()); - m_ScheduledTasks.pop_front(); + if ((*itr)->m_TargetTick < WorldAge) + { + auto next = itr; + ++next; + Tasks.push_back(std::move(*itr)); + m_ScheduledTasks.erase(itr); + itr = next; + } + else + { + // All the eligible tasks have been moved, bail out now + break; + } } } @@ -1084,7 +1095,6 @@ void cWorld::TickScheduledTasks(void) for (cScheduledTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) { (*itr)->m_Task->Run(*this); - delete *itr; } // for itr - m_Tasks[] } @@ -1254,7 +1264,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if (ch == NULL) + if (ch == nullptr) { continue; } @@ -2009,7 +2019,7 @@ void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Ex for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2027,7 +2037,7 @@ void cWorld::BroadcastChat(const cCompositeChat & a_Message, const cClientHandle for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2170,7 +2180,7 @@ void cWorld::BroadcastPlayerListAddPlayer(const cPlayer & a_Player, const cClien for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2188,7 +2198,7 @@ void cWorld::BroadcastPlayerListRemovePlayer(const cPlayer & a_Player, const cCl for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2206,7 +2216,7 @@ void cWorld::BroadcastPlayerListUpdateGameMode(const cPlayer & a_Player, const c for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2224,7 +2234,7 @@ void cWorld::BroadcastPlayerListUpdatePing(const cPlayer & a_Player, const cClie for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2242,7 +2252,7 @@ void cWorld::BroadcastPlayerListUpdateDisplayName(const cPlayer & a_Player, cons for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2269,7 +2279,7 @@ void cWorld::BroadcastScoreboardObjective(const AString & a_Name, const AString for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2287,7 +2297,7 @@ void cWorld::BroadcastScoreUpdate(const AString & a_Objective, const AString & a for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2305,7 +2315,7 @@ void cWorld::BroadcastDisplayObjective(const AString & a_Objective, cScoreboard: for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2350,7 +2360,7 @@ void cWorld::BroadcastTeleportEntity(const cEntity & a_Entity, const cClientHand for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2377,7 +2387,7 @@ void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2404,7 +2414,7 @@ void cWorld::BroadcastWeather(eWeather a_Weather, const cClientHandle * a_Exclud for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if ((ch == a_Exclude) || (ch == nullptr) || !ch->IsLoggedIn() || ch->IsDestroyed()) { continue; } @@ -2593,14 +2603,14 @@ void cWorld::UnloadUnusedChunks(void) void cWorld::QueueUnloadUnusedChunks(void) { - QueueTask(new cWorld::cTaskUnloadUnusedChunks); + QueueTask(make_unique<cWorld::cTaskUnloadUnusedChunks>()); } -void cWorld::CollectPickupsByPlayer(cPlayer * a_Player) +void cWorld::CollectPickupsByPlayer(cPlayer & a_Player) { m_ChunkMap->CollectPickupsByPlayer(a_Player); } @@ -2639,7 +2649,7 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) // Remove the player's client from the list of clients to be ticked: cClientHandle * Client = a_Player->GetClientHandle(); - if (Client != NULL) + if (Client != nullptr) { Client->RemoveFromWorld(); m_ChunkMap->RemoveClientFromChunks(Client); @@ -2692,7 +2702,7 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback) { - cPlayer * BestMatch = NULL; + cPlayer * BestMatch = nullptr; size_t BestRating = 0; size_t NameLength = a_PlayerNameHint.length(); @@ -2711,7 +2721,7 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa } } // for itr - m_Players[] - if (BestMatch != NULL) + if (BestMatch != nullptr) { return a_Callback.Item (BestMatch); } @@ -2722,13 +2732,30 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa +bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback) +{ + cCSLock Lock(m_CSPlayers); + for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + if ((*itr)->GetUUID() == a_PlayerUUID) + { + return a_Callback.Item(*itr); + } + } + return false; +} + + + + + // TODO: This interface is dangerous! cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight) { cTracer LineOfSight(this); double ClosestDistance = a_SightLimit; - cPlayer * ClosestPlayer = NULL; + cPlayer * ClosestPlayer = nullptr; cCSLock Lock(m_CSPlayers); for (cPlayerList::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) @@ -2767,7 +2794,7 @@ void cWorld::SendPlayerList(cPlayer * a_DestPlayer) for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch != NULL) && !ch->IsDestroyed()) + if ((ch != nullptr) && !ch->IsDestroyed()) { a_DestPlayer->GetClientHandle()->SendPlayerListAddPlayer(*(*itr)); } @@ -2850,19 +2877,19 @@ void cWorld::RemoveClientFromChunks(cClientHandle * a_Client) -void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) +void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority, cClientHandle * a_Client) { - m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Client); + m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, a_Client); } -void cWorld::ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) +void cWorld::ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority, cClientHandle * a_Client) { a_Client->AddWantedChunk(a_ChunkX, a_ChunkZ); - m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Client); + m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, a_Client); } @@ -2902,25 +2929,19 @@ bool cWorld::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AStrin AString Line2(a_Line2); AString Line3(a_Line3); AString Line4(a_Line4); - if (cRoot::Get()->GetPluginManager()->CallHookUpdatingSign(this, a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4, a_Player)) + + if (cRoot::Get()->GetPluginManager()->CallHookUpdatingSign(*this, a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4, a_Player)) { return false; } + if (m_ChunkMap->SetSignLines(a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4)) { - cRoot::Get()->GetPluginManager()->CallHookUpdatedSign(this, a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4, a_Player); + cRoot::Get()->GetPluginManager()->CallHookUpdatedSign(*this, a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4, a_Player); return true; } - return false; -} - - - - -bool cWorld::UpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) -{ - return SetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player); + return false; } @@ -2954,7 +2975,7 @@ bool cWorld::IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ) BLOCKTYPE Block; NIBBLETYPE Meta; GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta); - if (Block != E_BLOCK_TRAPDOOR) + if ((Block != E_BLOCK_TRAPDOOR) && (Block != E_BLOCK_IRON_TRAPDOOR)) { return false; } @@ -2971,7 +2992,7 @@ bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Op BLOCKTYPE Block; NIBBLETYPE Meta; GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta); - if (Block != E_BLOCK_TRAPDOOR) + if ((Block != E_BLOCK_TRAPDOOR) && (Block != E_BLOCK_IRON_TRAPDOOR)) { return false; } @@ -3003,7 +3024,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) { - m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ, false); + m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkZ); } @@ -3049,17 +3070,17 @@ void cWorld::SaveAllChunks(void) void cWorld::QueueSaveAllChunks(void) { - QueueTask(new cWorld::cTaskSaveAllChunks); + QueueTask(make_unique<cWorld::cTaskSaveAllChunks>()); } -void cWorld::QueueTask(cTask * a_Task) +void cWorld::QueueTask(std::unique_ptr<cTask> a_Task) { cCSLock Lock(m_CSTasks); - m_Tasks.push_back(a_Task); + m_Tasks.push_back(std::move(a_Task)); } @@ -3076,11 +3097,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task) { if ((*itr)->m_TargetTick >= TargetTick) { - m_ScheduledTasks.insert(itr, new cScheduledTask(TargetTick, a_Task)); + m_ScheduledTasks.insert(itr, make_unique<cScheduledTask>(TargetTick, a_Task)); return; } } - m_ScheduledTasks.push_back(new cScheduledTask(TargetTick, a_Task)); + m_ScheduledTasks.push_back(make_unique<cScheduledTask>(TargetTick, a_Task)); } @@ -3211,10 +3232,10 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) { - cMonster * Monster = NULL; + cMonster * Monster = nullptr; Monster = cMonster::NewMonsterFromType(a_MonsterType); - if (Monster != NULL) + if (Monster != nullptr) { Monster->SetPosition(a_PosX, a_PosY, a_PosZ); } @@ -3240,7 +3261,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster) if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { delete a_Monster; - a_Monster = NULL; + a_Monster = nullptr; return -1; } @@ -3248,7 +3269,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster) if (!a_Monster->Initialize(*this)) { delete a_Monster; - a_Monster = NULL; + a_Monster = nullptr; return -1; } @@ -3265,14 +3286,14 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster) int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed) { cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); - if (Projectile == NULL) + if (Projectile == nullptr) { return -1; } if (!Projectile->Initialize(*this)) { delete Projectile; - Projectile = NULL; + Projectile = nullptr; return -1; } return Projectile->GetUniqueID(); @@ -3355,7 +3376,7 @@ cRedstoneSimulator<cChunk, cWorld> * cWorld::InitializeRedstoneSimulator(cIniFil SimulatorName = "Incremental"; } - cRedstoneSimulator<cChunk, cWorld> * res = NULL; + cRedstoneSimulator<cChunk, cWorld> * res = nullptr; if (NoCaseCompare(SimulatorName, "Incremental") == 0) { @@ -3388,7 +3409,7 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c SimulatorName = "Vanilla"; } - cFluidSimulator * res = NULL; + cFluidSimulator * res = nullptr; bool IsWater = (strcmp(a_FluidName, "Water") == 0); // Used for defaults int Rate = 1; if ( @@ -3478,7 +3499,7 @@ void cWorld::AddQueuedPlayers(void) for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) { cClientHandle * Client = (*itr)->GetClientHandle(); - if (Client != NULL) + if (Client != nullptr) { m_Clients.push_back(Client); } @@ -3489,9 +3510,8 @@ void cWorld::AddQueuedPlayers(void) for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) { cClientHandle * Client = (*itr)->GetClientHandle(); - if (Client != NULL) + if (Client != nullptr) { - Client->StreamChunks(); Client->SendPlayerMoveLook(); Client->SendHealth(); Client->SendWholeInventory(*(*itr)->GetWindow()); @@ -3590,7 +3610,7 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc cSetChunkDataPtr SetChunkData(new cSetChunkData( a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_ChunkDesc.GetBlockTypes(), BlockMetas, - NULL, NULL, // We don't have lighting, chunk will be lighted when needed + nullptr, nullptr, // We don't have lighting, chunk will be lighted when needed &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(), a_ChunkDesc.GetEntities(), a_ChunkDesc.GetBlockEntities(), true @@ -3633,7 +3653,7 @@ bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(int a_ChunkX, int a_Ch void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) { cPluginManager::Get()->CallHookChunkGenerating( - m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc + *m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc ); } @@ -3644,7 +3664,7 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerating(cChunkDesc & a_Ch void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_ChunkDesc) { cPluginManager::Get()->CallHookChunkGenerated( - m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc + *m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc ); } diff --git a/src/World.h b/src/World.h index 90dada259..fe57b0789 100644 --- a/src/World.h +++ b/src/World.h @@ -26,6 +26,7 @@ #include "MapManager.h" #include "Blocks/WorldInterface.h" #include "Blocks/BroadcastInterface.h" +#include "ClientHandle.h" @@ -103,7 +104,7 @@ public: virtual void Run(cWorld & a_World) = 0; } ; - typedef std::vector<cTask *> cTasks; + typedef std::vector<std::unique_ptr<cTask>> cTasks; class cTaskSaveAllChunks : @@ -212,52 +213,52 @@ public: // Broadcast respective packets to all clients of the chunk where the event is taking place // (Please keep these alpha-sorted) void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); // tolua_export - void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude + void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr); // tolua_export + void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr); + void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude // tolua_begin - void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL, eMessageType a_ChatPrefix = mtCustom); - void BroadcastChatInfo (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { BroadcastChat(a_Message, a_Exclude, mtInformation); } - void BroadcastChatFailure(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { BroadcastChat(a_Message, a_Exclude, mtFailure); } - void BroadcastChatSuccess(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { BroadcastChat(a_Message, a_Exclude, mtSuccess); } - void BroadcastChatWarning(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { BroadcastChat(a_Message, a_Exclude, mtWarning); } - void BroadcastChatFatal (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { BroadcastChat(a_Message, a_Exclude, mtFailure); } - void BroadcastChatDeath (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { BroadcastChat(a_Message, a_Exclude, mtDeath); } - void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = NULL); + void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = nullptr, eMessageType a_ChatPrefix = mtCustom); + void BroadcastChatInfo (const AString & a_Message, const cClientHandle * a_Exclude = nullptr) { BroadcastChat(a_Message, a_Exclude, mtInformation); } + void BroadcastChatFailure(const AString & a_Message, const cClientHandle * a_Exclude = nullptr) { BroadcastChat(a_Message, a_Exclude, mtFailure); } + void BroadcastChatSuccess(const AString & a_Message, const cClientHandle * a_Exclude = nullptr) { BroadcastChat(a_Message, a_Exclude, mtSuccess); } + void BroadcastChatWarning(const AString & a_Message, const cClientHandle * a_Exclude = nullptr) { BroadcastChat(a_Message, a_Exclude, mtWarning); } + void BroadcastChatFatal (const AString & a_Message, const cClientHandle * a_Exclude = nullptr) { BroadcastChat(a_Message, a_Exclude, mtFailure); } + void BroadcastChatDeath (const AString & a_Message, const cClientHandle * a_Exclude = nullptr) { BroadcastChat(a_Message, a_Exclude, mtDeath); } + void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = nullptr); // tolua_end - void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectEntity (const cEntity & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - virtual void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) override; // tolua_export - void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = NULL); // tolua_export - void BroadcastPlayerListAddPlayer (const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerListRemovePlayer (const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerListUpdateGameMode (const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerListUpdatePing (const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName, const cClientHandle * a_Exclude = NULL); - void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); + void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr); + void BroadcastCollectEntity (const cEntity & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = nullptr); + void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + virtual void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export + void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = nullptr); // tolua_export + void BroadcastPlayerListAddPlayer (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastPlayerListRemovePlayer (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastPlayerListUpdateGameMode (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastPlayerListUpdatePing (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); + void BroadcastPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName, const cClientHandle * a_Exclude = nullptr); + void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = nullptr); void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); - void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export - void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export - void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); - void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL); + void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr); // tolua_export + void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = nullptr); // tolua_export + void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); + void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); + void BroadcastTimeUpdate (const cClientHandle * a_Exclude = nullptr); virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override; - void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL); + void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = nullptr); virtual cBroadcastInterface & GetBroadcastManager(void) override { @@ -298,7 +299,7 @@ public: /** Queues a task to unload unused chunks onto the tick thread. The prefferred way of unloading*/ void QueueUnloadUnusedChunks(void); // tolua_export - void CollectPickupsByPlayer(cPlayer * a_Player); + void CollectPickupsByPlayer(cPlayer & a_Player); /** Adds the player to the world. Uses a queue to store the player object until the Tick thread processes the addition event. @@ -323,6 +324,9 @@ public: // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) cPlayer * FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true); + /** Finds the player over his uuid and calls the callback */ + bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player /** Adds the entity into its appropriate chunk; takes ownership of the entity ptr. @@ -359,12 +363,12 @@ public: /** Sends the chunk to the client specified, if the client doesn't have the chunk yet. If chunk not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid + lighted). */ - void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); + void SendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority, cClientHandle * a_Client); /** Sends the chunk to the client specified, even if the client already has the chunk. If the chunk's not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid + lighted). */ - void ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - + void ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::eChunkPriority a_Priority, cClientHandle * a_Client); + /** Removes client from ChunkSender's queue of chunks to be sent */ void RemoveClientFromChunkSender(cClientHandle * a_Client); @@ -374,11 +378,8 @@ public: /** Marks the chunk as failed-to-load: */ void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ); - /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */ - bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - - /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() */ - bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp + /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be nullptr. Returns true if sign text changed. */ + bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = nullptr); // Exported in ManualBindings.cpp /** Sets the command block command. Returns true if command changed. */ bool SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command); // tolua_export @@ -396,7 +397,7 @@ public: void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export /** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */ - void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL); + void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr); bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); @@ -506,7 +507,7 @@ public: // tolua_end - inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; } + inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager.get(); } inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; } inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } @@ -646,6 +647,12 @@ public: eShrapnelLevel GetTNTShrapnelLevel(void) const { return m_TNTShrapnelLevel; } void SetTNTShrapnelLevel(eShrapnelLevel a_Flag) { m_TNTShrapnelLevel = a_Flag; } + int GetMaxViewDistance(void) const { return m_MaxViewDistance; } + void SetMaxViewDistance(int a_MaxViewDistance) + { + m_MaxViewDistance = Clamp(a_MaxViewDistance, cClientHandle::MIN_VIEW_DISTANCE, cClientHandle::MAX_VIEW_DISTANCE); + } + bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } @@ -671,7 +678,7 @@ public: void QueueSaveAllChunks(void); // tolua_export /** Queues a task onto the tick thread. The task object will be deleted once the task is finished */ - void QueueTask(cTask * a_Task); // Exported in ManualBindings.cpp + void QueueTask(std::unique_ptr<cTask> a_Task); // Exported in ManualBindings.cpp /** Queues a task onto the tick thread, with the specified delay. The task object will be deleted once the task is finished */ @@ -764,7 +771,7 @@ public: cChunkGenerator & GetGenerator(void) { return m_Generator; } cWorldStorage & GetStorage (void) { return m_Storage; } - cChunkMap * GetChunkMap (void) { return m_ChunkMap; } + cChunkMap * GetChunkMap (void) { return m_ChunkMap.get(); } /** Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call */ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export @@ -781,7 +788,7 @@ public: /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata */ - int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed = NULL); // tolua_export + int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed = nullptr); // tolua_export /** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } @@ -857,11 +864,12 @@ private: virtual ~cScheduledTask() { delete m_Task; - m_Task = NULL; + m_Task = nullptr; } }; - typedef std::list<cScheduledTask *> cScheduledTasks; + typedef std::unique_ptr<cScheduledTask> cScheduledTaskPtr; + typedef std::list<cScheduledTaskPtr> cScheduledTasks; AString m_WorldName; @@ -913,11 +921,11 @@ private: std::vector<BlockTickQueueItem *> m_BlockTickQueue; std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; // Second is for safely removing the objects from the queue - cSimulatorManager * m_SimulatorManager; - cSandSimulator * m_SandSimulator; - cFluidSimulator * m_WaterSimulator; - cFluidSimulator * m_LavaSimulator; - cFireSimulator * m_FireSimulator; + std::unique_ptr<cSimulatorManager> m_SimulatorManager; + std::unique_ptr<cSandSimulator> m_SandSimulator; + cFluidSimulator * m_WaterSimulator; + cFluidSimulator * m_LavaSimulator; + std::unique_ptr<cFireSimulator> m_FireSimulator; cRedstoneSimulator<cChunk, cWorld> * m_RedstoneSimulator; cCriticalSection m_CSPlayers; @@ -927,7 +935,7 @@ private: unsigned int m_MaxPlayers; - cChunkMap * m_ChunkMap; + std::unique_ptr<cChunkMap> m_ChunkMap; bool m_bAnimals; std::set<eMonsterType> m_AllowedMobs; @@ -960,6 +968,9 @@ private: */ eShrapnelLevel m_TNTShrapnelLevel; + /** The maximum view distance that a player can have in this world. */ + int m_MaxViewDistance; + /** Name of the nether world */ AString m_NetherWorldName; diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt index a00ff3b2f..59193db2a 100644 --- a/src/WorldStorage/CMakeLists.txt +++ b/src/WorldStorage/CMakeLists.txt @@ -14,7 +14,6 @@ SET (SRCS ScoreboardSerializer.cpp StatSerializer.cpp WSSAnvil.cpp - WSSCompact.cpp WorldStorage.cpp) SET (HDRS @@ -27,7 +26,6 @@ SET (HDRS ScoreboardSerializer.h StatSerializer.h WSSAnvil.h - WSSCompact.h WorldStorage.h) if(NOT MSVC) diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index d32ef52b3..05d5709db 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -481,7 +481,7 @@ void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart) void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) { - const char * EntityClass = NULL; + const char * EntityClass = nullptr; switch (a_Monster->GetMobType()) { case mtBat: EntityClass = "Bat"; break; @@ -618,6 +618,28 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) m_Writer.AddByte("IsConverting", (((const cZombie *)a_Monster)->IsConverting() ? 1 : 0)); break; } + case mtInvalidType: + case mtBlaze: + case mtCaveSpider: + case mtChicken: + case mtCow: + case mtEnderDragon: + case mtGhast: + case mtGiant: + case mtIronGolem: + case mtMooshroom: + case mtOcelot: + case mtPig: + case mtSilverfish: + case mtSnowGolem: + case mtSpider: + case mtSquid: + case mtWitch: + case mtZombiePigman: + { + // Other mobs have no special tags. + break; + } } m_Writer.EndCompound(); } @@ -699,21 +721,21 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging) { - m_Writer.AddByte("Direction", (unsigned char)a_Hanging->GetDirection()); - m_Writer.AddInt("TileX", a_Hanging->GetTileX()); - m_Writer.AddInt("TileY", a_Hanging->GetTileY()); - m_Writer.AddInt("TileZ", a_Hanging->GetTileZ()); - switch (a_Hanging->GetDirection()) + m_Writer.AddInt("TileX", a_Hanging->GetBlockX()); + m_Writer.AddInt("TileY", a_Hanging->GetBlockY()); + m_Writer.AddInt("TileZ", a_Hanging->GetBlockZ()); + switch (a_Hanging->GetFacing()) { - case BLOCK_FACE_YM: m_Writer.AddByte("Dir", (unsigned char)2); break; - case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break; - case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break; - case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break; + case BLOCK_FACE_XM: m_Writer.AddByte("Facing", 1); break; + case BLOCK_FACE_XP: m_Writer.AddByte("Facing", 3); break; + case BLOCK_FACE_ZM: m_Writer.AddByte("Facing", 2); break; + case BLOCK_FACE_ZP: m_Writer.AddByte("Facing", 0); break; - case BLOCK_FACE_XM: - case BLOCK_FACE_XP: + case BLOCK_FACE_YM: + case BLOCK_FACE_YP: case BLOCK_FACE_NONE: { + // These directions are invalid, but they may have been previously loaded, so keep them. break; } } @@ -754,7 +776,7 @@ void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame) AddBasicEntity(a_ItemFrame, "ItemFrame"); AddHangingEntity(a_ItemFrame); AddItem(a_ItemFrame->GetItem(), -1, "Item"); - m_Writer.AddByte("ItemRotation", (unsigned char)a_ItemFrame->GetRotation()); + m_Writer.AddByte("ItemRotation", (unsigned char)a_ItemFrame->GetItemRotation()); m_Writer.AddFloat("ItemDropChance", 1.0F); m_Writer.EndCompound(); } @@ -766,7 +788,7 @@ void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame) void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart) { m_Writer.BeginList("Items", TAG_Compound); - for (int i = 0; i < cMinecartWithChest::NumSlots; i++) + for (int i = 0; i < cMinecartWithChest::ContentsHeight * cMinecartWithChest::ContentsWidth; i++) { const cItem & Item = a_Minecart->GetSlot(i); if (Item.IsEmpty()) diff --git a/src/WorldStorage/ScoreboardSerializer.cpp b/src/WorldStorage/ScoreboardSerializer.cpp index e30eecf67..404604382 100644 --- a/src/WorldStorage/ScoreboardSerializer.cpp +++ b/src/WorldStorage/ScoreboardSerializer.cpp @@ -174,13 +174,13 @@ void cScoreboardSerializer::SaveScoreboardToNBT(cFastNBTWriter & a_Writer) a_Writer.BeginCompound("DisplaySlots"); cObjective * Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsList); - a_Writer.AddString("slot_0", (Objective == NULL) ? "" : Objective->GetName()); + a_Writer.AddString("slot_0", (Objective == nullptr) ? "" : Objective->GetName()); Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsSidebar); - a_Writer.AddString("slot_1", (Objective == NULL) ? "" : Objective->GetName()); + a_Writer.AddString("slot_1", (Objective == nullptr) ? "" : Objective->GetName()); Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsName); - a_Writer.AddString("slot_2", (Objective == NULL) ? "" : Objective->GetName()); + a_Writer.AddString("slot_2", (Objective == nullptr) ? "" : Objective->GetName()); a_Writer.EndCompound(); // DisplaySlots diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 092b9514c..0c77b4d67 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -126,7 +126,7 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : #endif // _DEBUG gzFile gz = gzopen((FILE_IO_PREFIX + fnam).c_str(), "wb"); - if (gz != NULL) + if (gz != nullptr) { gzwrite(gz, Writer.GetResult().data(), (unsigned)Writer.GetResult().size()); } @@ -193,7 +193,7 @@ bool cWSSAnvil::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data) { cCSLock Lock(m_CS); cMCAFile * File = LoadMCAFile(a_Chunk); - if (File == NULL) + if (File == nullptr) { return false; } @@ -208,7 +208,7 @@ bool cWSSAnvil::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Dat { cCSLock Lock(m_CS); cMCAFile * File = LoadMCAFile(a_Chunk); - if (File == NULL) + if (File == nullptr) { return false; } @@ -234,7 +234,7 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk) // Is it already cached? for (cMCAFiles::iterator itr = m_Files.begin(); itr != m_Files.end(); ++itr) { - if (((*itr) != NULL) && ((*itr)->GetRegionX() == RegionX) && ((*itr)->GetRegionZ() == RegionZ)) + if (((*itr) != nullptr) && ((*itr)->GetRegionX() == RegionX) && ((*itr)->GetRegionZ() == RegionZ)) { // Move the file to front and return it: cMCAFile * f = *itr; @@ -253,9 +253,9 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk) cFile::CreateFolder(FILE_IO_PREFIX + FileName); AppendPrintf(FileName, "/r.%d.%d.mca", RegionX, RegionZ); cMCAFile * f = new cMCAFile(FileName, RegionX, RegionZ); - if (f == NULL) + if (f == nullptr) { - return NULL; + return nullptr; } m_Files.push_front(f); @@ -373,7 +373,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT // Load the biomes from NBT, if present and valid. First try MCS-style, then Vanilla-style: cChunkDef::BiomeMap BiomeMap; cChunkDef::BiomeMap * Biomes = LoadBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "MCSBiomes")); - if (Biomes == NULL) + if (Biomes == nullptr) { // MCS-style biomes not available, load vanilla-style: Biomes = LoadVanillaBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes")); @@ -426,9 +426,9 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT cSetChunkDataPtr SetChunkData(new cSetChunkData( a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, - IsLightValid ? BlockLight : NULL, - IsLightValid ? SkyLight : NULL, - NULL, Biomes, + IsLightValid ? BlockLight : nullptr, + IsLightValid ? SkyLight : nullptr, + nullptr, Biomes, Entities, BlockEntities, false )); @@ -525,12 +525,12 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadVanillaBiomeMapFromNBT(cChunkDef::BiomeMap { if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_ByteArray)) { - return NULL; + return nullptr; } if (a_NBT.GetDataLength(a_TagIdx) != 16 * 16) { // The biomes stored don't match in size - return NULL; + return nullptr; } const unsigned char * VanillaBiomeData = (const unsigned char *)(a_NBT.GetData(a_TagIdx)); for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++) @@ -538,7 +538,7 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadVanillaBiomeMapFromNBT(cChunkDef::BiomeMap if ((VanillaBiomeData)[i] == 0xff) { // Unassigned biomes - return NULL; + return nullptr; } (*a_BiomeMap)[i] = (EMCSBiome)(VanillaBiomeData[i]); } @@ -553,12 +553,12 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_Bio { if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_IntArray)) { - return NULL; + return nullptr; } if (a_NBT.GetDataLength(a_TagIdx) != sizeof(*a_BiomeMap)) { // The biomes stored don't match in size - return NULL; + return nullptr; } const char * BiomeData = (a_NBT.GetData(a_TagIdx)); for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++) @@ -567,7 +567,7 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_Bio if ((*a_BiomeMap)[i] == 0xff) { // Unassigned biomes - return NULL; + return nullptr; } } return a_BiomeMap; @@ -631,7 +631,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, RelY, RelZ); NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, RelX, RelY, RelZ); std::auto_ptr<cBlockEntity> be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta)); - if (be.get() == NULL) + if (be.get() == nullptr) { continue; } @@ -670,7 +670,7 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WALLSIGN); // Blocktypes that have block entities but don't load their contents from disk: - case E_BLOCK_ENDER_CHEST: return NULL; + case E_BLOCK_ENDER_CHEST: return nullptr; } // All the other blocktypes should have no entities assigned to them. Report an error: @@ -686,7 +686,7 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a ItemTypeToString(a_BlockType).c_str(), a_BlockType, TypeName.c_str(), a_BlockX, a_BlockY, a_BlockZ ); - return NULL; + return nullptr; } @@ -696,11 +696,28 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx) { int Type = a_NBT.FindChildByName(a_TagIdx, "id"); - if ((Type < 0) || (a_NBT.GetType(Type) != TAG_Short)) + if (Type <= 0) { return false; } - a_Item.m_ItemType = a_NBT.GetShort(Type); + + if (a_NBT.GetType(Type) == TAG_String) + { + if (!StringToItem(a_NBT.GetString(Type), a_Item)) + { + // Can't resolve item type + return false; + } + } + else if (a_NBT.GetType(Type) == TAG_Short) + { + a_Item.m_ItemType = a_NBT.GetShort(Type); + } + else + { + return false; + } + if (a_Item.m_ItemType < 0) { a_Item.Empty(); @@ -836,7 +853,7 @@ cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagI // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Beacon")) { - return NULL; + return nullptr; } std::auto_ptr<cBeaconEntity> Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -881,13 +898,13 @@ cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagId // https://github.com/mc-server/MCServer/blob/d0551e2e0a98a28f31a88d489d17b408e4a7d38d/src/WorldStorage/WSSAnvil.cpp#L637 if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Chest") && !CheckBlockEntityType(a_NBT, a_TagIdx, "TrappedChest")) { - return NULL; + return nullptr; } int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return NULL; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this + return nullptr; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this } std::auto_ptr<cChestEntity> Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType)); LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items); @@ -903,7 +920,7 @@ cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Control")) { - return NULL; + return nullptr; } std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -940,13 +957,13 @@ cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_T // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Trap")) { - return NULL; + return nullptr; } int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return NULL; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this + return nullptr; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this } std::auto_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items); @@ -962,13 +979,13 @@ cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_Tag // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Dropper")) { - return NULL; + return nullptr; } int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return NULL; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this + return nullptr; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this } std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items); @@ -984,7 +1001,7 @@ cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_T // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "FlowerPot")) { - return NULL; + return nullptr; } std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -1015,13 +1032,13 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Furnace")) { - return NULL; + return nullptr; } int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return NULL; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this + return nullptr; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this } std::auto_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World)); @@ -1073,13 +1090,13 @@ cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagI // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Hopper")) { - return NULL; + return nullptr; } int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return NULL; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this + return nullptr; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this } std::auto_ptr<cHopperEntity> Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items); @@ -1095,7 +1112,7 @@ cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_Tag // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "RecordPlayer")) { - return NULL; + return nullptr; } std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -1116,7 +1133,7 @@ cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_Tag // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Skull")) { - return NULL; + return nullptr; } std::auto_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -1151,7 +1168,7 @@ cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_T // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Music")) { - return NULL; + return nullptr; } std::auto_ptr<cNoteEntity> NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -1172,7 +1189,7 @@ cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx // Check if the data has a proper type: if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Sign")) { - return NULL; + return nullptr; } std::auto_ptr<cSignEntity> Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World)); @@ -1660,30 +1677,41 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx) { - int Direction = a_NBT.FindChildByName(a_TagIdx, "Direction"); - if (Direction > 0) + // "Facing" tag is the prime source of the Facing; if not available, translate from older "Direction" or "Dir" + int Facing = a_NBT.FindChildByName(a_TagIdx, "Facing"); + if (Facing > 0) { - Direction = (int)a_NBT.GetByte(Direction); - if ((Direction < 2) || (Direction > 5)) - { - a_Hanging.SetDirection(BLOCK_FACE_NORTH); - } - else + Facing = (int)a_NBT.GetByte(Facing); + if ((Facing >= 2) && (Facing <= 5)) { - a_Hanging.SetDirection(static_cast<eBlockFace>(Direction)); + a_Hanging.SetFacing(static_cast<eBlockFace>(Facing)); } } else { - Direction = a_NBT.FindChildByName(a_TagIdx, "Dir"); - if (Direction > 0) + Facing = a_NBT.FindChildByName(a_TagIdx, "Direction"); + if (Facing > 0) { - switch ((int)a_NBT.GetByte(Direction)) + switch ((int)a_NBT.GetByte(Facing)) { - case 0: a_Hanging.SetDirection(BLOCK_FACE_NORTH); break; - case 1: a_Hanging.SetDirection(BLOCK_FACE_TOP); break; - case 2: a_Hanging.SetDirection(BLOCK_FACE_BOTTOM); break; - case 3: a_Hanging.SetDirection(BLOCK_FACE_SOUTH); break; + case 0: a_Hanging.SetFacing(BLOCK_FACE_ZM); break; + case 1: a_Hanging.SetFacing(BLOCK_FACE_XM); break; + case 2: a_Hanging.SetFacing(BLOCK_FACE_ZP); break; + case 3: a_Hanging.SetFacing(BLOCK_FACE_XP); break; + } + } + else + { + Facing = a_NBT.FindChildByName(a_TagIdx, "Dir"); // Has values 0 and 2 swapped + if (Facing > 0) + { + switch ((int)a_NBT.GetByte(Facing)) + { + case 0: a_Hanging.SetFacing(BLOCK_FACE_ZP); break; + case 1: a_Hanging.SetFacing(BLOCK_FACE_XM); break; + case 2: a_Hanging.SetFacing(BLOCK_FACE_ZM); break; + case 3: a_Hanging.SetFacing(BLOCK_FACE_XP); break; + } } } } @@ -1732,7 +1760,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT int Rotation = a_NBT.FindChildByName(a_TagIdx, "ItemRotation"); if (Rotation > 0) { - ItemFrame->SetRotation((Byte)a_NBT.GetByte(Rotation)); + ItemFrame->SetItemRotation((Byte)a_NBT.GetByte(Rotation)); } a_Entities.push_back(ItemFrame.release()); @@ -1744,7 +1772,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx)) { return; @@ -1808,7 +1836,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0), cItem())); + std::auto_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0), cItem())); if (!LoadProjectileBaseFromNBT(*SplashPotion.get(), a_NBT, a_TagIdx)) { return; @@ -1832,7 +1860,7 @@ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedN void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + std::auto_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Snowball.get(), a_NBT, a_TagIdx)) { return; @@ -1848,7 +1876,7 @@ void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + std::auto_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Egg.get(), a_NBT, a_TagIdx)) { return; @@ -1864,7 +1892,7 @@ void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + std::auto_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Fireball.get(), a_NBT, a_TagIdx)) { return; @@ -1880,7 +1908,7 @@ void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + std::auto_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*FireCharge.get(), a_NBT, a_TagIdx)) { return; @@ -1896,7 +1924,7 @@ void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + std::auto_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Enderpearl.get(), a_NBT, a_TagIdx)) { return; @@ -2853,7 +2881,7 @@ bool cWSSAnvil::cMCAFile::OpenFile(bool a_IsForReading) if (m_File.Read(m_Header, sizeof(m_Header)) != sizeof(m_Header)) { // Cannot read the header - perhaps the file has just been created? - // Try writing a NULL header (both chunk offsets and timestamps): + // Try writing a nullptr header (both chunk offsets and timestamps): memset(m_Header, 0, sizeof(m_Header)); if ( (m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) || // Real header - chunk offsets diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 591ec6757..9c579a617 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -113,10 +113,10 @@ protected: /// Saves the chunk into NBT data using a_Writer; returns true on success bool SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer); - /// Loads the chunk's biome map from vanilla-format; returns a_BiomeMap if biomes present and valid, NULL otherwise + /// Loads the chunk's biome map from vanilla-format; returns a_BiomeMap if biomes present and valid, nullptr otherwise cChunkDef::BiomeMap * LoadVanillaBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx); - /// Loads the chunk's biome map from MCS format; returns a_BiomeMap if biomes present and valid, NULL otherwise + /// Loads the chunk's biome map from MCS format; returns a_BiomeMap if biomes present and valid, nullptr otherwise cChunkDef::BiomeMap * LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx); /// Loads the chunk's entities from NBT data (a_Tag is the Level\\Entities list tag; may be -1) @@ -126,7 +126,7 @@ protected: void LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntitites, const cParsedNBT & a_NBT, int a_Tag, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); /** Loads the data for a block entity from the specified NBT tag. - Returns the loaded block entity, or NULL upon failure. */ + Returns the loaded block entity, or nullptr upon failure. */ cBlockEntity * LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a_Tag, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /// Loads a cItem contents from the specified NBT tag; returns true if successful. Doesn't load the Slot tag diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp deleted file mode 100644 index 6760186b2..000000000 --- a/src/WorldStorage/WSSCompact.cpp +++ /dev/null @@ -1,1066 +0,0 @@ - -// WSSCompact.cpp - -// Interfaces to the cWSSCompact class representing the "compact" storage schema (PAK-files) - -#include "Globals.h" -#include "WSSCompact.h" -#include "../World.h" -#include "zlib/zlib.h" -#include "json/json.h" -#include "../StringCompression.h" -#include "../BlockEntities/BeaconEntity.h" -#include "../BlockEntities/ChestEntity.h" -#include "../BlockEntities/CommandBlockEntity.h" -#include "../BlockEntities/DispenserEntity.h" -#include "../BlockEntities/FlowerPotEntity.h" -#include "../BlockEntities/FurnaceEntity.h" -#include "../BlockEntities/JukeboxEntity.h" -#include "../BlockEntities/MobHeadEntity.h" -#include "../BlockEntities/NoteEntity.h" -#include "../BlockEntities/SignEntity.h" -#include "../SetChunkData.h" - - - - - -#pragma pack(push, 1) -/// The chunk header, as stored in the file: -struct cWSSCompact::sChunkHeader -{ - int m_ChunkX; - int m_ChunkZ; - int m_CompressedSize; - int m_UncompressedSize; -} ; -#pragma pack(pop) - - - - - -/// The maximum number of PAK files that are cached -const size_t MAX_PAK_FILES = 16; - -/// The maximum number of unsaved chunks before the cPAKFile saves them to disk -const int MAX_DIRTY_CHUNKS = 16; - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cJsonChunkSerializer: - -cJsonChunkSerializer::cJsonChunkSerializer(void) : - m_HasJsonData(false) -{ -} - - - - - -void cJsonChunkSerializer::Entity(cEntity * a_Entity) -{ - // TODO: a_Entity->SaveToJson(m_Root); -} - - - - - -void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity) -{ - const char * SaveInto = NULL; - switch (a_BlockEntity->GetBlockType()) - { - case E_BLOCK_BEACON: SaveInto = "Beacons"; break; - case E_BLOCK_CHEST: SaveInto = "Chests"; break; - case E_BLOCK_DISPENSER: SaveInto = "Dispensers"; break; - case E_BLOCK_DROPPER: SaveInto = "Droppers"; break; - case E_BLOCK_FLOWER_POT: SaveInto = "FlowerPots"; break; - case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break; - case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break; - case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break; - case E_BLOCK_NOTE_BLOCK: SaveInto = "Notes"; break; - case E_BLOCK_JUKEBOX: SaveInto = "Jukeboxes"; break; - case E_BLOCK_COMMAND_BLOCK: SaveInto = "CommandBlocks"; break; - case E_BLOCK_HEAD: SaveInto = "MobHeads"; break; - - default: - { - ASSERT(!"Unhandled blocktype in BlockEntities list while saving to JSON"); - break; - } - } // switch (BlockEntity->GetBlockType()) - if (SaveInto == NULL) - { - return; - } - - Json::Value val; - a_BlockEntity->SaveToJson(val); - m_Root[SaveInto].append(val); - m_HasJsonData = true; -} - - - - - -void cJsonChunkSerializer::LightIsValid(bool a_IsLightValid) -{ - if (a_IsLightValid) - { - m_Root["IsLightValid"] = true; - m_HasJsonData = true; - } -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cWSSCompact: - -cWSSCompact::~cWSSCompact() -{ - for (cPAKFiles::iterator itr = m_PAKFiles.begin(); itr != m_PAKFiles.end(); ++itr) - { - delete *itr; - } -} - - - - - -bool cWSSCompact::LoadChunk(const cChunkCoords & a_Chunk) -{ - AString ChunkData; - int UncompressedSize = 0; - if (!GetChunkData(a_Chunk, UncompressedSize, ChunkData)) - { - // The reason for failure is already printed in GetChunkData() - return false; - } - - return LoadChunkFromData(a_Chunk, UncompressedSize, ChunkData, m_World); -} - - - - - -bool cWSSCompact::SaveChunk(const cChunkCoords & a_Chunk) -{ - cCSLock Lock(m_CS); - - cPAKFile * f = LoadPAKFile(a_Chunk); - if (f == NULL) - { - // For some reason we couldn't locate the file - LOG("Cannot locate a proper PAK file for chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); - return false; - } - return f->SaveChunk(a_Chunk, m_World); -} - - - - - -cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk) -{ - // ASSUMES that m_CS has been locked - - // We need to retain this weird conversion code, because some edge chunks are in the wrong PAK file - const int LayerX = FAST_FLOOR_DIV(a_Chunk.m_ChunkX, 32); - const int LayerZ = FAST_FLOOR_DIV(a_Chunk.m_ChunkZ, 32); - - // Is it already cached? - for (cPAKFiles::iterator itr = m_PAKFiles.begin(); itr != m_PAKFiles.end(); ++itr) - { - if (((*itr) != NULL) && ((*itr)->GetLayerX() == LayerX) && ((*itr)->GetLayerZ() == LayerZ)) - { - // Move the file to front and return it: - cPAKFile * f = *itr; - if (itr != m_PAKFiles.begin()) - { - m_PAKFiles.erase(itr); - m_PAKFiles.push_front(f); - } - return f; - } - } - - // Load it anew: - AString FileName; - Printf(FileName, "%s/X%i_Z%i.pak", m_World->GetName().c_str(), LayerX, LayerZ); - cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ, m_CompressionFactor); - if (f == NULL) - { - return NULL; - } - m_PAKFiles.push_front(f); - - // If there are too many PAK files cached, delete the last one used: - if (m_PAKFiles.size() > MAX_PAK_FILES) - { - delete m_PAKFiles.back(); - m_PAKFiles.pop_back(); - } - return f; -} - - - - - -bool cWSSCompact::GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data) -{ - cCSLock Lock(m_CS); - cPAKFile * f = LoadPAKFile(a_Chunk); - if (f == NULL) - { - return false; - } - return f->GetChunkData(a_Chunk, a_UncompressedSize, a_Data); -} - - - - - -/* -// TODO: Rewrite saving to use the same principles as loading -bool cWSSCompact::SetChunkData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data) -{ - cCSLock Lock(m_CS); - cPAKFile * f = LoadPAKFile(a_Chunk); - if (f == NULL) - { - return false; - } - return f->SetChunkData(a_Chunk, a_UncompressedSize, a_Data); -} -*/ - - - - - -bool cWSSCompact::EraseChunkData(const cChunkCoords & a_Chunk) -{ - cCSLock Lock(m_CS); - cPAKFile * f = LoadPAKFile(a_Chunk); - if (f == NULL) - { - return false; - } - return f->EraseChunkData(a_Chunk); -} - - - - - -void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World) -{ - // Load beacon: - Json::Value AllBeacons = a_Value.get("Beacons", Json::nullValue); - if (!AllBeacons.empty()) - { - for (Json::Value::iterator itr = AllBeacons.begin(); itr != AllBeacons.end(); ++itr) - { - std::auto_ptr<cBeaconEntity> BeaconEntity(new cBeaconEntity(0, 0, 0, a_World)); - if (!BeaconEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING BEACON FROM JSON!"); - } - else - { - a_BlockEntities.push_back(BeaconEntity.release()); - } - } // for itr - AllBeacons[] - } - - // Load chests: - Json::Value AllChests = a_Value.get("Chests", Json::nullValue); - if (!AllChests.empty()) - { - for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr) - { - std::auto_ptr<cChestEntity> ChestEntity(new cChestEntity(0, 0, 0, a_World, E_BLOCK_CHEST)); - if (!ChestEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING CHEST FROM JSON!"); - } - else - { - a_BlockEntities.push_back(ChestEntity.release()); - } - } // for itr - AllChests[] - } - - // Load dispensers: - Json::Value AllDispensers = a_Value.get("Dispensers", Json::nullValue); - for (Json::Value::iterator itr = AllDispensers.begin(); itr != AllDispensers.end(); ++itr) - { - std::auto_ptr<cDispenserEntity> DispenserEntity(new cDispenserEntity(0, 0, 0, a_World)); - if (!DispenserEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING DISPENSER FROM JSON!"); - } - else - { - a_BlockEntities.push_back(DispenserEntity.release()); - } - } // for itr - AllDispensers[] - - // Load Flowerpots: - Json::Value AllFlowerPots = a_Value.get("FlowerPots", Json::nullValue); - for (Json::Value::iterator itr = AllFlowerPots.begin(); itr != AllFlowerPots.end(); ++itr) - { - std::auto_ptr<cFlowerPotEntity> FlowerPotEntity(new cFlowerPotEntity(0, 0, 0, a_World)); - if (!FlowerPotEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING FLOWERPOT FROM JSON!"); - } - else - { - a_BlockEntities.push_back(FlowerPotEntity.release()); - } - } // for itr - AllFlowerPots[] - - // Load furnaces: - Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue); - for (Json::Value::iterator itr = AllFurnaces.begin(); itr != AllFurnaces.end(); ++itr) - { - // TODO: The block type and meta aren't correct, there's no way to get them here - std::auto_ptr<cFurnaceEntity> FurnaceEntity(new cFurnaceEntity(0, 0, 0, E_BLOCK_FURNACE, 0, a_World)); - if (!FurnaceEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING FURNACE FROM JSON!"); - } - else - { - a_BlockEntities.push_back(FurnaceEntity.release()); - } - } // for itr - AllFurnaces[] - - // Load signs: - Json::Value AllSigns = a_Value.get("Signs", Json::nullValue); - for (Json::Value::iterator itr = AllSigns.begin(); itr != AllSigns.end(); ++itr) - { - std::auto_ptr<cSignEntity> SignEntity(new cSignEntity(E_BLOCK_SIGN_POST, 0, 0, 0, a_World)); - if (!SignEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING SIGN FROM JSON!"); - } - else - { - a_BlockEntities.push_back(SignEntity.release()); - } - } // for itr - AllSigns[] - - // Load note blocks: - Json::Value AllNotes = a_Value.get("Notes", Json::nullValue); - for (Json::Value::iterator itr = AllNotes.begin(); itr != AllNotes.end(); ++itr) - { - std::auto_ptr<cNoteEntity> NoteEntity(new cNoteEntity(0, 0, 0, a_World)); - if (!NoteEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING NOTE BLOCK FROM JSON!"); - } - else - { - a_BlockEntities.push_back(NoteEntity.release()); - } - } // for itr - AllNotes[] - - // Load jukeboxes: - Json::Value AllJukeboxes = a_Value.get("Jukeboxes", Json::nullValue); - for (Json::Value::iterator itr = AllJukeboxes.begin(); itr != AllJukeboxes.end(); ++itr) - { - std::auto_ptr<cJukeboxEntity> JukeboxEntity(new cJukeboxEntity(0, 0, 0, a_World)); - if (!JukeboxEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING JUKEBOX FROM JSON!"); - } - else - { - a_BlockEntities.push_back(JukeboxEntity.release()); - } - } // for itr - AllJukeboxes[] - - // Load command blocks: - Json::Value AllCommandBlocks = a_Value.get("CommandBlocks", Json::nullValue); - for (Json::Value::iterator itr = AllCommandBlocks.begin(); itr != AllCommandBlocks.end(); ++itr) - { - std::auto_ptr<cCommandBlockEntity> CommandBlockEntity(new cCommandBlockEntity(0, 0, 0, a_World)); - if (!CommandBlockEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING COMMAND BLOCK FROM JSON!"); - } - else - { - a_BlockEntities.push_back(CommandBlockEntity.release()); - } - } // for itr - AllCommandBlocks[] - - // Load mob heads: - Json::Value AllMobHeads = a_Value.get("MobHeads", Json::nullValue); - for (Json::Value::iterator itr = AllMobHeads.begin(); itr != AllMobHeads.end(); ++itr) - { - std::auto_ptr<cMobHeadEntity> MobHeadEntity(new cMobHeadEntity(0, 0, 0, a_World)); - if (!MobHeadEntity->LoadFromJson(*itr)) - { - LOGWARNING("ERROR READING MOB HEAD FROM JSON!"); - } - else - { - a_BlockEntities.push_back(MobHeadEntity.release()); - } - } // for itr - AllMobHeads[] -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cWSSCompact::cPAKFile - -#define READ(Var) \ - if (f.Read(&Var, sizeof(Var)) != sizeof(Var)) \ - { \ - LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", #Var, m_FileName.c_str(), __LINE__, f.Tell()); \ - return; \ - } - -cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor) : - m_FileName(a_FileName), - m_CompressionFactor(a_CompressionFactor), - m_LayerX(a_LayerX), - m_LayerZ(a_LayerZ), - m_NumDirty(0), - m_ChunkVersion( CHUNK_VERSION), // Init with latest version - m_PakVersion( PAK_VERSION) -{ - cFile f; - if (!f.Open(m_FileName, cFile::fmRead)) - { - return; - } - - // Read headers: - READ(m_PakVersion); - if (m_PakVersion != 1) - { - LOGERROR("File \"%s\" is in an unknown pak format (%d)", m_FileName.c_str(), m_PakVersion); - return; - } - - READ(m_ChunkVersion); - switch (m_ChunkVersion) - { - case 1: - { - m_ChunkSize.Set(16, 128, 16); - break; - } - case 2: - case 3: - { - m_ChunkSize.Set(16, 256, 16); - break; - } - default: - { - LOGERROR("File \"%s\" is in an unknown chunk format (%d)", m_FileName.c_str(), m_ChunkVersion); - return; - } - }; - - short NumChunks = 0; - READ(NumChunks); - - // Read chunk headers: - for (int i = 0; i < NumChunks; i++) - { - sChunkHeader * Header = new sChunkHeader; - - // Here we do not use the READ macro, as it does not free the resources - // allocated with new in case of error. - if (f.Read(Header, sizeof(*Header)) != sizeof(*Header)) - { - LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", "Header", m_FileName.c_str(), __LINE__, f.Tell()); - delete Header; - Header = NULL; - return; - } - m_ChunkHeaders.push_back(Header); - } // for i - chunk headers - - // Read chunk data: - if (f.ReadRestOfFile(m_DataContents) == -1) - { - LOGERROR("Cannot read file \"%s\" contents", m_FileName.c_str()); - return; - } - - if (m_ChunkVersion == 1) // Convert chunks to version 2 - { - UpdateChunk1To2(); - } -#if AXIS_ORDER == AXIS_ORDER_XZY - if (m_ChunkVersion == 2) // Convert chunks to version 3 - { - UpdateChunk2To3(); - } -#endif -} - - - - - -cWSSCompact::cPAKFile::~cPAKFile() -{ - if (m_NumDirty > 0) - { - SynchronizeFile(); - } - for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr) - { - delete *itr; - } -} - - - - - -bool cWSSCompact::cPAKFile::GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data) -{ - int ChunkX = a_Chunk.m_ChunkX; - int ChunkZ = a_Chunk.m_ChunkZ; - sChunkHeader * Header = NULL; - int Offset = 0; - for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr) - { - if (((*itr)->m_ChunkX == ChunkX) && ((*itr)->m_ChunkZ == ChunkZ)) - { - Header = *itr; - break; - } - Offset += (*itr)->m_CompressedSize; - } - if ((Header == NULL) || (Offset + Header->m_CompressedSize > (int)m_DataContents.size())) - { - // Chunk not found / data invalid - return false; - } - - a_UncompressedSize = Header->m_UncompressedSize; - a_Data.assign(m_DataContents, Offset, Header->m_CompressedSize); - return true; -} - - - - - -bool cWSSCompact::cPAKFile::SaveChunk(const cChunkCoords & a_Chunk, cWorld * a_World) -{ - if (!SaveChunkToData(a_Chunk, a_World)) - { - return false; - } - if (m_NumDirty > MAX_DIRTY_CHUNKS) - { - SynchronizeFile(); - } - return true; -} - - - - - -void cWSSCompact::cPAKFile::UpdateChunk1To2() -{ - int Offset = 0; - AString NewDataContents; - int ChunksConverted = 0; - for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr) - { - sChunkHeader * Header = *itr; - - if (ChunksConverted % 32 == 0) - { - LOGINFO("Updating \"%s\" version 1 to version 2: " SIZE_T_FMT " %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size()); - } - ChunksConverted++; - - AString Data; - int UncompressedSize = Header->m_UncompressedSize; - Data.assign(m_DataContents, Offset, Header->m_CompressedSize); - Offset += Header->m_CompressedSize; - - // Crude data integrity check: - int ExpectedSize = (16*128*16)*2 + (16*128*16)/2; // For version 1 - if (UncompressedSize < ExpectedSize) - { - LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing", - Header->m_ChunkX, Header->m_ChunkZ, - UncompressedSize, ExpectedSize - ); - Offset += Header->m_CompressedSize; - continue; - } - - // Decompress the data: - AString UncompressedData; - { - int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize); - if (errorcode != Z_OK) - { - LOGERROR("Error %d decompressing data for chunk [%d, %d]", - errorcode, - Header->m_ChunkX, Header->m_ChunkZ - ); - Offset += Header->m_CompressedSize; - continue; - } - } - - if (UncompressedSize != (int)UncompressedData.size()) - { - LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", - UncompressedSize, UncompressedData.size(), - Header->m_ChunkX, Header->m_ChunkZ - ); - Offset += Header->m_CompressedSize; - continue; - } - - - // Old version is 128 blocks high with YZX axis order - char ConvertedData[cChunkDef::BlockDataSize]; - int Index = 0; - unsigned int InChunkOffset = 0; - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) - { - for (int y = 0; y < 128; ++y) - { - ConvertedData[Index++] = UncompressedData[y + z * 128 + x * 128 * 16 + InChunkOffset]; - } - // Add 128 empty blocks after an old y column - memset(ConvertedData + Index, E_BLOCK_AIR, 128); - Index += 128; - } - InChunkOffset += (16 * 128 * 16); - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) // Metadata - { - for (int y = 0; y < 64; ++y) - { - ConvertedData[Index++] = UncompressedData[y + z * 64 + x * 64 * 16 + InChunkOffset]; - } - memset(ConvertedData + Index, 0, 64); - Index += 64; - } - InChunkOffset += (16 * 128 * 16) / 2; - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) // Block light - { - for (int y = 0; y < 64; ++y) - { - ConvertedData[Index++] = UncompressedData[y + z * 64 + x * 64 * 16 + InChunkOffset]; - } - memset(ConvertedData + Index, 0, 64); - Index += 64; - } - InChunkOffset += (16*128*16)/2; - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) // Sky light - { - for (int y = 0; y < 64; ++y) - { - ConvertedData[Index++] = UncompressedData[y + z * 64 + x * 64 * 16 + InChunkOffset]; - } - memset(ConvertedData + Index, 0, 64); - Index += 64; - } - InChunkOffset += (16 * 128 * 16) / 2; - - AString Converted(ConvertedData, ARRAYCOUNT(ConvertedData)); - - // Add JSON data afterwards - if (UncompressedData.size() > InChunkOffset) - { - Converted.append( UncompressedData.begin() + InChunkOffset, UncompressedData.end()); - } - - // Re-compress data - AString CompressedData; - { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor); - if (errorcode != Z_OK) - { - LOGERROR("Error %d compressing data for chunk [%d, %d]", - errorcode, - Header->m_ChunkX, Header->m_ChunkZ - ); - continue; - } - } - - // Save into file's cache - Header->m_UncompressedSize = (int)Converted.size(); - Header->m_CompressedSize = (int)CompressedData.size(); - NewDataContents.append(CompressedData); - } - - // Done converting - m_DataContents = NewDataContents; - m_ChunkVersion = 2; - SynchronizeFile(); - - LOGINFO("Updated \"%s\" version 1 to version 2", m_FileName.c_str()); -} - - - - - -void cWSSCompact::cPAKFile::UpdateChunk2To3() -{ - int Offset = 0; - AString NewDataContents; - int ChunksConverted = 0; - for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr) - { - sChunkHeader * Header = *itr; - - if (ChunksConverted % 32 == 0) - { - LOGINFO("Updating \"%s\" version 2 to version 3: " SIZE_T_FMT " %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size()); - } - ChunksConverted++; - - AString Data; - int UncompressedSize = Header->m_UncompressedSize; - Data.assign(m_DataContents, Offset, Header->m_CompressedSize); - Offset += Header->m_CompressedSize; - - // Crude data integrity check: - const int ExpectedSize = (16 * 256 * 16) * 2 + (16 * 256 * 16) / 2; // For version 2 - if (UncompressedSize < ExpectedSize) - { - LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing", - Header->m_ChunkX, Header->m_ChunkZ, - UncompressedSize, ExpectedSize - ); - Offset += Header->m_CompressedSize; - continue; - } - - // Decompress the data: - AString UncompressedData; - { - int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize); - if (errorcode != Z_OK) - { - LOGERROR("Error %d decompressing data for chunk [%d, %d]", - errorcode, - Header->m_ChunkX, Header->m_ChunkZ - ); - Offset += Header->m_CompressedSize; - continue; - } - } - - if (UncompressedSize != (int)UncompressedData.size()) - { - LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", - UncompressedSize, UncompressedData.size(), - Header->m_ChunkX, Header->m_ChunkZ - ); - Offset += Header->m_CompressedSize; - continue; - } - - char ConvertedData[ExpectedSize]; - memset(ConvertedData, 0, ExpectedSize); - - // Cannot use cChunk::MakeIndex because it might change again????????? - // For compatibility, use what we know is current - #define MAKE_3_INDEX( x, y, z) ( x + (z * 16) + (y * 16 * 16)) - - unsigned int InChunkOffset = 0; - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) for (int y = 0; y < 256; ++y) // YZX Loop order is important, in 1.1 Y was first then Z then X - { - ConvertedData[ MAKE_3_INDEX(x, y, z) ] = UncompressedData[InChunkOffset]; - ++InChunkOffset; - } // for y, z, x - - - unsigned int index2 = 0; - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) for (int y = 0; y < 256; ++y) - { - ConvertedData[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4)) & 0x0f) << ((x&1)*4); - ++index2; - } - InChunkOffset += index2 / 2; - index2 = 0; - - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) for (int y = 0; y < 256; ++y) - { - ConvertedData[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4)) & 0x0f) << ((x&1)*4); - ++index2; - } - InChunkOffset += index2 / 2; - index2 = 0; - - for (int x = 0; x < 16; ++x) for (int z = 0; z < 16; ++z) for (int y = 0; y < 256; ++y) - { - ConvertedData[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4)) & 0x0f) << ((x&1)*4); - ++index2; - } - InChunkOffset += index2 / 2; - - AString Converted(ConvertedData, ExpectedSize); - - // Add JSON data afterwards - if (UncompressedData.size() > InChunkOffset) - { - Converted.append( UncompressedData.begin() + InChunkOffset, UncompressedData.end()); - } - - // Re-compress data - AString CompressedData; - { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor); - if (errorcode != Z_OK) - { - LOGERROR("Error %d compressing data for chunk [%d, %d]", - errorcode, - Header->m_ChunkX, Header->m_ChunkZ - ); - continue; - } - } - - // Save into file's cache - Header->m_UncompressedSize = (int)Converted.size(); - Header->m_CompressedSize = (int)CompressedData.size(); - NewDataContents.append(CompressedData); - } - - // Done converting - m_DataContents = NewDataContents; - m_ChunkVersion = 3; - SynchronizeFile(); - - LOGINFO("Updated \"%s\" version 2 to version 3", m_FileName.c_str()); -} - - - - - -bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World) -{ - // Crude data integrity check: - if (a_UncompressedSize < cChunkDef::BlockDataSize) - { - LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing", - a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, - a_UncompressedSize, cChunkDef::BlockDataSize - ); - EraseChunkData(a_Chunk); - return false; - } - - // Decompress the data: - AString UncompressedData; - int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, (size_t)a_UncompressedSize); - if (errorcode != Z_OK) - { - LOGERROR("Error %d decompressing data for chunk [%d, %d]", - errorcode, - a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ - ); - return false; - } - - if (a_UncompressedSize != (int)UncompressedData.size()) - { - LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", - a_UncompressedSize, UncompressedData.size(), - a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ - ); - return false; - } - - cEntityList Entities; - cBlockEntityList BlockEntities; - bool IsLightValid = false; - - if (a_UncompressedSize > cChunkDef::BlockDataSize) - { - Json::Value root; // will contain the root value after parsing. - Json::Reader reader; - if (!reader.parse( UncompressedData.data() + cChunkDef::BlockDataSize, root, false)) - { - LOGERROR("Failed to parse trailing JSON in chunk [%d, %d]!", - a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ - ); - } - else - { - LoadEntitiesFromJson(root, Entities, BlockEntities, a_World); - IsLightValid = root.get("IsLightValid", false).asBool(); - } - } - - BLOCKTYPE * BlockData = (BLOCKTYPE *)UncompressedData.data(); - NIBBLETYPE * MetaData = (NIBBLETYPE *)(BlockData + MetaOffset); - NIBBLETYPE * BlockLight = (NIBBLETYPE *)(BlockData + LightOffset); - NIBBLETYPE * SkyLight = (NIBBLETYPE *)(BlockData + SkyLightOffset); - - a_World->QueueSetChunkData(cSetChunkDataPtr(new cSetChunkData( - a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, - BlockData, MetaData, - IsLightValid ? BlockLight : NULL, - IsLightValid ? SkyLight : NULL, - NULL, NULL, - Entities, BlockEntities, - false - ))); - - return true; -} - - - - - -bool cWSSCompact::cPAKFile::EraseChunkData(const cChunkCoords & a_Chunk) -{ - int ChunkX = a_Chunk.m_ChunkX; - int ChunkZ = a_Chunk.m_ChunkZ; - int Offset = 0; - for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr) - { - if (((*itr)->m_ChunkX == ChunkX) && ((*itr)->m_ChunkZ == ChunkZ)) - { - m_DataContents.erase(Offset, (*itr)->m_CompressedSize); - delete *itr; - itr = m_ChunkHeaders.erase(itr); - return true; - } - Offset += (*itr)->m_CompressedSize; - } - - return false; -} - - - - - -bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld * a_World) -{ - // Serialize the chunk: - cJsonChunkSerializer Serializer; - if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer)) - { - // Chunk not valid - LOG("cWSSCompact: Trying to save chunk [%d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); - return false; - } - - AString Data; - Data.assign((const char *)Serializer.GetBlockData(), cChunkDef::BlockDataSize); - if (Serializer.HasJsonData()) - { - AString JsonData; - Json::StyledWriter writer; - JsonData = writer.write(Serializer.GetRoot()); - Data.append(JsonData); - } - - // Compress the data: - AString CompressedData; - int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor); - if (errorcode != Z_OK) - { - LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); - return false; - } - - // Erase any existing data for the chunk: - EraseChunkData(a_Chunk); - - // Save the header: - sChunkHeader * Header = new sChunkHeader; - if (Header == NULL) - { - LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); - return false; - } - Header->m_CompressedSize = (int)CompressedData.size(); - Header->m_ChunkX = a_Chunk.m_ChunkX; - Header->m_ChunkZ = a_Chunk.m_ChunkZ; - Header->m_UncompressedSize = (int)Data.size(); - m_ChunkHeaders.push_back(Header); - - m_DataContents.append(CompressedData.data(), CompressedData.size()); - - m_NumDirty++; - return true; -} - - - - - -#define WRITE(Var) \ - if (f.Write(&Var, sizeof(Var)) != sizeof(Var)) \ - { \ - LOGERROR("cWSSCompact: ERROR writing %s to file \"%s\" (line %d); file offset %d", #Var, m_FileName.c_str(), __LINE__, f.Tell()); \ - return; \ - } - -void cWSSCompact::cPAKFile::SynchronizeFile(void) -{ - cFile f; - if (!f.Open(m_FileName, cFile::fmWrite)) - { - LOGERROR("Cannot open PAK file \"%s\" for writing", m_FileName.c_str()); - return; - } - - WRITE(m_PakVersion); - WRITE(m_ChunkVersion); - short NumChunks = (short)m_ChunkHeaders.size(); - WRITE(NumChunks); - for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr) - { - WRITE(**itr); - } - if (f.Write(m_DataContents.data(), m_DataContents.size()) != (int)m_DataContents.size()) - { - LOGERROR("cWSSCompact: ERROR writing chunk contents to file \"%s\" (line %d); file offset %d", m_FileName.c_str(), __LINE__, f.Tell()); - return; - } - m_NumDirty = 0; -} - - - - diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h deleted file mode 100644 index 83e9cb49f..000000000 --- a/src/WorldStorage/WSSCompact.h +++ /dev/null @@ -1,157 +0,0 @@ - -// WSSCompact.h - -// Interfaces to the cWSSCompact class representing the "Compact" storage schema (PAK-files) - - - - - -#pragma once -#ifndef WSSCOMPACT_H_INCLUDED -#define WSSCOMPACT_H_INCLUDED - -#include "WorldStorage.h" -#include "../Vector3.h" -#include "json/json.h" -#include "ChunkDataCallback.h" - - - - - -/// Helper class for serializing a chunk into Json -class cJsonChunkSerializer : - public cChunkDataArrayCollector -{ -public: - - cJsonChunkSerializer(void); - - Json::Value & GetRoot (void) {return m_Root; } - BLOCKTYPE * GetBlockData(void) {return (BLOCKTYPE *)m_BlockData; } - bool HasJsonData (void) const {return m_HasJsonData; } - -protected: - - // NOTE: block data is serialized into inherited cChunkDataCollector's m_BlockData[] array - - // Entities and BlockEntities are serialized to Json - Json::Value m_Root; - bool m_HasJsonData; - - // cChunkDataCollector overrides: - virtual void Entity (cEntity * a_Entity) override; - virtual void BlockEntity (cBlockEntity * a_Entity) override; - virtual void LightIsValid (bool a_IsLightValid) override; -} ; - - - - - -class cWSSCompact : - public cWSSchema -{ -public: - cWSSCompact(cWorld * a_World, int a_CompressionFactor) : cWSSchema(a_World), m_CompressionFactor(a_CompressionFactor) {} - virtual ~cWSSCompact(); - -protected: - - enum - { - // Offsets to individual components in the joined blockdata array - MetaOffset = cChunkDef::NumBlocks, - LightOffset = MetaOffset + cChunkDef::NumBlocks / 2, - SkyLightOffset = LightOffset + cChunkDef::NumBlocks / 2, - } ; - - struct sChunkHeader; - typedef std::vector<sChunkHeader *> sChunkHeaders; - - /// Implements a cache for a single PAK file; implements lazy-write in order to be able to write multiple chunks fast - class cPAKFile - { - public: - - cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor); - ~cPAKFile(); - - bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data); - bool SetChunkData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data); - bool EraseChunkData(const cChunkCoords & a_Chunk); - - bool SaveChunk(const cChunkCoords & a_Chunk, cWorld * a_World); - - int GetLayerX(void) const {return m_LayerX; } - int GetLayerZ(void) const {return m_LayerZ; } - - static const int PAK_VERSION = 1; -#if AXIS_ORDER == AXIS_ORDER_XZY - static const int CHUNK_VERSION = 3; -#elif AXIS_ORDER == AXIS_ORDER_YZX - static const int CHUNK_VERSION = 2; -#endif - protected: - - AString m_FileName; - int m_CompressionFactor; - int m_LayerX; - int m_LayerZ; - - sChunkHeaders m_ChunkHeaders; - AString m_DataContents; // Data contents of the file, cached - - int m_NumDirty; // Number of chunks that were written into m_DataContents but not into the file - - Vector3i m_ChunkSize; // Is related to m_ChunkVersion - char m_ChunkVersion; - char m_PakVersion; - - bool SaveChunkToData(const cChunkCoords & a_Chunk, cWorld * a_World); // Saves the chunk to m_DataContents, updates headers and m_NumDirty - void SynchronizeFile(void); // Writes m_DataContents along with the headers to file, resets m_NumDirty - - void UpdateChunk1To2(void); // Height from 128 to 256 - void UpdateChunk2To3(void); // Axis order from YZX to XZY - } ; - - typedef std::list<cPAKFile *> cPAKFiles; - - cCriticalSection m_CS; - cPAKFiles m_PAKFiles; // A MRU cache of PAK files - - int m_CompressionFactor; - - /// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache - cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk); - - /// Gets chunk data from the correct file; locks CS as needed - bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data); - - /// Sets chunk data to the correct file; locks CS as needed - bool SetChunkData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data); - - /// Erases chunk data from the correct file; locks CS as needed - bool EraseChunkData(const cChunkCoords & a_Chunk); - - /// Loads the chunk from the data (no locking needed) - bool LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World); - - void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World); - - // cWSSchema overrides: - virtual bool LoadChunk(const cChunkCoords & a_Chunk) override; - virtual bool SaveChunk(const cChunkCoords & a_Chunk) override; - virtual const AString GetName(void) const override {return "compact"; } -} ; - - - - - -#endif // WSSCOMPACT_H_INCLUDED - - - - diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 179cf9393..31318ee67 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -7,7 +7,6 @@ #include "Globals.h" #include "WorldStorage.h" -#include "WSSCompact.h" #include "WSSAnvil.h" #include "../World.h" #include "../Generating/ChunkGenerator.h" @@ -40,8 +39,8 @@ protected: cWorldStorage::cWorldStorage(void) : super("cWorldStorage"), - m_World(NULL), - m_SaveSchema(NULL) + m_World(nullptr), + m_SaveSchema(nullptr) { } @@ -187,7 +186,6 @@ void cWorldStorage::InitSchemas(int a_StorageCompressionFactor) { // The first schema added is considered the default m_Schemas.push_back(new cWSSAnvil (m_World, a_StorageCompressionFactor)); - m_Schemas.push_back(new cWSSCompact (m_World, a_StorageCompressionFactor)); m_Schemas.push_back(new cWSSForgetful(m_World)); // Add new schemas here diff --git a/src/XMLParser.h b/src/XMLParser.h index e39405529..5b53e55cf 100644 --- a/src/XMLParser.h +++ b/src/XMLParser.h @@ -68,7 +68,7 @@ protected: 3, Create an instance of your class: CMyParser Parser; 4, Call Create(): - Parser.Create(NULL, NULL); + Parser.Create(nullptr, nullptr); 4, Call Parse(), repeatedly: Parser.Parse(Buffer, Length); */ @@ -84,7 +84,7 @@ public: CExpatImpl () { - m_p = NULL; + m_p = nullptr; } // @cmember Destructor @@ -99,24 +99,24 @@ public: // @cmember Create a parser - bool Create (const XML_Char * pszEncoding = NULL, const XML_Char * pszSep = NULL) + bool Create (const XML_Char * pszEncoding = nullptr, const XML_Char * pszSep = nullptr) { // Destroy the old parser Destroy (); - // If the encoding or seperator are empty, then NULL - if (pszEncoding != NULL && pszEncoding [0] == 0) + // If the encoding or seperator are empty, then nullptr + if (pszEncoding != nullptr && pszEncoding [0] == 0) { - pszEncoding = NULL; + pszEncoding = nullptr; } - if (pszSep != NULL && pszSep [0] == 0) + if (pszSep != nullptr && pszSep [0] == 0) { - pszSep = NULL; + pszSep = nullptr; } // Create the new parser - m_p = XML_ParserCreate_MM (pszEncoding, NULL, pszSep); - if (m_p == NULL) + m_p = XML_ParserCreate_MM (pszEncoding, nullptr, pszSep); + if (m_p == nullptr) { return false; } @@ -134,11 +134,11 @@ public: void Destroy (void) { - if (m_p != NULL) + if (m_p != nullptr) { XML_ParserFree (m_p); } - m_p = NULL; + m_p = nullptr; } @@ -146,7 +146,7 @@ public: bool Parse (const char *pszBuffer, int nLength, bool fIsFinal = true) { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_Parse (m_p, pszBuffer, nLength, fIsFinal) != 0; } @@ -154,7 +154,7 @@ public: bool ParseBuffer (int nLength, bool fIsFinal = true) { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_ParseBuffer (m_p, nLength, fIsFinal) != 0; } @@ -162,7 +162,7 @@ public: void *GetBuffer (int nLength) { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetBuffer (m_p, nLength); } @@ -174,23 +174,23 @@ protected: void EnableStartElementHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetStartElementHandler (m_p, fEnable ? StartElementHandler : NULL); + assert (m_p != nullptr); + XML_SetStartElementHandler (m_p, fEnable ? StartElementHandler : nullptr); } // @cmember Enable/Disable the end element handler void EnableEndElementHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetEndElementHandler (m_p, fEnable ? EndElementHandler : NULL); + assert (m_p != nullptr); + XML_SetEndElementHandler (m_p, fEnable ? EndElementHandler : nullptr); } // @cmember Enable/Disable the element handlers void EnableElementHandler (bool fEnable = true) { - assert (m_p != NULL); + assert (m_p != nullptr); EnableStartElementHandler (fEnable); EnableEndElementHandler (fEnable); } @@ -199,47 +199,47 @@ protected: void EnableCharacterDataHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetCharacterDataHandler (m_p, fEnable ? CharacterDataHandler : NULL); + assert (m_p != nullptr); + XML_SetCharacterDataHandler (m_p, fEnable ? CharacterDataHandler : nullptr); } // @cmember Enable/Disable the processing instruction handler void EnableProcessingInstructionHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetProcessingInstructionHandler (m_p, fEnable ? ProcessingInstructionHandler : NULL); + assert (m_p != nullptr); + XML_SetProcessingInstructionHandler (m_p, fEnable ? ProcessingInstructionHandler : nullptr); } // @cmember Enable/Disable the comment handler void EnableCommentHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetCommentHandler (m_p, fEnable ? CommentHandler : NULL); + assert (m_p != nullptr); + XML_SetCommentHandler (m_p, fEnable ? CommentHandler : nullptr); } // @cmember Enable/Disable the start CDATA section handler void EnableStartCdataSectionHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetStartCdataSectionHandler (m_p, fEnable ? StartCdataSectionHandler : NULL); + assert (m_p != nullptr); + XML_SetStartCdataSectionHandler (m_p, fEnable ? StartCdataSectionHandler : nullptr); } // @cmember Enable/Disable the end CDATA section handler void EnableEndCdataSectionHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetEndCdataSectionHandler (m_p, fEnable ? EndCdataSectionHandler : NULL); + assert (m_p != nullptr); + XML_SetEndCdataSectionHandler (m_p, fEnable ? EndCdataSectionHandler : nullptr); } // @cmember Enable/Disable the CDATA section handlers void EnableCdataSectionHandler (bool fEnable = true) { - assert (m_p != NULL); + assert (m_p != nullptr); EnableStartCdataSectionHandler (fEnable); EnableEndCdataSectionHandler (fEnable); } @@ -248,45 +248,45 @@ protected: void EnableDefaultHandler (bool fEnable = true, bool fExpand = true) { - assert (m_p != NULL); + assert (m_p != nullptr); if (fExpand) { - XML_SetDefaultHandlerExpand (m_p, fEnable ? DefaultHandler : NULL); + XML_SetDefaultHandlerExpand (m_p, fEnable ? DefaultHandler : nullptr); } else - XML_SetDefaultHandler (m_p, fEnable ? DefaultHandler : NULL); + XML_SetDefaultHandler (m_p, fEnable ? DefaultHandler : nullptr); } // @cmember Enable/Disable external entity ref handler void EnableExternalEntityRefHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetExternalEntityRefHandler (m_p, fEnable ? ExternalEntityRefHandler : NULL); + assert (m_p != nullptr); + XML_SetExternalEntityRefHandler (m_p, fEnable ? ExternalEntityRefHandler : nullptr); } // @cmember Enable/Disable unknown encoding handler void EnableUnknownEncodingHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetUnknownEncodingHandler (m_p, fEnable ? UnknownEncodingHandler : NULL); + assert (m_p != nullptr); + XML_SetUnknownEncodingHandler (m_p, fEnable ? UnknownEncodingHandler : nullptr); } // @cmember Enable/Disable start namespace handler void EnableStartNamespaceDeclHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetStartNamespaceDeclHandler (m_p, fEnable ? StartNamespaceDeclHandler : NULL); + assert (m_p != nullptr); + XML_SetStartNamespaceDeclHandler (m_p, fEnable ? StartNamespaceDeclHandler : nullptr); } // @cmember Enable/Disable end namespace handler void EnableEndNamespaceDeclHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetEndNamespaceDeclHandler (m_p, fEnable ? EndNamespaceDeclHandler : NULL); + assert (m_p != nullptr); + XML_SetEndNamespaceDeclHandler (m_p, fEnable ? EndNamespaceDeclHandler : nullptr); } // @cmember Enable/Disable namespace handlers @@ -301,32 +301,32 @@ protected: void EnableXmlDeclHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetXmlDeclHandler (m_p, fEnable ? XmlDeclHandler : NULL); + assert (m_p != nullptr); + XML_SetXmlDeclHandler (m_p, fEnable ? XmlDeclHandler : nullptr); } // @cmember Enable/Disable the start DOCTYPE declaration handler void EnableStartDoctypeDeclHandler (bool fEnable = true) { - assert (m_p != NULL); - XML_SetStartDoctypeDeclHandler (m_p, fEnable ? StartDoctypeDeclHandler : NULL); + assert (m_p != nullptr); + XML_SetStartDoctypeDeclHandler (m_p, fEnable ? StartDoctypeDeclHandler : nullptr); } // @cmember Enable/Disable the end DOCTYPE declaration handler void EnableEndDoctypeDeclHandler (bool fEnable = true) { - assert (m_p != NULL); + assert (m_p != nullptr); XML_SetEndDoctypeDeclHandler (m_p, - fEnable ? EndDoctypeDeclHandler : NULL); + fEnable ? EndDoctypeDeclHandler : nullptr); } // @cmember Enable/Disable the DOCTYPE declaration handler void EnableDoctypeDeclHandler (bool fEnable = true) { - assert (m_p != NULL); + assert (m_p != nullptr); EnableStartDoctypeDeclHandler (fEnable); EnableEndDoctypeDeclHandler (fEnable); } @@ -338,7 +338,7 @@ public: enum XML_Error GetErrorCode () { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetErrorCode (m_p); } @@ -346,7 +346,7 @@ public: long GetCurrentByteIndex () { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetCurrentByteIndex (m_p); } @@ -354,7 +354,7 @@ public: int GetCurrentLineNumber () { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetCurrentLineNumber (m_p); } @@ -362,7 +362,7 @@ public: int GetCurrentColumnNumber () { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetCurrentColumnNumber (m_p); } @@ -370,7 +370,7 @@ public: int GetCurrentByteCount () { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetCurrentByteCount (m_p); } @@ -378,7 +378,7 @@ public: const char *GetInputContext (int *pnOffset, int *pnSize) { - assert (m_p != NULL); + assert (m_p != nullptr); return XML_GetInputContext (m_p, pnOffset, pnSize); } @@ -682,17 +682,17 @@ protected: XML_Parser m_p; - /// Returns the value of the specified attribute, if found; NULL otherwise + /// Returns the value of the specified attribute, if found; nullptr otherwise static const XML_Char * FindAttr(const XML_Char ** iAttrs, const XML_Char * iAttrToFind) { - for (const XML_Char ** Attr = iAttrs; *Attr != NULL; Attr += 2) + for (const XML_Char ** Attr = iAttrs; *Attr != nullptr; Attr += 2) { if (strcmp(*Attr, iAttrToFind) == 0) { return *(Attr + 1); } } // for Attr - iAttrs[] - return NULL; + return nullptr; } } ; diff --git a/src/main.cpp b/src/main.cpp index 86ecd4000..463c54c28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -133,8 +133,8 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except ExcInformation.ClientPointers = 0; // Write the dump file: - HANDLE dumpFile = CreateFile(g_DumpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - g_WriteMiniDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, g_DumpFlags, (a_ExceptionInfo) ? &ExcInformation : NULL, NULL, NULL); + HANDLE dumpFile = CreateFile(g_DumpFileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + g_WriteMiniDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, g_DumpFlags, (a_ExceptionInfo) ? &ExcInformation : nullptr, nullptr, nullptr); CloseHandle(dumpFile); // Revert to old stack: @@ -187,7 +187,7 @@ int main( int argc, char **argv) #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) HINSTANCE hDbgHelp = LoadLibrary("DBGHELP.DLL"); g_WriteMiniDump = (pMiniDumpWriteDump)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if (g_WriteMiniDump != NULL) + if (g_WriteMiniDump != nullptr) { _snprintf_s(g_DumpFileName, ARRAYCOUNT(g_DumpFileName), _TRUNCATE, "crash_mcs_%x.dmp", GetCurrentProcessId()); SetUnhandledExceptionFilter(LastChanceExceptionFilter); @@ -269,7 +269,7 @@ int main( int argc, char **argv) } else if (NoCaseCompare(Arg, "nooutbuf") == 0) { - setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stdout, nullptr, _IONBF, 0); } } // for i - argv[] diff --git a/tests/Redstone/creatable.cpp b/tests/Redstone/creatable.cpp index f26ebe85c..02c622788 100644 --- a/tests/Redstone/creatable.cpp +++ b/tests/Redstone/creatable.cpp @@ -99,6 +99,7 @@ class MockChunk { public: cRedstoneSimulatorChunkData * GetRedstoneSimulatorData() { return NULL; } + void SetRedstoneSimulatorData(cRedstoneSimulatorChunkData * a_Data) {} bool IsRedstoneDirty() { return true; } void SetIsRedstoneDirty(bool a_Param) {} |