diff options
170 files changed, 5406 insertions, 3369 deletions
diff --git a/.travis.yml b/.travis.yml index 84b963a89..2fd3bf991 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: cpp -compiler: - - gcc - - clang +compiler: clang before_install: - if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]; then sudo pip install cpp_coveralls; fi @@ -29,8 +27,6 @@ after_success: env: - TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer - TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug - - TRAVIS_MCSERVER_BUILD_TYPE=RELEASE TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer - - TRAVIS_MCSERVER_BUILD_TYPE=DEBUG TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer_debug matrix: include: diff --git a/CIbuild.sh b/CIbuild.sh index 755dc7daa..f5a9005da 100755 --- a/CIbuild.sh +++ b/CIbuild.sh @@ -11,7 +11,7 @@ cd src lua CheckBasicStyle.lua cd .. make -j 2; -make -j 2 test; +make -j 2 test ARGS="-V"; cd MCServer/; if [ "$TRAVIS_MCSERVER_BUILD_TYPE" != "COVERAGE" ] then echo stop | $MCSERVER_PATH; diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index a7a597fb7..9ee818a2c 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -197,6 +197,7 @@ g_APIDesc = baMetas = { Notes = "Operations should work on block metas" }, baLight = { Notes = "Operations should work on block (emissive) light" }, baSkyLight = { Notes = "Operations should work on skylight" }, + msDifference = { Notes = "Block becomes air if Src and Dst are the same. Otherwise it becomes the source block." }, msOverwrite = { Notes = "Src overwrites anything in Dst" }, msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" }, msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" }, @@ -355,9 +356,11 @@ g_APIDesc = ]], Functions = { + CanBeTerraformed = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns true if the block is suitable to be changed by a generator" }, FullyOccupiesVoxel = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block fully occupies its voxel." }, Get = { Params = "Type", Return = "{{cBlockInfo}}", Notes = "(STATIC) Returns the {{cBlockInfo}} structure for the specified type." }, GetLightValue = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block emits on its own." }, + GetPlaceSound = { Params = "Type", Return = "", Notes = "(STATIC) Returns the name of the sound that is played when placing the block." }, GetSpreadLightFalloff = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block consumes." }, IsOneHitDig = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block will be destroyed after a single hit." }, IsPistonBreakable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether a piston can break the specified block." }, @@ -368,12 +371,14 @@ g_APIDesc = }, Variables = { + m_CanBeTerraformed = { Type = "bool", Notes = "Is this block suited to be terraformed?" }, m_FullyOccupiesVoxel = { Type = "bool", Notes = "Does this block fully occupy its voxel - is it a 'full' block?" }, m_IsSnowable = { Type = "bool", Notes = "Can this block hold snow atop?" }, m_IsSolid = { Type = "bool", Notes = "Is this block solid (player cannot walk through)?" }, m_LightValue = { Type = "number", Notes = "How much light do the blocks emit on their own?" }, m_OneHitDig = { Type = "bool", Notes = "Is a block destroyed after a single hit?" }, m_PistonBreakable = { Type = "bool", Notes = "Can a piston break this block?" }, + m_PlaceSound = { Type = "string", Notes = "The name of the sound that is placed when a block is placed." }, m_RequiresSpecialTool = { Type = "bool", Notes = "Does this block require a tool to drop?" }, m_SpreadLightFalloff = { Type = "number", Notes = "How much light do the blocks consume?" }, m_Transparent = { Type = "bool", Notes = "Is a block completely transparent? (light doesn't get decreased(?))" }, @@ -447,6 +452,7 @@ g_APIDesc = GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z coord of the chunk contained." }, GetHeight = { Params = "RelX, RelZ", Return = "number", Notes = "Returns the height at the specified relative coords" }, GetMaxHeight = { Params = "", Return = "number", Notes = "Returns the maximum height contained in the heightmap." }, + GetMinHeight = { Params = "", Return = "number", Notes = "Returns the minimum height value in the heightmap." }, IsUsingDefaultBiomes = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default biome generator" }, IsUsingDefaultComposition = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default composition generator" }, IsUsingDefaultFinish = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default finishers" }, @@ -2419,6 +2425,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") BroadcastChatInfo = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." }, BroadcastChatSuccess = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." }, BroadcastChatWarning = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." }, + BroadcastEntityAnimation = { Params = "{{cEntity|TargetEntity}}, Animation, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends an animation of an entity to all clienthandles (except ExcludeClient if given)" }, BroadcastParticleEffect = { Params = "ParticleName, X, Y, Z, OffSetX, OffSetY, OffSetZ, ParticleData, ParticleAmmount, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Spawns the specified particles to all players in the world exept the optional ExeptClient. A list of available particles by thinkofdeath can be found {{https://gist.github.com/thinkofdeath/5110835|Here}}" }, BroadcastSoundEffect = { Params = "SoundName, X, Y, Z, Volume, Pitch, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified sound effect to all players in this world, except the optional ExceptClient" }, BroadcastSoundParticleEffect = { Params = "EffectID, X, Y, Z, EffectData, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified effect to all players in this world, except the optional ExceptClient" }, @@ -2471,15 +2478,20 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") }, GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "number", Notes = "Returns the block skylight of the block at the specified coords, or 0 if the appropriate chunk is not loaded." }, GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BlockValid, BlockType, BlockMeta", Notes = "Returns the block type and metadata for the block at the specified coords. The first value specifies if the block is in a valid loaded chunk, the other values are valid only if BlockValid is true." }, + GetDefaultWeatherInterval = { Params = "eWeather", Return = "", Notes = "Returns the default weather interval for the specific weather type. Returns -1 for any unknown weather." }, GetDimension = { Params = "", Return = "eDimension", Notes = "Returns the dimension of the world - dimOverworld, dimNether or dimEnd." }, GetGameMode = { Params = "", Return = "eGameMode", Notes = "Returns the gamemode of the world - gmSurvival, gmCreative or gmAdventure." }, GetGeneratorQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks that are queued in the chunk generator." }, GetHeight = { Params = "BlockX, BlockZ", Return = "number", Notes = "Returns the maximum height of the particula block column in the world. If the chunk is not loaded, it waits for it to load / generate. <b>WARNING</b>: Do not use, Use TryGetHeight() instead for a non-waiting version, otherwise you run the risk of a deadlock!" }, GetIniFileName = { Params = "", Return = "string", Notes = "Returns the name of the world.ini file that the world uses to store the information." }, GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." }, + GetLinkedEndWorldName = { Params = "", Return = "string", Notes = "Returns the name of the end world this world is linked to." }, + GetLinkedNetherWorldName = { Params = "", Return = "string", Notes = "Returns the name of the Netherworld linked to this world." }, + GetLinkedOverworldName = { Params = "", Return = "string", Notes = "Returns the name of the world this world is linked to." }, GetMapManager = { Params = "", Return = "{{cMapManager}}", Notes = "Returns the {{cMapManager|MapManager}} object used by this world." }, GetMaxCactusHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which cacti will grow naturally." }, GetMaxSugarcaneHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which sugarcane will grow naturally." }, + GetMaxViewDistance = { Params = "", Return = "number", Notes = "Returns the maximum viewdistance that players can see in this world. The view distance is the amount of chunks around the player that the player can see." }, GetName = { Params = "", Return = "string", Notes = "Returns the name of the world, as specified in the settings.ini file." }, GetNumChunks = { Params = "", Return = "number", Notes = "Returns the number of chunks currently loaded." }, GetScoreBoard = { Params = "", Return = "{{cScoreBoard}}", Notes = "Returns the {{cScoreBoard|ScoreBoard}} object used by this world. " }, @@ -2491,6 +2503,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") GetStorageSaveQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks queued up for saving" }, GetTicksUntilWeatherChange = { Params = "", Return = "number", Notes = "Returns the number of ticks that will pass before the weather is changed" }, GetTimeOfDay = { Params = "", Return = "number", Notes = "Returns the number of ticks that have passed from the sunrise, 0 .. 24000." }, + GetTNTShrapnelLevel = { Params = "", Return = "{{Globals#ShrapnelLevel|ShrapnelLevel}}", Notes = "Returns the shrapnel level, representing the block types that are propelled outwards following an explosion. Based on this value and a random picker, blocks are selectively converted to physics entities (FallingSand) and flung outwards." }, GetWeather = { Params = "", Return = "eWeather", Notes = "Returns the current weather in the world (wSunny, wRain, wStorm). To check for weather, use IsWeatherXXX() functions instead." }, GetWorldAge = { Params = "", Return = "number", Notes = "Returns the total age of the world, in ticks. The age always grows, cannot be set by plugins and is unrelated to TimeOfDay." }, GrowCactus = { Params = "BlockX, BlockY, BlockZ, NumBlocksToGrow", Return = "", Notes = "Grows a cactus block at the specified coords, by up to the specified number of blocks. Adheres to the world's maximum cactus growth (GetMaxCactusHeight())." }, @@ -2501,11 +2514,14 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") GrowTreeByBiome = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Grows a tree based at the specified coords. The tree type is picked from types available for the biome at those coords." }, GrowTreeFromSapling = { Params = "BlockX, BlockY, BlockZ, SaplingMeta", Return = "", Notes = "Grows a tree based at the specified coords. The tree type is determined from the sapling meta (the sapling itself needn't be present)." }, IsBlockDirectlyWatered = { Params = "BlockX, BlockY, BlockZ", Return = "bool", Notes = "Returns true if the specified block has a water block right next to it (on the X/Z axes)" }, + IsDaylightCycleEnabled = { Params = "", Return = "bool", Notes = "Returns true if the daylight cycle is enabled." }, IsDeepSnowEnabled = { Params = "", Return = "bool", Notes = "Returns whether the configuration has DeepSnow enabled." }, IsGameModeAdventure = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmAdventure." }, IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmCreative." }, + IsGameModeSpectator = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmSpectator." }, IsGameModeSurvival = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmSurvival." }, IsPVPEnabled = { Params = "", Return = "bool", Notes = "Returns whether PVP is enabled in the world settings." }, + IsTrapdoorOpen = { Params = "BlockX, BlockY, BlockZ", Return = "bool", Notes = "Returns false if there is no trapdoor there or if the block isn't a trapdoor or if the chunk wasn't loaded. Returns true if trapdoor is open." }, IsWeatherRain = { Params = "", Return = "bool", Notes = "Returns true if the current world is raining." }, IsWeatherRainAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location is raining (takes into account biomes)." }, IsWeatherStorm = { Params = "", Return = "bool", Notes = "Returns true if the current world is stormy." }, @@ -2514,6 +2530,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") IsWeatherSunnyAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the current weather is sunny at the specified location (takes into account biomes)." }, IsWeatherWet = { Params = "", Return = "bool", Notes = "Returns true if the current world has any precipitation (rain or storm)." }, IsWeatherWetAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location has any precipitation (rain or storm) (takes into account biomes)." }, + PrepareChunk = { Params = "ChunkX, ChunkZ, [Callback]", Return = "", Notes = "Queues the chunk for preparing - making sure that it's generated and lit. It is legal to call with no callback. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback(ChunkX, ChunkZ)</pre>" }, QueueBlockForTick = { Params = "BlockX, BlockY, BlockZ, TicksToWait", Return = "", Notes = "Queues the specified block to be ticked after the specified number of gameticks." }, QueueSaveAllChunks = { Params = "", Return = "", Notes = "Queues all chunks to be saved in the world storage thread" }, QueueSetBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta, TickDelay", Return = "", Notes = "Queues the block to be set to the specified blocktype and meta after the specified amount of game ticks. Uses SetBlock() for the actual setting, so simulators are woken up and block entities are handled correctly." }, @@ -2537,18 +2554,28 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") SetNextBlockTick = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Sets the blockticking to start at the specified block in the next tick." }, SetCommandBlockCommand = { Params = "BlockX, BlockY, BlockZ, Command", Return = "bool", Notes = "Sets the command to be executed in a command block at the specified coordinates. Returns if command was changed." }, SetCommandBlocksEnabled = { Params = "IsEnabled (bool)", Return = "", Notes = "Sets whether command blocks should be enabled on the (entire) server." }, + SetDaylightCycleEnabled = { Params = "bool", Return = "", Notes = "Starts or stops the daylight cycle." }, + SetLinkedEndWorldName = { Params = "string", Return = "", Notes = "Sets the name of the world that the end portal should link to." }, + SetLinkedNetherWorldName = { Params = "string", Return = "", Notes = "Sets the name of the world that the nether portal should link to." }, + SetLinkedOverworldName = { Params = "string", Return = "", Notes = "Sets the name of the world that the nether portal should link to?" }, + SetMaxViewDistance = { Params = "number", Return = "", Notes = "Sets the maximum viewdistance of the players in the world." }, 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." }, 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." }, + SetTNTShrapnelLevel = { Params = "{{Globals#ShrapnelLevel|ShrapnelLevel}}", Return = "", Notes = "Sets the Shrampel level of the world." }, + SetTrapdoorOpen = { Params = "BlockX, BlockY, BlockZ, bool", Return = "", Notes = "Opens or closes a trapdoor at the specific coordinates." }, 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." }, + ShouldBroadcastAchievementMessages = { Params = "", Return = "bool", Notes = "Returns true if the server should broadcast achievement messages in this world." }, + ShouldBroadcastDeathMessages = { Params = "", Return = "bool", Notes = "Returns true if the server should broadcast death messages in this world." }, + ShouldUseChatPrefixes = { Params = "", Return = "bool", Notes = "Returns whether coloured chat prefixes are prepended to chat messages or the entire message is simply coloured." }, ShouldLavaSpawnFire = { Params = "", Return = "bool", Notes = "Returns true if the world is configured to spawn fires near lava (world.ini: [Physics].ShouldLavaSpawnFire value)" }, SpawnItemPickups = { { Params = "{{cItems|Pickups}}, X, Y, Z, FlyAwaySpeed", Return = "", Notes = "Spawns the specified pickups at the position specified. The FlyAway speed is used to initialize the random speed in which the pickups fly away from the spawn position." }, { Params = "{{cItems|Pickups}}, X, Y, Z, SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Spawns the specified pickups at the position specified. All the pickups fly away from the spawn position using the specified speed." }, }, + SpawnMinecart = { Params = "X, Y, Z, MinecartType, Item, BlockHeight", Return = "number", Notes = "Spawns a minecart at the specific coordinates. MinecartType is the item type of the minecart. If the minecart is an empty minecart then the given item is the block inside the minecart, and blockheight is the distance of the block and the minecart." }, SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " }, SpawnFallingBlock = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "EntityID", Notes = "Spawns an {{cFallingBlock|Falling Block}} entity at the specified coords with the given block type/meta" }, SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" }, @@ -2556,6 +2583,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress") 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 = "(<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." }, + VillagersShouldHarvestCrops = { Params = "", Return = "", Notes = "Returns true if villagers can harvest crops." }, 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)." }, }, @@ -2871,41 +2899,18 @@ end This class represents the tolua bridge between the Lua API and MCServer. It supports some low level operations and queries on the objects. See also the tolua++'s documentation at {{http://www.codenix.com/~tolua/tolua++.html#utilities}}. Normally you shouldn't use any of these - functions except for cast() and type() + functions except for type() ]], Functions = { - cast = { Params = "Object, TypeStr", Return = "Object", Notes = "Casts the object to the specified type through the inheritance hierarchy." }, + cast = { Params = "Object, TypeStr", Return = "Object", Notes = "Casts the object to the specified type.<br/><b>Note:</b> This is a potentially unsafe operation and it could crash the server. There is normally no need to use this function at all, so don't use it unless you know exactly what you're doing." }, getpeer = { Params = "", Return = "", Notes = "" }, inherit = { Params = "", Return = "", Notes = "" }, releaseownership = { Params = "", Return = "", Notes = "" }, setpeer = { Params = "", Return = "", Notes = "" }, takeownership = { Params = "", Return = "", Notes = "" }, - type = { Params = "Object", Return = "TypeStr", Notes = "Returns a string representing the type of the object. This works similar to Lua's built-in type() function, but recognizes the underlying C++ types, too." }, + type = { Params = "Object", Return = "TypeStr", Notes = "Returns a string representing the type of the object. This works similar to Lua's built-in type() function, but recognizes the underlying C++ classes, too." }, }, - AdditionalInfo = - { - { - Header = "Usage example", - Contents = - [[ - The tolua.cast() function is normally used to cast between related types. For example in the - hook callbacks you often receive a generic {{cEntity}} object, when in fact you know that the - object is a {{cMonster}}. You can cast the object to access its cMonster functions: -<pre class="prettyprint lang-lua"> -function OnTakeDamage(a_ReceiverEntity, TDI) - if (a_ReceiverEntity.IsMob()) then - local Mob = tolua.cast(a_ReceiverEntity, "cMonster"); -- Cast a_ReceiverEntity into a {{cMonster}} instance - if (Mob:GetMonsterType() == cMonster.mtSheep) then - local Sheep = tolua.cast(Mob, "cSheep"); -- Cast Mob into a {{cSheep}} instance - -- Do something sheep-specific - end - end -end -</pre> - ]], - } - } -- AdditionalInfo }, -- tolua Globals = @@ -2965,6 +2970,7 @@ end RotateBlockFaceCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees clockwise." }, StringSplit = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered."}, StringSplitAndTrim = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered. Each of the separate strings is trimmed (whitespace removed from the beginning and end of the string)"}, + StringSplitWithQuotes = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered. Whitespace wrapped with single or double quotes will be ignored"}, StringToBiome = {Params = "string", Return = "{{Globals#BiomeTypes|BiomeType}}", Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value"}, StringToDamageType = {Params = "string", Return = "{{Globals#DamageType|DamageType}}", Notes = "Converts a string representation to a {{Globals#DamageType|DamageType}} enumerated value."}, StringToDimension = {Params = "string", Return = "{{Globals#WorldDimension|Dimension}}", Notes = "Converts a string representation to a {{Globals#WorldDimension|Dimension}} enumerated value"}, @@ -3088,7 +3094,14 @@ end These constants are used to differentiate the various sources of spreads, such as grass growing. They are used in the {{OnBlockSpread|HOOK_BLOCK_SPREAD}} hook. ]], - } + }, + ShrapnelLevel = + { + Include = "^sl.*", + TextBefore = [[ + The following constants define the block types that are propelled outwards after an explosion. + ]], + }, }, }, -- Globals }, diff --git a/MCServer/Plugins/APIDump/Classes/Network.lua b/MCServer/Plugins/APIDump/Classes/Network.lua index 797788661..c7626562d 100644 --- a/MCServer/Plugins/APIDump/Classes/Network.lua +++ b/MCServer/Plugins/APIDump/Classes/Network.lua @@ -289,6 +289,7 @@ g_Server = nil { Connect = { Params = "Host, Port, LinkCallbacks", Return = "bool", Notes = "(STATIC) Begins establishing a (client) TCP connection to the specified host. Uses the LinkCallbacks table to report progress, success, errors and incoming data. Returns false if it fails immediately (bad port value, bad hostname format), true otherwise. Host can be either an IP address or a hostname." }, CreateUDPEndpoint = { Params = "Port, UDPCallbacks", Return = "{{cUDPEndpoint|UDPEndpoint}}", Notes = "(STATIC) Creates a UDP endpoint that listens for incoming datagrams on the specified port, and can be used to send or broadcast datagrams. Uses the UDPCallbacks to report incoming datagrams or errors. If the endpoint cannot be created, the OnError callback is called with the error details and the returned endpoint will report IsOpen() == false. The plugin needs to store the returned endpoint object for as long as it needs the UDP port open; if the endpoint is garbage-collected by Lua, the socket will be closed and no more incoming data will be reported.<br>If the Port is zero, the OS chooses an available UDP port for the endpoint; use {{cUDPEndpoint}}:GetPort() to query the port number in such case." }, + EnumLocalIPAddresses = { Params = "", Return = "array-table of strings", Notes = "(STATIC) Returns all local IP addresses for network interfaces currently available on the machine." }, HostnameToIP = { Params = "Host, LookupCallbacks", Return = "bool", Notes = "(STATIC) Begins a DNS lookup to find the IP address(es) for the specified host. Uses the LookupCallbacks table to report progress, success or errors. Returns false if it fails immediately (bad hostname format), true if the lookup started successfully. Host can be either a hostname or an IP address." }, IPToHostname = { Params = "Address, LookupCallbacks", Return = "bool", Notes = "(STATIC) Begins a reverse-DNS lookup to find out the hostname for the specified IP address. Uses the LookupCallbacks table to report progress, success or errors. Returns false if it fails immediately (bad address format), true if the lookup started successfully." }, Listen = { Params = "Port, ListenCallbacks", Return = "{{cServerHandle|ServerHandle}}", Notes = "(STATIC) Starts listening on the specified port. Uses the ListenCallbacks to report incoming connections or errors. Returns a {{cServerHandle}} object representing the server. If the listen operation failed, the OnError callback is called with the error details and the returned server handle will report IsListening() == false. The plugin needs to store the server handle object for as long as it needs the server running, if the server handle is garbage-collected by Lua, the listening socket will be closed and all current connections dropped." }, diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index a25bab9cf..239bec69c 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -62,7 +62,7 @@ local function CreateAPITables() Variables = { }, Descendants = {}, -- Will be filled by ReadDescriptions(), array of class APIs (references to other member in the tree) - }}, + }, { Name = "cBlockArea", Functions = { @@ -78,7 +78,9 @@ local function CreateAPITables() Variables = { }, ... - }} + }, + + cCuboid = {} -- Each array item also has the map item by its name }; local Globals = { Functions = { @@ -135,7 +137,9 @@ local function CreateAPITables() (v ~= g_APIDesc) ) then if (type(v) == "table") then - table.insert(API, ParseClass(i, v)); + local cls = ParseClass(i, v) + table.insert(API, cls); + API[cls.Name] = cls else Add(Globals, i, v); end @@ -1449,6 +1453,103 @@ end +--- Returns true if a_Descendant is declared to be a (possibly indirect) descendant of a_Base +local function IsDeclaredDescendant(a_DescendantName, a_BaseName, a_API) + -- Check params: + assert(type(a_DescendantName) == "string") + assert(type(a_BaseName) == "string") + assert(type(a_API) == "table") + if not(a_API[a_BaseName]) then + return false + end + assert(type(a_API[a_BaseName]) == "table", "Not a class name: " .. a_BaseName) + assert(type(a_API[a_BaseName].Descendants) == "table") + + -- Check direct inheritance: + for _, desc in ipairs(a_API[a_BaseName].Descendants) do + if (desc.Name == a_DescendantName) then + return true + end + end -- for desc - a_BaseName's descendants + + -- Check indirect inheritance: + for _, desc in ipairs(a_API[a_BaseName].Descendants) do + if (IsDeclaredDescendant(a_DescendantName, desc.Name, a_API)) then + return true + end + end -- for desc - a_BaseName's descendants + + return false +end + + + + + +--- Checks the specified class' inheritance +-- Reports any problems as new items in the a_Report table +local function CheckClassInheritance(a_Class, a_API, a_Report) + -- Check params: + assert(type(a_Class) == "table") + assert(type(a_API) == "table") + assert(type(a_Report) == "table") + + -- Check that the declared descendants are really descendants: + local registry = debug.getregistry() + for _, desc in ipairs(a_Class.Descendants or {}) do + local isParent = false + local parents = registry["tolua_super"][_G[desc.Name]] + if not(parents[a_Class.Name]) then + table.insert(a_Report, desc.Name .. " is not a descendant of " .. a_Class.Name) + end + end -- for desc - a_Class.Descendants[] + + -- Check that all inheritance is listed for the class: + local parents = registry["tolua_super"][_G[a_Class.Name]] -- map of "classname" -> true for each class that a_Class inherits + for clsName, isParent in pairs(parents or {}) do + if ((clsName ~= "") and not(clsName:match("const .*"))) then + if not(IsDeclaredDescendant(a_Class.Name, clsName, a_API)) then + table.insert(a_Report, a_Class.Name .. " inherits from " .. clsName .. " but this isn't documented") + end + end + end +end + + + + + +--- Checks each class's declared inheritance versus the actual inheritance +local function CheckAPIDescendants(a_API) + -- Check each class: + local report = {} + for _, cls in ipairs(a_API) do + if (cls.Name ~= "Globals") then + CheckClassInheritance(cls, a_API, report) + end + end + + -- If there's anything to report, output it to a file: + if (report[1] ~= nil) then + LOG("There are inheritance errors in the API description:") + for _, msg in ipairs(report) do + LOG(" " .. msg) + end + + local f, err = io.open("API/_inheritance_errors.txt", "w") + if (f == nil) then + LOG("Cannot report inheritance problems to a file: " .. tostring(err)) + return + end + f:write(table.concat(report, "\n")) + f:close() + end +end + + + + + local function DumpApi() LOG("Dumping the API...") @@ -1501,6 +1602,9 @@ local function DumpApi() LOG("Reading descriptions..."); ReadDescriptions(API); + -- Check that the API lists the inheritance properly, report any problems to a file: + CheckAPIDescendants(API) + -- Dump all available API objects in HTML format into a subfolder: DumpAPIHtml(API); diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject 6e9d612b9eb548d888d2bf986488aad762a99be +Subproject ee3cd9ba917baa94d6b9bfe7c9205609e0722fa diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index c8069a411..d0c362ab4 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -1643,6 +1643,81 @@ end +--- Monitors the state of the "inh" entity-spawning hook +-- if false, the hook is installed before the "inh" command processing +local isInhHookInstalled = false + +function HandleConsoleInh(a_Split, a_FullCmd) + -- Check the param: + local kindStr = a_Split[2] or "pkArrow" + local kind = cProjectileEntity[kindStr] + if (kind == nil) then + return true, "There's no projectile kind '" .. kindStr .. "'." + end + + -- Get the world to test in: + local world = cRoot:Get():GetDefaultWorld() + if (world == nil) then + return true, "Cannot test inheritance, no default world" + end + + -- Install the hook, if needed: + if not(isInhHookInstalled) then + cPluginManager:AddHook(cPluginManager.HOOK_SPAWNING_ENTITY, + function (a_CBWorld, a_CBEntity) + LOG("New entity is spawning:") + LOG(" Lua type: '" .. type(a_CBEntity) .. "'") + LOG(" ToLua type: '" .. tolua.type(a_CBEntity) .. "'") + LOG(" GetEntityType(): '" .. a_CBEntity:GetEntityType() .. "'") + LOG(" GetClass(): '" .. a_CBEntity:GetClass() .. "'") + end + ) + isInhHookInstalled = true + end + + -- Create the projectile: + LOG("Creating a " .. kindStr .. " projectile in world " .. world:GetName() .. "...") + local msg + world:ChunkStay({{0, 0}}, + nil, + function () + -- Create a projectile at {8, 100, 8}: + local entityID = world:CreateProjectile(8, 100, 8, kind, nil, nil) + if (entityID < 0) then + msg = "Cannot test inheritance, projectile creation failed." + return + end + LOG("Entity created, ID #" .. entityID) + + -- Call a function on the newly created entity: + local hasExecutedCallback = false + world:DoWithEntityByID( + entityID, + function (a_CBEntity) + LOG("Projectile created and found using the DoWithEntityByID() callback") + LOG("Lua type: '" .. type(a_CBEntity) .. "'") + LOG("ToLua type: '" .. tolua.type(a_CBEntity) .. "'") + LOG("GetEntityType(): '" .. a_CBEntity:GetEntityType() .. "'") + LOG("GetClass(): '" .. a_CBEntity:GetClass() .. "'") + hasExecutedCallback = true + end + ) + if not(hasExecutedCallback) then + msg = "The callback failed to execute" + return + end + + msg = "Inheritance test finished" + end + ) + + return true, msg +end + + + + + function HandleConsoleLoadChunk(a_Split) -- Check params: local numParams = #a_Split @@ -1741,3 +1816,58 @@ end + +function HandleConsoleBBox(a_Split) + local bbox = cBoundingBox(0, 10, 0, 10, 0, 10) + local v1 = Vector3d(1, 1, 1) + local v2 = Vector3d(5, 5, 5) + local v3 = Vector3d(11, 11, 11) + + if (bbox:IsInside(v1)) then + LOG("v1 is inside bbox") + else + LOG("v1 is not inside bbox") + end + + if (bbox:IsInside(v2)) then + LOG("v2 is inside bbox") + else + LOG("v2 is not inside bbox") + end + + if (bbox:IsInside(v3)) then + LOG("v3 is inside bbox") + else + LOG("v3 is not inside bbox") + end + + if (bbox:IsInside(v1, v2)) then + LOG("v1*v2 is inside bbox") + else + LOG("v1*v2 is not inside bbox") + end + + if (bbox:IsInside(v2, v1)) then + LOG("v2*v1 is inside bbox") + else + LOG("v2*v1 is not inside bbox") + end + + if (bbox:IsInside(v1, v3)) then + LOG("v1*v3 is inside bbox") + else + LOG("v1*v3 is not inside bbox") + end + + if (bbox:IsInside(v2, v3)) then + LOG("v2*v3 is inside bbox") + else + LOG("v2*v3 is not inside bbox") + end + + return true +end + + + + diff --git a/MCServer/Plugins/Debuggers/Info.lua b/MCServer/Plugins/Debuggers/Info.lua index 63a4b9177..0370145df 100644 --- a/MCServer/Plugins/Debuggers/Info.lua +++ b/MCServer/Plugins/Debuggers/Info.lua @@ -200,12 +200,24 @@ g_PluginInfo = ConsoleCommands = { + ["bbox"] = + { + Handler = HandleConsoleBBox, + HelpString = "Performs cBoundingBox API tests", + }, + ["hash"] = { Handler = HandleConsoleHash, HelpString = "Tests the crypto hashing functions", }, + ["inh"] = + { + Handler = HandleConsoleInh, + HelpString = "Tests the bindings of the cEntity inheritance", + }, + ["loadchunk"] = { Handler = HandleConsoleLoadChunk, diff --git a/MCServer/Plugins/NetworkTest/Info.lua b/MCServer/Plugins/NetworkTest/Info.lua index 52422d427..d8c3095fe 100644 --- a/MCServer/Plugins/NetworkTest/Info.lua +++ b/MCServer/Plugins/NetworkTest/Info.lua @@ -50,6 +50,12 @@ g_PluginInfo = }, -- ParameterCombinations }, -- close + ips = + { + HelpString = "Prints all locally available IP addresses", + Handler = HandleConsoleNetIps, + }, -- ips + listen = { HelpString = "Creates a new listening socket on the specified port with the specified service attached to it", diff --git a/MCServer/Plugins/NetworkTest/NetworkTest.lua b/MCServer/Plugins/NetworkTest/NetworkTest.lua index daab0a4bf..22056d4e9 100644 --- a/MCServer/Plugins/NetworkTest/NetworkTest.lua +++ b/MCServer/Plugins/NetworkTest/NetworkTest.lua @@ -288,6 +288,19 @@ end +function HandleConsoleNetIps(a_Split) + local Addresses = cNetwork:EnumLocalIPAddresses() + LOG("IP addresses enumerated, " .. #Addresses .. " found") + for idx, addr in ipairs(Addresses) do + LOG(" IP #" .. idx .. ": " .. addr) + end + return true +end + + + + + function HandleConsoleNetLookup(a_Split) -- Get the name to look up: local Addr = a_Split[3] or "google.com" diff --git a/MCServer/delete_windows_service.cmd b/MCServer/delete_windows_service.cmd new file mode 100644 index 000000000..ab6238e2f --- /dev/null +++ b/MCServer/delete_windows_service.cmd @@ -0,0 +1,4 @@ +@echo off
+set SERVICENAME="MCServer"
+
+sc delete %SERVICENAME%
\ No newline at end of file diff --git a/MCServer/install_windows_service.cmd b/MCServer/install_windows_service.cmd new file mode 100644 index 000000000..ba8a8c128 --- /dev/null +++ b/MCServer/install_windows_service.cmd @@ -0,0 +1,7 @@ +rem Alter this if you need to install multiple instances.
+@echo off
+set SERVICENAME="MCServer"
+
+set CURRENTDIR=%CD%
+sc create %SERVICENAME% binPath= "%CURRENTDIR%\MCServer.exe /service" start= auto DisplayName= %SERVICENAME%
+sc description %SERVICENAME% "Minecraft server instance"
\ No newline at end of file diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index 6d347e07d..f24747a24 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -8,6 +8,7 @@ #include "Server.h" #include <iostream> #include "PolarSSL++/CryptoKey.h" +#include "../../src/Logger.h" #ifdef _WIN32 #include <direct.h> // For _mkdir() @@ -214,7 +215,11 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) : Printf(m_LogNameBase, "Logs/Log_%d_%d", (int)time(NULL), a_ClientSocket); AString fnam(m_LogNameBase); fnam.append(".log"); - m_LogFile = fopen(fnam.c_str(), "w"); + #ifdef _WIN32 + fopen_s(&m_LogFile, fnam.c_str(), "w"); + #else + m_LogFile = fopen(fnam.c_str(), "w"); + #endif Log("Log file created"); printf("Connection is logged to file \"%s\"\n", fnam.c_str()); } @@ -788,31 +793,31 @@ bool cConnection::HandleClientHandshake(void) // Read the packet from the client: HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, ProtocolVersion); HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ServerHost); - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, ServerPort); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, ServerPort); HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, NextState); m_ClientBuffer.CommitRead(); Log("Received an initial handshake packet from the client:"); Log(" ProtocolVersion = %u", ProtocolVersion); Log(" ServerHost = \"%s\"", ServerHost.c_str()); - Log(" ServerPort = %d", ServerPort); + Log(" ServerPort = %u", ServerPort); Log(" NextState = %u", NextState); // Send the same packet to the server, but with our port: cByteBuffer Packet(512); - Packet.WriteVarInt(0); // Packet type - initial handshake - Packet.WriteVarInt(ProtocolVersion); + Packet.WriteVarInt32(0); // Packet type - initial handshake + Packet.WriteVarInt32(ProtocolVersion); Packet.WriteVarUTF8String(ServerHost); - Packet.WriteBEShort(m_Server.GetConnectPort()); - Packet.WriteVarInt(NextState); + Packet.WriteBEUInt16(m_Server.GetConnectPort()); + Packet.WriteVarInt32(NextState); AString Pkt; Packet.ReadAll(Pkt); cByteBuffer ToServer(512); ToServer.WriteVarUTF8String(Pkt); SERVERSEND(ToServer); - m_ClientProtocolState = (int)NextState; - m_ServerProtocolState = (int)NextState; + m_ClientProtocolState = static_cast<int>(NextState); + m_ServerProtocolState = static_cast<int>(NextState); return true; } @@ -852,10 +857,10 @@ bool cConnection::HandleClientLoginStart(void) bool cConnection::HandleClientAnimation(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Animation); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_CLIENT_PACKET_READ(ReadBEInt8, Int8, Animation); Log("Received a PACKET_ANIMATION from the client:"); - Log(" EntityID: %d", EntityID); + Log(" EntityID: %u", EntityID); Log(" Animation: %d", Animation); COPY_TO_SERVER(); return true; @@ -867,15 +872,15 @@ bool cConnection::HandleClientAnimation(void) bool cConnection::HandleClientBlockDig(void) { - HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, Status); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, BlockY); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, BlockFace); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, Status); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, BlockY); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, BlockZ); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, BlockFace); Log("Received a PACKET_BLOCK_DIG from the client:"); - Log(" Status = %d", Status); - Log(" Pos = <%d, %d, %d>", BlockX, BlockY, BlockZ); - Log(" BlockFace = %d", BlockFace); + Log(" Status = %u (0x%02x)", Status, Status); + Log(" Pos = <%d, %u, %d>", BlockX, BlockY, BlockZ); + Log(" BlockFace = %u (0x%02x)", BlockFace, BlockFace); COPY_TO_SERVER(); return true; } @@ -886,23 +891,23 @@ bool cConnection::HandleClientBlockDig(void) bool cConnection::HandleClientBlockPlace(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, BlockY); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Face); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, BlockY); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, BlockZ); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, Face); AString Desc; if (!ParseSlot(m_ClientBuffer, Desc)) { return false; } - HANDLE_CLIENT_PACKET_READ(ReadChar, char, CursorX); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, CursorY); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, CursorZ); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, CursorX); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, CursorY); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, CursorZ); Log("Received a PACKET_BLOCK_PLACE from the client:"); - Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ); - Log(" Face = %d", Face); + Log(" Block = {%d, %u, %d}", BlockX, BlockY, BlockZ); + Log(" Face = %u (0x%02x)", Face, Face); Log(" Item = %s", Desc.c_str()); - Log(" Cursor = <%d, %d, %d>", CursorX, CursorY, CursorZ); + Log(" Cursor = <%u, %u, %u>", CursorX, CursorY, CursorZ); COPY_TO_SERVER(); return true; } @@ -926,9 +931,9 @@ bool cConnection::HandleClientChatMessage(void) bool cConnection::HandleClientClientStatuses(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Statuses); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, Statuses); Log("Received a PACKET_CLIENT_STATUSES from the CLIENT:"); - Log(" Statuses = %d", Statuses); + Log(" Statuses = %u (0x%02x)", Statuses, Statuses); COPY_TO_SERVER(); return true; @@ -940,14 +945,14 @@ bool cConnection::HandleClientClientStatuses(void) bool cConnection::HandleClientCreativeInventoryAction(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, SlotNum); AString Item; if (!ParseSlot(m_ClientBuffer, Item)) { return false; } Log("Received a PACKET_CREATIVE_INVENTORY_ACTION from the client:"); - Log(" SlotNum = %d", SlotNum); + Log(" SlotNum = %u", SlotNum); Log(" Item = %s", Item.c_str()); COPY_TO_SERVER(); return true; @@ -972,12 +977,12 @@ bool cConnection::HandleClientDisconnect(void) bool cConnection::HandleClientEntityAction(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID); - HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, ActionType); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, HorseJumpBoost); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, PlayerID); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, ActionType); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, HorseJumpBoost); Log("Received a PACKET_ENTITY_ACTION from the client:"); Log(" PlayerID = %d", PlayerID); - Log(" ActionType = %d", ActionType); + Log(" ActionType = %u", ActionType); Log(" HorseJumpBoost = %d (0x%08x)", HorseJumpBoost, HorseJumpBoost); COPY_TO_SERVER(); return true; @@ -989,7 +994,7 @@ bool cConnection::HandleClientEntityAction(void) bool cConnection::HandleClientKeepAlive(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, ID); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, ID); Log("Received a PACKET_KEEPALIVE from the client"); COPY_TO_SERVER(); return true; @@ -1002,11 +1007,11 @@ bool cConnection::HandleClientKeepAlive(void) bool cConnection::HandleClientLocaleAndView(void) { HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Locale); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, ViewDistance); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, ChatFlags); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Unused); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, ShowCape); + HANDLE_CLIENT_PACKET_READ(ReadBEInt8, Int8, ViewDistance); + HANDLE_CLIENT_PACKET_READ(ReadBEInt8, Int8, ChatFlags); + HANDLE_CLIENT_PACKET_READ(ReadBEInt8, Int8, Unused); + HANDLE_CLIENT_PACKET_READ(ReadBEInt8, Int8, Difficulty); + HANDLE_CLIENT_PACKET_READ(ReadBEInt8, Int8, ShowCape); Log("Received a PACKET_LOCALE_AND_VIEW from the client"); COPY_TO_SERVER(); return true; @@ -1031,11 +1036,11 @@ bool cConnection::HandleClientPing(void) bool cConnection::HandleClientPlayerAbilities(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Flags); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, Flags); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, FlyingSpeed); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, WalkingSpeed); Log("Receives a PACKET_PLAYER_ABILITIES from the client:"); - Log(" Flags = %d (0x%02x)", Flags, Flags); + Log(" Flags = %u (0x%02x)", Flags, Flags); Log(" FlyingSpeed = %f", FlyingSpeed); Log(" WalkingSpeed = %f", WalkingSpeed); COPY_TO_SERVER(); @@ -1050,7 +1055,7 @@ bool cConnection::HandleClientPlayerLook(void) { HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Yaw); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Pitch); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, OnGround); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, OnGround); Log("Received a PACKET_PLAYER_LOOK from the client"); COPY_TO_SERVER(); return true; @@ -1062,7 +1067,7 @@ bool cConnection::HandleClientPlayerLook(void) bool cConnection::HandleClientPlayerOnGround(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, OnGround); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, OnGround); Log("Received a PACKET_PLAYER_ON_GROUND from the client"); COPY_TO_SERVER(); return true; @@ -1078,7 +1083,7 @@ bool cConnection::HandleClientPlayerPosition(void) HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosY); HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance); HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosZ); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsOnGround); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, IsOnGround); Log("Received a PACKET_PLAYER_POSITION from the client"); // TODO: list packet contents @@ -1099,7 +1104,7 @@ bool cConnection::HandleClientPlayerPositionLook(void) HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosZ); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Yaw); HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Pitch); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsOnGround); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, IsOnGround); Log("Received a PACKET_PLAYER_POSITION_LOOK from the client"); Log(" Pos = {%.03f, %.03f, %.03f}", PosX, PosY, PosZ); Log(" Stance = %.03f", Stance); @@ -1117,7 +1122,7 @@ bool cConnection::HandleClientPlayerPositionLook(void) bool cConnection::HandleClientPluginMessage(void) { HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ChannelName); - HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, Length); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, Length); AString Data; if (!m_ClientBuffer.ReadString(Data, Length)) { @@ -1136,7 +1141,7 @@ bool cConnection::HandleClientPluginMessage(void) bool cConnection::HandleClientSlotSelect(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_CLIENT_PACKET_READ(ReadBEInt16, Int16, SlotNum); Log("Received a PACKET_SLOT_SELECT from the client"); Log(" SlotNum = %d", SlotNum); COPY_TO_SERVER(); @@ -1186,9 +1191,9 @@ bool cConnection::HandleClientTabCompletion(void) bool cConnection::HandleClientUpdateSign(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_CLIENT_PACKET_READ(ReadBEInt16, Int16, BlockY); + HANDLE_CLIENT_PACKET_READ(ReadBEInt32, Int32, BlockZ); HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line1); HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line2); HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line3); @@ -1206,11 +1211,11 @@ bool cConnection::HandleClientUpdateSign(void) bool cConnection::HandleClientUseEntity(void) { - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, MouseButton); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, MouseButton); Log("Received a PACKET_USE_ENTITY from the client:"); Log(" EntityID = %d", EntityID); - Log(" MouseButton = %d", MouseButton); + Log(" MouseButton = %u", MouseButton); COPY_TO_SERVER(); return true; } @@ -1221,20 +1226,20 @@ bool cConnection::HandleClientUseEntity(void) bool cConnection::HandleClientWindowClick(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, WindowID); - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, SlotNum); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Button); - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, TransactionID); - HANDLE_CLIENT_PACKET_READ(ReadChar, char, Mode); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, WindowID); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, SlotNum); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, Button); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, TransactionID); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, Mode); AString Item; if (!ParseSlot(m_ClientBuffer, Item)) { return false; } Log("Received a PACKET_WINDOW_CLICK from the client"); - Log(" WindowID = %d", WindowID); - Log(" SlotNum = %d", SlotNum); - Log(" Button = %d, Mode = %d", Button, Mode); + Log(" WindowID = %u", WindowID); + Log(" SlotNum = %u", SlotNum); + Log(" Button = %u, Mode = %u", Button, Mode); Log(" TransactionID = 0x%x", TransactionID); Log(" ClickedItem = %s", Item.c_str()); COPY_TO_SERVER(); @@ -1247,9 +1252,9 @@ bool cConnection::HandleClientWindowClick(void) bool cConnection::HandleClientWindowClose(void) { - HANDLE_CLIENT_PACKET_READ(ReadChar, char, WindowID); + HANDLE_CLIENT_PACKET_READ(ReadBEUInt8, UInt8, WindowID); Log("Received a PACKET_WINDOW_CLOSE from the client:"); - Log(" WindowID = %d", WindowID); + Log(" WindowID = %u", WindowID); COPY_TO_SERVER(); return true; } @@ -1355,13 +1360,13 @@ bool cConnection::HandleServerLoginSuccess(void) bool cConnection::HandleServerAttachEntity(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, VehicleID); - HANDLE_SERVER_PACKET_READ(ReadBool, bool, Leash); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, VehicleID); + HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsOnLeash); Log("Received a PACKET_ATTACH_ENTITY from the server:"); - Log(" EntityID = %d (0x%x)", EntityID, EntityID); - Log(" VehicleID = %d (0x%x)", VehicleID, VehicleID); - Log(" Leash = %s", Leash ? "true" : "false"); + Log(" EntityID = %u (0x%x)", EntityID, EntityID); + Log(" VehicleID = %u (0x%x)", VehicleID, VehicleID); + Log(" IsOnLeash = %s", IsOnLeash ? "true" : "false"); COPY_TO_CLIENT(); return true; } @@ -1372,15 +1377,15 @@ bool cConnection::HandleServerAttachEntity(void) bool cConnection::HandleServerBlockAction(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte1); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte2); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, BlockY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Byte1); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Byte2); HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockID); Log("Received a PACKET_BLOCK_ACTION from the server:"); Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ); - Log(" Bytes = (%d, %d) == (0x%x, 0x%x)", Byte1, Byte2, Byte1, Byte2); + Log(" Bytes = (%u, %u) == (0x%x, 0x%x)", Byte1, Byte2, Byte1, Byte2); Log(" BlockID = %u", BlockID); COPY_TO_CLIENT(); return true; @@ -1392,15 +1397,15 @@ bool cConnection::HandleServerBlockAction(void) bool cConnection::HandleServerBlockChange(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, BlockY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockZ); HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockType); - HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, BlockMeta); Log("Received a PACKET_BLOCK_CHANGE from the server"); - Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ); - Log(" BlockType = %d (0x%x", BlockType, BlockType); - Log(" BlockMeta = %d", BlockMeta); + Log(" Pos = {%d, %u, %d}", BlockX, BlockY, BlockZ); + Log(" BlockType = %u (0x%x", BlockType, BlockType); + Log(" BlockMeta = %u", BlockMeta); COPY_TO_CLIENT(); return true; } @@ -1411,10 +1416,10 @@ bool cConnection::HandleServerBlockChange(void) bool cConnection::HandleServerChangeGameState(void) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, Reason); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Reason); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Data); Log("Received a PACKET_CHANGE_GAME_STATE from the server:"); - Log(" Reason = %d", Reason); + Log(" Reason = %u", Reason); Log(" Data = %f", Data); COPY_TO_CLIENT(); return true; @@ -1439,11 +1444,11 @@ bool cConnection::HandleServerChatMessage(void) bool cConnection::HandleServerCollectPickup(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, CollectedID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, CollectorID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CollectedID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CollectorID); Log("Received a PACKET_COLLECT_PICKUP from the server:"); - Log(" CollectedID = %d", CollectedID); - Log(" CollectorID = %d", CollectorID); + Log(" CollectedID = %u", CollectedID); + Log(" CollectorID = %u", CollectorID); COPY_TO_CLIENT(); return true; } @@ -1454,9 +1459,9 @@ bool cConnection::HandleServerCollectPickup(void) bool cConnection::HandleServerCompass(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, SpawnX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, SpawnY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, SpawnZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, SpawnX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, SpawnY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, SpawnZ); Log("Received PACKET_COMPASS from the server:"); Log(" Spawn = {%d, %d, %d}", SpawnX, SpawnY, SpawnZ); COPY_TO_CLIENT(); @@ -1469,7 +1474,7 @@ bool cConnection::HandleServerCompass(void) bool cConnection::HandleServerDestroyEntities(void) { - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NumEntities); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, NumEntities); if (!m_ServerBuffer.SkipRead(static_cast<size_t>(NumEntities) * 4)) { return false; @@ -1486,9 +1491,9 @@ bool cConnection::HandleServerDestroyEntities(void) bool cConnection::HandleServerEntity(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); Log("Received a PACKET_ENTITY from the server:"); - Log(" EntityID = %d", EntityID); + Log(" EntityID = %u", EntityID); COPY_TO_CLIENT(); return true; } @@ -1499,16 +1504,16 @@ bool cConnection::HandleServerEntity(void) bool cConnection::HandleServerEntityEquipment(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, SlotNum); AString Item; if (!ParseSlot(m_ServerBuffer, Item)) { return false; } Log("Received a PACKET_ENTITY_EQUIPMENT from the server:"); - Log(" EntityID = %d", EntityID); - Log(" SlotNum = %d", SlotNum); + Log(" EntityID = %u", EntityID); + Log(" SlotNum = %u", SlotNum); Log(" Item = %s", Item.c_str()); COPY_TO_CLIENT(); return true; @@ -1520,11 +1525,11 @@ bool cConnection::HandleServerEntityEquipment(void) bool cConnection::HandleServerEntityHeadLook(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, HeadYaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, HeadYaw); Log("Received a PACKET_ENTITY_HEAD_LOOK from the server:"); - Log(" EntityID = %d", EntityID); - Log(" HeadYaw = %d", HeadYaw); + Log(" EntityID = %u", EntityID); + Log(" HeadYaw = %u", HeadYaw); COPY_TO_CLIENT(); return true; } @@ -1535,13 +1540,13 @@ bool cConnection::HandleServerEntityHeadLook(void) bool cConnection::HandleServerEntityLook(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); Log("Received a PACKET_ENTITY_LOOK from the server:"); - Log(" EntityID = %d", EntityID); - Log(" Yaw = %d", Yaw); - Log(" Pitch = %d", Pitch); + Log(" EntityID = %u", EntityID); + Log(" Yaw = %u", Yaw); + Log(" Pitch = %u", Pitch); COPY_TO_CLIENT(); return true; } @@ -1552,7 +1557,7 @@ bool cConnection::HandleServerEntityLook(void) bool cConnection::HandleServerEntityMetadata(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); AString Metadata; if (!ParseMetadata(m_ServerBuffer, Metadata)) { @@ -1561,8 +1566,9 @@ bool cConnection::HandleServerEntityMetadata(void) AString HexDump; CreateHexDump(HexDump, Metadata.data(), Metadata.size(), 32); Log("Received a PACKET_ENTITY_METADATA from the server:"); - Log(" EntityID = %d", EntityID); - Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str()); + Log(" EntityID = %u", EntityID); + auto len = static_cast<unsigned>(Metadata.length()); + Log(" Metadata, length = %u (0x%x):\n%s", len, len, HexDump.c_str()); LogMetadata(Metadata, 4); COPY_TO_CLIENT(); return true; @@ -1574,24 +1580,24 @@ bool cConnection::HandleServerEntityMetadata(void) bool cConnection::HandleServerEntityProperties(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Count); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, Count); Log("Received a PACKET_ENTITY_PROPERTIES from the server:"); - Log(" EntityID = %d", EntityID); - Log(" Count = %d", Count); + Log(" EntityID = %u", EntityID); + Log(" Count = %u", Count); - for (int i = 0; i < Count; i++) + for (UInt32 i = 0; i < Count; i++) { HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Key); HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Value); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ListLength); - Log(" \"%s\" = %f; %d modifiers", Key.c_str(), Value, ListLength); - for (short j = 0; j < ListLength; j++) + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, ListLength); + Log(" \"%s\" = %f; %u modifiers", Key.c_str(), Value, ListLength); + for (UInt16 j = 0; j < ListLength; j++) { - HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDHi); - HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDLo); + HANDLE_SERVER_PACKET_READ(ReadBEUInt64, UInt64, UUIDHi); + HANDLE_SERVER_PACKET_READ(ReadBEUInt64, UInt64, UUIDLo); HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, DblVal); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ByteVal); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, ByteVal); Log(" [%d] = {0x%08llx%08llx, %f, %u}", j, UUIDHi, UUIDLo, DblVal, ByteVal); } } // for i @@ -1605,12 +1611,12 @@ bool cConnection::HandleServerEntityProperties(void) bool cConnection::HandleServerEntityRelativeMove(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dx); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dy); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dz); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, dx); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, dy); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, dz); Log("Received a PACKET_ENTITY_RELATIVE_MOVE from the server:"); - Log(" EntityID = %d", EntityID); + Log(" EntityID = %u", EntityID); Log(" RelMove = %s", PrintableAbsIntTriplet(dx, dy, dz).c_str()); COPY_TO_CLIENT(); return true; @@ -1622,17 +1628,17 @@ bool cConnection::HandleServerEntityRelativeMove(void) bool cConnection::HandleServerEntityRelativeMoveLook(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dx); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dy); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dz); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, dx); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, dy); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, dz); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); Log("Received a PACKET_ENTITY_RELATIVE_MOVE_LOOK from the server:"); - Log(" EntityID = %d", EntityID); + Log(" EntityID = %u", EntityID); Log(" RelMove = %s", PrintableAbsIntTriplet(dx, dy, dz).c_str()); - Log(" Yaw = %d", Yaw); - Log(" Pitch = %d", Pitch); + Log(" Yaw = %u", Yaw); + Log(" Pitch = %u", Pitch); COPY_TO_CLIENT(); return true; } @@ -1643,11 +1649,11 @@ bool cConnection::HandleServerEntityRelativeMoveLook(void) bool cConnection::HandleServerEntityStatus(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Status); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Status); Log("Received a PACKET_ENTITY_STATUS from the server:"); - Log(" EntityID = %d", EntityID); - Log(" Status = %d", Status); + Log(" EntityID = %u", EntityID); + Log(" Status = %u (0x%02x)", Status, Status); COPY_TO_CLIENT(); return true; } @@ -1658,17 +1664,17 @@ bool cConnection::HandleServerEntityStatus(void) bool cConnection::HandleServerEntityTeleport(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, AbsX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, AbsY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, AbsZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); Log("Received a PACKET_ENTITY_TELEPORT from the server:"); - Log(" EntityID = %d", EntityID); + Log(" EntityID = %u", EntityID); Log(" Pos = %s", PrintableAbsIntTriplet(AbsX, AbsY, AbsZ).c_str()); - Log(" Yaw = %d", Yaw); - Log(" Pitch = %d", Pitch); + Log(" Yaw = %u", Yaw); + Log(" Pitch = %u", Pitch); COPY_TO_CLIENT(); return true; } @@ -1679,12 +1685,12 @@ bool cConnection::HandleServerEntityTeleport(void) bool cConnection::HandleServerEntityVelocity(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityY); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, VelocityX); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, VelocityY); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, VelocityZ); Log("Received a PACKET_ENTITY_VELOCITY from the server:"); - Log(" EntityID = %d", EntityID); + Log(" EntityID = %u", EntityID); Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str()); COPY_TO_CLIENT(); return true; @@ -1703,12 +1709,12 @@ bool cConnection::HandleServerExplosion(void) HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, NumRecords); std::vector<sCoords> Records; Records.reserve(NumRecords); - int PosXI = (int)PosX, PosYI = (int)PosY, PosZI = (int)PosZ; + int PosXI = static_cast<int>(PosX), PosYI = static_cast<int>(PosY), PosZI = static_cast<int>(PosZ); for (UInt32 i = 0; i < NumRecords; i++) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, rx); - HANDLE_SERVER_PACKET_READ(ReadChar, char, ry); - HANDLE_SERVER_PACKET_READ(ReadChar, char, rz); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, rx); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, ry); + HANDLE_SERVER_PACKET_READ(ReadBEInt8, Int8, rz); Records.push_back(sCoords(PosXI + rx, PosYI + ry, PosZI + rz)); } HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PlayerMotionX); @@ -1734,10 +1740,10 @@ bool cConnection::HandleServerExplosion(void) bool cConnection::HandleServerIncrementStatistic(void) { // 0xc8 - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, StatisticID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Amount); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, StatisticID); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, Amount); Log("Received a PACKET_INCREMENT_STATISTIC from the server:"); - Log(" StatisticID = %d (0x%x)", StatisticID, StatisticID); + Log(" StatisticID = %u (0x%x)", StatisticID, StatisticID); Log(" Amount = %d", Amount); COPY_TO_CLIENT(); return true; @@ -1749,18 +1755,18 @@ bool cConnection::HandleServerIncrementStatistic(void) bool cConnection::HandleServerJoinGame(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode); - HANDLE_SERVER_PACKET_READ(ReadChar, char, Dimension); - HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_SERVER_PACKET_READ(ReadChar, char, MaxPlayers); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, GameMode); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Dimension); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Difficulty); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, MaxPlayers); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, LevelType); Log("Received a PACKET_LOGIN from the server:"); - Log(" EntityID = %d", EntityID); - Log(" GameMode = %d", GameMode); - Log(" Dimension = %d", Dimension); - Log(" Difficulty = %d", Difficulty); - Log(" MaxPlayers = %d", MaxPlayers); + Log(" EntityID = %u", EntityID); + Log(" GameMode = %u", GameMode); + Log(" Dimension = %u", Dimension); + Log(" Difficulty = %u", Difficulty); + Log(" MaxPlayers = %u", MaxPlayers); Log(" LevelType = \"%s\"", LevelType.c_str()); COPY_TO_CLIENT(); return true; @@ -1772,9 +1778,9 @@ bool cConnection::HandleServerJoinGame(void) bool cConnection::HandleServerKeepAlive(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PingID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, PingID); Log("Received a PACKET_KEEP_ALIVE from the server:"); - Log(" ID = %d", PingID); + Log(" ID = %u", PingID); COPY_TO_CLIENT() return true; } @@ -1856,11 +1862,11 @@ bool cConnection::HandleServerKick(void) bool cConnection::HandleServerMapChunk(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ); - HANDLE_SERVER_PACKET_READ(ReadChar, char, IsContiguous); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AdditionalBitmap); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, ChunkX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, ChunkZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, IsContiguous); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, PrimaryBitmap); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, AdditionalBitmap); HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CompressedSize); AString CompressedData; if (!m_ServerBuffer.ReadString(CompressedData, CompressedSize)) @@ -1899,10 +1905,10 @@ bool cConnection::HandleServerMapChunkBulk(void) ChunkMetas.reserve(ChunkCount); for (short i = 0; i < ChunkCount; i++) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AddBitmap); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, ChunkX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, ChunkZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, PrimaryBitmap); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, AddBitmap); ChunkMetas.push_back(sChunkMeta(ChunkX, ChunkZ, PrimaryBitmap, AddBitmap)); } @@ -1932,8 +1938,8 @@ bool cConnection::HandleServerMapChunkBulk(void) bool cConnection::HandleServerMultiBlockChange(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, ChunkX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, ChunkZ); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, NumBlocks); HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, DataSize); AString BlockChangeData; @@ -1955,16 +1961,16 @@ bool cConnection::HandleServerMultiBlockChange(void) bool cConnection::HandleServerNamedSoundEffect(void) { HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, SoundName); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Volume); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); Log("Received a PACKET_NAMED_SOUND_EFFECT from the server:"); Log(" SoundName = \"%s\"", SoundName.c_str()); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ, 8).c_str()); Log(" Volume = %f", Volume); - Log(" Pitch = %d", Pitch); + Log(" Pitch = %u", Pitch); COPY_TO_CLIENT(); return true; } @@ -1975,11 +1981,11 @@ bool cConnection::HandleServerNamedSoundEffect(void) bool cConnection::HandleServerPlayerAbilities(void) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, Flags); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Flags); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, FlyingSpeed); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, WalkingSpeed); Log("Received a PACKET_PLAYER_ABILITIES from the server:"); - Log(" Flags = %d (0x%02x)", Flags, Flags); + Log(" Flags = %u (0x%02x)", Flags, Flags); Log(" FlyingSpeed = %f", FlyingSpeed); Log(" WalkingSpeed = %f", WalkingSpeed); COPY_TO_CLIENT(); @@ -1992,11 +1998,11 @@ bool cConnection::HandleServerPlayerAbilities(void) bool cConnection::HandleServerPlayerAnimation(void) { - HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, PlayerID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, AnimationID); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, PlayerID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, AnimationID); Log("Received a PACKET_PLAYER_ANIMATION from the server:"); Log(" PlayerID: %u (0x%x)", PlayerID, PlayerID); - Log(" Animation: %d", AnimationID); + Log(" Animation: %u", AnimationID); COPY_TO_CLIENT(); return true; } @@ -2008,10 +2014,10 @@ bool cConnection::HandleServerPlayerAnimation(void) bool cConnection::HandleServerPlayerListItem(void) { HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, PlayerName); - HANDLE_SERVER_PACKET_READ(ReadChar, char, IsOnline); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Ping); + HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsOnline); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, Ping); Log("Received a PACKET_PLAYERLIST_ITEM from the server:"); - Log(" PlayerName = \"%s\"", PlayerName.c_str()); + Log(" PlayerName = \"%s\" (%s)", PlayerName.c_str(), IsOnline ? "online" : "offline"); Log(" Ping = %d", Ping); COPY_TO_CLIENT(); return true; @@ -2028,7 +2034,7 @@ bool cConnection::HandleServerPlayerPositionLook(void) HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosZ); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Yaw); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Pitch); - HANDLE_SERVER_PACKET_READ(ReadChar, char, IsOnGround); + HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsOnGround); Log("Received a PACKET_PLAYER_POSITION_LOOK from the server"); // TODO: list packet contents @@ -2063,14 +2069,14 @@ bool cConnection::HandleServerPluginMessage(void) bool cConnection::HandleServerRespawn(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Dimension); - HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty); - HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, Dimension); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Difficulty); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, GameMode); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, LevelType); Log("Received a respawn packet from the server:"); Log(" Dimension = %d", Dimension); - Log(" Difficulty = %d", Difficulty); - Log(" GameMode = %d", GameMode); + Log(" Difficulty = %u", Difficulty); + Log(" GameMode = %u", GameMode); Log(" LevelType = \"%s\"", LevelType.c_str()); COPY_TO_CLIENT(); return true; @@ -2082,13 +2088,13 @@ bool cConnection::HandleServerRespawn(void) bool cConnection::HandleServerSetExperience(void) { - HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, ExperienceBar); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Level); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, TotalExperience); + HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, ExperienceBar); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, Level); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, TotalExperience); Log("Received a PACKET_SET_EXPERIENCE from the server:"); Log(" ExperienceBar = %.05f", ExperienceBar); - Log(" Level = %d", Level); - Log(" TotalExperience = %d", TotalExperience); + Log(" Level = %u", Level); + Log(" TotalExperience = %u", TotalExperience); COPY_TO_CLIENT(); return true; } @@ -2099,16 +2105,16 @@ bool cConnection::HandleServerSetExperience(void) bool cConnection::HandleServerSetSlot(void) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowID); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, WindowID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, SlotNum); AString Item; if (!ParseSlot(m_ServerBuffer, Item)) { return false; } Log("Received a PACKET_SET_SLOT from the server:"); - Log(" WindowID = %d", WindowID); - Log(" SlotNum = %d", SlotNum); + Log(" WindowID = %u", WindowID); + Log(" SlotNum = %u", SlotNum); Log(" Item = %s", Item.c_str()); COPY_TO_CLIENT(); return true; @@ -2120,9 +2126,9 @@ bool cConnection::HandleServerSetSlot(void) bool cConnection::HandleServerSlotSelect(void) { - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, SlotNum); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, SlotNum); Log("Received a PACKET_SLOT_SELECT from the server:"); - Log(" SlotNum = %d", SlotNum); + Log(" SlotNum = %u", SlotNum); COPY_TO_CLIENT(); return true; } @@ -2133,17 +2139,17 @@ bool cConnection::HandleServerSlotSelect(void) bool cConnection::HandleServerSoundEffect(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EffectID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Data); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NoVolumeDecrease); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, EffectID); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, Data); + HANDLE_SERVER_PACKET_READ(ReadBool, bool, NoVolumeDecrease); Log("Received a PACKET_SOUND_EFFECT from the server:"); Log(" EffectID = %d", EffectID); Log(" Pos = {%d, %d, %d}", PosX, PosY, PosZ); Log(" Data = %d", Data); - Log(" NoVolumeDecrease = %d", NoVolumeDecrease); + Log(" NoVolumeDecrease = %s", NoVolumeDecrease ? "true" : "false"); COPY_TO_CLIENT(); return true; } @@ -2154,15 +2160,15 @@ bool cConnection::HandleServerSoundEffect(void) bool cConnection::HandleServerSpawnExperienceOrbs(void) { - HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Count); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, Count); Log("Received a SPAWN_EXPERIENCE_ORBS packet from the server:"); Log(" EntityID = %u (0x%x)", EntityID, EntityID); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); - Log(" Count = %d", Count); + Log(" Count = %u", Count); COPY_TO_CLIENT(); return true; } @@ -2174,16 +2180,16 @@ bool cConnection::HandleServerSpawnExperienceOrbs(void) bool cConnection::HandleServerSpawnMob(void) { HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); - HANDLE_SERVER_PACKET_READ(ReadChar, char, MobType); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, HeadYaw); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityY); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, MobType); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, HeadYaw); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, VelocityX); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, VelocityY); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, VelocityZ); AString Metadata; if (!ParseMetadata(m_ServerBuffer, Metadata)) { @@ -2193,11 +2199,12 @@ bool cConnection::HandleServerSpawnMob(void) CreateHexDump(HexDump, Metadata.data(), Metadata.size(), 32); Log("Received a PACKET_SPAWN_MOB from the server:"); Log(" EntityID = %u (0x%x)", EntityID, EntityID); - Log(" MobType = %d", MobType); + Log(" MobType = %u (0x%x)", MobType, MobType); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); - Log(" Angles = [%d, %d, %d]", Yaw, Pitch, HeadYaw); + Log(" Angles = [%u, %u, %u]", Yaw, Pitch, HeadYaw); Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str()); - Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str()); + auto len = static_cast<unsigned>(Metadata.length()); + Log(" Metadata, length = %u (0x%x):\n%s", len, len, HexDump.c_str()); LogMetadata(Metadata, 4); COPY_TO_CLIENT(); return true; @@ -2240,12 +2247,12 @@ bool cConnection::HandleServerSpawnNamedEntity(void) HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Signature) Data.push_back(sSpawnData(Name, Value, Signature)); } - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, CurrentItem); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, SelectedItem); AString Metadata; if (!ParseMetadata(m_ServerBuffer, Metadata)) { @@ -2265,9 +2272,10 @@ bool cConnection::HandleServerSpawnNamedEntity(void) ); } // for itr - Data[] Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); - Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); - Log(" CurrentItem = %d", CurrentItem); - Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str()); + Log(" Rotation = <yaw %u, pitch %u>", Yaw, Pitch); + Log(" SelectedItem = %u", SelectedItem); + auto len = static_cast<unsigned>(Metadata.length()); + Log(" Metadata, length = %u (0x%x):\n%s", len, len, HexDump.c_str()); LogMetadata(Metadata, 4); COPY_TO_CLIENT(); return true; @@ -2294,26 +2302,26 @@ bool cConnection::HandleServerSpawnObjectVehicle(void) // Only log up to 128 bytes Buffer.erase(128, AString::npos); } - DataLog(Buffer.data(), Buffer.size(), "Buffer while parsing the PACKET_SPAWN_OBJECT_VEHICLE packet (%d bytes):", Buffer.size()); + DataLog(Buffer.data(), Buffer.size(), "Buffer while parsing the PACKET_SPAWN_OBJECT_VEHICLE packet (%u bytes):", static_cast<unsigned>(Buffer.size())); #endif // _DEBUG - HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ObjType); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, ObjType); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, DataIndicator); AString ExtraData; - short VelocityX = 0; - short VelocityY = 0; - short VelocityZ = 0; + Int16 VelocityX = 0; + Int16 VelocityY = 0; + Int16 VelocityZ = 0; if (DataIndicator != 0) { - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SpeedX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SpeedY); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SpeedZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, SpeedX); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, SpeedY); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, SpeedZ); VelocityX = SpeedX; VelocityY = SpeedY; VelocityZ = SpeedZ; // Speed vars are local to this scope, but we need them available later /* // This doesn't seem to work - for a falling block I'm getting no extra data at all @@ -2340,14 +2348,14 @@ bool cConnection::HandleServerSpawnObjectVehicle(void) } Log("Received a PACKET_SPAWN_OBJECT_VEHICLE from the server:"); Log(" EntityID = %u (0x%x)", EntityID, EntityID); - Log(" ObjType = %d (0x%x)", ObjType, ObjType); + Log(" ObjType = %u (0x%x)", ObjType, ObjType); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); - Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); - Log(" DataIndicator = %d (0x%x)", DataIndicator, DataIndicator); + Log(" Rotation = <yaw %u, pitch %u>", Yaw, Pitch); + Log(" DataIndicator = %u (0x%x)", DataIndicator, DataIndicator); if (DataIndicator != 0) { Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str()); - DataLog(ExtraData.data(), ExtraData.size(), " ExtraData size = %d:", ExtraData.size()); + DataLog(ExtraData.data(), ExtraData.size(), " ExtraData size = %u:", static_cast<unsigned>(ExtraData.size())); } COPY_TO_CLIENT(); return true; @@ -2361,10 +2369,10 @@ bool cConnection::HandleServerSpawnPainting(void) { HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ImageName); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Direction); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, Direction); Log("Received a PACKET_SPAWN_PAINTING from the server:"); Log(" EntityID = %u", EntityID); Log(" ImageName = \"%s\"", ImageName.c_str()); @@ -2380,23 +2388,23 @@ bool cConnection::HandleServerSpawnPainting(void) bool cConnection::HandleServerSpawnPickup(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); AString ItemDesc; if (!ParseSlot(m_ServerBuffer, ItemDesc)) { return false; } - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Rotation); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Roll); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosX); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, PosZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Yaw); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Pitch); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Roll); Log("Received a PACKET_SPAWN_PICKUP from the server:"); Log(" EntityID = %d", EntityID); Log(" Item = %s", ItemDesc.c_str()); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); - Log(" Angles = [%d, %d, %d]", Rotation, Pitch, Roll); + Log(" Angles = [%u, %u, %u]", Yaw, Pitch, Roll); COPY_TO_CLIENT(); return true; } @@ -2446,8 +2454,12 @@ bool cConnection::HandleServerStatusResponse(void) { Response.assign(Response.substr(0, idx + sizeof(DescSearch) - 1) + "ProtoProxy: " + Response.substr(idx + sizeof(DescSearch) - 1)); } + else + { + Log("Cannot find the description json element, ProtoProxy signature not inserted"); + } cByteBuffer Packet(Response.size() + 50); - Packet.WriteVarInt(0); // Packet type - status response + Packet.WriteVarInt32(0); // Packet type - status response Packet.WriteVarUTF8String(Response); AString Pkt; Packet.ReadAll(Pkt); @@ -2492,8 +2504,8 @@ bool cConnection::HandleServerTabCompletion(void) bool cConnection::HandleServerTimeUpdate(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, WorldAge); - HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, TimeOfDay); + HANDLE_SERVER_PACKET_READ(ReadBEUInt64, UInt64, WorldAge); + HANDLE_SERVER_PACKET_READ(ReadBEUInt64, UInt64, TimeOfDay); Log("Received a PACKET_TIME_UPDATE from the server"); COPY_TO_CLIENT(); return true; @@ -2506,7 +2518,7 @@ bool cConnection::HandleServerTimeUpdate(void) bool cConnection::HandleServerUpdateHealth(void) { HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Health); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Food); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, Food); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Saturation); Log("Received a PACKET_UPDATE_HEALTH from the server"); COPY_TO_CLIENT(); @@ -2519,9 +2531,9 @@ bool cConnection::HandleServerUpdateHealth(void) bool cConnection::HandleServerUpdateSign(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, BlockY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockZ); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line1); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line2); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line3); @@ -2539,10 +2551,10 @@ bool cConnection::HandleServerUpdateSign(void) bool cConnection::HandleServerUpdateTileEntity(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Action); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockX); + HANDLE_SERVER_PACKET_READ(ReadBEInt16, Int16, BlockY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, Action); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, DataLength); AString Data; @@ -2552,8 +2564,8 @@ bool cConnection::HandleServerUpdateTileEntity(void) } Log("Received a PACKET_UPDATE_TILE_ENTITY from the server:"); Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ); - Log(" Action = %d", Action); - DataLog(Data.data(), Data.size(), " Data (%u bytes)", Data.size()); + Log(" Action = %u", Action); + DataLog(Data.data(), Data.size(), " Data (%u bytes)", DataLength); // Save metadata to a file: AString fnam; @@ -2576,13 +2588,13 @@ bool cConnection::HandleServerUpdateTileEntity(void) bool cConnection::HandleServerUseBed(void) { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BedX); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BedY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BedZ); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, EntityID); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BedX); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, BedY); + HANDLE_SERVER_PACKET_READ(ReadBEInt32, Int32, BedZ); Log("Received a use bed packet from the server:"); - Log(" EntityID = %d", EntityID); - Log(" Bed = {%d, %d, %d}", BedX, BedY, BedZ); + Log(" EntityID = %u", EntityID); + Log(" Bed = {%d, %u, %d}", BedX, BedY, BedZ); COPY_TO_CLIENT(); return true; } @@ -2593,9 +2605,9 @@ bool cConnection::HandleServerUseBed(void) bool cConnection::HandleServerWindowClose(void) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, WindowID); Log("Received a PACKET_WINDOW_CLOSE from the server:"); - Log(" WindowID = %d", WindowID); + Log(" WindowID = %u", WindowID); COPY_TO_CLIENT(); return true; } @@ -2606,20 +2618,20 @@ bool cConnection::HandleServerWindowClose(void) bool cConnection::HandleServerWindowContents(void) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowID); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NumSlots); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, WindowID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, NumSlots); Log("Received a PACKET_WINDOW_CONTENTS from the server:"); - Log(" WindowID = %d", WindowID); - Log(" NumSlots = %d", NumSlots); + Log(" WindowID = %u", WindowID); + Log(" NumSlots = %u", NumSlots); AStringVector Items; - for (short i = 0; i < NumSlots; i++) + for (UInt16 i = 0; i < NumSlots; i++) { AString Item; if (!ParseSlot(m_ServerBuffer, Item)) { return false; } - Log(" %d: %s", i, Item.c_str()); + Log(" %u: %s", i, Item.c_str()); } COPY_TO_CLIENT(); @@ -2632,25 +2644,25 @@ bool cConnection::HandleServerWindowContents(void) bool cConnection::HandleServerWindowOpen(void) { - HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowID); - HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowType); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, WindowID); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, WindowType); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Title); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NumSlots); - HANDLE_SERVER_PACKET_READ(ReadByte, Byte, UseProvidedTitle); - int HorseEntityID = 0; + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, NumSlots); + HANDLE_SERVER_PACKET_READ(ReadBEUInt8, UInt8, UseProvidedTitle); + UInt32 HorseEntityID = 0; if (WindowType == 11) // Horse / Donkey / Mule { - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, intHorseInt); + HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, intHorseInt); HorseEntityID = intHorseInt; } Log("Received a PACKET_WINDOW_OPEN from the server:"); - Log(" WindowID = %d", WindowID); - Log(" WindowType = %d", WindowType); - Log(" Title = \"%s\", Use = %d", Title.c_str(), UseProvidedTitle); - Log(" NumSlots = %d", NumSlots); + Log(" WindowID = %u", WindowID); + Log(" WindowType = %u (0x%02x)", WindowType, WindowType); + Log(" Title = \"%s\", Use = %u", Title.c_str(), UseProvidedTitle); + Log(" NumSlots = %u", NumSlots); if (WindowType == 11) { - Log(" HorseEntityID = %d (0x%08x)", HorseEntityID, HorseEntityID); + Log(" HorseEntityID = %u (0x%08x)", HorseEntityID, HorseEntityID); } COPY_TO_CLIENT(); return true; @@ -2680,7 +2692,7 @@ bool cConnection::HandleServerUnknownPacket(UInt32 a_PacketType, UInt32 a_Packet bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc) { short ItemType; - if (!a_Buffer.ReadBEShort(ItemType)) + if (!a_Buffer.ReadBEInt16(ItemType)) { return false; } @@ -2693,11 +2705,11 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc) { return false; } - char ItemCount; - short ItemDamage; + Int8 ItemCount; + Int16 ItemDamage; UInt16 MetadataLength; - a_Buffer.ReadChar(ItemCount); // We already know we can read these bytes - we checked before. - a_Buffer.ReadBEShort(ItemDamage); + a_Buffer.ReadBEInt8(ItemCount); // We already know we can read these bytes - we checked before. + a_Buffer.ReadBEInt16(ItemDamage); a_Buffer.ReadBEUInt16(MetadataLength); Printf(a_ItemDesc, "%d:%d * %d", ItemType, ItemDamage, ItemCount); if (MetadataLength <= 0) @@ -2734,8 +2746,8 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc) bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata) { - Byte x; - if (!a_Buffer.ReadByte(x)) + UInt8 x; + if (!a_Buffer.ReadBEUInt8(x)) { return false; } @@ -2763,7 +2775,7 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata) } rs = rs - static_cast<int>(a_Buffer.GetReadableSpace()); cByteBuffer LenBuf(8); - LenBuf.WriteVarInt(Len); + LenBuf.WriteVarInt32(Len); AString VarLen; LenBuf.ReadAll(VarLen); a_Metadata.append(VarLen); @@ -2800,7 +2812,7 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata) return false; } a_Metadata.append(data); - if (!a_Buffer.ReadByte(x)) + if (!a_Buffer.ReadBEUInt8(x)) { return false; } @@ -2826,7 +2838,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount) { case 0: { - Log("%sbyte[%u] = %d", Indent.c_str(), Index, a_Metadata[pos + 1]); + Log("%sbyte[%u] = %u", Indent.c_str(), Index, static_cast<unsigned char>(a_Metadata[pos + 1])); pos += 1; break; } @@ -2940,15 +2952,15 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c // Send the packet to the server: Log("Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER"); cByteBuffer ToServer(1024); - ToServer.WriteByte(0x01); // To server: Encryption key response - ToServer.WriteBEShort((short)sizeof(EncryptedSecret)); + ToServer.WriteBEUInt8(0x01); // To server: Encryption key response + ToServer.WriteBEUInt16(static_cast<UInt16>(sizeof(EncryptedSecret))); ToServer.WriteBuf(EncryptedSecret, sizeof(EncryptedSecret)); - ToServer.WriteBEShort((short)sizeof(EncryptedNonce)); + ToServer.WriteBEUInt16(static_cast<UInt16>(sizeof(EncryptedNonce))); ToServer.WriteBuf(EncryptedNonce, sizeof(EncryptedNonce)); - DataLog(EncryptedSecret, sizeof(EncryptedSecret), "Encrypted secret (%u bytes)", (unsigned)sizeof(EncryptedSecret)); - DataLog(EncryptedNonce, sizeof(EncryptedNonce), "Encrypted nonce (%u bytes)", (unsigned)sizeof(EncryptedNonce)); + DataLog(EncryptedSecret, sizeof(EncryptedSecret), "Encrypted secret (%u bytes)", static_cast<unsigned>(sizeof(EncryptedSecret))); + DataLog(EncryptedNonce, sizeof(EncryptedNonce), "Encrypted nonce (%u bytes)", static_cast<unsigned>(sizeof(EncryptedNonce))); cByteBuffer Len(5); - Len.WriteVarInt(static_cast<UInt32>(ToServer.GetReadableSpace())); + Len.WriteVarInt32(static_cast<UInt32>(ToServer.GetReadableSpace())); SERVERSEND(Len); SERVERSEND(ToServer); m_ServerState = csEncryptedUnderstood; diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h index a9b5aa1b1..efc0a9988 100644 --- a/Tools/ProtoProxy/Globals.h +++ b/Tools/ProtoProxy/Globals.h @@ -73,13 +73,15 @@ // Integral types with predefined sizes: -typedef long long Int64; -typedef int Int32; -typedef short Int16; +typedef signed long long Int64; +typedef signed int Int32; +typedef signed short Int16; +typedef signed char Int8; typedef unsigned long long UInt64; typedef unsigned int UInt32; typedef unsigned short UInt16; +typedef unsigned char UInt8; typedef unsigned char Byte; @@ -245,7 +247,3 @@ public: - -#define LOGERROR printf -#define LOGINFO printf -#define LOGWARNING printf diff --git a/Tools/ProtoProxy/ProtoProxy.cpp b/Tools/ProtoProxy/ProtoProxy.cpp index 2724ef704..3f427f83f 100644 --- a/Tools/ProtoProxy/ProtoProxy.cpp +++ b/Tools/ProtoProxy/ProtoProxy.cpp @@ -5,6 +5,8 @@ #include "Globals.h" #include "Server.h" +#include "../../src/Logger.h" +#include "../../src/LoggerListeners.h" @@ -12,8 +14,16 @@ int main(int argc, char ** argv) { + // Initialize logging subsystem: + cLogger::InitiateMultithreading(); + auto consoleLogListener = MakeConsoleListener(); + auto fileLogListener = new cFileListener(); + cLogger::GetInstance().AttachListener(consoleLogListener); + cLogger::GetInstance().AttachListener(fileLogListener); + int ListenPort = (argc > 1) ? atoi(argv[1]) : 25564; int ConnectPort = (argc > 2) ? atoi(argv[2]) : 25565; + printf("Initializing ProtoProxy. Listen port %d, connect port %d.\n", ListenPort, ConnectPort); cServer Server; int res = Server.Init(ListenPort, ConnectPort); if (res != 0) diff --git a/Tools/ProtoProxy/Server.cpp b/Tools/ProtoProxy/Server.cpp index 5bba98057..98baec8da 100644 --- a/Tools/ProtoProxy/Server.cpp +++ b/Tools/ProtoProxy/Server.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "Server.h" #include "Connection.h" +#include "../../src/Logger.h" @@ -28,15 +29,11 @@ int cServer::Init(short a_ListenPort, short a_ConnectPort) int res = WSAStartup(0x0202, &wsa); if (res != 0) { - printf("Cannot initialize WinSock: %d\n", res); + LOGERROR("Cannot initialize WinSock: %d", res); return res; } #endif // _WIN32 - LOGINFO("Generating protocol encryption keypair..."); - m_PrivateKey.Generate(); - m_PublicKeyDER = m_PrivateKey.GetPubKeyDER(); - m_ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_ListenSocket < 0) { @@ -45,22 +42,22 @@ int cServer::Init(short a_ListenPort, short a_ConnectPort) #else int err = errno; #endif - printf("Failed to create listener socket: %d\n", err); + LOGERROR("Failed to create listener socket: %d", err); return err; } sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; - local.sin_addr.s_addr = 130; // INADDR_ANY; // All interfaces + local.sin_addr.s_addr = INADDR_ANY; // All interfaces local.sin_port = htons(a_ListenPort); - if (!bind(m_ListenSocket, (sockaddr *)&local, sizeof(local))) + if (bind(m_ListenSocket, (sockaddr *)&local, sizeof(local)) != 0) { #ifdef _WIN32 int err = WSAGetLastError(); #else int err = errno; #endif - printf("Failed to bind listener socket: %d\n", err); + LOGERROR("Failed to bind listener socket: %d", err); return err; } if (listen(m_ListenSocket, 1) != 0) @@ -73,9 +70,12 @@ int cServer::Init(short a_ListenPort, short a_ConnectPort) printf("Failed to listen on socket: %d\n", err); return err; } + LOGINFO("Listening on port %d, connecting to localhost:%d", a_ListenPort, a_ConnectPort); - printf("Listening on port %d, connecting to localhost:%d\n", a_ListenPort, a_ConnectPort); - + LOGINFO("Generating protocol encryption keypair..."); + m_PrivateKey.Generate(); + m_PublicKeyDER = m_PrivateKey.GetPubKeyDER(); + return 0; } diff --git a/Tools/ProtoProxy/Server.h b/Tools/ProtoProxy/Server.h index 8adc7093d..9782503fb 100644 --- a/Tools/ProtoProxy/Server.h +++ b/Tools/ProtoProxy/Server.h @@ -21,7 +21,7 @@ class cServer SOCKET m_ListenSocket; cRsaPrivateKey m_PrivateKey; AString m_PublicKeyDER; - short m_ConnectPort; + UInt16 m_ConnectPort; public: cServer(void); @@ -32,7 +32,7 @@ public: cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; } const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; } - short GetConnectPort(void) const { return m_ConnectPort; } + UInt16 GetConnectPort(void) const { return m_ConnectPort; } } ; diff --git a/Tools/QtBiomeVisualiser/GeneratorSetup.cpp b/Tools/QtBiomeVisualiser/GeneratorSetup.cpp index 8f97e1f37..54b7ef36e 100644 --- a/Tools/QtBiomeVisualiser/GeneratorSetup.cpp +++ b/Tools/QtBiomeVisualiser/GeneratorSetup.cpp @@ -120,15 +120,23 @@ void GeneratorSetup::editChanged(const QString & a_NewValue) void GeneratorSetup::updateFromIni() { - m_eSeed->setText(QString::number(m_IniFile->GetValueI("Seed", "Seed", 0))); + // Set the seed editbox: + int seed = m_IniFile->GetValueI("Seed", "Seed", 0); + m_eSeed->setText(QString::number(seed)); int keyID = m_IniFile->FindKey("Generator"); if (keyID <= -1) { return; } - int numItems = m_IniFile->GetNumValues(keyID); + + // Set the Generator combobox: AString generatorName = m_IniFile->GetValue("Generator", "BiomeGen"); size_t generatorNameLen = generatorName.length(); + int index = m_cbGenerator->findText(QString::fromStdString(generatorName)); + m_cbGenerator->setCurrentIndex(index); + + // Create the controls for all the generator settings in the INI file: + int numItems = m_IniFile->GetNumValues(keyID); for (int i = 0; i < numItems; i++) { AString itemName = m_IniFile->GetValueName(keyID, i); diff --git a/Tools/QtBiomeVisualiser/Globals.h b/Tools/QtBiomeVisualiser/Globals.h index e2e9a9970..cc90f9383 100644 --- a/Tools/QtBiomeVisualiser/Globals.h +++ b/Tools/QtBiomeVisualiser/Globals.h @@ -176,8 +176,7 @@ template class SizeChecker<UInt16, 2>; // OS-dependent stuff: #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN - - #define _WIN32_WINNT 0x501 // We want to target WinXP and higher + #define _WIN32_WINNT _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher #include <Windows.h> #include <winsock2.h> @@ -248,11 +247,9 @@ template class SizeChecker<UInt16, 2>; #ifndef TEST_GLOBALS // Common headers (part 1, without macros): #include "src/StringUtils.h" - #include "src/OSSupport/Sleep.h" #include "src/OSSupport/CriticalSection.h" #include "src/OSSupport/Semaphore.h" #include "src/OSSupport/Event.h" - #include "src/OSSupport/Thread.h" #include "src/OSSupport/File.h" #include "src/Logger.h" #else diff --git a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro index cccee1305..daf2d4020 100644 --- a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro +++ b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro @@ -22,6 +22,7 @@ SOURCES += \ ../../src/LoggerListeners.cpp \ ../../src/Logger.cpp \ ../../src/IniFile.cpp \ + ../../src/OSSupport/Event.cpp \ ../../src/OSSupport/File.cpp \ ../../src/OSSupport/CriticalSection.cpp \ ../../src/OSSupport/IsThread.cpp \ @@ -69,6 +70,7 @@ HEADERS += \ ../../src/LoggerListeners.h \ ../../src/Logger.h \ ../../src/IniFile.h \ + ../../src/OSSupport/Event.h \ ../../src/OSSupport/File.h \ ../../src/OSSupport/CriticalSection.h \ ../../src/OSSupport/IsThread.h \ diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 7e174e770..8f55eba07 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -1,4 +1,19 @@ +// AllToLua.pkg + +// Defines the bindings that are exported to Lua by the ToLua processor + +/* + Each file referenced in the $cfile is parsed by ToLua, and bindings are generated for classes and functions +marked with "// tolua_export", or between the "// tolua_begin" and "// tolua_end" markers. + + Note that if class D inherits from class B, then class B needs to be parsed before class D, otherwise the +inheritance doesn't work properly (#1789). +*/ + + + + $#include "../Globals.h" // Typedefs from Globals.h, so that we don't have to process that file: @@ -27,14 +42,38 @@ $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 "../Server.h" +$cfile "../World.h" +$cfile "../Inventory.h" +$cfile "../Enchantments.h" +$cfile "../Item.h" +$cfile "../ItemGrid.h" +$cfile "../WebAdmin.h" +$cfile "../Root.h" +$cfile "../Cuboid.h" +$cfile "../BoundingBox.h" +$cfile "../Tracer.h" +$cfile "../BlockArea.h" +$cfile "../Generating/ChunkDesc.h" +$cfile "../CraftingRecipes.h" +$cfile "../UI/Window.h" +$cfile "../CompositeChat.h" +$cfile "../Map.h" +$cfile "../MapManager.h" +$cfile "../Scoreboard.h" +$cfile "../Statistics.h" +$cfile "../Protocol/MojangAPI.h" + +// Entities: $cfile "../Entities/Entity.h" +$cfile "../Entities/Pawn.h" +$cfile "../Entities/ProjectileEntity.h" +$cfile "../Entities/ArrowEntity.h" $cfile "../Entities/EntityEffect.h" $cfile "../Entities/ExpBottleEntity.h" $cfile "../Entities/FireChargeEntity.h" @@ -43,25 +82,21 @@ $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/WitherSkullEntity.h" -$cfile "../Server.h" -$cfile "../World.h" -$cfile "../Inventory.h" -$cfile "../Enchantments.h" -$cfile "../Item.h" -$cfile "../ItemGrid.h" -$cfile "../BlockEntities/BeaconEntity.h" +$cfile "../Mobs/MonsterTypes.h" +$cfile "../Mobs/Monster.h" + +// Block entities: $cfile "../BlockEntities/BlockEntity.h" +$cfile "../BlockEntities/BeaconEntity.h" $cfile "../BlockEntities/BlockEntityWithItems.h" $cfile "../BlockEntities/ChestEntity.h" $cfile "../BlockEntities/CommandBlockEntity.h" @@ -76,30 +111,6 @@ $cfile "../BlockEntities/SignEntity.h" $cfile "../BlockEntities/MobHeadEntity.h" $cfile "../BlockEntities/MobSpawnerEntity.h" $cfile "../BlockEntities/FlowerPotEntity.h" -$cfile "../WebAdmin.h" -$cfile "../Root.h" -$cfile "../Cuboid.h" -$cfile "../BoundingBox.h" -$cfile "../Tracer.h" -$cfile "../BlockArea.h" -$cfile "../Generating/ChunkDesc.h" -$cfile "../CraftingRecipes.h" -$cfile "../UI/Window.h" -$cfile "../Mobs/Monster.h" -$cfile "../CompositeChat.h" -$cfile "../Map.h" -$cfile "../MapManager.h" -$cfile "../Scoreboard.h" -$cfile "../Statistics.h" -$cfile "../Protocol/MojangAPI.h" - - - - - -// Need to declare this class so that the usertype is properly registered in Bindings.cpp - -// it seems impossible to register a usertype in ManualBindings.cpp -class cLineBlockTracer; diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp index 35730878d..d4014059b 100644 --- a/src/Bindings/LuaWindow.cpp +++ b/src/Bindings/LuaWindow.cpp @@ -167,6 +167,24 @@ void cLuaWindow::Destroy(void) +void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer& a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas Areas; + for (auto Area : m_SlotAreas) + { + if (Area != a_ClickedArea) + { + Areas.push_back(Area); + } + } + + super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false); +} + + + + + void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) { if (a_ItemGrid != &m_Contents) diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h index dab99a2e2..d4fc58660 100644 --- a/src/Bindings/LuaWindow.h +++ b/src/Bindings/LuaWindow.h @@ -35,8 +35,10 @@ This reference needs to be unreferenced in the Destroy() function. */ // tolua_begin class cLuaWindow : - public cWindow, - public cItemGrid::cListener + public cWindow + // tolua_end + , public cItemGrid::cListener + // tolua_begin { typedef cWindow super; @@ -84,6 +86,7 @@ protected: // cWindow overrides: virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override; virtual void Destroy(void) override; + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; // cItemGrid::cListener overrides: virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index cac81f325..6e579b364 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -266,6 +266,24 @@ static int tolua_StringSplit(lua_State * tolua_S) +static int tolua_StringSplitWithQuotes(lua_State * tolua_S) +{ + cLuaState S(tolua_S); + + AString str; + AString delim; + + S.GetStackValues(1, str, delim); + + AStringVector Split = StringSplitWithQuotes(str, delim); + S.Push(Split); + return 1; +} + + + + + static int tolua_StringSplitAndTrim(lua_State * tolua_S) { cLuaState LuaState(tolua_S); @@ -572,7 +590,7 @@ static int tolua_DoWith(lua_State* tolua_S) template < class Ty1, class Ty2, - bool (Ty1::*Func1)(int, cItemCallback<Ty2> &) + bool (Ty1::*Func1)(UInt32, cItemCallback<Ty2> &) > static int tolua_DoWithID(lua_State* tolua_S) { @@ -620,11 +638,11 @@ static int tolua_DoWithID(lua_State* tolua_S) private: virtual bool Item(Ty2 * a_Item) override { - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call - tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); // Push the item + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call + tolua_pushusertype(LuaState, a_Item, a_Item->GetClass()); // Push the item if (TableRef != LUA_REFNIL) { - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param } int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); @@ -1281,23 +1299,27 @@ tolua_lerror: class cLuaWorldTask : - public cWorld::cTask + public cWorld::cTask, + public cPluginLua::cResettable { public: cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) : - m_Plugin(a_Plugin), + cPluginLua::cResettable(a_Plugin), m_FnRef(a_FnRef) { } protected: - cPluginLua & m_Plugin; int m_FnRef; // cWorld::cTask overrides: virtual void Run(cWorld & a_World) override { - m_Plugin.Call(m_FnRef, &a_World); + cCSLock Lock(m_CSPlugin); + if (m_Plugin != nullptr) + { + m_Plugin->Call(m_FnRef, &a_World); + } } } ; @@ -1336,7 +1358,9 @@ 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(make_unique<cLuaWorldTask>(*Plugin, FnRef)); + auto task = std::make_shared<cLuaWorldTask>(*Plugin, FnRef); + Plugin->AddResettable(task); + self->QueueTask(task); return 0; } @@ -1345,23 +1369,27 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) class cLuaScheduledWorldTask : - public cWorld::cTask + public cWorld::cTask, + public cPluginLua::cResettable { public: cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : - m_Plugin(a_Plugin), + cPluginLua::cResettable(a_Plugin), m_FnRef(a_FnRef) { } protected: - cPluginLua & m_Plugin; int m_FnRef; // cWorld::cTask overrides: virtual void Run(cWorld & a_World) override { - m_Plugin.Call(m_FnRef, &a_World); + cCSLock Lock(m_CSPlugin); + if (m_Plugin != nullptr) + { + m_Plugin->Call(m_FnRef, &a_World); + } } }; @@ -1407,7 +1435,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0); - World->ScheduleTask(DelayTicks, new cLuaScheduledWorldTask(*Plugin, FnRef)); + auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef); + Plugin->AddResettable(task); + World->ScheduleTask(DelayTicks, task); return 0; } @@ -3659,19 +3689,22 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_cclass(tolua_S, "cCryptoHash", "cCryptoHash", "", nullptr); tolua_usertype(tolua_S, "cStringCompression"); tolua_cclass(tolua_S, "cStringCompression", "cStringCompression", "", nullptr); + tolua_usertype(tolua_S, "cLineBlockTracer"); + tolua_cclass(tolua_S, "cLineBlockTracer", "cLineBlockTracer", "", nullptr); // Globals: - tolua_function(tolua_S, "Clamp", tolua_Clamp); - tolua_function(tolua_S, "StringSplit", tolua_StringSplit); - tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim); - tolua_function(tolua_S, "LOG", tolua_LOG); - tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO); - tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); - tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); - tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); - tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode); - tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode); - tolua_function(tolua_S, "md5", tolua_md5_obsolete); // OBSOLETE, use cCryptoHash.md5() instead + tolua_function(tolua_S, "Clamp", tolua_Clamp); + tolua_function(tolua_S, "StringSplit", tolua_StringSplit); + tolua_function(tolua_S, "StringSplitWithQuotes", tolua_StringSplitWithQuotes); + tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim); + tolua_function(tolua_S, "LOG", tolua_LOG); + tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO); + tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); + tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); + tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode); + tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode); + tolua_function(tolua_S, "md5", tolua_md5_obsolete); // OBSOLETE, use cCryptoHash.md5() instead tolua_beginmodule(tolua_S, "cFile"); tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); @@ -3846,6 +3879,10 @@ void ManualBindings::Bind(lua_State * tolua_S) BindRankManager(tolua_S); BindNetwork(tolua_S); + tolua_beginmodule(tolua_S, "cEntity"); + tolua_constant(tolua_S, "INVALID_ID", cEntity::INVALID_ID); + tolua_endmodule(tolua_S); + tolua_endmodule(tolua_S); } diff --git a/src/Bindings/ManualBindings_Network.cpp b/src/Bindings/ManualBindings_Network.cpp index a628eb9ca..628cda7f0 100644 --- a/src/Bindings/ManualBindings_Network.cpp +++ b/src/Bindings/ManualBindings_Network.cpp @@ -129,6 +129,30 @@ static int tolua_cNetwork_CreateUDPEndpoint(lua_State * L) +/** Binds cNetwork::EnumLocalIPAddresses */ +static int tolua_cNetwork_EnumLocalIPAddresses(lua_State * L) +{ + // Function signature: + // cNetwork:EnumLocalIPAddresses() -> {string, ...} + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cNetwork") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Push the enumerated addresses: + S.Push(cNetwork::EnumLocalIPAddresses()); + return 1; +} + + + + + /** Binds cNetwork::HostnameToIP */ static int tolua_cNetwork_HostnameToIP(lua_State * L) { @@ -903,11 +927,12 @@ void ManualBindings::BindNetwork(lua_State * tolua_S) // Fill in the functions (alpha-sorted): tolua_beginmodule(tolua_S, "cNetwork"); - tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect); - tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint); - tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP); - tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname); - tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen); + tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect); + tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint); + tolua_function(tolua_S, "EnumLocalIPAddresses", tolua_cNetwork_EnumLocalIPAddresses); + tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP); + tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname); + tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cServerHandle"); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 6ade8ef9f..3f9fa7655 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -111,12 +111,12 @@ 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, const AString & a_FullCommand) = 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. */ - virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) = 0; + virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) = 0; /// All bound commands are to be removed, do any language-dependent cleanup here virtual void ClearCommands(void) {} diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index fb7650d42..0a2a8411d 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -6,10 +6,11 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #ifdef __APPLE__ -#define LUA_USE_MACOSX + #define LUA_USE_MACOSX #else -#define LUA_USE_POSIX + #define LUA_USE_POSIX #endif + #include "PluginLua.h" #include "../CommandOutput.h" #include "PluginManager.h" @@ -52,24 +53,40 @@ cPluginLua::~cPluginLua() void cPluginLua::Close(void) { - if (m_LuaState.IsValid()) - { - // Release all the references in the hook map: - for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH) - { - for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR) - { - delete *itrR; - } // for itrR - itrH->second[] - } // for itrH - m_HookMap[] - m_HookMap.clear(); - - m_LuaState.Close(); - } - else + cCSLock Lock(m_CriticalSection); + + // If already closed, bail out: + if (!m_LuaState.IsValid()) { + ASSERT(m_Resettables.empty()); ASSERT(m_HookMap.empty()); + return; } + + // Notify and remove all m_Resettables (unlock the m_CriticalSection while resetting them): + cResettablePtrs resettables; + std::swap(m_Resettables, resettables); + { + cCSUnlock Unlock(Lock); + for (auto resettable: resettables) + { + resettable->Reset(); + } + m_Resettables.clear(); + } // cCSUnlock (m_CriticalSection) + + // Release all the references in the hook map: + for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH) + { + for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR) + { + delete *itrR; + } // for itrR - itrH->second[] + } // for itrH - m_HookMap[] + m_HookMap.clear(); + + // Close the Lua engine: + m_LuaState.Close(); } @@ -1465,7 +1482,7 @@ bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, s -bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) +bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) { ASSERT(!a_Split.empty()); CommandMap::iterator cmd = m_Commands.find(a_Split[0]); @@ -1477,7 +1494,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, a_FullCommand, cLuaState::Return, res); return res; } @@ -1485,7 +1502,7 @@ bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player -bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) +bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) { ASSERT(!a_Split.empty()); CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]); @@ -1500,7 +1517,7 @@ bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOut cCSLock Lock(m_CriticalSection); bool res = false; AString str; - m_LuaState.Call(cmd->second, a_Split, cLuaState::Return, res, str); + m_LuaState.Call(cmd->second, a_Split, a_FullCommand, cLuaState::Return, res, str); if (res && !str.empty()) { a_Output.Out(str); @@ -1709,6 +1726,16 @@ int cPluginLua::CallFunctionFromForeignState( +void cPluginLua::AddResettable(cPluginLua::cResettablePtr a_Resettable) +{ + cCSLock Lock(m_CriticalSection); + m_Resettables.push_back(a_Resettable); +} + + + + + AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request) { cCSLock Lock(m_CriticalSection); @@ -1826,3 +1853,25 @@ void cPluginLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int + +//////////////////////////////////////////////////////////////////////////////// +// cPluginLua::cResettable: + +cPluginLua::cResettable::cResettable(cPluginLua & a_Plugin): + m_Plugin(&a_Plugin) +{ +} + + + + + +void cPluginLua::cResettable::Reset(void) +{ + cCSLock Lock(m_CSPlugin); + m_Plugin = nullptr; +} + + + + diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 7b528501b..c14b02687 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -59,6 +59,37 @@ public: /** RAII lock for m_Plugin.m_CriticalSection */ cCSLock m_Lock; } ; + + + + /** A base class that represents something related to a plugin + The plugin can reset this class so that the instance can continue to exist but will not engage the (possibly non-existent) plugin anymore. + This is used for scheduled tasks etc., so that they can be queued and reset when the plugin is terminated, without removing them from the queue. */ + class cResettable + { + public: + /** Creates a new instance bound to the specified plugin. */ + cResettable(cPluginLua & a_Plugin); + + // Force a virtual destructor in descendants: + virtual ~cResettable() {} + + /** Resets the plugin instance stored within. + The instance will continue to exist, but should not call into the plugin anymore. */ + virtual void Reset(void); + + protected: + /** The plugin that this instance references. + If nullptr, the plugin has already unloaded and the instance should bail out any processing. + Protected against multithreaded access by m_CSPlugin. */ + cPluginLua * m_Plugin; + + /** The mutex protecting m_Plugin against multithreaded access. */ + cCriticalSection m_CSPlugin; + }; + + typedef SharedPtr<cResettable> cResettablePtr; + typedef std::vector<cResettablePtr> cResettablePtrs; cPluginLua(const AString & a_PluginDirectory); @@ -131,9 +162,9 @@ public: virtual bool OnWorldStarted (cWorld & a_World) override; virtual bool OnWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) override; - virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) override; + virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) override; - virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) override; + virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) override; virtual void ClearCommands(void) override; @@ -187,42 +218,16 @@ public: int a_ParamEnd ); - // The following templates allow calls to arbitrary Lua functions residing in the plugin: - - /** Call a Lua function with 0 args */ - template <typename FnT> bool Call(FnT a_Fn) - { - cCSLock Lock(m_CriticalSection); - return m_LuaState.Call(a_Fn); - } - - /** Call a Lua function with 1 arg */ - template <typename FnT, typename ArgT0> bool Call(FnT a_Fn, ArgT0 a_Arg0) + /** Call a Lua function residing in the plugin. */ + template <typename FnT, typename... Args> + bool Call(FnT a_Fn, Args && ... a_Args) { cCSLock Lock(m_CriticalSection); - return m_LuaState.Call(a_Fn, a_Arg0); + return m_LuaState.Call(a_Fn, a_Args...); } - /** Call a Lua function with 2 args */ - template <typename FnT, typename ArgT0, typename ArgT1> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1) - { - cCSLock Lock(m_CriticalSection); - return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1); - } - - /** Call a Lua function with 3 args */ - template <typename FnT, typename ArgT0, typename ArgT1, typename ArgT2> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1, ArgT2 a_Arg2) - { - cCSLock Lock(m_CriticalSection); - return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1, a_Arg2); - } - - /** Call a Lua function with 4 args */ - template <typename FnT, typename ArgT0, typename ArgT1, typename ArgT2, typename ArgT3> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3) - { - cCSLock Lock(m_CriticalSection); - return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1, a_Arg2, a_Arg3); - } + /** Adds the specified cResettable instance to m_Resettables, so that it is notified when the plugin is being closed. */ + void AddResettable(cResettablePtr a_Resettable); protected: /** Maps command name into Lua function reference */ @@ -234,15 +239,27 @@ protected: /** Maps hook types into arrays of Lua function references to call for each hook type */ typedef std::map<int, cLuaRefs> cHookMap; + + /** The mutex protecting m_LuaState and each of the m_Resettables[] against multithreaded use. */ cCriticalSection m_CriticalSection; + + /** The plugin's Lua state. */ cLuaState m_LuaState; + /** Objects that need notification when the plugin is about to be unloaded. */ + cResettablePtrs m_Resettables; + + /** In-game commands that the plugin has registered. */ CommandMap m_Commands; + + /** Console commands that the plugin has registered. */ CommandMap m_ConsoleCommands; + /** Hooks that the plugin has registered. */ cHookMap m_HookMap; - /** Releases all Lua references and closes the LuaState */ + + /** Releases all Lua references, notifies and removes all m_Resettables[] and closes the m_LuaState. */ void Close(void); } ; // tolua_export diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 41b36337e..8935f7dd3 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -1465,7 +1465,7 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player, ASSERT(cmd->second.m_Plugin != nullptr); - if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player)) + if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player, a_Command)) { return crError; } @@ -1768,7 +1768,7 @@ bool cPluginManager::IsConsoleCommandBound(const AString & a_Command) -bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) +bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_Command) { if (a_Split.empty()) { @@ -1795,7 +1795,7 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma return false; } - return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output); + return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output, a_Command); } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index c8b4de9d6..4efcbb6f3 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -284,7 +284,7 @@ public: bool IsConsoleCommandBound(const AString & a_Command); // tolua_export /** Executes the command split into a_Split, as if it was given on the console. Returns true if executed. Output is sent to the a_Output callback */ - bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output); + bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_Command); /** Appends all commands beginning with a_Text (case-insensitive) into a_Results. If a_Player is not nullptr, only commands for which the player has permissions are added. diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 37ce7a8ab..fb3940ce9 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -4,6 +4,7 @@ #include "BeaconEntity.h" #include "../BlockArea.h" #include "../Entities/Player.h" +#include "../UI/BeaconWindow.h" @@ -289,7 +290,7 @@ void cBeaconEntity::UsedBy(cPlayer * a_Player) OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this)); Window = GetWindow(); } - + if (Window != nullptr) { // if (a_Player->GetWindow() != Window) diff --git a/src/BlockEntities/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h index 2c2ced1cb..740dbca51 100644 --- a/src/BlockEntities/BlockEntityWithItems.h +++ b/src/BlockEntities/BlockEntityWithItems.h @@ -21,7 +21,9 @@ // tolua_begin class cBlockEntityWithItems : public cBlockEntity, + // tolua_end public cItemGrid::cListener, + // tolua_begin public cBlockEntityWindowOwner { typedef cBlockEntity super; diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 0cd9c66e0..1c186310c 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -4,7 +4,7 @@ #include "ChestEntity.h" #include "../Item.h" #include "../Entities/Player.h" -#include "../UI/Window.h" +#include "../UI/ChestWindow.h" @@ -80,7 +80,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player) void cChestEntity::OpenNewWindow(void) { // TODO: cats are an obstruction - if ((GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()))) + if ((GetPosY() < cChunkDef::Height - 1) && cBlockInfo::IsSolid(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()))) { // Obstruction, don't open return; @@ -99,7 +99,7 @@ void cChestEntity::OpenNewWindow(void) virtual bool Item(cChestEntity * a_Chest) override { - if ((a_Chest->GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ()))) + if ((a_Chest->GetPosY() < cChunkDef::Height - 1) && cBlockInfo::IsSolid(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ()))) { // Obstruction, don't open return false; diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 42a0476b6..a847f1b65 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -105,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, static_cast<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)) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -144,29 +144,37 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20); - m_Contents.ChangeSlotCount(a_SlotNum, -1); + if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20) != cEntity::INVALID_ID) + { + m_Contents.ChangeSlotCount(a_SlotNum, -1); + } break; } case E_ITEM_ARROW: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); - m_Contents.ChangeSlotCount(a_SlotNum, -1); + if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + { + m_Contents.ChangeSlotCount(a_SlotNum, -1); + } break; } case E_ITEM_SNOWBALL: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); - m_Contents.ChangeSlotCount(a_SlotNum, -1); + if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + { + m_Contents.ChangeSlotCount(a_SlotNum, -1); + } break; } case E_ITEM_EGG: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); - m_Contents.ChangeSlotCount(a_SlotNum, -1); + if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + { + m_Contents.ChangeSlotCount(a_SlotNum, -1); + } break; } @@ -188,9 +196,14 @@ 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) +UInt32 cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & 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); + return 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 + ); } diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 12e12942a..62072d43b 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -24,8 +24,9 @@ public: // tolua_begin - /** Spawns a projectile of the given kind in front of the dispenser with the specified speed. */ - void SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed); + /** Spawns a projectile of the given kind in front of the dispenser with the specified speed. + Returns the UniqueID of the spawned projectile, or 0 on failure. */ + UInt32 SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed); /** Returns a unit vector in the cardinal direction of where the dispenser is facing. */ Vector3d GetShootVector(NIBBLETYPE a_Meta); diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp index 5e98506f1..039f5d360 100644 --- a/src/BlockEntities/DropSpenserEntity.cpp +++ b/src/BlockEntities/DropSpenserEntity.cpp @@ -8,6 +8,7 @@ #include "DropSpenserEntity.h" #include "../Entities/Player.h" #include "../Chunk.h" +#include "../UI/DropSpenserWindow.h" diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp index e18490a1e..ab5c5a2de 100644 --- a/src/BlockEntities/EnderChestEntity.cpp +++ b/src/BlockEntities/EnderChestEntity.cpp @@ -4,7 +4,7 @@ #include "EnderChestEntity.h" #include "../Item.h" #include "../Entities/Player.h" -#include "../UI/Window.h" +#include "../UI/EnderChestWindow.h" diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index cc5a00af7..2621b560b 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -2,7 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "FurnaceEntity.h" -#include "../UI/Window.h" +#include "../UI/FurnaceWindow.h" #include "../Entities/Player.h" #include "../Root.h" #include "../Chunk.h" diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index c2d6cabbb..bfd4b8322 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -9,6 +9,7 @@ #include "../Entities/Player.h" #include "../Entities/Pickup.h" #include "../Bindings/PluginManager.h" +#include "../UI/HopperWindow.h" #include "ChestEntity.h" #include "FurnaceEntity.h" diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index 9b3f605f9..764d7af84 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -169,7 +169,7 @@ void cMobSpawnerEntity::SpawnEntity(void) Monster->SetPosition(PosX, RelY, PosZ); Monster->SetYaw(Random.NextFloat() * 360.0f); - if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != mtInvalidType) + if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cEntity::INVALID_ID) { EntitiesSpawned = true; Chunk->BroadcastSoundParticleEffect(2004, (int)(PosX * 8.0), (int)(RelY * 8.0), (int)(PosZ * 8.0), 0); diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 06f4232d3..7f0db3cfc 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -26,8 +26,18 @@ class cBlockIDMap typedef std::map<AString, std::pair<short, short>, Comparator> ItemMap; public: + static bool m_bHasRunInit; + cBlockIDMap(void) { + // Dont load items.ini on construct, this will search the wrong path when running as a service. + } + + + void init() + { + m_bHasRunInit = true; + cIniFile Ini; if (!Ini.ReadFile("items.ini")) { @@ -174,7 +184,7 @@ protected: - +bool cBlockIDMap::m_bHasRunInit = false; static cBlockIDMap gsBlockIDMap; @@ -209,6 +219,10 @@ int BlockStringToType(const AString & a_BlockTypeString) return res; } + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString)); } @@ -222,6 +236,11 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item) { ItemName = ItemName.substr(10); } + + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.ResolveItem(ItemName, a_Item); } @@ -231,6 +250,10 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item) AString ItemToString(const cItem & a_Item) { + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.Desolve(a_Item.m_ItemType, a_Item.m_ItemDamage); } @@ -240,6 +263,10 @@ AString ItemToString(const cItem & a_Item) AString ItemTypeToString(short a_ItemType) { + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.Desolve(a_ItemType, -1); } diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 20514580e..abfa0f782 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -4,6 +4,7 @@ #include "BlockHandler.h" #include "../World.h" #include "../Entities/Player.h" +#include "../UI/AnvilWindow.h" diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 57b9855d0..e56f4bfe0 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -1,14 +1,9 @@ #include "Globals.h" #include "BlockBed.h" - - - #include "BroadcastInterface.h" -#include "ChunkInterface.h" #include "Entities/../World.h" #include "Entities/Player.h" -#include "WorldInterface.h" @@ -64,21 +59,22 @@ class cPlayerBedStateUnsetter : public cPlayerListCallback { public: - cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) : - m_Position(a_Position), m_WorldInterface(a_WorldInterface) + cPlayerBedStateUnsetter(Vector3i a_Position, cChunkInterface & a_ChunkInterface) : + m_Position(a_Position), + m_ChunkInterface(a_ChunkInterface) { } virtual bool Item(cPlayer * a_Player) override { + cBlockBedHandler::SetBedOccupationState(m_ChunkInterface, a_Player->GetLastBedPos(), false); a_Player->SetIsInBed(false); - m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2); return false; } private: Vector3i m_Position; - cWorldInterface & m_WorldInterface; + cChunkInterface & m_ChunkInterface; }; @@ -97,7 +93,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface if (a_WorldInterface.GetTimeOfDay() > 13000) { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (Meta & 0x4) + if ((Meta & 0x4) == 0x4) { a_Player->SendMessageFailure("This bed is occupied"); } @@ -105,7 +101,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface { Vector3i PillowDirection(0, 0, 0); - if (Meta & 0x8) + if ((Meta & 0x8) == 0x8) { // Is pillow a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX, a_BlockY, a_BlockZ); @@ -122,15 +118,15 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface } } - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit - a_Player->SetIsInBed(true); a_Player->SetBedPos(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + SetBedOccupationState(a_ChunkInterface, a_Player->GetLastBedPos(), true); + a_Player->SetIsInBed(true); a_Player->SendMessageSuccess("Home position set successfully"); cTimeFastForwardTester Tester; if (a_WorldInterface.ForEachPlayer(Tester)) { - cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface); + cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_ChunkInterface); a_WorldInterface.ForEachPlayer(Unsetter); a_WorldInterface.SetTimeOfDay(0); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 5b746110a..46f361686 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -4,9 +4,9 @@ #include "BlockHandler.h" #include "MetaRotator.h" #include "Item.h" +#include "ChunkInterface.h" -class cChunkInterface; class cPlayer; class cWorldInterface; @@ -21,17 +21,14 @@ public: : cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType) { } - - + virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; 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; - virtual bool IsUseable(void) override { return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { @@ -39,14 +36,12 @@ public: a_Pickups.push_back(cItem(E_ITEM_BED, 1, 0)); } - virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override { return true; } - // Bed specific helper functions static NIBBLETYPE RotationToMetaData(double a_Rotation) { @@ -61,7 +56,6 @@ public: return ((char)a_Rotation + 2) % 4; } - static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) @@ -73,6 +67,21 @@ public: } return Vector3i(); } + + static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, const Vector3i & a_BedPosition, bool a_IsOccupied) + { + auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z); + if (a_IsOccupied) + { + Meta |= 0x04; // Where 0x4 = occupied bit + } + else + { + Meta &= 0x0b; // Clear the "occupied" bit of the bed's block + } + + a_ChunkInterface.SetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z, Meta); + } } ; diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index 5240ddf53..6c5cc6b68 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -81,7 +81,7 @@ 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) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR) && (a_RelY < cChunkDef::Height) && ((a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR) || (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_BIG_FLOWER))); + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR) && (a_RelY < cChunkDef::Height - 1) && ((a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR) || (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_BIG_FLOWER))); } diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index 12bca92dd..32512a2ef 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -59,7 +59,7 @@ public: a_Chunk.GetWorld()->QueueLightChunk(a_Chunk.GetPosX(), a_Chunk.GetPosZ()); return; } - else if (std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY + 1, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY + 1, a_RelZ))) < 9) + else if ((a_RelY < cChunkDef::Height - 1) && std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY + 1, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY + 1, a_RelZ))) < 9) { // Source block is not bright enough to spread return; @@ -69,9 +69,9 @@ public: cFastRandom rand; for (int i = 0; i < 2; i++) // Pick two blocks to grow to { - int OfsX = rand.NextInt(3, a_RelX) - 1; // [-1 .. 1] - int OfsY = rand.NextInt(5, a_RelY) - 3; // [-3 .. 1] - int OfsZ = rand.NextInt(3, a_RelZ) - 1; // [-1 .. 1] + int OfsX = rand.NextInt(3) - 1; // [-1 .. 1] + int OfsY = rand.NextInt(5) - 3; // [-3 .. 1] + int OfsZ = rand.NextInt(3) - 1; // [-1 .. 1] BLOCKTYPE DestBlock; NIBBLETYPE DestMeta; diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h index 81d2cb9a0..40001f356 100644 --- a/src/Blocks/BlockEnchantmentTable.h +++ b/src/Blocks/BlockEnchantmentTable.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "../UI/Window.h" +#include "../UI/EnchantingWindow.h" #include "../Entities/Player.h" diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index 02a48a4af..23a7392da 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -45,7 +45,7 @@ public: } // Farmland too dry. If nothing is growing on top, turn back to dirt: - BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height) ? E_BLOCK_AIR : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); + BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height - 1) ? E_BLOCK_AIR : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); switch (UpperBlock) { case E_BLOCK_CROPS: diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index 8c0aae041..2823baedc 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -99,7 +99,7 @@ public: // Check if it's fuel: BLOCKTYPE BlockType; if ( - ((a_RelY + y < 0) || (a_RelY + y > cChunkDef::Height)) || + ((a_RelY + y < 0) || (a_RelY + y >= cChunkDef::Height)) || !a_Chunk.UnboundedRelGetBlockType(a_RelX + x, a_RelY + y, a_RelZ + z, BlockType) || !cFireSimulator::IsFuel(BlockType) ) @@ -126,7 +126,7 @@ public: for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++) { if ( - ((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y <= cChunkDef::Height)) && + ((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y < cChunkDef::Height)) && a_Chunk.UnboundedRelGetBlockType(RelX + CrossCoords[i].x, RelY + CrossCoords[i].y, RelZ + CrossCoords[i].z, BlockType) && (BlockType == E_BLOCK_AIR) ) diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 8d245cabe..d9f4913d8 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -61,6 +61,16 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld +void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) +{ + // Returning Piston Item without Direction-Metavalue + a_Pickups.push_back(cItem(m_BlockType, 1)); +} + + + + + bool cBlockPistonHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -169,7 +179,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8); a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false); - a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); + a_World->ScheduleTask(PISTON_TICK_DELAY, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks)); } @@ -219,7 +229,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ std::vector<Vector3i> ScheduledBlocks; ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz)); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks)); return; } } @@ -229,7 +239,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ std::vector<Vector3i> ScheduledBlocks; ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks)); } diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index f868f4d8e..9a891025a 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -15,6 +15,8 @@ public: virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override; + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 97ba26ee3..581a29447 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -55,7 +55,7 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height)) + if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height - 1)) { return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1 } diff --git a/src/Blocks/BlockWorkbench.h b/src/Blocks/BlockWorkbench.h index 699badaf2..e40e15606 100644 --- a/src/Blocks/BlockWorkbench.h +++ b/src/Blocks/BlockWorkbench.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "../UI/Window.h" +#include "../UI/CraftingWindow.h" #include "../Entities/Player.h" diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 106c314e7..44c118195 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -30,14 +30,16 @@ public: /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) = 0; - /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */ + /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified. */ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false) = 0; - /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ - virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0; + /** Spawns a mob of the specified type. + Returns the mob's UniqueID if recognized and spawned, or cEntity::INVALID_ID on failure. */ + virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0; - /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */ - virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0; + /** Spawns an experience orb at the given location with the given reward. + Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */ + virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0; /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) = 0; diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index f3dc44d91..dc757d8f6 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -81,9 +81,9 @@ public: void TestWrite(void) { cByteBuffer buf(50); - buf.WriteVarInt(5); - buf.WriteVarInt(300); - buf.WriteVarInt(0); + buf.WriteVarInt32(5); + buf.WriteVarInt32(300); + buf.WriteVarInt32(0); AString All; buf.ReadAll(All); assert_test(All.size() == 4); @@ -101,8 +101,8 @@ public: assert_test(buf.Write("a", 1)); assert_test(buf.CanReadBytes(1)); assert_test(buf.GetReadableSpace() == 1); - unsigned char v = 0; - assert_test(buf.ReadByte(v)); + UInt8 v = 0; + assert_test(buf.ReadBEUInt8(v)); assert_test(v == 'a'); assert_test(buf.GetReadableSpace() == 0); buf.CommitRead(); @@ -317,7 +317,7 @@ bool cByteBuffer::CanWriteBytes(size_t a_Count) const -bool cByteBuffer::ReadChar(char & a_Value) +bool cByteBuffer::ReadBEInt8(Int8 & a_Value) { CHECK_THREAD CheckValid(); @@ -330,7 +330,7 @@ bool cByteBuffer::ReadChar(char & a_Value) -bool cByteBuffer::ReadByte(unsigned char & a_Value) +bool cByteBuffer::ReadBEUInt8(UInt8 & a_Value) { CHECK_THREAD CheckValid(); @@ -343,15 +343,15 @@ bool cByteBuffer::ReadByte(unsigned char & a_Value) -bool cByteBuffer::ReadBEShort(short & a_Value) +bool cByteBuffer::ReadBEInt16(Int16 & a_Value) { CHECK_THREAD CheckValid(); NEEDBYTES(2); - Int16 val; + UInt16 val; ReadBuf(&val, 2); val = ntohs(val); - a_Value = *(reinterpret_cast<short *>(&val)); + memcpy(&a_Value, &val, 2); return true; } @@ -373,13 +373,15 @@ bool cByteBuffer::ReadBEUInt16(UInt16 & a_Value) -bool cByteBuffer::ReadBEInt(int & a_Value) +bool cByteBuffer::ReadBEInt32(Int32 & a_Value) { CHECK_THREAD CheckValid(); NEEDBYTES(4); - ReadBuf(&a_Value, 4); - a_Value = (int)ntohl((u_long)a_Value); + UInt32 val; + ReadBuf(&val, 4); + val = ntohl(val); + memcpy(&a_Value, &val, 4); return true; } @@ -415,6 +417,20 @@ bool cByteBuffer::ReadBEInt64(Int64 & a_Value) +bool cByteBuffer::ReadBEUInt64(UInt64 & a_Value) +{ + CHECK_THREAD + CheckValid(); + NEEDBYTES(8); + ReadBuf(&a_Value, 8); + a_Value = NetworkToHostULong8(&a_Value); + return true; +} + + + + + bool cByteBuffer::ReadBEFloat(float & a_Value) { CHECK_THREAD @@ -448,7 +464,7 @@ bool cByteBuffer::ReadBool(bool & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(1); - char Value = 0; + UInt8 Value = 0; ReadBuf(&Value, 1); a_Value = (Value != 0); return true; @@ -462,24 +478,19 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value) { CHECK_THREAD CheckValid(); - short Length; - if (!ReadBEShort(Length)) + UInt16 Length; + if (!ReadBEUInt16(Length)) { return false; } - if (Length < 0) - { - ASSERT(!"Negative string length? Are you sure?"); - return true; - } - return ReadUTF16String(a_Value, (size_t)Length); + return ReadUTF16String(a_Value, Length); } -bool cByteBuffer::ReadVarInt(UInt32 & a_Value) +bool cByteBuffer::ReadVarInt32(UInt32 & a_Value) { CHECK_THREAD CheckValid(); @@ -490,7 +501,29 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value) { NEEDBYTES(1); ReadBuf(&b, 1); - Value = Value | (((UInt32)(b & 0x7f)) << Shift); + Value = Value | ((static_cast<UInt32>(b & 0x7f)) << Shift); + Shift += 7; + } while ((b & 0x80) != 0); + a_Value = Value; + return true; +} + + + + + +bool cByteBuffer::ReadVarInt64(UInt64 & a_Value) +{ + CHECK_THREAD + CheckValid(); + UInt64 Value = 0; + int Shift = 0; + unsigned char b = 0; + do + { + NEEDBYTES(1); + ReadBuf(&b, 1); + Value = Value | ((static_cast<UInt64>(b & 0x7f)) << Shift); Shift += 7; } while ((b & 0x80) != 0); a_Value = Value; @@ -540,7 +573,7 @@ bool cByteBuffer::ReadLEInt(int & a_Value) -bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ) +bool cByteBuffer::ReadPosition64(int & a_BlockX, int & a_BlockY, int & a_BlockZ) { CHECK_THREAD Int64 Value; @@ -565,7 +598,7 @@ bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ) -bool cByteBuffer::WriteChar(char a_Value) +bool cByteBuffer::WriteBEInt8(Int8 a_Value) { CHECK_THREAD CheckValid(); @@ -577,7 +610,7 @@ bool cByteBuffer::WriteChar(char a_Value) -bool cByteBuffer::WriteByte(unsigned char a_Value) +bool cByteBuffer::WriteBEUInt8(UInt8 a_Value) { CHECK_THREAD CheckValid(); @@ -589,33 +622,48 @@ bool cByteBuffer::WriteByte(unsigned char a_Value) -bool cByteBuffer::WriteBEShort(short a_Value) +bool cByteBuffer::WriteBEInt16(Int16 a_Value) { CHECK_THREAD CheckValid(); PUTBYTES(2); - u_short Converted = htons((u_short)a_Value); - return WriteBuf(&Converted, 2); + UInt16 val; + memcpy(&val, &a_Value, 2); + val = htons(val); + return WriteBuf(&val, 2); } -bool cByteBuffer::WriteBEUShort(unsigned short a_Value) +bool cByteBuffer::WriteBEUInt16(UInt16 a_Value) { CHECK_THREAD CheckValid(); PUTBYTES(2); - u_short Converted = htons((u_short)a_Value); - return WriteBuf(&Converted, 2); + a_Value = htons(a_Value); + return WriteBuf(&a_Value, 2); } -bool cByteBuffer::WriteBEInt(int a_Value) +bool cByteBuffer::WriteBEInt32(Int32 a_Value) +{ + CHECK_THREAD + CheckValid(); + PUTBYTES(4); + UInt32 Converted = HostToNetwork4(&a_Value); + return WriteBuf(&Converted, 4); +} + + + + + +bool cByteBuffer::WriteBEUInt32(UInt32 a_Value) { CHECK_THREAD CheckValid(); @@ -641,6 +689,19 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value) +bool cByteBuffer::WriteBEUInt64(UInt64 a_Value) +{ + CHECK_THREAD + CheckValid(); + PUTBYTES(8); + UInt64 Converted = HostToNetwork8(&a_Value); + return WriteBuf(&Converted, 8); +} + + + + + bool cByteBuffer::WriteBEFloat(float a_Value) { CHECK_THREAD @@ -672,14 +733,15 @@ bool cByteBuffer::WriteBool(bool a_Value) { CHECK_THREAD CheckValid(); - return WriteChar(a_Value ? 1 : 0); + UInt8 val = a_Value ? 1 : 0; + return Write(&val, 1); } -bool cByteBuffer::WriteVarInt(UInt32 a_Value) +bool cByteBuffer::WriteVarInt32(UInt32 a_Value) { CHECK_THREAD CheckValid(); @@ -700,12 +762,35 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value) + +bool cByteBuffer::WriteVarInt64(UInt64 a_Value) +{ + CHECK_THREAD + CheckValid(); + + // A 64-bit integer can be encoded by at most 10 bytes: + unsigned char b[10]; + 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); + + return WriteBuf(b, idx); +} + + + + + bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) { CHECK_THREAD CheckValid(); PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early. - bool res = WriteVarInt((UInt32)(a_Value.size())); + bool res = WriteVarInt32(static_cast<UInt32>(a_Value.size())); if (!res) { return false; @@ -717,15 +802,15 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) -bool cByteBuffer::WriteLEInt(int a_Value) +bool cByteBuffer::WriteLEInt32(Int32 a_Value) { CHECK_THREAD CheckValid(); #ifdef IS_LITTLE_ENDIAN - return WriteBuf((const char *)&a_Value, 4); + return WriteBuf(reinterpret_cast<const char *>(&a_Value), 4); #else int Value = ((a_Value >> 24) & 0xff) | ((a_Value >> 16) & 0xff00) | ((a_Value >> 8) & 0xff0000) | (a_Value & 0xff000000); - return WriteBuf((const char *)&Value, 4); + return WriteBuf(reinterpret_cast<const char *>(&Value), 4); #endif } @@ -733,10 +818,15 @@ bool cByteBuffer::WriteLEInt(int a_Value) -bool cByteBuffer::WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cByteBuffer::WritePosition64(Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ) { CHECK_THREAD - return WriteBEInt64(((Int64)a_BlockX & 0x3FFFFFF) << 38 | ((Int64)a_BlockY & 0xFFF) << 26 | ((Int64)a_BlockZ & 0x3FFFFFF)); + CheckValid(); + return WriteBEInt64( + (static_cast<Int64>(a_BlockX & 0x3FFFFFF) << 38) | + (static_cast<Int64>(a_BlockY & 0xFFF) << 26) | + (static_cast<Int64>(a_BlockZ & 0x3FFFFFF)) + ); } diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index f480ad557..0a4935327 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -52,48 +52,53 @@ public: bool CanWriteBytes(size_t a_Count) const; // Read the specified datatype and advance the read pointer; return true if successfully read: - bool ReadChar (char & a_Value); - bool ReadByte (unsigned char & a_Value); - bool ReadBEShort (short & a_Value); + bool ReadBEInt8 (Int8 & a_Value); + bool ReadBEInt16 (Int16 & a_Value); + bool ReadBEInt32 (Int32 & a_Value); + bool ReadBEInt64 (Int64 & a_Value); + bool ReadBEUInt8 (UInt8 & a_Value); bool ReadBEUInt16 (UInt16 & a_Value); - bool ReadBEInt (int & a_Value); bool ReadBEUInt32 (UInt32 & a_Value); - bool ReadBEInt64 (Int64 & a_Value); + bool ReadBEUInt64 (UInt64 & a_Value); bool ReadBEFloat (float & a_Value); bool ReadBEDouble (double & a_Value); bool ReadBool (bool & a_Value); bool ReadBEUTF16String16(AString & a_Value); // string length as BE short, then string as UTF-16BE - bool ReadVarInt (UInt32 & a_Value); + bool ReadVarInt32 (UInt32 & a_Value); + bool ReadVarInt64 (UInt64 & a_Value); bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8 bool ReadLEInt (int & a_Value); - bool ReadPosition (int & a_BlockX, int & a_BlockY, int & a_BlockZ); + bool ReadPosition64 (int & a_BlockX, int & a_BlockY, int & a_BlockZ); - /** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */ + /** Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short, char, Byte, double, ...) */ template <typename T> bool ReadVarInt(T & a_Value) { - UInt32 v; - bool res = ReadVarInt(v); + UInt64 v; + bool res = ReadVarInt64(v); if (res) { - a_Value = v; + a_Value = static_cast<T>(v); } return res; } // Write the specified datatype; return true if successfully written - bool WriteChar (char a_Value); - bool WriteByte (unsigned char a_Value); - bool WriteBEShort (short a_Value); - bool WriteBEUShort (unsigned short a_Value); - bool WriteBEInt (int a_Value); + bool WriteBEInt8 (Int8 a_Value); + bool WriteBEInt16 (Int16 a_Value); + bool WriteBEInt32 (Int32 a_Value); bool WriteBEInt64 (Int64 a_Value); + bool WriteBEUInt8 (UInt8 a_Value); + bool WriteBEUInt16 (UInt16 a_Value); + bool WriteBEUInt32 (UInt32 a_Value); + bool WriteBEUInt64 (UInt64 a_Value); bool WriteBEFloat (float a_Value); bool WriteBEDouble (double a_Value); bool WriteBool (bool a_Value); - bool WriteVarInt (UInt32 a_Value); + bool WriteVarInt32 (UInt32 a_Value); + bool WriteVarInt64 (UInt64 a_Value); bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 - bool WriteLEInt (int a_Value); - bool WritePosition (int a_BlockX, int a_BlockY, int a_BlockZ); + bool WriteLEInt32 (Int32 a_Value); + bool WritePosition64 (Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ); /** Reads a_Count bytes into a_Buffer; returns true if successful */ bool ReadBuf(void * a_Buffer, size_t a_Count); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c39f5f6e6..b91c4f65a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,7 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings - WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs + WorldStorage Mobs Entities Simulator BlockEntities UI Generating/Prefabs Noise ) @@ -318,7 +318,7 @@ if (NOT MSVC) target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks Noise Protocol Generating Generating_Prefabs WorldStorage - Mobs Entities Simulator UI BlockEntities PolarSSL++ + Mobs Entities Simulator BlockEntities UI PolarSSL++ ) endif () if (WIN32) diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index 648a5711b..19156b537 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -101,9 +101,9 @@ local g_ViolationPatterns = {"&&[^(]+!=", "Add parenthesis around comparison"}, {"!=[^)]+||", "Add parenthesis around comparison"}, {"||[^(]+!=", "Add parenthesis around comparison"}, - {"<[^)T][^)]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)" - {"&&[^(]+<", "Add parenthesis around comparison"}, - {"<[^)T][^)]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)" + {"<[^)>]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)" + -- Cannot check a < following a && due to functions of the form x fn(y&& a, z<b> c) + {"<[^)>]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)" {"||[^(]+<", "Add parenthesis around comparison"}, -- Cannot check ">" because of "obj->m_Flag &&". Check at least ">=": {">=[^)]+&&", "Add parenthesis around comparison"}, diff --git a/src/Chunk.cpp b/src/Chunk.cpp index e05fa4a99..95dc7708e 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -776,10 +776,22 @@ void cChunk::BroadcastPendingBlockChanges(void) { return; } - - for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr) + + if (m_PendingSendBlocks.size() >= 10240) + { + // Resend the full chunk + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr) + { + m_World->ForceSendChunkTo(m_PosX, m_PosZ, cChunkSender::E_CHUNK_PRIORITY_MEDIUM, (*itr)); + } + } + else { - (*itr)->SendBlockChanges(m_PosX, m_PosZ, m_PendingSendBlocks); + // Only send block changes + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr) + { + (*itr)->SendBlockChanges(m_PosX, m_PosZ, m_PendingSendBlocks); + } } m_PendingSendBlocks.clear(); } @@ -919,7 +931,7 @@ void cChunk::ApplyWeatherToTop() FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1); } } - else if (cBlockInfo::IsSnowable(TopBlock) && (Height + 1 < cChunkDef::Height)) + else if (cBlockInfo::IsSnowable(TopBlock) && (Height < cChunkDef::Height - 1)) { SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0); } @@ -1241,7 +1253,7 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - if ((a_RelY < 0) || (a_RelY > cChunkDef::Height)) + if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height)) { LOGWARNING("UnboundedRelSetBlock(): requesting a block with a_RelY out of range: %d", a_RelY); return false; @@ -1262,7 +1274,7 @@ bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - if ((a_RelY < 0) || (a_RelY > cChunkDef::Height)) + if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height)) { LOGWARNING("UnboundedRelFastSetBlock(): requesting a block with a_RelY out of range: %d", a_RelY); return false; @@ -1957,7 +1969,7 @@ void cChunk::RemoveEntity(cEntity * a_Entity) -bool cChunk::HasEntity(int a_EntityID) +bool cChunk::HasEntity(UInt32 a_EntityID) { for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) { @@ -2015,7 +2027,7 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ -bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult) +bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult) { // The entity list is locked by the parent chunkmap's CS for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) @@ -2802,7 +2814,7 @@ void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char -void cChunk::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude) +void cChunk::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude) { for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { @@ -2810,7 +2822,7 @@ void cChunk::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_bl { continue; } - (*itr)->SendBlockBreakAnim(a_entityID, a_blockX, a_blockY, a_blockZ, a_stage); + (*itr)->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage); } // for itr - LoadedByClient[] } diff --git a/src/Chunk.h b/src/Chunk.h index 1ce862371..e8c60a74b 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -241,7 +241,7 @@ public: void AddEntity(cEntity * a_Entity); void RemoveEntity(cEntity * a_Entity); - bool HasEntity(int a_EntityID); + bool HasEntity(UInt32 a_EntityID); /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible @@ -251,7 +251,7 @@ public: bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible /** 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. */ - bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible + bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible /** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */ bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible @@ -317,7 +317,7 @@ public: // (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 = nullptr); - void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr); + void BroadcastBlockBreakAnimation(UInt32 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); diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp index 57b27c5e0..80f40d39e 100644 --- a/src/ChunkData.cpp +++ b/src/ChunkData.cpp @@ -361,7 +361,7 @@ void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Lengt } else { - memset(&a_Dest[(i * SectionBlockCount) - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy); + memset(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy); } } } diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 2dd04f801..87da86131 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -373,19 +373,19 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c -void cChunkMap::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude) +void cChunkMap::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_blockX, a_blockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == nullptr) { return; } // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->BroadcastBlockBreakAnimation(a_entityID, a_blockX, a_blockY, a_blockZ, a_stage, a_Exclude); + Chunk->BroadcastBlockBreakAnimation(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage, a_Exclude); } @@ -1322,10 +1322,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) { cChunkInterface ChunkInterface(this); - if (a_BlockType == E_BLOCK_AIR) - { - BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ); - } + BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ); int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); @@ -1756,7 +1753,7 @@ void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) -bool cChunkMap::HasEntity(int a_UniqueID) +bool cChunkMap::HasEntity(UInt32 a_UniqueID) { cCSLock Lock(m_CSLayers); for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) @@ -2048,7 +2045,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ -bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) +bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback) { cCSLock Lock(m_CSLayers); bool res = false; @@ -2999,7 +2996,7 @@ bool cChunkMap::cChunkLayer::ForEachEntity(cEntityCallback & a_Callback) -bool cChunkMap::cChunkLayer::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn) +bool cChunkMap::cChunkLayer::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn) { // 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++) @@ -3019,7 +3016,7 @@ bool cChunkMap::cChunkLayer::DoWithEntityByID(int a_EntityID, cEntityCallback & -bool cChunkMap::cChunkLayer::HasEntity(int a_EntityID) +bool cChunkMap::cChunkLayer::HasEntity(UInt32 a_EntityID) { for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { diff --git a/src/ChunkMap.h b/src/ChunkMap.h index f08d02337..0fac79c84 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -71,7 +71,7 @@ public: // (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 = nullptr); - void BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude = nullptr); + void BroadcastBlockBreakAnimation(UInt32 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 = nullptr); void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); @@ -217,7 +217,7 @@ public: void AddEntityIfNotPresent(cEntity * a_Entity); /** Returns true if the entity with specified ID is present in the chunks */ - bool HasEntity(int a_EntityID); + bool HasEntity(UInt32 a_EntityID); /** Removes the entity from its appropriate chunk */ void RemoveEntity(cEntity * a_Entity); @@ -236,61 +236,80 @@ public: /** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected); - /** 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 and callback returned false. */ - bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible + /** 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 and callback returned false. */ + bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback); // Lua-accessible - /** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */ + /** Calls the callback for each block entity in the specified chunk. + Returns true if all block entities processed, false if the callback aborted by returning true. */ bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Lua-accessible - /** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */ + /** Calls the callback for each chest in the specified chunk. + Returns true if all chests processed, false if the callback aborted by returning true. */ bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible - /** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */ + /** Calls the callback for each dispenser in the specified chunk. + Returns true if all dispensers processed, false if the callback aborted by returning true. */ bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); - /** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */ + /** Calls the callback for each dropper in the specified chunk. + Returns true if all droppers processed, false if the callback aborted by returning true. */ bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback); - /** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */ + /** Calls the callback for each dropspenser in the specified chunk. + Returns true if all dropspensers processed, false if the callback aborted by returning true. */ bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback); - /** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */ + /** Calls the callback for each furnace in the specified chunk. + Returns true if all furnaces processed, false if the callback aborted by returning true. */ bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Lua-accessible - /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ + /** Calls the callback for the block entity at the specified coords. + Returns false if there's no block entity at those coords, true if found. */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible - /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + /** Calls the callback for the beacon at the specified coords. + Returns false if there's no beacon at those coords, true if found. */ bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible - /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ + /** Calls the callback for the chest at the specified coords. + Returns false if there's no chest at those coords, true if found. */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible - /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ + /** Calls the callback for the dispenser at the specified coords. + Returns false if there's no dispenser at those coords or callback returns true, returns true if found. */ bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible - /** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ + /** Calls the callback for the dropper at the specified coords. + Returns false if there's no dropper at those coords or callback returns true, returns true if found. */ bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Lua-accessible - /** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ + /** Calls the callback for the dropspenser at the specified coords. + Returns false if there's no dropspenser at those coords or callback returns true, returns true if found. */ bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Lua-accessible - /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ + /** Calls the callback for the furnace at the specified coords. + Returns false if there's no furnace at those coords or callback returns true, returns true if found. */ bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible - /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ + /** Calls the callback for the noteblock at the specified coords. + Returns false if there's no noteblock at those coords or callback returns true, returns true if found. */ bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible - /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ + /** Calls the callback for the command block at the specified coords. + Returns false if there's no command block at those coords or callback returns true, returns true if found. */ bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible - /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ + /** Calls the callback for the mob head block at the specified coords. + Returns false if there's no mob head block at those coords or callback returns true, returns true if found. */ bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Lua-accessible - /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */ + /** Calls the callback for the flower pot at the specified coords. + Returns false if there's no flower pot at those coords or callback returns true, returns true if found. */ bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Lua-accessible - /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ + /** Retrieves the test on the sign at the specified coords. + Returns false if there's no sign at those coords, true if found. */ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible /** Touches the chunk, causing it to be loaded or generated */ @@ -423,10 +442,10 @@ private: bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible /** 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. */ - bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible + bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible /** Returns true if there is an entity with the specified ID within this layer's chunks */ - bool HasEntity(int a_EntityID); + bool HasEntity(UInt32 a_EntityID); protected: diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 2e0e86653..28fccb68e 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -12,12 +12,16 @@ #include "BlockEntities/CommandBlockEntity.h" #include "BlockEntities/SignEntity.h" #include "UI/Window.h" +#include "UI/AnvilWindow.h" +#include "UI/BeaconWindow.h" +#include "UI/EnchantingWindow.h" #include "Item.h" #include "Mobs/Monster.h" #include "ChatColor.h" #include "Items/ItemHandler.h" #include "Blocks/BlockHandler.h" #include "Blocks/BlockSlab.h" +#include "Blocks/BlockBed.h" #include "Blocks/ChunkInterface.h" #include "Root.h" @@ -672,7 +676,7 @@ bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Usernam -void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem) +void cClientHandle::HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_HeldItem, eClickAction a_ClickAction) { // This is for creative Inventory changes if (!m_Player->IsGameModeCreative()) @@ -686,18 +690,18 @@ void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_Hel return; } - m_Player->GetWindow()->Clicked(*m_Player, 0, a_SlotNum, (a_SlotNum >= 0) ? caLeftClick : caLeftClickOutside, a_HeldItem); + m_Player->GetWindow()->Clicked(*m_Player, 0, a_SlotNum, a_ClickAction, a_HeldItem); } -void cClientHandle::HandleEnchantItem(Byte a_WindowID, Byte a_Enchantment) +void cClientHandle::HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment) { if (a_Enchantment > 2) { - LOGWARNING("%s attempt to crash the server with invalid enchanting selection!", GetUsername().c_str()); + LOGWARNING("%s attempt to crash the server with invalid enchanting selection (%u)!", GetUsername().c_str(), a_Enchantment); Kick("Invalid enchanting!"); return; } @@ -947,7 +951,7 @@ void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, in -void cClientHandle::HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand) +void cClientHandle::HandleCommandBlockEntityChange(UInt32 a_EntityID, const AString & a_NewCommand) { // TODO LOGWARNING("%s: Not implemented yet", __FUNCTION__); @@ -974,7 +978,7 @@ void cClientHandle::HandleAnvilItemName(const AString & a_ItemName) -void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status) +void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status @@ -1002,6 +1006,12 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB int BlockY = a_BlockY; int BlockZ = a_BlockZ; AddFaceDirection(BlockX, BlockY, BlockZ, a_BlockFace); + + if ((BlockY < 0) || (BlockY >= cChunkDef::Height)) + { + return; + } + if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(BlockX, BlockY, BlockZ))->IsClickedThrough()) { a_BlockX = BlockX; @@ -1498,30 +1508,6 @@ void cClientHandle::HandleAnimation(int a_Animation) return; } - // Because the animation ID sent to servers by clients are different to those sent back, we need this - switch (a_Animation) - { - case 0: // No animation - wiki.vg doesn't say that client has something specific for it, so I suppose it will just become -1 - case 1: - case 2: - case 3: - { - a_Animation--; // Offset by -1 - break; - } - case 5: - case 6: - case 7: - { - a_Animation -= 2; // Offset by -2 - break; - } - default: // Anything else is the same - { - break; - } - } - m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, a_Animation, this); } @@ -1529,7 +1515,7 @@ void cClientHandle::HandleAnimation(int a_Animation) -void cClientHandle::HandleSlotSelected(short a_SlotNum) +void cClientHandle::HandleSlotSelected(Int16 a_SlotNum) { m_Player->GetInventory().SetEquippedSlotNum(a_SlotNum); m_Player->GetWorld()->BroadcastEntityEquipment(*m_Player, 0, m_Player->GetInventory().GetEquippedItem(), this); @@ -1548,7 +1534,7 @@ void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways) -void cClientHandle::HandleWindowClose(char a_WindowID) +void cClientHandle::HandleWindowClose(UInt8 a_WindowID) { m_Player->CloseWindowIfID(a_WindowID); } @@ -1557,7 +1543,7 @@ void cClientHandle::HandleWindowClose(char a_WindowID) -void cClientHandle::HandleWindowClick(char a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem) +void cClientHandle::HandleWindowClick(UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem) { LOGD("WindowClick: WinID %d, SlotNum %d, action: %s, Item %s x %d", a_WindowID, a_SlotNum, ClickActionToString(a_ClickAction), @@ -1595,7 +1581,7 @@ void cClientHandle::HandleUpdateSign( -void cClientHandle::HandleUseEntity(int a_TargetEntityID, bool a_IsLeftClick) +void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick) { // TODO: Let plugins interfere via a hook @@ -1740,7 +1726,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username) -void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching) +void cClientHandle::HandleEntityCrouch(UInt32 a_EntityID, bool a_IsCrouching) { if (a_EntityID != m_Player->GetUniqueID()) { @@ -1755,7 +1741,7 @@ void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching) -void cClientHandle::HandleEntityLeaveBed(int a_EntityID) +void cClientHandle::HandleEntityLeaveBed(UInt32 a_EntityID) { if (a_EntityID != m_Player->GetUniqueID()) { @@ -1763,14 +1749,16 @@ void cClientHandle::HandleEntityLeaveBed(int a_EntityID) return; } - m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2); + cChunkInterface Interface(GetPlayer()->GetWorld()->GetChunkMap()); + cBlockBedHandler::SetBedOccupationState(Interface, GetPlayer()->GetLastBedPos(), false); + GetPlayer()->SetIsInBed(false); } -void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting) +void cClientHandle::HandleEntitySprinting(UInt32 a_EntityID, bool a_IsSprinting) { if (a_EntityID != m_Player->GetUniqueID()) { @@ -2042,7 +2030,7 @@ void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, ch -void cClientHandle::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) +void cClientHandle::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { m_Protocol->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 8129d6a50..9e5287985 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -144,7 +144,7 @@ public: // tolua_export // (Please keep these alpha-sorted) void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType); - void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage); + void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage); void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // tolua_export void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes); void SendChat (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = ""); @@ -276,16 +276,18 @@ public: // tolua_export /** 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 HandleCommandBlockEntityChange(UInt32 a_EntityID, const AString & a_NewCommand); - void HandleCreativeInventory (short a_SlotNum, const cItem & a_HeldItem); + /** Called when the client clicks the creative inventory window. + a_ClickAction specifies whether the click was inside the window or not (caLeftClick or caLeftClickOutside). */ + void HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_HeldItem, eClickAction a_ClickAction); /** Called when the player enchants an Item in the Enchanting table UI. */ - void HandleEnchantItem(Byte a_WindowID, Byte a_Enchantment); + void HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment); - void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching); - void HandleEntityLeaveBed (int a_EntityID); - void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting); + void HandleEntityCrouch (UInt32 a_EntityID, bool a_IsCrouching); + void HandleEntityLeaveBed (UInt32 a_EntityID); + void HandleEntitySprinting (UInt32 a_EntityID, bool a_IsSprinting); /** Kicks the client if the same username is already logged in. Returns false if the client has been kicked, true otherwise. */ @@ -298,7 +300,7 @@ public: // tolua_export bool HandleHandshake (const AString & a_Username); void HandleKeepAlive (int a_KeepAliveID); - void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status); + void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status); /** Called when the protocol receives a MC|TrSel packet, indicating that the player used a trade in the NPC UI. */ @@ -312,7 +314,7 @@ public: // tolua_export void HandlePluginMessage (const AString & a_Channel, const AString & a_Message); void HandleRespawn (void); void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem); - void HandleSlotSelected (short a_SlotNum); + void HandleSlotSelected (Int16 a_SlotNum); void HandleSteerVehicle (float Forward, float Sideways); void HandleTabCompletion (const AString & a_Text); void HandleUpdateSign ( @@ -321,9 +323,9 @@ public: // tolua_export const AString & a_Line3, const AString & a_Line4 ); void HandleUnmount (void); - void HandleUseEntity (int a_TargetEntityID, bool a_IsLeftClick); - void HandleWindowClick (char a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem); - void HandleWindowClose (char a_WindowID); + void HandleUseEntity (UInt32 a_TargetEntityID, bool a_IsLeftClick); + void HandleWindowClick (UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem); + void HandleWindowClose (UInt8 a_WindowID); /** Called when the protocol has finished logging the user in. Return true to allow the user in; false to kick them. diff --git a/src/Endianness.h b/src/Endianness.h index 9aeb44986..ed9637fcc 100644 --- a/src/Endianness.h +++ b/src/Endianness.h @@ -2,7 +2,7 @@ #pragma once #undef ntohll -#define ntohll(x) ((((UInt64)ntohl((u_long)x)) << 32) + ntohl(x >> 32)) +#define ntohll(x) ((((UInt64)ntohl((UInt32)x)) << 32) + ntohl(x >> 32)) @@ -11,10 +11,10 @@ // Changes endianness inline UInt64 HostToNetwork8(const void * a_Value) { - unsigned long long __HostToNetwork8; - memcpy( &__HostToNetwork8, a_Value, sizeof( __HostToNetwork8)); - __HostToNetwork8 = (( ( (unsigned long long)htonl((u_long)__HostToNetwork8)) << 32) + htonl(__HostToNetwork8 >> 32)); - return __HostToNetwork8; + UInt64 buf; + memcpy( &buf, a_Value, sizeof( buf)); + buf = (( ( (UInt64)htonl((UInt32)buf)) << 32) + htonl(buf >> 32)); + return buf; } @@ -23,10 +23,10 @@ inline UInt64 HostToNetwork8(const void * a_Value) inline UInt32 HostToNetwork4(const void* a_Value) { - unsigned int __HostToNetwork4; - memcpy( &__HostToNetwork4, a_Value, sizeof( __HostToNetwork4)); - __HostToNetwork4 = ntohl( __HostToNetwork4); - return __HostToNetwork4; + UInt32 buf; + memcpy( &buf, a_Value, sizeof( buf)); + buf = ntohl( buf); + return buf; } @@ -59,6 +59,18 @@ inline Int64 NetworkToHostLong8(const void * a_Value) +inline UInt64 NetworkToHostULong8(const void * a_Value) +{ + UInt64 buf; + memcpy(&buf, a_Value, 8); + buf = ntohll(buf); + return buf; +} + + + + + inline float NetworkToHostFloat4(const void * a_Value) { UInt32 buf; diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 0fbbfb681..3c1fabb1b 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -72,14 +72,8 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001)) - { - SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later - } - Vector3d Hit = a_HitPos; - Vector3d SinkMovement = (GetSpeed() / 1000); - Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside) + Hit += GetSpeed().NormalizeCopy() / 100000; // Make arrow sink into block a bit so it lodges (TODO: investigate how to stop them going so far so that they become black clientside) super::OnHitSolidBlock(Hit, a_HitFace); Vector3i BlockHit = Hit.Floor(); @@ -195,11 +189,6 @@ void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) if (m_IsInGround) { - // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL - // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) - // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync - // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position - if (!m_HasTeleported) // Sent a teleport already, don't do again { if (m_HitGroundTimer > std::chrono::milliseconds(500)) diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp index 6d8b4ef31..6177eb32f 100644 --- a/src/Entities/Boat.cpp +++ b/src/Entities/Boat.cpp @@ -98,7 +98,7 @@ void cBoat::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) SetSpeed(GetSpeed() * 0.97); // Slowly decrease the speed - if ((POSY_TOINT < 0) || (POSY_TOINT > cChunkDef::Height)) + if ((POSY_TOINT < 0) || (POSY_TOINT >= cChunkDef::Height)) { return; } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 1bc4690e1..c8df6b4b1 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -18,49 +18,50 @@ -int cEntity::m_EntityCount = 0; +UInt32 cEntity::m_EntityCount = 0; cCriticalSection cEntity::m_CSCount; -cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) - : m_UniqueID(0) - , m_Health(1) - , m_MaxHealth(1) - , m_AttachedTo(nullptr) - , m_Attachee(nullptr) - , m_bDirtyHead(true) - , m_bDirtyOrientation(true) - , m_bHasSentNoSpeed(true) - , m_bOnGround(false) - , m_Gravity(-9.81f) - , m_LastPos(a_X, a_Y, a_Z) - , m_IsInitialized(false) - , m_WorldTravellingFrom(nullptr) - , m_EntityType(a_EntityType) - , m_World(nullptr) - , m_IsFireproof(false) - , m_TicksSinceLastBurnDamage(0) - , m_TicksSinceLastLavaDamage(0) - , m_TicksSinceLastFireDamage(0) - , m_TicksLeftBurning(0) - , m_TicksSinceLastVoidDamage(0) - , m_IsSwimming(false) - , m_IsSubmerged(false) - , m_AirLevel(0) - , m_AirTickTimer(0) - , m_TicksAlive(0) - , m_HeadYaw(0.0) - , m_Rot(0.0, 0.0, 0.0) - , m_Pos(a_X, a_Y, a_Z) - , m_WaterSpeed(0, 0, 0) - , m_Mass (0.001) // Default 1g - , m_Width(a_Width) - , m_Height(a_Height) - , m_InvulnerableTicks(0) -{ +cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height): + m_UniqueID(INVALID_ID), // Proper ID will be assigned later in the constructor code + m_Health(1), + m_MaxHealth(1), + m_AttachedTo(nullptr), + m_Attachee(nullptr), + m_bDirtyHead(true), + m_bDirtyOrientation(true), + m_bHasSentNoSpeed(true), + m_bOnGround(false), + m_Gravity(-9.81f), + m_LastPos(a_X, a_Y, a_Z), + m_IsInitialized(false), + m_WorldTravellingFrom(nullptr), + m_EntityType(a_EntityType), + m_World(nullptr), + m_IsFireproof(false), + m_TicksSinceLastBurnDamage(0), + m_TicksSinceLastLavaDamage(0), + m_TicksSinceLastFireDamage(0), + m_TicksLeftBurning(0), + m_TicksSinceLastVoidDamage(0), + m_IsSwimming(false), + m_IsSubmerged(false), + m_AirLevel(0), + m_AirTickTimer(0), + m_TicksAlive(0), + m_HeadYaw(0.0), + m_Rot(0.0, 0.0, 0.0), + m_Pos(a_X, a_Y, a_Z), + m_WaterSpeed(0, 0, 0), + m_Mass (0.001), // Default 1g + m_Width(a_Width), + m_Height(a_Height), + m_InvulnerableTicks(0) +{ + // Assign a proper ID: cCSLock Lock(m_CSCount); m_EntityCount++; m_UniqueID = m_EntityCount; @@ -1263,7 +1264,7 @@ bool cEntity::DetectPortal() { if (GetWorld()->GetDimension() == dimOverworld) { - if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty()) + if (GetWorld()->GetLinkedNetherWorldName().empty() && GetWorld()->GetLinkedEndWorldName().empty()) { // Teleportation to either dimension not enabled, don't bother proceeding return false; @@ -1314,7 +1315,7 @@ bool cEntity::DetectPortal() } else { - if (GetWorld()->GetNetherWorldName().empty()) + if (GetWorld()->GetLinkedNetherWorldName().empty()) { return false; } @@ -1327,7 +1328,7 @@ bool cEntity::DetectPortal() ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); } - return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedNetherWorldName(), dimNether, GetWorld()->GetName()), false); } } case E_BLOCK_END_PORTAL: @@ -1358,7 +1359,7 @@ bool cEntity::DetectPortal() } else { - if (GetWorld()->GetEndWorldName().empty()) + if (GetWorld()->GetLinkedEndWorldName().empty()) { return false; } @@ -1371,7 +1372,7 @@ bool cEntity::DetectPortal() ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); } - return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedEndWorldName(), dimEnd, GetWorld()->GetName()), false); } } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 809e974d2..9bb1837f1 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -142,6 +142,10 @@ public: static const int VOID_BOUNDARY = -46; ///< Y position to begin applying void damage static const int FALL_DAMAGE_HEIGHT = 4; ///< Y difference after which fall damage is applied + + /** Special ID that is considered an "invalid value", signifying no entity. */ + static const UInt32 INVALID_ID = 0; // Exported to Lua in ManualBindings.cpp, ToLua doesn't parse initialized constants. + cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); virtual ~cEntity(); @@ -248,7 +252,7 @@ public: virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways); void SteerVehicle(float a_Forward, float a_Sideways); - inline int GetUniqueID(void) const { return m_UniqueID; } + inline UInt32 GetUniqueID(void) const { return m_UniqueID; } inline bool IsDestroyed(void) const { return !m_IsInitialized; } /// Schedules the entity for destroying; if a_ShouldBroadcast is set to true, broadcasts the DestroyEntity packet @@ -464,12 +468,15 @@ public: protected: static cCriticalSection m_CSCount; - static int m_EntityCount; + static UInt32 m_EntityCount; /** Measured in meter/second (m/s) */ Vector3d m_Speed; - int m_UniqueID; + /** The ID of the entity that is guaranteed to be unique within a single run of the server. + Always nonzero (a zero UniqueID (cEntity::INVALID_ID) is used for error reporting). + Note that the UniqueID is not persisted through storage. */ + UInt32 m_UniqueID; int m_Health; int m_MaxHealth; diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index 75105a0cd..7301a3c9d 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -77,7 +77,10 @@ void cFallingBlock::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) ); */ - cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta); + if (BlockY < cChunkDef::Height - 1) + { + cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta); + } Destroy(true); return; } diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp index a6b9c40c8..a37d8702e 100644 --- a/src/Entities/HangingEntity.cpp +++ b/src/Entities/HangingEntity.cpp @@ -11,7 +11,7 @@ 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) + m_Facing(cHangingEntity::BlockFaceToProtocolFace(a_Facing)) { SetMaxHealth(1); SetHealth(1); @@ -21,60 +21,9 @@ cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_Facing, do -void cHangingEntity::SetFacing(eBlockFace a_Facing) -{ - // Y-based faces are not allowed: - switch (a_Facing) - { - 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_Facing = a_Facing; -} - - - - - 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_Facing) - { - case BLOCK_FACE_ZP: Dir = 0; break; - case BLOCK_FACE_ZM: Dir = 2; break; - case BLOCK_FACE_XM: Dir = 1; break; - case BLOCK_FACE_XP: Dir = 3; break; - default: - { - 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; - } - } - - if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180 - { - SetYaw((Dir * 90) - 180); - } - else - { - SetYaw(Dir * 90); - } - - a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch()); - a_ClientHandle.SendEntityMetadata(*this); + SetYaw(GetProtocolFacing() * 90); } diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h index d1ef79a68..507502ac6 100644 --- a/src/Entities/HangingEntity.h +++ b/src/Entities/HangingEntity.h @@ -24,28 +24,82 @@ public: // tolua_begin /** Returns the direction in which the entity is facing. */ - eBlockFace GetFacing() const { return m_Facing; } - + eBlockFace GetFacing() const { return cHangingEntity::ProtocolFaceToBlockFace(m_Facing); } + /** Set the direction in which the entity is facing. */ - void SetFacing(eBlockFace a_Facing); - - /** Returns the X coord of the block in which the entity resides. */ - int GetBlockX() const { return POSX_TOINT; } - - /** Returns the Y coord of the block in which the entity resides. */ - int GetBlockY() const { return POSY_TOINT; } - - /** Returns the Z coord of the block in which the entity resides. */ - int GetBlockZ() const { return POSZ_TOINT; } + void SetFacing(eBlockFace a_Facing) { m_Facing = cHangingEntity::BlockFaceToProtocolFace(a_Facing); } // tolua_end -private: + /** Returns the direction in which the entity is facing. */ + Byte GetProtocolFacing() const { return m_Facing; } - virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override {} + /** Set the direction in which the entity is facing. */ + void SetProtocolFacing(Byte a_Facing) + { + ASSERT((a_Facing <= 3) && (a_Facing >= 0)); + m_Facing = a_Facing; + } - eBlockFace m_Facing; +protected: + + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; + virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override + { + UNUSED(a_Dt); + UNUSED(a_Chunk); + } + + /** Converts protocol hanging item facing to eBlockFace values */ + inline static eBlockFace ProtocolFaceToBlockFace(Byte a_ProtocolFace) + { + eBlockFace Dir; + + // 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 (a_ProtocolFace) + { + case 0: Dir = BLOCK_FACE_ZP; break; + case 2: Dir = BLOCK_FACE_ZM; break; + case 1: Dir = BLOCK_FACE_XM; break; + case 3: Dir = BLOCK_FACE_XP; break; + default: + { + LOGINFO("Invalid facing (%d) in a cHangingEntity, adjusting to BLOCK_FACE_XP.", a_ProtocolFace); + ASSERT(!"Tried to convert a bad facing!"); + + Dir = cHangingEntity::ProtocolFaceToBlockFace(3); + } + } + + return Dir; + } + + /** Converts eBlockFace values to protocol hanging item faces */ + inline static Byte BlockFaceToProtocolFace(eBlockFace a_BlockFace) + { + Byte Dir; + + // 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 (a_BlockFace) + { + case BLOCK_FACE_ZP: Dir = 0; break; + case BLOCK_FACE_ZM: Dir = 2; break; + case BLOCK_FACE_XM: Dir = 1; break; + case BLOCK_FACE_XP: Dir = 3; break; + default: + { + // Uncomment when entities are initialised with their real data, instead of dummy values: + // LOGINFO("Invalid facing (%d) in a cHangingEntity, adjusting to BLOCK_FACE_XP.", a_BlockFace); + // ASSERT(!"Tried to convert a bad facing!"); + + Dir = cHangingEntity::BlockFaceToProtocolFace(BLOCK_FACE_XP); + } + } + + return Dir; + } + + Byte m_Facing; }; // tolua_export diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp index dfffcd3ed..4e6e38f1f 100644 --- a/src/Entities/ItemFrame.cpp +++ b/src/Entities/ItemFrame.cpp @@ -92,3 +92,14 @@ void cItemFrame::GetDrops(cItems & a_Items, cEntity * a_Killer) + +void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle) +{ + super::SpawnOn(a_ClientHandle); + a_ClientHandle.SendSpawnObject(*this, 71, GetProtocolFacing(), (Byte)GetYaw(), (Byte)GetPitch()); + a_ClientHandle.SendEntityMetadata(*this); +} + + + + diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h index ced8c37af..ff43e5ee1 100644 --- a/src/Entities/ItemFrame.h +++ b/src/Entities/ItemFrame.h @@ -24,7 +24,7 @@ public: // tolua_begin /** Returns the item in the frame */ - const cItem & GetItem(void) { return m_Item; } + const cItem & GetItem(void) const { return m_Item; } /** Set the item in the frame */ void SetItem(cItem & a_Item) { m_Item = a_Item; } @@ -42,6 +42,7 @@ private: virtual void OnRightClicked(cPlayer & a_Player) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; cItem m_Item; Byte m_ItemRotation; diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 776f957f4..ee10cf6b3 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -11,6 +11,7 @@ #include "../Chunk.h" #include "Player.h" #include "../BoundingBox.h" +#include "../UI/MinecartWithChestWindow.h" #define NO_SPEED 0.0 #define MAX_SPEED 8 @@ -23,7 +24,7 @@ class cMinecartCollisionCallback : public cEntityCallback { public: - cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, int a_UniqueID, int a_AttacheeUniqueID) : + cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, UInt32 a_UniqueID, UInt32 a_AttacheeUniqueID) : m_DoesInteserct(false), m_CollidedEntityPos(0, 0, 0), m_Pos(a_Pos), @@ -76,8 +77,8 @@ protected: Vector3d m_Pos; double m_Height, m_Width; - int m_UniqueID; - int m_AttacheeUniqueID; + UInt32 m_UniqueID; + UInt32 m_AttacheeUniqueID; }; @@ -823,7 +824,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) { - cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == nullptr) ? -1 : m_Attachee->GetUniqueID())); + cMinecartCollisionCallback MinecartCollisionCallback( + GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), + ((m_Attachee == nullptr) ? cEntity::INVALID_ID : m_Attachee->GetUniqueID()) + ); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback); diff --git a/src/Entities/Painting.cpp b/src/Entities/Painting.cpp index 6f6277f28..02a8f6ed0 100644 --- a/src/Entities/Painting.cpp +++ b/src/Entities/Painting.cpp @@ -10,10 +10,9 @@ -cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z) - : cEntity(etPainting, a_X, a_Y, a_Z, 1, 1), - m_Name(a_Name), - m_Direction(a_Direction) +cPainting::cPainting(const AString & a_Name, eBlockFace a_Direction, double a_X, double a_Y, double a_Z) + : cHangingEntity(etPainting, a_Direction, a_X, a_Y, a_Z), + m_Name(a_Name) { } @@ -24,6 +23,7 @@ cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double void cPainting::SpawnOn(cClientHandle & a_Client) { + super::SpawnOn(a_Client); a_Client.SendPaintingSpawn(*this); } @@ -31,16 +31,6 @@ void cPainting::SpawnOn(cClientHandle & a_Client) -void cPainting::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) -{ - UNUSED(a_Dt); - UNUSED(a_Chunk); -} - - - - - void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer) { if ((a_Killer != nullptr) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h index 6e8a382fc..20968d4f0 100644 --- a/src/Entities/Painting.h +++ b/src/Entities/Painting.h @@ -1,7 +1,7 @@ #pragma once -#include "Entity.h" +#include "HangingEntity.h" @@ -9,9 +9,9 @@ // tolua_begin class cPainting : - public cEntity + public cHangingEntity { - typedef cEntity super; + typedef cHangingEntity super; public: @@ -19,19 +19,14 @@ public: CLASS_PROTODEF(cPainting) - cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z); + cPainting(const AString & a_Name, eBlockFace a_Direction, double a_X, double a_Y, double a_Z); - // tolua_begin - - const AString & GetName(void) const { return m_Name; } - int GetDirection(void) const { return m_Direction; } - - // tolua_end + /** Returns the protocol name of the painting */ + const AString & GetName(void) const { return m_Name; } // tolua_export private: virtual void SpawnOn(cClientHandle & a_Client) override; - virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override { @@ -40,7 +35,6 @@ private: } AString m_Name; - int m_Direction; }; // tolua_export diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 0d36d0b23..c89e7b87c 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -5,7 +5,7 @@ #include <unordered_map> #include "../ChatColor.h" #include "../Server.h" -#include "../UI/Window.h" +#include "../UI/InventoryWindow.h" #include "../UI/WindowOwner.h" #include "../World.h" #include "../Bindings/PluginManager.h" diff --git a/src/Entities/Player.h b/src/Entities/Player.h index e02c66bd3..3dae58dc1 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -314,8 +314,18 @@ public: // tolua_end - /** Sets a player's in-bed state; we can't be sure plugins will keep this value updated, so no exporting */ - void SetIsInBed(bool a_Flag) { m_bIsInBed = a_Flag; } + /** Sets a player's in-bed state + We can't be sure plugins will keep this value updated, so no exporting + If value is false (not in bed), will update players of the fact that they have been ejected from the bed + */ + void SetIsInBed(bool a_Flag) + { + m_bIsInBed = a_Flag; + if (!a_Flag) + { + GetWorld()->BroadcastEntityAnimation(*this, 2); + } + } /** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */ void StartEating(void); diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 4f20bfae6..4684e3e09 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -221,7 +221,7 @@ 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 != nullptr) ? a_Creator->GetUniqueID() : -1), + ((a_Creator != nullptr) ? a_Creator->GetUniqueID() : cEntity::INVALID_ID), ((a_Creator != nullptr) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : ""), ((a_Creator != nullptr) ? a_Creator->GetEquippedWeapon().m_Enchantments : cEnchantments()) ), @@ -334,12 +334,7 @@ AString cProjectileEntity::GetMCAClassName(void) const void cProjectileEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - - // TODO: see BroadcastMovementUpdate; RelativeMove packet jerkiness affects projectiles too (cause of sympton described in cArrowEntity::Tick()) - if (GetProjectileKind() != pkArrow) - { - BroadcastMovementUpdate(); - } + BroadcastMovementUpdate(); } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 93e442d8c..de460a8ad 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -69,7 +69,7 @@ public: /** Returns the unique ID of the entity who created this projectile May return an ID <0 */ - int GetCreatorUniqueID(void) { return m_CreatorData.m_UniqueID; } + UInt32 GetCreatorUniqueID(void) { return m_CreatorData.m_UniqueID; } /** Returns the name of the player that created the projectile Will be empty for non-player creators @@ -90,18 +90,17 @@ public: protected: /** A structure that stores the Entity ID and Playername of the projectile's creator - Used to migitate invalid pointers caused by the creator being destroyed - */ + Used to migitate invalid pointers caused by the creator being destroyed. */ struct CreatorData { - CreatorData(int a_UniqueID, const AString & a_Name, const cEnchantments & a_Enchantments) : + CreatorData(UInt32 a_UniqueID, const AString & a_Name, const cEnchantments & a_Enchantments) : m_UniqueID(a_UniqueID), m_Name(a_Name), m_Enchantments(a_Enchantments) { } - const int m_UniqueID; + const UInt32 m_UniqueID; AString m_Name; cEnchantments m_Enchantments; }; @@ -110,8 +109,7 @@ 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 nullptr (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 */ diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp index 515dc25ea..737b13535 100644 --- a/src/FastRandom.cpp +++ b/src/FastRandom.cpp @@ -6,6 +6,12 @@ #include "Globals.h" #include "FastRandom.h" +#ifdef _WIN32 + #define thread_local __declspec(thread) +#endif + +thread_local unsigned int m_Counter = 0; + @@ -86,7 +92,7 @@ public: cFastRandom::cFastRandom(void) : - m_LinearRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count())) + m_LinearRand(m_Counter++) { } @@ -105,18 +111,6 @@ int cFastRandom::NextInt(int a_Range) -int cFastRandom::NextInt(int a_Range, int a_Salt) -{ - m_LinearRand.seed(a_Salt); - std::uniform_int_distribution<> distribution(0, a_Range - 1); - return distribution(m_LinearRand); -} - - - - - - float cFastRandom::NextFloat(float a_Range) { std::uniform_real_distribution<float> distribution(0, a_Range); @@ -128,18 +122,6 @@ float cFastRandom::NextFloat(float a_Range) -float cFastRandom::NextFloat(float a_Range, int a_Salt) -{ - m_LinearRand.seed(a_Salt); - std::uniform_real_distribution<float> distribution(0, a_Range); - return distribution(m_LinearRand); -} - - - - - - int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End) { std::uniform_int_distribution<> distribution(a_Begin, a_End); @@ -154,7 +136,7 @@ int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End) // MTRand: MTRand::MTRand() : - m_MersenneRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count())) + m_MersenneRand(m_Counter++) { } diff --git a/src/FastRandom.h b/src/FastRandom.h index 64a087c97..30395a293 100644 --- a/src/FastRandom.h +++ b/src/FastRandom.h @@ -36,16 +36,10 @@ public: /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M */ int NextInt(int a_Range); - - /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness */ - int NextInt(int a_Range, int a_Salt); /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M */ float NextFloat(float a_Range); - /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness */ - float NextFloat(float a_Range, int a_Salt); - /** Returns a random float between 0 and 1. */ float NextFloat(void) { return NextFloat(1); } diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 112aa8146..ea952a852 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -291,6 +291,22 @@ const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_In +bool cFurnaceRecipe::IsFuel(const cItem & a_Item) const +{ + for (auto & Fuel : m_pState->Fuel) + { + if ((Fuel.In->m_ItemType == a_Item.m_ItemType) && (Fuel.In->m_ItemCount <= a_Item.m_ItemCount)) + { + return true; + } + } + return false; +} + + + + + int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const { int BestFuel = 0; diff --git a/src/FurnaceRecipe.h b/src/FurnaceRecipe.h index 936ef706d..912b6aba2 100644 --- a/src/FurnaceRecipe.h +++ b/src/FurnaceRecipe.h @@ -34,6 +34,9 @@ public: /** Returns a recipe for the specified input, nullptr if no recipe found */ const cRecipe * GetRecipeFrom(const cItem & a_Ingredient) const; + + /** Returns true if the item is a fuel, false if not. */ + bool IsFuel(const cItem & a_Item) const; /** Returns the amount of time that the specified fuel burns, in ticks */ int GetBurnTime(const cItem & a_Fuel) const; diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp index 265db30ad..867155ad2 100644 --- a/src/Generating/BioGen.cpp +++ b/src/Generating/BioGen.cpp @@ -941,21 +941,21 @@ 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 - )))))))))))))); + + std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12) + | MakeIntGen<cIntGenZoom <10>>(a_Seed + 11) + | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 6) + | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5) + | MakeIntGen<cIntGenZoom <8>>(a_Seed + 10) + | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5) + | MakeIntGen<cIntGenZoom <8>>(a_Seed + 9) + | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5) + | MakeIntGen<cIntGenZoom <8>>(a_Seed + 8) + | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5) + | MakeIntGen<cIntGenZoom <9>>(a_Seed + 4) + | MakeIntGen<cIntGenRiver <7>>(a_Seed + 3) + | MakeIntGen<cIntGenZoom <10>>(a_Seed + 2) + | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 1); auto alteration = std::make_shared<cIntGenZoom <8>>(a_Seed, @@ -1000,9 +1000,9 @@ public: 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 - ))))))))))))))))))))))))))))))); + std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30) + | MakeIntGen<cIntGenZoom <6>> (a_Seed + 10) + ))))))))))))))))))))))))))))); m_Gen = std::make_shared<cIntGenSmooth <16>>(a_Seed, diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 260253d62..5839a4ccc 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -571,7 +571,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc) continue; } - if (!cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) && (Height < cChunkDef::Height - 1)) + if (!cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) || (Height >= cChunkDef::Height - 1)) { // The top block can't be snown over. continue; diff --git a/src/Generating/IntGen.h b/src/Generating/IntGen.h index b25e378c0..854563f41 100644 --- a/src/Generating/IntGen.h +++ b/src/Generating/IntGen.h @@ -31,6 +31,8 @@ by using templates. #include "../BiomeDef.h" +#include <tuple> + @@ -53,6 +55,9 @@ template <int SizeX, int SizeZ = SizeX> class cIntGen { public: + + typedef cIntGen<SizeX, SizeZ> IntGenType; + /** 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() {} @@ -62,9 +67,70 @@ public: /** 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; + +}; + +// Code adapted from http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer + +template<int... > +struct sSeq +{ +}; + +template<int N, int... S> +struct sGens : sGens<N - 1, N - 1, S...> +{ +}; + +template<int... S> +struct sGens<0, S...> +{ + typedef sSeq<S...> type; +}; + + +template<class Gen, class... Args> +class cIntGenFactory +{ + +public: + + typedef Gen Generator; + + cIntGenFactory(Args&&... a_args) : + m_args(std::make_tuple<Args...>(std::forward<Args>(a_args)...)) + { + } + + template <class LhsGen> + std::shared_ptr<Gen> construct(LhsGen&& a_Lhs) + { + return construct_impl<LhsGen>(std::forward<LhsGen>(a_Lhs), typename sGens<sizeof...(Args)>::type()); + } + + +private: + std::tuple<Args...> m_args; + + template <class LhsGen, int... S> + std::shared_ptr<Gen> construct_impl(LhsGen&& a_Lhs, sSeq<S...>) + { + return std::make_shared<Gen>(std::get<S>(m_args)..., std::forward<LhsGen>(a_Lhs)); + } + }; +template<class T, class RhsGen, class... Args> +std::shared_ptr<RhsGen> operator| (std::shared_ptr<T> a_Lhs, cIntGenFactory<RhsGen, Args...> a_Rhs) +{ + return a_Rhs.construct(static_cast<std::shared_ptr<typename T::IntGenType>>(a_Lhs)); +} +template<class Gen, class... Args> +cIntGenFactory<Gen, Args...> MakeIntGen(Args&&... a_Args) +{ + return cIntGenFactory<Gen, Args...>(std::forward<Args>(a_Args)...); +} @@ -688,7 +754,7 @@ public: int IdxZ = z * SizeX; for (int x = 0; x < SizeX; x++) { - int val = a_Values[x + IdxZ]; + size_t val = (size_t)a_Values[x + IdxZ]; const cBiomesInGroups & Biomes = (val > bgfRare) ? rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] : biomesInGroups[val % ARRAYCOUNT(biomesInGroups)]; diff --git a/src/Generating/ShapeGen.cpp b/src/Generating/ShapeGen.cpp index 45a9c3b93..43601ee20 100644 --- a/src/Generating/ShapeGen.cpp +++ b/src/Generating/ShapeGen.cpp @@ -41,7 +41,7 @@ public: { for (int x = 0; x < cChunkDef::Width; x++) { - HEIGHTTYPE height = cChunkDef::GetHeight(heightMap, x, z) + 1; + int height = cChunkDef::GetHeight(heightMap, x, z) + 1; Byte * shapeColumn = &(a_Shape[(x + 16 * z) * 256]); for (int y = 0; y < height; y++) { diff --git a/src/Globals.h b/src/Globals.h index 7c2ab38d8..bd180c08f 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -132,13 +132,15 @@ // Integral types with predefined sizes: -typedef long long Int64; -typedef int Int32; -typedef short Int16; +typedef signed long long Int64; +typedef signed int Int32; +typedef signed short Int16; +typedef signed char Int8; typedef unsigned long long UInt64; typedef unsigned int UInt32; typedef unsigned short UInt16; +typedef unsigned char UInt8; typedef unsigned char Byte; @@ -156,10 +158,12 @@ class SizeChecker<T, Size, true> template class SizeChecker<Int64, 8>; template class SizeChecker<Int32, 4>; template class SizeChecker<Int16, 2>; +template class SizeChecker<Int8, 1>; template class SizeChecker<UInt64, 8>; template class SizeChecker<UInt32, 4>; template class SizeChecker<UInt16, 2>; +template class SizeChecker<UInt8, 1>; // A macro to disallow the copy constructor and operator = functions // This should be used in the private: declarations for any class that shouldn't allow copying itself diff --git a/src/Inventory.h b/src/Inventory.h index 4e76bc0d3..311f64562 100644 --- a/src/Inventory.h +++ b/src/Inventory.h @@ -31,7 +31,9 @@ You can use the invArmorOffset, invInventoryOffset and invHotbarOffset constants */ class cInventory : + // tolua_end public cItemGrid::cListener + // tolua_begin { public: diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h index 71143d5a8..524c49a5c 100644 --- a/src/Items/ItemDoor.h +++ b/src/Items/ItemDoor.h @@ -34,7 +34,7 @@ public: AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Door (bottom block) can be placed in Y range of [1, 254]: - if ((a_BlockY < 1) || (a_BlockY + 2 >= cChunkDef::Height)) + if ((a_BlockY < 1) || (a_BlockY >= cChunkDef::Height - 2)) { return false; } diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index a2a77ce21..d6f2e24b4 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -21,30 +21,17 @@ 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 { - if (a_Dir == BLOCK_FACE_NONE) + if ((a_Dir == BLOCK_FACE_NONE) || (a_Dir == BLOCK_FACE_YM) || (a_Dir == BLOCK_FACE_YP)) { - // Client sends this if clicked on top or bottom face + // Paintings can't be flatly placed return false; } AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again if (Block == E_BLOCK_AIR) { - int Dir = 0; - - // The client uses different values for painting directions and block faces. Our constants are for the block faces, so we convert them here to painting faces - switch (a_Dir) - { - case BLOCK_FACE_ZP: break; // Initialised to zero - case BLOCK_FACE_ZM: Dir = 2; break; - case BLOCK_FACE_XM: Dir = 1; break; - case BLOCK_FACE_XP: Dir = 3; break; - default: ASSERT(!"Unhandled block face when trying spawn painting!"); return false; - } - static const struct // Define all the possible painting titles { AString Title; @@ -78,7 +65,7 @@ public: { "BurningSkull" } }; - cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, Dir, a_BlockX, a_BlockY, a_BlockZ); + cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_Dir, a_BlockX, a_BlockY, a_BlockZ); Painting->Initialize(*a_World); if (!a_Player->IsGameModeCreative()) diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h index 398ef6805..798573846 100644 --- a/src/Items/ItemPotion.h +++ b/src/Items/ItemPotion.h @@ -39,7 +39,7 @@ public: Vector3d Pos = a_Player->GetThrowStartPos(); Vector3d Speed = a_Player->GetLookVector() * 7; - if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity::pkSplashPotion, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0) + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity::pkSplashPotion, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID) { return false; } diff --git a/src/Items/ItemSlab.h b/src/Items/ItemSlab.h index 1b68b9d0c..b0b5ce005 100644 --- a/src/Items/ItemSlab.h +++ b/src/Items/ItemSlab.h @@ -44,8 +44,8 @@ public: NIBBLETYPE ClickedBlockMeta; a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlockType, ClickedBlockMeta); if ( - (ClickedBlockType == m_ItemType) && // Placing the same slab material - (ClickedBlockMeta == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single) + (ClickedBlockType == m_ItemType) && // Placing the same slab material + ((ClickedBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single) ) { // If clicking the top side of a bottom-half slab, combine into a doubleslab: diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h index dee8a9057..a07e4ef49 100644 --- a/src/Items/ItemSpawnEgg.h +++ b/src/Items/ItemSpawnEgg.h @@ -36,7 +36,7 @@ public: eMonsterType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage); if ( (MonsterType != mtInvalidType) && // Valid monster type - (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded + (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) != cEntity::INVALID_ID)) // Spawning succeeded { if (!a_Player->IsGameModeCreative()) { diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index c151c5d3a..cdcbdab3b 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -35,7 +35,7 @@ public: cFastRandom Random; a_World->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f)); - if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0) + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID) { return false; } @@ -135,7 +135,7 @@ public: return false; } - if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) < 0) + if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) == 0) { return false; } diff --git a/src/LoggerListeners.h b/src/LoggerListeners.h index d300184b1..c419aa75a 100644 --- a/src/LoggerListeners.h +++ b/src/LoggerListeners.h @@ -1,5 +1,6 @@ #include "Logger.h" +#include "OSSupport/File.h" diff --git a/src/Map.cpp b/src/Map.cpp index fbde00cf7..5e57cc8ec 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -66,10 +66,8 @@ void cMapDecorator::Update(void) { cFastRandom Random; - Int64 WorldAge = m_Player->GetWorld()->GetWorldAge(); - // TODO 2014-02-19 xdot: Refine - m_Rot = Random.NextInt(16, (int) WorldAge); + m_Rot = Random.NextInt(16); } else { @@ -189,6 +189,11 @@ public: return "cMap"; } + const char * GetClass(void) // Needed for ManualBindings' DoWith templates + { + return "cMap"; + } + protected: diff --git a/src/MapManager.cpp b/src/MapManager.cpp index 2a3ab192b..fc67bd901 100644 --- a/src/MapManager.cpp +++ b/src/MapManager.cpp @@ -22,7 +22,7 @@ cMapManager::cMapManager(cWorld * a_World) -bool cMapManager::DoWithMap(int a_ID, cMapCallback & a_Callback) +bool cMapManager::DoWithMap(UInt32 a_ID, cMapCallback & a_Callback) { cCSLock Lock(m_CS); cMap * Map = GetMapData(a_ID); diff --git a/src/MapManager.h b/src/MapManager.h index 2cc6a7bce..1059773c3 100644 --- a/src/MapManager.h +++ b/src/MapManager.h @@ -32,8 +32,7 @@ public: cMapManager(cWorld * a_World); /** Returns the map with the specified ID, nullptr if out of range. - WARNING: The returned map object is not thread safe. - */ + WARNING: The returned map object is not thread safe. */ cMap * GetMapData(unsigned int a_ID); /** Creates a new map. Returns nullptr on error */ @@ -41,13 +40,11 @@ public: /** Calls the callback for the map with the specified ID. Returns true if the map was found and the callback called, false if map not found. - Callback return value is ignored. - */ - bool DoWithMap(int a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp + Callback return value is ignored. */ + bool DoWithMap(UInt32 a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp /** Calls the callback for each map. - Returns true if all maps processed, false if the callback aborted by returning true. - */ + Returns true if all maps processed, false if the callback aborted by returning true. */ bool ForEachMap(cMapCallback & a_Callback); size_t GetNumMaps(void) const; // tolua_export diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index 541135996..dfeab1461 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -110,8 +110,7 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) if (allowedMobsSize > 0) { std::set<eMonsterType>::iterator itr = allowedMobs.begin(); - static int Counter = 0; - int iRandom = m_Random.NextInt((int)allowedMobsSize, Counter++); + int iRandom = m_Random.NextInt((int)allowedMobsSize); for (int i = 0; i < iRandom; i++) { @@ -133,7 +132,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R BLOCKTYPE TargetBlock = E_BLOCK_AIR; if (a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock)) { - if ((a_RelY + 1 > cChunkDef::Height) || (a_RelY - 1 < 0)) + if ((a_RelY >= cChunkDef::Height - 1) || (a_RelY <= 0)) { return false; } @@ -187,7 +186,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES) ) && (a_RelY >= 62) && - (Random.NextInt(3, a_Biome) != 0) + (Random.NextInt(3) != 0) ); } @@ -248,7 +247,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (!cBlockInfo::IsTransparent(BlockBelow)) && (SkyLight <= 7) && (BlockLight <= 7) && - (Random.NextInt(2, a_Biome) == 0) + (Random.NextInt(2) == 0) ); } @@ -272,7 +271,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!cBlockInfo::IsTransparent(BlockBelow)) && - (Random.NextInt(20, a_Biome) == 0) + (Random.NextInt(20) == 0) ); } diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index 72317d66b..526b39e39 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -85,7 +85,7 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) if (ReachedFinalDestination() && !LineOfSight.Trace(GetPosition(), AttackDirection, (int)AttackDirection.Length())) { // Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls) - Attack(a_Dt / 1000); + Attack(a_Dt); } } @@ -95,8 +95,7 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) void cAggressiveMonster::Attack(std::chrono::milliseconds a_Dt) { - m_AttackInterval += a_Dt.count() * m_AttackRate; - + m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate; if ((m_Target == nullptr) || (m_AttackInterval < 3.0)) { return; diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index 172ccd071..89eeb3709 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -32,7 +32,7 @@ void cBlaze::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cBlaze::Attack(std::chrono::milliseconds a_Dt) { - m_AttackInterval += a_Dt.count() * m_AttackRate; + m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate; if ((m_Target != nullptr) && (m_AttackInterval > 3.0)) { diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp index c4ae47f2f..41796402f 100644 --- a/src/Mobs/Creeper.cpp +++ b/src/Mobs/Creeper.cpp @@ -67,30 +67,29 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer) } AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER); - if ((a_Killer != nullptr) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0)) + // If the creeper was killed by a skeleton, add a random music disc drop: + if ( + (a_Killer != nullptr) && + a_Killer->IsProjectile() && + ((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID)) { class cProjectileCreatorCallback : public cEntityCallback { public: - cProjectileCreatorCallback(void) - { - } + cProjectileCreatorCallback(void) {} virtual bool Item(cEntity * a_Entity) override { - if (a_Entity->IsMob() && ((cMonster *)a_Entity)->GetMobType() == mtSkeleton) + if (a_Entity->IsMob() && ((reinterpret_cast<cMonster *>(a_Entity))->GetMobType() == mtSkeleton)) { return true; } return false; } - }; - - cProjectileCreatorCallback PCC; - if (GetWorld()->DoWithEntityByID(((cProjectileEntity *)a_Killer)->GetCreatorUniqueID(), PCC)) + } PCC; + if (GetWorld()->DoWithEntityByID((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID(), PCC)) { - // 12 music discs. TickRand starts from 0 to 11. Disk IDs start at 2256, so add that. There. - AddRandomDropItem(a_Drops, 1, 1, (short)m_World->GetTickRandomNumber(11) + 2256); + AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC)); } } } diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index ea0295102..d17047ab7 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -34,7 +34,7 @@ void cGhast::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cGhast::Attack(std::chrono::milliseconds a_Dt) { - m_AttackInterval += a_Dt.count() * m_AttackRate; + m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate; if ((m_Target != nullptr) && (m_AttackInterval > 3.0)) { diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 6e07bfbb6..a86497753 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -135,7 +135,7 @@ void cMonster::TickPathFinding() { 0, -1}, } ; - if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */) + if ((PosY - 1 < 0) || (PosY + 2 >= cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */) { // Too low/high, can't really do anything FinishPathFinding(); diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp index e4d1760e0..c0cdec035 100644 --- a/src/Mobs/Sheep.cpp +++ b/src/Mobs/Sheep.cpp @@ -91,7 +91,7 @@ void cSheep::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) int PosY = POSY_TOINT - 1; int PosZ = POSZ_TOINT; - if ((PosY <= 0) || (PosY > cChunkDef::Height)) + if ((PosY <= 0) || (PosY >= cChunkDef::Height)) { return; } diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index dd59d6454..331c8e8ad 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -69,8 +69,7 @@ void cSkeleton::MoveToPosition(const Vector3d & a_Position) void cSkeleton::Attack(std::chrono::milliseconds a_Dt) { - m_AttackInterval += a_Dt.count() * m_AttackRate; - + m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate; if ((m_Target != nullptr) && (m_AttackInterval > 3.0)) { // Setting this higher gives us more wiggle room for attackrate diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index 81b37ef0e..0d3c9a63e 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -13,6 +13,7 @@ SET (SRCS HostnameLookup.cpp IPLookup.cpp IsThread.cpp + NetworkInterfaceEnum.cpp NetworkSingleton.cpp Semaphore.cpp ServerHandleImpl.cpp diff --git a/src/OSSupport/CriticalSection.h b/src/OSSupport/CriticalSection.h index 17fcdfc12..d52f049d2 100644 --- a/src/OSSupport/CriticalSection.h +++ b/src/OSSupport/CriticalSection.h @@ -10,22 +10,22 @@ class cCriticalSection { public: - void Lock(void); void Unlock(void); // IsLocked/IsLockedByCurrentThread are only used in ASSERT statements, but because of the changes with ASSERT they must always be defined // The fake versions (in Release) will not effect the program in any way #ifdef _DEBUG - cCriticalSection(void); - bool IsLocked(void); - bool IsLockedByCurrentThread(void); + cCriticalSection(void); + bool IsLocked(void); + bool IsLockedByCurrentThread(void); #else - bool IsLocked(void) { return false; } - bool IsLockedByCurrentThread(void) { return false; } + bool IsLocked(void) { return false; } + bool IsLockedByCurrentThread(void) { return false; } #endif // _DEBUG private: + #ifdef _DEBUG int m_IsLocked; // Number of times this CS is locked std::thread::id m_OwningThreadID; diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h index 5dd596223..95a935bbe 100644 --- a/src/OSSupport/Network.h +++ b/src/OSSupport/Network.h @@ -318,6 +318,9 @@ public: If a_Port is 0, the OS is free to assign any port number it likes to the endpoint. Returns the endpoint object that can be interacted with. */ static cUDPEndpointPtr CreateUDPEndpoint(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks); + + /** Returns all local IP addresses for network interfaces currently available. */ + static AStringVector EnumLocalIPAddresses(void); }; diff --git a/src/OSSupport/NetworkInterfaceEnum.cpp b/src/OSSupport/NetworkInterfaceEnum.cpp new file mode 100644 index 000000000..c4af1e93c --- /dev/null +++ b/src/OSSupport/NetworkInterfaceEnum.cpp @@ -0,0 +1,185 @@ + +// NetworkInterfaceEnum.cpp + +// Implements the cNetwork::EnumLocalIPAddresses() interface enumeration function + +#include "Globals.h" +#include "Network.h" +#include "event2/util.h" +#ifdef _WIN32 + #include <IPHlpApi.h> + #pragma comment(lib, "IPHLPAPI.lib") +#else // _WIN32 + #include <sys/types.h> + #include <ifaddrs.h> + #include <netinet/in.h> + #include <arpa/inet.h> +#endif // else _WIN32 + + + + + +#ifdef SELF_TEST + +static class cEnumIPAddressTest +{ +public: + cEnumIPAddressTest(void) + { + printf("Enumerating all IP addresses...\n"); + auto IPs = cNetwork::EnumLocalIPAddresses(); + for (auto & ip: IPs) + { + printf(" %s\n", ip.c_str()); + } + printf("Done.\n"); + } +} g_EnumIPAddressTest; + +#endif // SELF_TEST + + + + + +#ifdef _WIN32 + +/** Converts the SOCKET_ADDRESS structure received from the OS into an IP address string. */ +static AString PrintAddress(SOCKET_ADDRESS & a_Addr) +{ + char IP[128]; + switch (a_Addr.lpSockaddr->sa_family) + { + case AF_INET: + { + auto sin = reinterpret_cast<const sockaddr_in *>(a_Addr.lpSockaddr); + evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin_addr), IP, sizeof(IP)); + break; + } + case AF_INET6: + { + auto sin = reinterpret_cast<const sockaddr_in6 *>(a_Addr.lpSockaddr); + evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin6_addr), IP, sizeof(IP)); + break; + } + default: + { + IP[0] = 0; + break; + } + } + return IP; +} + +#else // _WIN32 + +static AString PrintAddress(ifaddrs * InterfaceAddress) +{ + switch (InterfaceAddress->ifa_addr->sa_family) + { + case AF_INET: + { // IPv4 + char AddressBuffer[INET_ADDRSTRLEN]; + sockaddr_in InternetSocket; + + std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket)); + inet_ntop(AF_INET, &InternetSocket.sin_addr, AddressBuffer, INET_ADDRSTRLEN); + return AddressBuffer; + } + case AF_INET6: + { // IPv6 + char AddressBuffer[INET6_ADDRSTRLEN]; + sockaddr_in6 InternetSocket; + + std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket)); + inet_ntop(AF_INET6, &InternetSocket.sin6_addr, AddressBuffer, INET6_ADDRSTRLEN); + return AddressBuffer; + } + default: + { + LOG("Unknown address family: %i", InterfaceAddress->ifa_addr->sa_family); + return ""; + } + } +} + +#endif // else _WIN32 + + + + + +AStringVector cNetwork::EnumLocalIPAddresses(void) +{ + AStringVector res; + + #ifdef _WIN32 + + // Query the OS for all adapters' addresses: + char buffer[64 KiB]; // A buffer backing the address list + PIP_ADAPTER_ADDRESSES pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer); + ULONG outBufLen = sizeof(buffer); + DWORD dwRetVal = GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, nullptr, + pAddresses, &outBufLen + ); + if (dwRetVal != ERROR_SUCCESS) + { + LOG("GetAdaptersAddresses() failed: %u", dwRetVal); + return res; + } + + // Enumerate all active adapters + for (auto pCurrAddresses = pAddresses; pCurrAddresses != nullptr; pCurrAddresses = pCurrAddresses->Next) + { + if (pCurrAddresses->OperStatus != IfOperStatusUp) + { + // Adapter not active, skip it: + continue; + } + + // Collect all IP addresses on this adapter: + for (auto pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next) + { + auto Address = PrintAddress(pUnicast->Address); + if (!Address.empty()) + { + res.push_back(Address); + } + } // for pUnicast + } // for pCurrAddresses + + #else // _WIN32 + + struct ifaddrs * ifAddrStruct = nullptr; + getifaddrs(&ifAddrStruct); + + for (auto ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == nullptr) + { + continue; + } + + auto Address = PrintAddress(ifa); + if (!Address.empty()) + { + res.emplace_back(Address); + } + } + + if (ifAddrStruct != nullptr) + { + freeifaddrs(ifAddrStruct); + } + + #endif // else _WIN32 + + return res; +} + + + + diff --git a/src/OSSupport/UDPEndpointImpl.cpp b/src/OSSupport/UDPEndpointImpl.cpp index ece521ab8..31ca107ce 100644 --- a/src/OSSupport/UDPEndpointImpl.cpp +++ b/src/OSSupport/UDPEndpointImpl.cpp @@ -197,6 +197,15 @@ cUDPEndpointImpl::cUDPEndpointImpl(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_C +cUDPEndpointImpl::~cUDPEndpointImpl() +{ + Close(); +} + + + + + void cUDPEndpointImpl::Close(void) { if (m_Port == 0) diff --git a/src/OSSupport/UDPEndpointImpl.h b/src/OSSupport/UDPEndpointImpl.h index 75942b0cf..0e28d0b13 100644 --- a/src/OSSupport/UDPEndpointImpl.h +++ b/src/OSSupport/UDPEndpointImpl.h @@ -35,6 +35,8 @@ public: If a_Port is 0, the OS is free to assign any port number it likes to the endpoint. */ cUDPEndpointImpl(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks); + ~cUDPEndpointImpl(); + // cUDPEndpoint overrides: virtual void Close(void) override; virtual bool IsOpen(void) const override; diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt index 7c97e67bc..c3a45ca47 100644 --- a/src/Protocol/CMakeLists.txt +++ b/src/Protocol/CMakeLists.txt @@ -8,19 +8,23 @@ SET (SRCS Authenticator.cpp ChunkDataSerializer.cpp MojangAPI.cpp + Packetizer.cpp Protocol17x.cpp Protocol18x.cpp - ProtocolRecognizer.cpp) + ProtocolRecognizer.cpp +) SET (HDRS Authenticator.h ChunkDataSerializer.h MojangAPI.h + Packetizer.h Protocol.h Protocol17x.h Protocol18x.h - ProtocolRecognizer.h) + ProtocolRecognizer.h +) -if(NOT MSVC) +if (NOT MSVC) add_library(Protocol ${SRCS} ${HDRS}) endif() diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp index 5d080656d..60fd5f935 100644 --- a/src/Protocol/ChunkDataSerializer.cpp +++ b/src/Protocol/ChunkDataSerializer.cpp @@ -187,11 +187,11 @@ void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_Chu // Create the packet: cByteBuffer Packet(512 KiB); - Packet.WriteVarInt(0x21); // Packet id (Chunk Data packet) - Packet.WriteBEInt(a_ChunkX); - Packet.WriteBEInt(a_ChunkZ); - Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag - Packet.WriteBEUShort(0xffff); // We're aways sending the full chunk with no additional data, so the bitmap is 0xffff + Packet.WriteVarInt32(0x21); // Packet id (Chunk Data packet) + Packet.WriteBEInt32(a_ChunkX); + Packet.WriteBEInt32(a_ChunkZ); + Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag + Packet.WriteBEUInt16(0xffff); // We're aways sending the full chunk with no additional data, so the bitmap is 0xffff // Write the chunk size: const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width; @@ -201,15 +201,15 @@ void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_Chu sizeof(m_BlockSkyLight) + // Block sky light BiomeDataSize // Biome data ); - Packet.WriteVarInt(ChunkSize); + Packet.WriteVarInt32(ChunkSize); // Write the block types to the packet: for (size_t Index = 0; Index < cChunkDef::NumBlocks; Index++) { BLOCKTYPE BlockType = m_BlockTypes[Index] & 0xFF; NIBBLETYPE BlockMeta = m_BlockMetas[Index / 2] >> ((Index & 1) * 4) & 0x0f; - Packet.WriteByte((unsigned char)(BlockType << 4) | BlockMeta); - Packet.WriteByte((unsigned char)(BlockType >> 4)); + Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType << 4) | BlockMeta); + Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType >> 4)); } // Write the rest: @@ -234,8 +234,8 @@ void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_Chu else { AString PostData; - Buffer.WriteVarInt((UInt32)Packet.GetUsedSpace() + 1); - Buffer.WriteVarInt(0); + Buffer.WriteVarInt32(static_cast<UInt32>(Packet.GetUsedSpace() + 1)); + Buffer.WriteVarInt32(0); Buffer.ReadAll(PostData); Buffer.CommitRead(); diff --git a/src/Protocol/Packetizer.cpp b/src/Protocol/Packetizer.cpp new file mode 100644 index 000000000..0a84d4678 --- /dev/null +++ b/src/Protocol/Packetizer.cpp @@ -0,0 +1,101 @@ + +// Packetizer.cpp + +// Implements the cPacketizer class representing a wrapper for sending a single packet over a protocol. + +#include "Globals.h" +#include "Packetizer.h" + + + + + +/** Converts the hex digit character to its value. */ +static UInt8 HexDigitValue(char a_Character) +{ + switch (a_Character) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + case 'A': return 10; + case 'B': return 11; + case 'C': return 12; + case 'D': return 13; + case 'E': return 14; + case 'F': return 15; + default: + { + LOGWARNING("Bad hex digit: %c", a_Character); + ASSERT(!"Bad hex digit"); + return 0; + } + } +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cPacketizer: + +cPacketizer::~cPacketizer() +{ + m_Protocol.SendPacket(*this); +} + + + + + +void cPacketizer::WriteByteAngle(double a_Angle) +{ + WriteBEInt8(static_cast<Int8>(255 * a_Angle / 360)); +} + + + + + +void cPacketizer::WriteFPInt(double a_Value) +{ + WriteBEInt32(static_cast<Int32>(a_Value * 32)); +} + + + + + +void cPacketizer::WriteUUID(const AString & a_UUID) +{ + if (a_UUID.length() != 32) + { + LOGWARNING("%s: Attempt to send a bad uuid (length isn't 32): %s", __FUNCTION__, a_UUID.c_str()); + ASSERT(!"Wrong uuid length!"); + return; + } + + for (size_t i = 0; i < 32; i += 2) + { + auto val = static_cast<UInt8>(HexDigitValue(a_UUID[i]) << 4 | HexDigitValue(a_UUID[i + 1])); + VERIFY(m_Out.WriteBEUInt8(val)); + } +} + + + + diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h new file mode 100644 index 000000000..7f5e9c2c3 --- /dev/null +++ b/src/Protocol/Packetizer.h @@ -0,0 +1,155 @@ + +// Packetizer.h + +// Declares the cPacketizer class representing a wrapper for sending a single packet over a protocol. +// The class provides auto-locking, serialization and send-on-instance-destroy semantics + + + + + +#pragma once + +#include "Protocol.h" +#include "../ByteBuffer.h" + + + + + +/** Composes an individual packet in the protocol's m_OutPacketBuffer; sends it just before being destructed. */ +class cPacketizer +{ +public: + /** Starts serializing a new packet into the protocol's m_OutPacketBuffer. + Locks the protocol's m_CSPacket to avoid multithreading issues. */ + cPacketizer(cProtocol & a_Protocol, UInt32 a_PacketType) : + m_Protocol(a_Protocol), + m_Out(a_Protocol.m_OutPacketBuffer), + m_Lock(a_Protocol.m_CSPacket), + m_PacketType(a_PacketType) // Used for logging purposes + { + m_Out.WriteVarInt32(a_PacketType); + } + + /** Sends the packet via the contained protocol's SendPacket() function. */ + ~cPacketizer(); + + inline void WriteBool(bool a_Value) + { + VERIFY(m_Out.WriteBool(a_Value)); + } + + inline void WriteBEUInt8(UInt8 a_Value) + { + VERIFY(m_Out.WriteBEUInt8(a_Value)); + } + + + inline void WriteBEInt8(Int8 a_Value) + { + VERIFY(m_Out.WriteBEInt8(a_Value)); + } + + + inline void WriteBEInt16(Int16 a_Value) + { + VERIFY(m_Out.WriteBEInt16(a_Value)); + } + + + inline void WriteBEUInt16(short a_Value) + { + VERIFY(m_Out.WriteBEUInt16(a_Value)); + } + + + inline void WriteBEInt32(Int32 a_Value) + { + VERIFY(m_Out.WriteBEInt32(a_Value)); + } + + + inline void WriteBEUInt32(UInt32 a_Value) + { + VERIFY(m_Out.WriteBEUInt32(a_Value)); + } + + + inline void WriteBEInt64(Int64 a_Value) + { + VERIFY(m_Out.WriteBEInt64(a_Value)); + } + + + inline void WriteBEUInt64(UInt64 a_Value) + { + VERIFY(m_Out.WriteBEUInt64(a_Value)); + } + + + inline void WriteBEFloat(float a_Value) + { + VERIFY(m_Out.WriteBEFloat(a_Value)); + } + + + inline void WriteBEDouble(double a_Value) + { + VERIFY(m_Out.WriteBEDouble(a_Value)); + } + + + inline void WriteVarInt32(UInt32 a_Value) + { + VERIFY(m_Out.WriteVarInt32(a_Value)); + } + + + inline void WriteString(const AString & a_Value) + { + VERIFY(m_Out.WriteVarUTF8String(a_Value)); + } + + + inline void WriteBuf(const char * a_Data, size_t a_Size) + { + VERIFY(m_Out.Write(a_Data, a_Size)); + } + + + /** Writes the specified block position as a single encoded 64-bit BigEndian integer. */ + inline void WritePosition64(int a_BlockX, int a_BlockY, int a_BlockZ) + { + VERIFY(m_Out.WritePosition64(a_BlockX, a_BlockY, a_BlockZ)); + } + + /** Writes the specified angle using a single byte. */ + void WriteByteAngle(double a_Angle); + + /** Writes the double value as a 27:5 fixed-point integer. */ + void WriteFPInt(double a_Value); + + /** Writes the specified UUID as a 128-bit BigEndian integer. */ + void WriteUUID(const AString & a_UUID); + + UInt32 GetPacketType(void) const { return m_PacketType; } + +protected: + /** The protocol instance in which the packet is being constructed. */ + cProtocol & m_Protocol; + + /** The protocol's buffer for the constructed packet data. */ + cByteBuffer & m_Out; + + /** The RAII lock preventing multithreaded access to the protocol buffer while constructing the packet. */ + cCSLock m_Lock; + + /** Type of the contained packet. + Used for logging purposes, the packet type is encoded into m_Out immediately in constructor. */ + UInt32 m_PacketType; +} ; + + + + diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 02a8a52f6..d8399049e 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -14,6 +14,7 @@ #include "../Endianness.h" #include "../Scoreboard.h" #include "../Map.h" +#include "../ByteBuffer.h" @@ -32,6 +33,7 @@ class cChunkDataSerializer; class cFallingBlock; class cCompositeChat; class cStatManager; +class cPacketizer; @@ -47,7 +49,9 @@ class cProtocol { public: cProtocol(cClientHandle * a_Client) : - m_Client(a_Client) + m_Client(a_Client), + m_OutPacketBuffer(64 KiB), + m_OutPacketLenBuffer(20) // 20 bytes is more than enough for one VarInt { } @@ -59,7 +63,7 @@ public: // Sending stuff to clients (alphabetically sorted): virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0; virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) = 0; - virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0; + virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0; virtual void SendChat (const AString & a_Message) = 0; @@ -136,11 +140,27 @@ public: virtual AString GetAuthServerID(void) = 0; protected: + friend class cPacketizer; + 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 + /** Provides synchronization for sending the entire packet at once. + Each SendXYZ() function must acquire this CS in order to send the whole packet at once. + Automated via cPacketizer class. */ + cCriticalSection m_CSPacket; + + /** Buffer for composing the outgoing packets, through cPacketizer */ + cByteBuffer m_OutPacketBuffer; + + /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */ + cByteBuffer m_OutPacketLenBuffer; + + /** 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; + + /** Sends a single packet contained within the cPacketizer class. + The cPacketizer's destructor calls this to send the contained packet; protocol may transform the data (compression in 1.8 etc). */ + virtual void SendPacket(cPacketizer & a_Packet) = 0; } ; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index f78c2e54b..2bc58e7e5 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -14,6 +14,7 @@ Implements the 1.7.x protocol classes: #include "Protocol17x.h" #include "ChunkDataSerializer.h" #include "PolarSSL++/Sha1Checksum.h" +#include "Packetizer.h" #include "../ClientHandle.h" #include "../Root.h" @@ -50,6 +51,13 @@ Implements the 1.7.x protocol classes: +/** The slot number that the client uses to indicate "outside the window". */ +static const Int16 SLOT_NUM_OUTSIDE = -999; + + + + + #define HANDLE_READ(ByteBuf, Proc, Type, Var) \ Type Var; \ if (!ByteBuf.Proc(Var))\ @@ -98,8 +106,6 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd m_ServerPort(a_ServerPort), m_State(a_State), m_ReceivedData(32 KiB), - m_OutPacketBuffer(64 KiB), - m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt m_IsEncrypted(false), m_LastSentDimension(dimNotSet) { @@ -159,8 +165,8 @@ void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_ ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1b); // Attach Entity packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteInt((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0); Pkt.WriteBool(false); } @@ -173,28 +179,28 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x24); // Block Action packet - Pkt.WriteInt(a_BlockX); - Pkt.WriteShort(static_cast<short>(a_BlockY)); - Pkt.WriteInt(a_BlockZ); - Pkt.WriteByte(static_cast<Byte>(a_Byte1)); - Pkt.WriteByte(static_cast<Byte>(a_Byte2)); - Pkt.WriteVarInt(a_BlockType); + Pkt.WriteBEInt32(a_BlockX); + Pkt.WriteBEInt16(static_cast<Int16>(a_BlockY)); + Pkt.WriteBEInt32(a_BlockZ); + Pkt.WriteBEInt8(a_Byte1); + Pkt.WriteBEInt8(a_Byte2); + Pkt.WriteVarInt32(a_BlockType); } -void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) +void cProtocol172::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x25); // Block Break Animation packet - Pkt.WriteVarInt(static_cast<UInt32>(a_EntityID)); - Pkt.WriteInt(a_BlockX); - Pkt.WriteInt(a_BlockY); - Pkt.WriteInt(a_BlockZ); - Pkt.WriteChar(a_Stage); + Pkt.WriteVarInt32(a_EntityID); + Pkt.WriteBEInt32(a_BlockX); + Pkt.WriteBEInt32(a_BlockY); + Pkt.WriteBEInt32(a_BlockZ); + Pkt.WriteBEInt8(a_Stage); } @@ -207,11 +213,11 @@ void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO ASSERT((a_BlockY >= 0) && (a_BlockY < 256)); cPacketizer Pkt(*this, 0x23); // Block Change packet - Pkt.WriteInt(a_BlockX); - Pkt.WriteByte(static_cast<Byte>(a_BlockY)); - Pkt.WriteInt(a_BlockZ); - Pkt.WriteVarInt(a_BlockType); - Pkt.WriteByte(a_BlockMeta); + Pkt.WriteBEInt32(a_BlockX); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_BlockY)); + Pkt.WriteBEInt32(a_BlockZ); + Pkt.WriteVarInt32(a_BlockType); + Pkt.WriteBEUInt8(a_BlockMeta); } @@ -223,15 +229,15 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x22); // Multi Block Change packet - Pkt.WriteInt(a_ChunkX); - Pkt.WriteInt(a_ChunkZ); - Pkt.WriteShort((short)a_Changes.size()); - Pkt.WriteInt((int)a_Changes.size() * 4); + Pkt.WriteBEInt32(a_ChunkX); + Pkt.WriteBEInt32(a_ChunkZ); + Pkt.WriteBEUInt16(static_cast<UInt16>(a_Changes.size())); + Pkt.WriteBEUInt32(static_cast<UInt32>(a_Changes.size() * 4)); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { int Coords = itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12); int Blocks = static_cast<int>(itr->m_BlockMeta | (itr->m_BlockType << 4)); - Pkt.WriteInt((Coords << 16) | Blocks); + Pkt.WriteBEInt32((Coords << 16) | Blocks); } // for itr - a_Changes[] } @@ -276,8 +282,8 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2, a_ChunkX, a_ChunkZ); cPacketizer Pkt(*this, 0x21); // Chunk Data packet - Pkt.WriteInt(a_ChunkX); - Pkt.WriteInt(a_ChunkZ); + Pkt.WriteBEInt32(a_ChunkX); + Pkt.WriteBEInt32(a_ChunkZ); Pkt.WriteBuf(ChunkData.data(), ChunkData.size()); } @@ -290,8 +296,8 @@ void cProtocol172::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0d); // Collect Item packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteInt(a_Player.GetUniqueID()); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32(a_Player.GetUniqueID()); } @@ -303,8 +309,8 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x13); // Destroy Entities packet - Pkt.WriteByte(1); - Pkt.WriteInt(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(1); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); } @@ -341,9 +347,9 @@ void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet - Pkt.WriteInt(a_BlockX); - Pkt.WriteInt(a_BlockY); - Pkt.WriteInt(a_BlockZ); + Pkt.WriteBEInt32(a_BlockX); + Pkt.WriteBEInt32(a_BlockY); + Pkt.WriteBEInt32(a_BlockZ); } @@ -357,10 +363,10 @@ void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in ASSERT((a_Amplifier >= 0) && (a_Amplifier < 256)); cPacketizer Pkt(*this, 0x1D); // Entity Effect packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(static_cast<Byte>(a_EffectID)); - Pkt.WriteByte(static_cast<Byte>(a_Amplifier)); - Pkt.WriteShort(a_Duration); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<Byte>(a_EffectID)); + Pkt.WriteBEUInt8(static_cast<Byte>(a_Amplifier)); + Pkt.WriteBEInt16(a_Duration); } @@ -372,9 +378,9 @@ void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x04); // Entity Equipment packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteShort(a_SlotNum); - Pkt.WriteItem(a_Item); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt16(a_SlotNum); + WriteItem(Pkt, a_Item); } @@ -386,7 +392,7 @@ void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x19); // Entity Head Look packet - Pkt.WriteInt(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); } @@ -399,7 +405,7 @@ void cProtocol172::SendEntityLook(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x16); // Entity Look packet - Pkt.WriteInt(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); } @@ -413,9 +419,9 @@ void cProtocol172::SendEntityMetadata(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteEntityMetadata(a_Entity); - Pkt.WriteByte(0x7f); // The termination byte + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + WriteEntityMetadata(Pkt, a_Entity); + Pkt.WriteBEUInt8(0x7f); // The termination byte } @@ -427,8 +433,8 @@ void cProtocol172::SendEntityProperties(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x20); // Entity Properties packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteEntityProperties(a_Entity); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + WriteEntityProperties(Pkt, a_Entity); } @@ -440,10 +446,10 @@ void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteChar(a_RelX); - Pkt.WriteChar(a_RelY); - Pkt.WriteChar(a_RelZ); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_RelX); + Pkt.WriteBEInt8(a_RelY); + Pkt.WriteBEInt8(a_RelZ); } @@ -455,10 +461,10 @@ void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteChar(a_RelX); - Pkt.WriteChar(a_RelY); - Pkt.WriteChar(a_RelZ); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_RelX); + Pkt.WriteBEInt8(a_RelY); + Pkt.WriteBEInt8(a_RelZ); Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); } @@ -472,8 +478,8 @@ void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1a); // Entity Status packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteChar(a_Status); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_Status); } @@ -485,11 +491,11 @@ void cProtocol172::SendEntityVelocity(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x12); // Entity Velocity packet - Pkt.WriteInt(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); // 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick - Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400)); - Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400)); - Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedZ() * 400)); } @@ -501,20 +507,20 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x27); // Explosion packet - Pkt.WriteFloat((float)a_BlockX); - Pkt.WriteFloat((float)a_BlockY); - Pkt.WriteFloat((float)a_BlockZ); - Pkt.WriteFloat((float)a_Radius); - Pkt.WriteInt((int)a_BlocksAffected.size()); + Pkt.WriteBEFloat(static_cast<float>(a_BlockX)); + Pkt.WriteBEFloat(static_cast<float>(a_BlockY)); + Pkt.WriteBEFloat(static_cast<float>(a_BlockZ)); + Pkt.WriteBEFloat(static_cast<float>(a_Radius)); + Pkt.WriteBEUInt32(static_cast<UInt32>(a_BlocksAffected.size())); for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr) { - Pkt.WriteChar((char)itr->x); - Pkt.WriteChar((char)itr->y); - Pkt.WriteChar((char)itr->z); + Pkt.WriteBEInt8(static_cast<Int8>(itr->x)); + Pkt.WriteBEInt8(static_cast<Int8>(itr->y)); + Pkt.WriteBEInt8(static_cast<Int8>(itr->z)); } // for itr - a_BlockAffected[] - Pkt.WriteFloat((float)a_PlayerMotion.x); - Pkt.WriteFloat((float)a_PlayerMotion.y); - Pkt.WriteFloat((float)a_PlayerMotion.z); + Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.x)); + Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.y)); + Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.z)); } @@ -526,8 +532,8 @@ void cProtocol172::SendGameMode(eGameMode a_GameMode) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2b); // Change Game State packet - Pkt.WriteByte(3); // Reason: Change game mode - Pkt.WriteFloat((float)a_GameMode); + Pkt.WriteBEUInt8(3); // Reason: Change game mode + Pkt.WriteBEFloat(static_cast<float>(a_GameMode)); // The protocol really represents the value with a float! } @@ -540,9 +546,9 @@ void cProtocol172::SendHealth(void) cPacketizer Pkt(*this, 0x06); // Update Health packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteFloat(static_cast<float>(Player->GetHealth())); - Pkt.WriteShort(static_cast<short>(Player->GetFoodLevel())); - Pkt.WriteFloat(static_cast<float>(Player->GetFoodSaturationLevel())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth())); + Pkt.WriteBEInt16(static_cast<short>(Player->GetFoodLevel())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel())); } @@ -554,9 +560,9 @@ void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2f); // Set Slot packet - Pkt.WriteChar(a_WindowID); - Pkt.WriteShort(a_SlotNum); - Pkt.WriteItem(a_Item); + Pkt.WriteBEInt8(a_WindowID); + Pkt.WriteBEInt16(a_SlotNum); + WriteItem(Pkt, a_Item); } @@ -573,7 +579,7 @@ void cProtocol172::SendKeepAlive(int a_PingID) } cPacketizer Pkt(*this, 0x00); // Keep Alive packet - Pkt.WriteInt(a_PingID); + Pkt.WriteBEInt32(a_PingID); } @@ -586,11 +592,11 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { cServer * Server = cRoot::Get()->GetServer(); cPacketizer Pkt(*this, 0x01); // Join Game packet - Pkt.WriteInt(a_Player.GetUniqueID()); - Pkt.WriteByte(static_cast<Byte>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 - Pkt.WriteChar(static_cast<char>(a_World.GetDimension())); - Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte(static_cast<Byte>(std::min(Server->GetMaxPlayers(), 60))); + Pkt.WriteBEUInt32(a_Player.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<Byte>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 + Pkt.WriteBEInt8(static_cast<char>(a_World.GetDimension())); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8(static_cast<Byte>(std::min(Server->GetMaxPlayers(), 60))); Pkt.WriteString("default"); // Level type - wtf? } m_LastSentDimension = a_World.GetDimension(); @@ -598,9 +604,9 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) // Send the spawn position: { cPacketizer Pkt(*this, 0x05); // Spawn Position packet - Pkt.WriteInt(static_cast<int>(a_World.GetSpawnX())); - Pkt.WriteInt(static_cast<int>(a_World.GetSpawnY())); - Pkt.WriteInt(static_cast<int>(a_World.GetSpawnZ())); + Pkt.WriteBEInt32(static_cast<int>(a_World.GetSpawnX())); + Pkt.WriteBEInt32(static_cast<int>(a_World.GetSpawnY())); + Pkt.WriteBEInt32(static_cast<int>(a_World.GetSpawnZ())); } // Send player abilities: @@ -632,19 +638,19 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x10); // Spawn Painting packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Painting.GetUniqueID())); + Pkt.WriteVarInt32(a_Painting.GetUniqueID()); Pkt.WriteString(a_Painting.GetName().c_str()); - Pkt.WriteInt(static_cast<int>(a_Painting.GetPosX())); - Pkt.WriteInt(static_cast<int>(a_Painting.GetPosY())); - Pkt.WriteInt(static_cast<int>(a_Painting.GetPosZ())); - Pkt.WriteInt(a_Painting.GetDirection()); + Pkt.WriteBEInt32(static_cast<int>(a_Painting.GetPosX())); + Pkt.WriteBEInt32(static_cast<int>(a_Painting.GetPosY())); + Pkt.WriteBEInt32(static_cast<int>(a_Painting.GetPosZ())); + Pkt.WriteBEInt32(a_Painting.GetProtocolFacing()); } -void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale) +void cProtocol172::SendMapColumn(int a_MapID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale) { ASSERT(m_State == 3); // In game mode? ASSERT(a_Length + 3 <= USHRT_MAX); @@ -652,12 +658,12 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo ASSERT((a_Y >= 0) && (a_Y < 256)); cPacketizer Pkt(*this, 0x34); - Pkt.WriteVarInt(static_cast<UInt32>(a_ID)); - Pkt.WriteShort (static_cast<short>(3 + a_Length)); + Pkt.WriteVarInt32(static_cast<UInt32>(a_MapID)); + Pkt.WriteBEUInt16(static_cast<UInt16>(3 + a_Length)); - Pkt.WriteByte(0); - Pkt.WriteByte(static_cast<Byte>(a_X)); - Pkt.WriteByte(static_cast<Byte>(a_Y)); + Pkt.WriteBEUInt8(0); + Pkt.WriteBEUInt8(static_cast<Byte>(a_X)); + Pkt.WriteBEUInt8(static_cast<Byte>(a_Y)); Pkt.WriteBuf(reinterpret_cast<const char *>(a_Colors), a_Length); } @@ -666,24 +672,24 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo -void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) +void cProtocol172::SendMapDecorators(int a_MapID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) { ASSERT(m_State == 3); // In game mode? ASSERT(1 + 3 * a_Decorators.size() < USHRT_MAX); cPacketizer Pkt(*this, 0x34); - Pkt.WriteVarInt(static_cast<UInt32>(a_ID)); - Pkt.WriteShort (static_cast<short>(1 + (3 * a_Decorators.size()))); + Pkt.WriteVarInt32(static_cast<UInt32>(a_MapID)); + Pkt.WriteBEUInt16(static_cast<UInt16>(1 + (3 * a_Decorators.size()))); - Pkt.WriteByte(1); + Pkt.WriteBEUInt8(1); for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) { ASSERT(it->GetPixelX() < 256); ASSERT(it->GetPixelZ() < 256); - Pkt.WriteByte(static_cast<Byte>((it->GetType() << 4) | static_cast<Byte>(it->GetRot() & 0xf))); - Pkt.WriteByte(static_cast<Byte>(it->GetPixelX())); - Pkt.WriteByte(static_cast<Byte>(it->GetPixelZ())); + Pkt.WriteBEUInt8(static_cast<Byte>((it->GetType() << 4) | static_cast<Byte>(it->GetRot() & 0xf))); + Pkt.WriteBEUInt8(static_cast<Byte>(it->GetPixelX())); + Pkt.WriteBEUInt8(static_cast<Byte>(it->GetPixelZ())); } } @@ -691,17 +697,17 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor -void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale) +void cProtocol172::SendMapInfo(int a_MapID, unsigned int a_Scale) { ASSERT(m_State == 3); // In game mode? ASSERT(a_Scale < 256); cPacketizer Pkt(*this, 0x34); - Pkt.WriteVarInt(static_cast<UInt32>(a_ID)); - Pkt.WriteShort (2); + Pkt.WriteVarInt32(static_cast<UInt32>(a_MapID)); + Pkt.WriteBEUInt16(2); - Pkt.WriteByte(2); - Pkt.WriteByte(static_cast<Byte>(a_Scale)); + Pkt.WriteBEUInt8(2); + Pkt.WriteBEUInt8(static_cast<Byte>(a_Scale)); } @@ -714,21 +720,21 @@ void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup) { cPacketizer Pkt(*this, 0x0e); // Spawn Object packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Pickup.GetUniqueID())); - Pkt.WriteByte(2); // Type = Pickup + Pkt.WriteVarInt32(a_Pickup.GetUniqueID()); + Pkt.WriteBEUInt8(2); // Type = Pickup Pkt.WriteFPInt(a_Pickup.GetPosX()); Pkt.WriteFPInt(a_Pickup.GetPosY()); Pkt.WriteFPInt(a_Pickup.GetPosZ()); Pkt.WriteByteAngle(a_Pickup.GetYaw()); Pkt.WriteByteAngle(a_Pickup.GetPitch()); - Pkt.WriteInt(0); // No object data + Pkt.WriteBEInt32(0); // No object data } { cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet - Pkt.WriteInt(a_Pickup.GetUniqueID()); - Pkt.WriteByte((0x05 << 5) | 10); // Slot type + index 10 - Pkt.WriteItem(a_Pickup.GetItem()); - Pkt.WriteByte(0x7f); // End of metadata + Pkt.WriteBEUInt32(a_Pickup.GetUniqueID()); + Pkt.WriteBEUInt8((0x05 << 5) | 10); // Slot type + index 10 + WriteItem(Pkt, a_Pickup.GetItem()); + Pkt.WriteBEUInt8(0x7f); // End of metadata } } @@ -756,9 +762,9 @@ void cProtocol172::SendPlayerAbilities(void) { Flags |= 0x04; } - Pkt.WriteByte(Flags); - Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed())); - Pkt.WriteFloat((float)(0.1 * Player->GetNormalMaxSpeed())); + Pkt.WriteBEUInt8(Flags); + Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed())); + Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed())); } @@ -770,8 +776,8 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0b); // Animation packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Entity.GetUniqueID())); - Pkt.WriteChar(a_Animation); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_Animation); } @@ -784,14 +790,14 @@ void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_Sr cPacketizer Pkt(*this, 0x2A); Pkt.WriteString(a_ParticleName); - Pkt.WriteFloat(a_SrcX); - Pkt.WriteFloat(a_SrcY); - Pkt.WriteFloat(a_SrcZ); - Pkt.WriteFloat(a_OffsetX); - Pkt.WriteFloat(a_OffsetY); - Pkt.WriteFloat(a_OffsetZ); - Pkt.WriteFloat(a_ParticleData); - Pkt.WriteInt(a_ParticleAmount); + Pkt.WriteBEFloat(a_SrcX); + Pkt.WriteBEFloat(a_SrcY); + Pkt.WriteBEFloat(a_SrcZ); + Pkt.WriteBEFloat(a_OffsetX); + Pkt.WriteBEFloat(a_OffsetY); + Pkt.WriteBEFloat(a_OffsetZ); + Pkt.WriteBEFloat(a_ParticleData); + Pkt.WriteBEInt32(a_ParticleAmount); } @@ -805,7 +811,7 @@ void cProtocol172::SendPlayerListAddPlayer(const cPlayer & a_Player) cPacketizer Pkt(*this, 0x38); // Playerlist Item packet Pkt.WriteString(a_Player.GetPlayerListName()); Pkt.WriteBool(true); - Pkt.WriteShort(a_Player.GetClientHandle()->GetPing()); + Pkt.WriteBEInt16(a_Player.GetClientHandle()->GetPing()); } @@ -819,7 +825,7 @@ void cProtocol172::SendPlayerListRemovePlayer(const cPlayer & a_Player) cPacketizer Pkt(*this, 0x38); Pkt.WriteString(a_Player.GetPlayerListName()); Pkt.WriteBool(false); - Pkt.WriteShort(0); + Pkt.WriteBEInt16(0); } @@ -863,22 +869,22 @@ void cProtocol172::SendPlayerMaxSpeed(void) cPacketizer Pkt(*this, 0x20); // Entity Properties cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteInt(Player->GetUniqueID()); - Pkt.WriteInt(1); // Count + Pkt.WriteBEUInt32(Player->GetUniqueID()); + Pkt.WriteBEInt32(1); // Count Pkt.WriteString("generic.movementSpeed"); // The default game speed is 0.1, multiply that value by the relative speed: - Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed()); + Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed()); if (Player->IsSprinting()) { - Pkt.WriteShort(1); // Modifier count - Pkt.WriteInt64(0x662a6b8dda3e4c1c); - Pkt.WriteInt64(static_cast<Int64>(0x881396ea6097278d)); // UUID of the modifier - Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); - Pkt.WriteByte(2); + Pkt.WriteBEInt16(1); // Modifier count + Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c); + Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier + Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); + Pkt.WriteBEUInt8(2); } else { - Pkt.WriteShort(0); // Modifier count + Pkt.WriteBEInt16(0); // Modifier count } } @@ -892,15 +898,15 @@ void cProtocol172::SendPlayerMoveLook(void) cPacketizer Pkt(*this, 0x08); // Player Position And Look packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteDouble(Player->GetPosX()); + Pkt.WriteBEDouble(Player->GetPosX()); // Protocol docs say this is PosY, but #323 says this is eye-pos // Moreover, the "+ 0.001" is there because otherwise the player falls through the block they were standing on. - Pkt.WriteDouble(Player->GetStance() + 0.001); + Pkt.WriteBEDouble(Player->GetStance() + 0.001); - Pkt.WriteDouble(Player->GetPosZ()); - Pkt.WriteFloat((float)Player->GetYaw()); - Pkt.WriteFloat((float)Player->GetPitch()); + Pkt.WriteBEDouble(Player->GetPosZ()); + Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch())); Pkt.WriteBool(Player->IsOnGround()); } @@ -924,7 +930,7 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet - Pkt.WriteVarInt((UInt32) a_Player.GetUniqueID()); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); if (a_Player.HasCustomName()) { @@ -940,10 +946,10 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) Pkt.WriteByteAngle(a_Player.GetYaw()); Pkt.WriteByteAngle(a_Player.GetPitch()); short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType; - Pkt.WriteShort(ItemType); - Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6 - Pkt.WriteFloat((float)a_Player.GetHealth()); - Pkt.WriteByte(0x7f); // Metadata: end + Pkt.WriteBEInt16(ItemType); + Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6 + Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth())); + Pkt.WriteBEUInt8(0x7f); // Metadata: end } @@ -953,10 +959,11 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message) { ASSERT(m_State == 3); // In game mode? + ASSERT(a_Message.size() <= std::numeric_limits<UInt16>::max()); cPacketizer Pkt(*this, 0x3f); Pkt.WriteString(a_Channel); - Pkt.WriteShort((short)a_Message.size()); + Pkt.WriteBEUInt16(static_cast<UInt16>(a_Message.size())); Pkt.WriteBuf(a_Message.data(), a_Message.size()); } @@ -970,8 +977,8 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect ASSERT((a_EffectID >= 0) && (a_EffectID < 256)); cPacketizer Pkt(*this, 0x1e); - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(static_cast<Byte>(a_EffectID)); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<Byte>(a_EffectID)); } @@ -988,9 +995,9 @@ void cProtocol172::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimens cPacketizer Pkt(*this, 0x07); // Respawn packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteInt((int)a_Dimension); - Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte((Byte)Player->GetEffectiveGameMode()); + Pkt.WriteBEInt32((int)a_Dimension); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8((Byte)Player->GetEffectiveGameMode()); Pkt.WriteString("default"); m_LastSentDimension = a_Dimension; } @@ -1005,9 +1012,9 @@ void cProtocol172::SendExperience (void) cPacketizer Pkt(*this, 0x1f); // Experience Packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteFloat(Player->GetXpPercentage()); - Pkt.WriteShort(Player->GetXpLevel()); - Pkt.WriteShort(Player->GetCurrentXp()); + Pkt.WriteBEFloat(Player->GetXpPercentage()); + Pkt.WriteBEInt16(static_cast<UInt16>(std::max<int>(Player->GetXpLevel(), std::numeric_limits<UInt16>::max()))); + Pkt.WriteBEInt16(static_cast<UInt16>(std::max<int>(Player->GetCurrentXp(), std::numeric_limits<UInt16>::max()))); } @@ -1020,11 +1027,11 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) ASSERT((a_ExpOrb.GetReward() >= 0) && (a_ExpOrb.GetReward() < SHRT_MAX)); cPacketizer Pkt(*this, 0x11); - Pkt.WriteVarInt(static_cast<UInt32>(a_ExpOrb.GetUniqueID())); + Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID()); Pkt.WriteFPInt(a_ExpOrb.GetPosX()); Pkt.WriteFPInt(a_ExpOrb.GetPosY()); Pkt.WriteFPInt(a_ExpOrb.GetPosZ()); - Pkt.WriteShort(static_cast<short>(a_ExpOrb.GetReward())); + Pkt.WriteBEInt16(static_cast<short>(a_ExpOrb.GetReward())); } @@ -1038,7 +1045,7 @@ void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString cPacketizer Pkt(*this, 0x3b); Pkt.WriteString(a_Name); Pkt.WriteString(a_DisplayName); - Pkt.WriteByte(a_Mode); + Pkt.WriteBEUInt8(a_Mode); } @@ -1051,12 +1058,12 @@ void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & cPacketizer Pkt(*this, 0x3c); Pkt.WriteString(a_Player); - Pkt.WriteByte(a_Mode); + Pkt.WriteBEUInt8(a_Mode); if (a_Mode != 1) { Pkt.WriteString(a_Objective); - Pkt.WriteInt((int) a_Score); + Pkt.WriteBEInt32((int) a_Score); } } @@ -1069,7 +1076,7 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x3d); - Pkt.WriteByte(static_cast<Byte>(a_Display)); + Pkt.WriteBEUInt8(static_cast<Byte>(a_Display)); Pkt.WriteString(a_Objective); } @@ -1083,11 +1090,11 @@ void cProtocol172::SendSoundEffect(const AString & a_SoundName, double a_X, doub cPacketizer Pkt(*this, 0x29); // Sound Effect packet Pkt.WriteString(a_SoundName); - Pkt.WriteInt(static_cast<int>(a_X * 8.0)); - Pkt.WriteInt(static_cast<int>(a_Y * 8.0)); - Pkt.WriteInt(static_cast<int>(a_Z * 8.0)); - Pkt.WriteFloat(a_Volume); - Pkt.WriteByte(static_cast<Byte>(a_Pitch * 63)); + Pkt.WriteBEInt32(static_cast<int>(a_X * 8.0)); + Pkt.WriteBEInt32(static_cast<int>(a_Y * 8.0)); + Pkt.WriteBEInt32(static_cast<int>(a_Z * 8.0)); + Pkt.WriteBEFloat(a_Volume); + Pkt.WriteBEUInt8(static_cast<Byte>(a_Pitch * 63)); } @@ -1100,11 +1107,11 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src ASSERT((a_SrcY >= 0) && (a_SrcY < 256)); cPacketizer Pkt(*this, 0x28); // Effect packet - Pkt.WriteInt(a_EffectID); - Pkt.WriteInt(a_SrcX); - Pkt.WriteByte(static_cast<Byte>(a_SrcY)); - Pkt.WriteInt(a_SrcZ); - Pkt.WriteInt(a_Data); + Pkt.WriteBEInt32(a_EffectID); + Pkt.WriteBEInt32(a_SrcX); + Pkt.WriteBEUInt8(static_cast<Byte>(a_SrcY)); + Pkt.WriteBEInt32(a_SrcZ); + Pkt.WriteBEInt32(a_Data); Pkt.WriteBool(false); } @@ -1117,17 +1124,17 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0e); // Spawn Object packet - Pkt.WriteVarInt(static_cast<UInt32>(a_FallingBlock.GetUniqueID())); - Pkt.WriteByte(70); // Falling block + Pkt.WriteVarInt32(a_FallingBlock.GetUniqueID()); + Pkt.WriteBEUInt8(70); // Falling block Pkt.WriteFPInt(a_FallingBlock.GetPosX()); Pkt.WriteFPInt(a_FallingBlock.GetPosY()); Pkt.WriteFPInt(a_FallingBlock.GetPosZ()); Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); - Pkt.WriteInt((static_cast<int>(a_FallingBlock.GetBlockType()) | ((static_cast<int>(a_FallingBlock.GetBlockMeta()) << 16)))); - Pkt.WriteShort(static_cast<short>(a_FallingBlock.GetSpeedX() * 400)); - Pkt.WriteShort(static_cast<short>(a_FallingBlock.GetSpeedY() * 400)); - Pkt.WriteShort(static_cast<short>(a_FallingBlock.GetSpeedZ() * 400)); + Pkt.WriteBEInt32((static_cast<int>(a_FallingBlock.GetBlockType()) | ((static_cast<int>(a_FallingBlock.GetBlockMeta()) << 16)))); + Pkt.WriteBEInt16(static_cast<short>(a_FallingBlock.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_FallingBlock.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_FallingBlock.GetSpeedZ() * 400)); } @@ -1139,19 +1146,19 @@ void cProtocol172::SendSpawnMob(const cMonster & a_Mob) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Mob.GetUniqueID())); - Pkt.WriteByte((Byte)a_Mob.GetMobType()); + Pkt.WriteVarInt32(a_Mob.GetUniqueID()); + Pkt.WriteBEUInt8((Byte)a_Mob.GetMobType()); Pkt.WriteFPInt(a_Mob.GetPosX()); Pkt.WriteFPInt(a_Mob.GetPosY()); Pkt.WriteFPInt(a_Mob.GetPosZ()); Pkt.WriteByteAngle(a_Mob.GetPitch()); Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); - Pkt.WriteShort(static_cast<short>(a_Mob.GetSpeedX() * 400)); - Pkt.WriteShort(static_cast<short>(a_Mob.GetSpeedY() * 400)); - Pkt.WriteShort(static_cast<short>(a_Mob.GetSpeedZ() * 400)); - Pkt.WriteEntityMetadata(a_Mob); - Pkt.WriteByte(0x7f); // Metadata terminator + Pkt.WriteBEInt16(static_cast<short>(a_Mob.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Mob.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Mob.GetSpeedZ() * 400)); + WriteEntityMetadata(Pkt, a_Mob); + Pkt.WriteBEUInt8(0x7f); // Metadata terminator } @@ -1163,19 +1170,19 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0xe); // Spawn Object packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Entity.GetUniqueID())); - Pkt.WriteChar(a_ObjectType); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_ObjectType); Pkt.WriteFPInt(a_Entity.GetPosX()); Pkt.WriteFPInt(a_Entity.GetPosY()); Pkt.WriteFPInt(a_Entity.GetPosZ()); Pkt.WriteByteAngle(a_Entity.GetPitch()); Pkt.WriteByteAngle(a_Entity.GetYaw()); - Pkt.WriteInt(a_ObjectData); + Pkt.WriteBEInt32(a_ObjectData); if (a_ObjectData != 0) { - Pkt.WriteShort(static_cast<short>(a_Entity.GetSpeedX() * 400)); - Pkt.WriteShort(static_cast<short>(a_Entity.GetSpeedY() * 400)); - Pkt.WriteShort(static_cast<short>(a_Entity.GetSpeedZ() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedZ() * 400)); } } @@ -1188,19 +1195,19 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0xe); // Spawn Object packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Vehicle.GetUniqueID())); - Pkt.WriteChar(a_VehicleType); + Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); + Pkt.WriteBEInt8(a_VehicleType); Pkt.WriteFPInt(a_Vehicle.GetPosX()); Pkt.WriteFPInt(a_Vehicle.GetPosY()); Pkt.WriteFPInt(a_Vehicle.GetPosZ()); Pkt.WriteByteAngle(a_Vehicle.GetPitch()); Pkt.WriteByteAngle(a_Vehicle.GetYaw()); - Pkt.WriteInt(a_VehicleSubType); + Pkt.WriteBEInt32(a_VehicleSubType); if (a_VehicleSubType != 0) { - Pkt.WriteShort(static_cast<short>(a_Vehicle.GetSpeedX() * 400)); - Pkt.WriteShort(static_cast<short>(a_Vehicle.GetSpeedY() * 400)); - Pkt.WriteShort(static_cast<short>(a_Vehicle.GetSpeedZ() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedZ() * 400)); } } @@ -1213,7 +1220,7 @@ void cProtocol172::SendStatistics(const cStatManager & a_Manager) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x37); - Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only + Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only for (size_t i = 0; i < (size_t)statCount; ++i) { @@ -1221,7 +1228,7 @@ void cProtocol172::SendStatistics(const cStatManager & a_Manager) const AString & StatName = cStatInfo::GetName((eStatistic) i); Pkt.WriteString(StatName); - Pkt.WriteVarInt(static_cast<UInt32>(Value)); + Pkt.WriteVarInt32(static_cast<UInt32>(Value)); } } @@ -1234,7 +1241,7 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Results.size())); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Results.size())); for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr) { @@ -1251,7 +1258,7 @@ void cProtocol172::SendTeleportEntity(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x18); - Pkt.WriteInt(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); Pkt.WriteFPInt(a_Entity.GetPosX()); Pkt.WriteFPInt(a_Entity.GetPosY()); Pkt.WriteFPInt(a_Entity.GetPosZ()); @@ -1268,8 +1275,8 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet - Pkt.WriteVarInt(0); // EntityID = 0, always - Pkt.WriteByte(1); // Type = Thunderbolt + Pkt.WriteVarInt32(0); // EntityID = 0, always + Pkt.WriteBEUInt8(1); // Type = Thunderbolt Pkt.WriteFPInt(a_BlockX); Pkt.WriteFPInt(a_BlockY); Pkt.WriteFPInt(a_BlockZ); @@ -1289,8 +1296,8 @@ void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_Do } cPacketizer Pkt(*this, 0x03); - Pkt.WriteInt64(a_WorldAge); - Pkt.WriteInt64(a_TimeOfDay); + Pkt.WriteBEInt64(a_WorldAge); + Pkt.WriteBEInt64(a_TimeOfDay); } @@ -1302,12 +1309,12 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x21); // Chunk Data packet - Pkt.WriteInt(a_ChunkX); - Pkt.WriteInt(a_ChunkZ); + Pkt.WriteBEInt32(a_ChunkX); + Pkt.WriteBEInt32(a_ChunkZ); Pkt.WriteBool(true); - Pkt.WriteShort(0); // Primary bitmap - Pkt.WriteShort(0); // Add bitmap - Pkt.WriteInt(0); // Compressed data size + Pkt.WriteBEInt16(0); // Primary bitmap + Pkt.WriteBEInt16(0); // Add bitmap + Pkt.WriteBEInt32(0); // Compressed data size } @@ -1318,9 +1325,9 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x35); // Update tile entity packet - Pkt.WriteInt(a_BlockEntity.GetPosX()); - Pkt.WriteShort(static_cast<short>(a_BlockEntity.GetPosY())); - Pkt.WriteInt(a_BlockEntity.GetPosZ()); + Pkt.WriteBEInt32(a_BlockEntity.GetPosX()); + Pkt.WriteBEInt16(static_cast<short>(a_BlockEntity.GetPosY())); + Pkt.WriteBEInt32(a_BlockEntity.GetPosZ()); Byte Action = 0; switch (a_BlockEntity.GetBlockType()) @@ -1332,9 +1339,9 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; } - Pkt.WriteByte(Action); + Pkt.WriteBEUInt8(Action); - Pkt.WriteBlockEntity(a_BlockEntity); + WriteBlockEntity(Pkt, a_BlockEntity); } @@ -1347,9 +1354,9 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons ASSERT((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height)); cPacketizer Pkt(*this, 0x33); - Pkt.WriteInt(a_BlockX); - Pkt.WriteShort((short)a_BlockY); - Pkt.WriteInt(a_BlockZ); + Pkt.WriteBEInt32(a_BlockX); + Pkt.WriteBEInt16(static_cast<Int16>(a_BlockY)); + Pkt.WriteBEInt32(a_BlockZ); // Need to send only up to 15 chars, otherwise the client crashes (#598) Pkt.WriteString(a_Line1.substr(0, 15)); Pkt.WriteString(a_Line2.substr(0, 15)); @@ -1364,12 +1371,13 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) { ASSERT(m_State == 3); // In game mode? + ASSERT((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height)); cPacketizer Pkt(*this, 0x0a); - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteInt(a_BlockX); - Pkt.WriteByte((Byte)a_BlockY); - Pkt.WriteInt(a_BlockZ); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt32(a_BlockX); + Pkt.WriteBEUInt8(static_cast<Byte>(a_BlockY)); + Pkt.WriteBEInt32(a_BlockZ); } @@ -1382,8 +1390,8 @@ void cProtocol172::SendWeather(eWeather a_Weather) { cPacketizer Pkt(*this, 0x2b); // Change Game State packet - Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain - Pkt.WriteFloat(0); // Unused for weather + Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain + Pkt.WriteBEFloat(0); // Unused for weather } // TODO: Fade effect, somehow @@ -1398,13 +1406,13 @@ void cProtocol172::SendWholeInventory(const cWindow & a_Window) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x30); // Window Items packet - Pkt.WriteChar(a_Window.GetWindowID()); - Pkt.WriteShort(static_cast<short>(a_Window.GetNumSlots())); + Pkt.WriteBEInt8(a_Window.GetWindowID()); + Pkt.WriteBEInt16(static_cast<short>(a_Window.GetNumSlots())); cItems Slots; a_Window.GetSlots(*(m_Client->GetPlayer()), Slots); for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr) { - Pkt.WriteItem(*itr); + WriteItem(Pkt, *itr); } // for itr - Slots[] } @@ -1417,7 +1425,7 @@ void cProtocol172::SendWindowClose(const cWindow & a_Window) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2e); - Pkt.WriteChar(a_Window.GetWindowID()); + Pkt.WriteBEInt8(a_Window.GetWindowID()); } @@ -1435,14 +1443,14 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window) } cPacketizer Pkt(*this, 0x2d); - Pkt.WriteChar(a_Window.GetWindowID()); - Pkt.WriteChar(static_cast<char>(a_Window.GetWindowType())); + Pkt.WriteBEInt8(a_Window.GetWindowID()); + Pkt.WriteBEInt8(static_cast<char>(a_Window.GetWindowType())); Pkt.WriteString(a_Window.GetWindowTitle()); - Pkt.WriteChar(static_cast<char>(a_Window.GetNumNonInventorySlots())); + Pkt.WriteBEInt8(static_cast<char>(a_Window.GetNumNonInventorySlots())); Pkt.WriteBool(true); if (a_Window.GetWindowType() == cWindow::wtAnimalChest) { - Pkt.WriteInt(0); // TODO: The animal's EntityID + Pkt.WriteBEInt32(0); // TODO: The animal's EntityID } } @@ -1455,9 +1463,9 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x31); // Window Property packet - Pkt.WriteChar(a_Window.GetWindowID()); - Pkt.WriteShort(a_Property); - Pkt.WriteShort(a_Value); + Pkt.WriteBEInt8(a_Window.GetWindowID()); + Pkt.WriteBEInt16(a_Property); + Pkt.WriteBEInt16(a_Value); } @@ -1556,7 +1564,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size) bb.ReadAll(Packet); Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection AString Out; - CreateHexDump(Out, Packet.data(), (int)Packet.size(), 24); + CreateHexDump(Out, Packet.data(), Packet.size(), 24); LOGD("Packet contents:\n%s", Out.c_str()); #endif // _DEBUG @@ -1702,7 +1710,7 @@ void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp); cPacketizer Pkt(*this, 0x01); // Ping packet - Pkt.WriteInt64(Timestamp); + Pkt.WriteBEInt64(Timestamp); } @@ -1756,49 +1764,52 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer) { - short EncKeyLength, EncNonceLength; - if (!a_ByteBuffer.ReadBEShort(EncKeyLength)) + UInt16 EncKeyLength, EncNonceLength; + if (!a_ByteBuffer.ReadBEUInt16(EncKeyLength)) { return; } - if ((EncKeyLength < 0) || (EncKeyLength > MAX_ENC_LEN)) + if (EncKeyLength > MAX_ENC_LEN) { - LOGD("Invalid Encryption Key length: %d. Kicking client.", EncKeyLength); + LOGD("Invalid Encryption Key length: %u (0x%04x). Kicking client.", EncKeyLength, EncKeyLength); m_Client->Kick("Invalid EncKeyLength"); return; } AString EncKey; - if (!a_ByteBuffer.ReadString(EncKey, static_cast<size_t>(EncKeyLength))) + if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength)) { return; } - if (!a_ByteBuffer.ReadBEShort(EncNonceLength)) + if (!a_ByteBuffer.ReadBEUInt16(EncNonceLength)) { return; } - if ((EncNonceLength < 0) || (EncNonceLength > MAX_ENC_LEN)) + if (EncNonceLength > MAX_ENC_LEN) { - LOGD("Invalid Encryption Nonce length: %d. Kicking client.", EncNonceLength); + LOGD("Invalid Encryption Nonce length: %u (0x%04x). Kicking client.", EncNonceLength, EncNonceLength); m_Client->Kick("Invalid EncNonceLength"); return; } AString EncNonce; - if (!a_ByteBuffer.ReadString(EncNonce, static_cast<size_t>(EncNonceLength))) + if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength)) { return; } // Decrypt EncNonce using privkey cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); - Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; - int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce)); + UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(UInt32)]; + int res = rsaDecryptor.Decrypt( + reinterpret_cast<const Byte *>(EncNonce.data()), EncNonce.size(), + reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce) + ); if (res != 4) { LOGD("Bad nonce length: got %d, exp %d", res, 4); m_Client->Kick("Hacked client"); return; } - if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this) + if (ntohl(DecryptedNonce[0]) != static_cast<UInt32>(reinterpret_cast<uintptr_t>(this))) { LOGD("Bad nonce value"); m_Client->Kick("Hacked client"); @@ -1807,7 +1818,10 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe // Decrypt the symmetric encryption key using privkey: Byte DecryptedKey[MAX_ENC_LEN]; - res = rsaDecryptor.Decrypt((const Byte *)EncKey.data(), EncKey.size(), DecryptedKey, sizeof(DecryptedKey)); + res = rsaDecryptor.Decrypt( + reinterpret_cast<const Byte *>(EncKey.data()), EncKey.size(), + DecryptedKey, sizeof(DecryptedKey) + ); if (res != 16) { LOGD("Bad key length"); @@ -1845,10 +1859,10 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) cPacketizer Pkt(*this, 0x01); Pkt.WriteString(Server->GetServerID()); const AString & PubKeyDer = Server->GetPublicKeyDER(); - Pkt.WriteShort((short)PubKeyDer.size()); + Pkt.WriteBEUInt16(static_cast<UInt16>(PubKeyDer.size())); Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); - Pkt.WriteShort(4); - Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) + Pkt.WriteBEInt16(4); + Pkt.WriteBEUInt32(static_cast<UInt32>(reinterpret_cast<uintptr_t>(this))); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) m_Client->SetUsername(Username); return; } @@ -1862,8 +1876,8 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketAnimation(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Animation); + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Animation); m_Client->HandleAnimation(Animation); } @@ -1873,12 +1887,12 @@ void cProtocol172::HandlePacketAnimation(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadChar, char, Status); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, BlockY); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); - HANDLE_READ(a_ByteBuffer, ReadChar, char, Face); - m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), Status); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face); + m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), Status); } @@ -1887,17 +1901,17 @@ void cProtocol172::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, BlockY); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); - HANDLE_READ(a_ByteBuffer, ReadChar, char, Face); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face); cItem Item; ReadItem(a_ByteBuffer, Item); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorX); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorY); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorZ); - m_Client->HandleRightClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ); + m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); } @@ -1917,11 +1931,11 @@ void cProtocol172::HandlePacketChatMessage(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ViewDistance); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatFlags); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatColors); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Difficulty); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ShowCape); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatColors); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Difficulty); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, ShowCape); m_Client->SetLocale(Locale); m_Client->SetViewDistance(ViewDistance); @@ -1934,7 +1948,7 @@ void cProtocol172::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ActionID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID); switch (ActionID) { case 0: @@ -1966,13 +1980,13 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); cItem Item; if (!ReadItem(a_ByteBuffer, Item)) { return; } - m_Client->HandleCreativeInventory(SlotNum, Item); + m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum < 0) ? caLeftClick : caLeftClickOutside); } @@ -1981,9 +1995,9 @@ void cProtocol172::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffe void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, PlayerID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Action); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, JumpBoost); + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, PlayerID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, JumpBoost); switch (Action) { @@ -2001,7 +2015,7 @@ void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, KeepAliveID); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, KeepAliveID); m_Client->HandleKeepAlive(KeepAliveID); } @@ -2021,10 +2035,11 @@ void cProtocol172::HandlePacketPlayer(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketPlayerAbilities(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Flags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed); + // Convert flags bitfield into individual bool flags: bool IsFlying = false, CanFly = false; if ((Flags & 2) != 0) { @@ -2087,11 +2102,11 @@ void cProtocol172::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer) 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()) + HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, Length); + if (Length != a_ByteBuffer.GetReadableSpace() - 1) { - LOGD("Invalid plugin message packet, payload length doesn't match packet length (exp %d, got %d)", - static_cast<int>(a_ByteBuffer.GetReadableSpace()) - 1, Length + LOGD("Invalid plugin message packet, payload length doesn't match packet length (exp %u, got %u)", + static_cast<unsigned>(a_ByteBuffer.GetReadableSpace() - 1), Length ); return; } @@ -2105,7 +2120,7 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) // Read the plugin message and relay to clienthandle: AString Data; - if (!a_ByteBuffer.ReadString(Data, static_cast<size_t>(Length))) + if (!a_ByteBuffer.ReadString(Data, Length)) { return; } @@ -2118,7 +2133,7 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); m_Client->HandleSlotSelected(SlotNum); } @@ -2158,9 +2173,9 @@ void cProtocol172::HandlePacketTabComplete(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketUpdateSign(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, BlockY); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line1); HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line2); HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line3); @@ -2174,8 +2189,8 @@ void cProtocol172::HandlePacketUpdateSign(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, MouseButton); + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, MouseButton); m_Client->HandleUseEntity(EntityID, (MouseButton == 1)); } @@ -2185,8 +2200,8 @@ void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment); m_Client->HandleEnchantItem(WindowID, Enchantment); } @@ -2197,11 +2212,11 @@ void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID); - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Button); - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, TransactionID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Button); + HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, TransactionID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode); cItem Item; ReadItem(a_ByteBuffer, Item); @@ -2209,8 +2224,8 @@ void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) eClickAction Action; switch ((Mode << 8) | Button) { - case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break; - case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break; + case 0x0000: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftClick : caLeftClickOutside; break; + case 0x0001: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightClick : caRightClickOutside; break; case 0x0100: Action = caShiftLeftClick; break; case 0x0101: Action = caShiftRightClick; break; case 0x0200: Action = caNumber1; break; @@ -2223,14 +2238,14 @@ void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) 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 0x0400: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutsideHoldNothing : caDropKey; break; + case 0x0401: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break; + case 0x0500: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintBegin : caUnknown; break; + case 0x0501: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftPaintProgress : caUnknown; break; + case 0x0502: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintEnd : caUnknown; break; + case 0x0504: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintBegin : caUnknown; break; + case 0x0505: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightPaintProgress : caUnknown; break; + case 0x0506: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintEnd : caUnknown; break; case 0x0600: Action = caDblClick; break; default: { @@ -2249,7 +2264,7 @@ void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); m_Client->HandleWindowClose(WindowID); } @@ -2257,20 +2272,20 @@ void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) -void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength) +void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, UInt16 a_PayloadLength) { if (a_Channel == "MC|AdvCdm") { size_t BeginningSpace = a_ByteBuffer.GetReadableSpace(); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, 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, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); break; @@ -2288,12 +2303,12 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const // Read the remainder of the packet (Vanilla sometimes sends bogus data at the end of the packet; #1692): size_t BytesRead = BeginningSpace - a_ByteBuffer.GetReadableSpace(); - if (BytesRead < static_cast<size_t>(a_PayloadLength)) + if (BytesRead < a_PayloadLength) { LOGD("Protocol 1.7: Skipping garbage data at the end of a vanilla MC|AdvCdm packet, %u bytes", static_cast<unsigned>(a_PayloadLength - BytesRead) ); - a_ByteBuffer.SkipRead(static_cast<size_t>(a_PayloadLength) - BytesRead); + a_ByteBuffer.SkipRead(a_PayloadLength - BytesRead); } return; } @@ -2301,7 +2316,7 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const { // Read the client's brand: AString Brand; - if (a_ByteBuffer.ReadString(Brand, static_cast<size_t>(a_PayloadLength))) + if (a_ByteBuffer.ReadString(Brand, a_PayloadLength)) { m_Client->SetClientBrand(Brand); } @@ -2312,15 +2327,15 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const } else if (a_Channel == "MC|Beacon") { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect1); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect2); m_Client->HandleBeaconSelection(Effect1, Effect2); return; } else if (a_Channel == "MC|ItemName") { AString ItemName; - if (a_ByteBuffer.ReadString(ItemName, static_cast<size_t>(a_PayloadLength))) + if (a_ByteBuffer.ReadString(ItemName, a_PayloadLength)) { m_Client->HandleAnvilItemName(ItemName); } @@ -2328,7 +2343,7 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const } else if (a_Channel == "MC|TrSel") { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum); m_Client->HandleNPCTrade(SlotNum); return; } @@ -2336,7 +2351,7 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const // Read the payload and send it through to the clienthandle: AString Message; - VERIFY(a_ByteBuffer.ReadString(Message, static_cast<size_t>(a_PayloadLength))); + VERIFY(a_ByteBuffer.ReadString(Message, a_PayloadLength)); m_Client->HandlePluginMessage(a_Channel, Message); } @@ -2368,9 +2383,42 @@ void cProtocol172::SendData(const char * a_Data, size_t a_Size) +void cProtocol172::SendPacket(cPacketizer & a_Packet) +{ + AString DataToSend; + + // Send the packet length + UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace()); + + m_OutPacketLenBuffer.WriteVarInt32(PacketLen); + m_OutPacketLenBuffer.ReadAll(DataToSend); + SendData(DataToSend.data(), DataToSend.size()); + m_OutPacketLenBuffer.CommitRead(); + + // Send the packet data: + m_OutPacketBuffer.ReadAll(DataToSend); + SendData(DataToSend.data(), DataToSend.size()); + m_OutPacketBuffer.CommitRead(); + + // Log the comm into logfile: + if (g_ShouldLogCommOut) + { + AString Hex; + ASSERT(DataToSend.size() > 0); + CreateHexDump(Hex, DataToSend.data(), DataToSend.size(), 16); + m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload (incl. type):\n%s\n", + a_Packet.GetPacketType(), a_Packet.GetPacketType(), PacketLen, PacketLen, m_State, Hex.c_str() + ); + } +} + + + + + bool cProtocol172::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item) { - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemType); + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType); if (ItemType == -1) { // The item is empty, no more data follows @@ -2379,8 +2427,8 @@ bool cProtocol172::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item) } a_Item.m_ItemType = ItemType; - HANDLE_PACKET_READ(a_ByteBuffer, ReadChar, char, ItemCount); - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemDamage); + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount); + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage); a_Item.m_ItemCount = ItemCount; a_Item.m_ItemDamage = ItemDamage; if (ItemCount <= 0) @@ -2388,15 +2436,10 @@ bool cProtocol172::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item) a_Item.Empty(); } - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, MetadataLength); - if (MetadataLength <= 0) - { - return true; - } - // Read the metadata + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEUInt16, UInt16, MetadataLength); AString Metadata; - if (!a_ByteBuffer.ReadString(Metadata, static_cast<size_t>(MetadataLength))) + if (!a_ByteBuffer.ReadString(Metadata, MetadataLength)) { return false; } @@ -2512,35 +2555,19 @@ void cProtocol172::StartEncryption(const Byte * a_Key) -//////////////////////////////////////////////////////////////////////////////// -// cProtocol172::cPacketizer: - -cProtocol172::cPacketizer::~cPacketizer() +eBlockFace cProtocol172::FaceIntToBlockFace(Int8 a_BlockFace) { - AString DataToSend; - - // Send the packet length - UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace(); - - m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen); - m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend); - m_Protocol.SendData(DataToSend.data(), DataToSend.size()); - m_Protocol.m_OutPacketLenBuffer.CommitRead(); - - // Send the packet data: - m_Out.ReadAll(DataToSend); - m_Protocol.SendData(DataToSend.data(), DataToSend.size()); - m_Out.CommitRead(); - - // Log the comm into logfile: - if (g_ShouldLogCommOut) + // Normalize the blockface values returned from the protocol + // Anything known gets mapped 1:1, everything else returns BLOCK_FACE_NONE + switch (a_BlockFace) { - AString Hex; - ASSERT(DataToSend.size() > 0); - CreateHexDump(Hex, DataToSend.data() + 1, DataToSend.size() - 1, 16); - m_Protocol.m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload:\n%s\n", - DataToSend[0], DataToSend[0], PacketLen, PacketLen, m_Protocol.m_State, Hex.c_str() - ); + case BLOCK_FACE_XM: return BLOCK_FACE_XM; + case BLOCK_FACE_XP: return BLOCK_FACE_XP; + case BLOCK_FACE_YM: return BLOCK_FACE_YM; + case BLOCK_FACE_YP: return BLOCK_FACE_YP; + case BLOCK_FACE_ZM: return BLOCK_FACE_ZM; + case BLOCK_FACE_ZP: return BLOCK_FACE_ZP; + default: return BLOCK_FACE_NONE; } } @@ -2548,7 +2575,7 @@ cProtocol172::cPacketizer::~cPacketizer() -void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) +void cProtocol172::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; ASSERT(ItemType >= -1); // Check validity of packets in debug runtime @@ -2560,17 +2587,17 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) if (a_Item.IsEmpty()) { - WriteShort(-1); + a_Pkt.WriteBEInt16(-1); return; } - WriteShort(ItemType); - WriteChar (a_Item.m_ItemCount); - WriteShort(a_Item.m_ItemDamage); + a_Pkt.WriteBEInt16(ItemType); + a_Pkt.WriteBEInt8(a_Item.m_ItemCount); + a_Pkt.WriteBEInt16(a_Item.m_ItemDamage); if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR)) { - WriteShort(-1); + a_Pkt.WriteBEInt16(-1); return; } @@ -2619,15 +2646,15 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort((short)Compressed.size()); - WriteBuf(Compressed.data(), Compressed.size()); + a_Pkt.WriteBEUInt16(static_cast<UInt16>(Compressed.size())); + a_Pkt.WriteBuf(Compressed.data(), Compressed.size()); } -void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEntity) +void cProtocol172::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) { cFastNBTWriter Writer; @@ -2635,46 +2662,41 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt { case E_BLOCK_BEACON: { - cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity; - - Writer.AddInt("x", BeaconEntity.GetPosX()); - Writer.AddInt("y", BeaconEntity.GetPosY()); - Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); + auto & BeaconEntity = reinterpret_cast<const cBeaconEntity &>(a_BlockEntity); + Writer.AddInt("x", BeaconEntity.GetPosX()); + Writer.AddInt("y", BeaconEntity.GetPosY()); + Writer.AddInt("z", BeaconEntity.GetPosZ()); + Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); - Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); + Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_COMMAND_BLOCK: { - cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity; - + auto & CommandBlockEntity = reinterpret_cast<const cCommandBlockEntity &>(a_BlockEntity); Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); - Writer.AddInt("x", CommandBlockEntity.GetPosX()); - Writer.AddInt("y", CommandBlockEntity.GetPosY()); - Writer.AddInt("z", CommandBlockEntity.GetPosZ()); - Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str()); + Writer.AddInt("x", CommandBlockEntity.GetPosX()); + Writer.AddInt("y", CommandBlockEntity.GetPosY()); + Writer.AddInt("z", CommandBlockEntity.GetPosZ()); + Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str()); // You can set custom names for windows in Vanilla // For a command block, this would be the 'name' prepended to anything it outputs into global chat - // MCS doesn't have this, so just leave it @ '@'. (geddit?) + // MCS doesn't have this, so just leave it at '@'. Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - + Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though if (!CommandBlockEntity.GetLastOutput().empty()) { - AString Output; - Printf(Output, "{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()); - - Writer.AddString("LastOutput", Output.c_str()); + Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); } break; } + case E_BLOCK_HEAD: { - cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity; - + auto & MobHeadEntity = reinterpret_cast<const cMobHeadEntity &>(a_BlockEntity); Writer.AddInt("x", MobHeadEntity.GetPosX()); Writer.AddInt("y", MobHeadEntity.GetPosY()); Writer.AddInt("z", MobHeadEntity.GetPosZ()); @@ -2684,10 +2706,10 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_FLOWER_POT: { - cFlowerPotEntity & FlowerPotEntity = (cFlowerPotEntity &)a_BlockEntity; - + auto & FlowerPotEntity = reinterpret_cast<const cFlowerPotEntity &>(a_BlockEntity); Writer.AddInt("x", FlowerPotEntity.GetPosX()); Writer.AddInt("y", FlowerPotEntity.GetPosY()); Writer.AddInt("z", FlowerPotEntity.GetPosZ()); @@ -2696,10 +2718,10 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_MOB_SPAWNER: { - cMobSpawnerEntity & MobSpawnerEntity = (cMobSpawnerEntity &)a_BlockEntity; - + auto & MobSpawnerEntity = reinterpret_cast<const cMobSpawnerEntity &>(a_BlockEntity); Writer.AddInt("x", MobSpawnerEntity.GetPosX()); Writer.AddInt("y", MobSpawnerEntity.GetPosY()); Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); @@ -2708,41 +2730,26 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "MobSpawner"); break; } - default: break; + + default: + { + break; + } } Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort((short)Compressed.size()); - WriteBuf(Compressed.data(), Compressed.size()); + a_Pkt.WriteBEUInt16(static_cast<UInt16>(Compressed.size())); + a_Pkt.WriteBuf(Compressed.data(), Compressed.size()); } -void cProtocol172::cPacketizer::WriteByteAngle(double a_Angle) -{ - WriteChar(static_cast<char>(255 * a_Angle / 360)); -} - - - - - -void cProtocol172::cPacketizer::WriteFPInt(double a_Value) -{ - int Value = (int)(a_Value * 32); - WriteInt(Value); -} - - - - - -void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) +void cProtocol172::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) { // Common metadata: Byte Flags = 0; @@ -2766,21 +2773,21 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) { Flags |= 0x20; } - WriteByte(0); // Byte(0) + index 0 - WriteByte(Flags); + a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0 + a_Pkt.WriteBEUInt8(Flags); switch (a_Entity.GetEntityType()) { case cEntity::etPlayer: break; // TODO? case cEntity::etPickup: { - WriteByte((5 << 5) | 10); // Slot(5) + index 10 - WriteItem(((const cPickup &)a_Entity).GetItem()); + a_Pkt.WriteBEUInt8((5 << 5) | 10); // Slot(5) + index 10 + WriteItem(a_Pkt, reinterpret_cast<const cPickup &>(a_Entity).GetItem()); break; } case cEntity::etMinecart: { - WriteByte(0x51); + a_Pkt.WriteBEUInt8(0x51); // The following expression makes Minecarts shake more with less health or higher damage taken // It gets half the maximum health, and takes it away from the current health minus the half health: @@ -2789,263 +2796,274 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) Health: 3 | 3 - (3 - 3) = 3 Health: 1 | 3 - (1 - 3) = 5 */ - 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 + auto & Minecart = reinterpret_cast<const cMinecart &>(a_Entity); + a_Pkt.WriteBEInt32((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4); + a_Pkt.WriteBEUInt8(0x52); + a_Pkt.WriteBEInt32(1); // Shaking direction, doesn't seem to affect anything + a_Pkt.WriteBEUInt8(0x73); + a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10)); // Damage taken / shake effect multiplyer - if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone) + if (Minecart.GetPayload() == cMinecart::mpNone) { - cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity); + auto & RideableMinecart = reinterpret_cast<const cRideableMinecart &>(Minecart); const cItem & MinecartContent = RideableMinecart.GetContent(); if (!MinecartContent.IsEmpty()) { - WriteByte(0x54); + a_Pkt.WriteBEUInt8(0x54); int Content = MinecartContent.m_ItemType; Content |= MinecartContent.m_ItemDamage << 8; - WriteInt(Content); - WriteByte(0x55); - WriteInt(RideableMinecart.GetBlockHeight()); - WriteByte(0x56); - WriteByte(1); + a_Pkt.WriteBEInt32(Content); + a_Pkt.WriteBEUInt8(0x55); + a_Pkt.WriteBEInt32(RideableMinecart.GetBlockHeight()); + a_Pkt.WriteBEUInt8(0x56); + a_Pkt.WriteBEUInt8(1); } } - else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace) + else if (Minecart.GetPayload() == cMinecart::mpFurnace) { - WriteByte(0x10); - WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cMinecartWithFurnace &>(Minecart).IsFueled() ? 1 : 0); } break; - } + } // case etMinecart + case cEntity::etProjectile: { - cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity; + auto & Projectile = reinterpret_cast<const cProjectileEntity &>(a_Entity); switch (Projectile.GetProjectileKind()) { case cProjectileEntity::pkArrow: { - WriteByte(0x10); - WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cArrowEntity &>(a_Entity).IsCritical() ? 1 : 0); break; } case cProjectileEntity::pkFirework: { - WriteByte(0xA8); - WriteItem(((const cFireworkEntity &)a_Entity).GetItem()); + a_Pkt.WriteBEUInt8(0xa8); + WriteItem(a_Pkt, reinterpret_cast<const cFireworkEntity &>(a_Entity).GetItem()); break; } default: break; } break; - } + } // case etProjectile + case cEntity::etMonster: { - WriteMobMetadata((const cMonster &)a_Entity); + WriteMobMetadata(a_Pkt, reinterpret_cast<const cMonster &>(a_Entity)); break; - } + } // case etMonster + case cEntity::etItemFrame: { - cItemFrame & Frame = (cItemFrame &)a_Entity; - WriteByte(0xA2); - WriteItem(Frame.GetItem()); - WriteByte(0x3); - WriteByte(Frame.GetItemRotation() / 2); + auto & Frame = reinterpret_cast<const cItemFrame &>(a_Entity); + a_Pkt.WriteBEUInt8(0xa2); + WriteItem(a_Pkt, Frame.GetItem()); + a_Pkt.WriteBEUInt8(0x03); + a_Pkt.WriteBEUInt8(Frame.GetItemRotation() / 2); + break; + } // case etItemFrame + + default: + { break; } - default: break; - } + } // switch (EntityType) } -void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) +void cProtocol172::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) { switch (a_Mob.GetMobType()) { - case mtCreeper: - { - WriteByte(0x10); - WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : 0); - WriteByte(0x11); - WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0); - break; - } - case mtBat: { - WriteByte(0x10); - WriteByte(((const cBat &)a_Mob).IsHanging() ? 1 : 0); - break; - } - - case mtPig: - { - WriteByte(0x10); - WriteByte(((const cPig &)a_Mob).IsSaddled() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cBat &>(a_Mob).IsHanging() ? 1 : 0); break; - } + } // case mtBat - case mtVillager: + case mtCreeper: { - WriteByte(0x50); - WriteInt(((const cVillager &)a_Mob).GetVilType()); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cCreeper &>(a_Mob).IsBlowing() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x11); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cCreeper &>(a_Mob).IsCharged() ? 1 : 0); break; - } + } // case mtCreeper - case mtZombie: + case mtEnderman: { - WriteByte(0x0c); - WriteByte(((const cZombie &)a_Mob).IsBaby() ? 1 : 0); - WriteByte(0x0d); - WriteByte(((const cZombie &)a_Mob).IsVillagerZombie() ? 1 : 0); - WriteByte(0x0e); - WriteByte(((const cZombie &)a_Mob).IsConverting() ? 1 : 0); + auto & Enderman = reinterpret_cast<const cEnderman &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8((Byte)(Enderman.GetCarriedBlock())); + a_Pkt.WriteBEUInt8(0x11); + a_Pkt.WriteBEUInt8((Byte)(Enderman.GetCarriedMeta())); + a_Pkt.WriteBEUInt8(0x12); + a_Pkt.WriteBEUInt8(Enderman.IsScreaming() ? 1 : 0); break; - } + } // case mtEnderman case mtGhast: { - WriteByte(0x10); - WriteByte(((const cGhast &)a_Mob).IsCharging()); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cGhast &>(a_Mob).IsCharging()); break; - } + } // case mtGhast - case mtWolf: + case mtHorse: { - const cWolf & Wolf = (const cWolf &)a_Mob; - Byte WolfStatus = 0; - if (Wolf.IsSitting()) + auto & Horse = reinterpret_cast<const cHorse &>(a_Mob); + int Flags = 0; + if (Horse.IsTame()) { - WolfStatus |= 0x1; + Flags |= 0x02; } - if (Wolf.IsAngry()) + if (Horse.IsSaddled()) { - WolfStatus |= 0x2; + Flags |= 0x04; } - if (Wolf.IsTame()) + if (Horse.IsChested()) { - WolfStatus |= 0x4; + Flags |= 0x08; } - WriteByte(0x10); - WriteByte(WolfStatus); - - WriteByte(0x72); - WriteFloat((float)(a_Mob.GetHealth())); - WriteByte(0x13); - WriteByte(Wolf.IsBegging() ? 1 : 0); - WriteByte(0x14); - WriteByte(static_cast<Byte>(Wolf.GetCollarColor())); + if (Horse.IsBaby()) + { + Flags |= 0x10; + } + if (Horse.IsEating()) + { + Flags |= 0x20; + } + if (Horse.IsRearing()) + { + Flags |= 0x40; + } + if (Horse.IsMthOpen()) + { + Flags |= 0x80; + } + a_Pkt.WriteBEUInt8(0x50); // Int at index 16 + a_Pkt.WriteBEInt32(Flags); + a_Pkt.WriteBEUInt8(0x13); // Byte at index 19 + a_Pkt.WriteBEUInt8(static_cast<Byte>(Horse.GetHorseType())); + a_Pkt.WriteBEUInt8(0x54); // Int at index 20 + int Appearance = 0; + Appearance = Horse.GetHorseColor(); + Appearance |= Horse.GetHorseStyle() << 8; + a_Pkt.WriteBEInt32(Appearance); + a_Pkt.WriteBEUInt8(0x56); // Int at index 22 + a_Pkt.WriteBEInt32(Horse.GetHorseArmour()); break; - } + } // case mtHorse + + case mtMagmaCube: + { + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(static_cast<Byte>(reinterpret_cast<const cMagmaCube &>(a_Mob).GetSize())); + break; + } // case mtMagmaCube + + case mtPig: + { + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cPig &>(a_Mob).IsSaddled() ? 1 : 0); + break; + } // case mtPig case mtSheep: { - WriteByte(0x10); - Byte SheepMetadata = static_cast<Byte>(((const cSheep &)a_Mob).GetFurColor() & 0x0f); - if (((const cSheep &)a_Mob).IsSheared()) + a_Pkt.WriteBEUInt8(0x10); + auto & Sheep = reinterpret_cast<const cSheep &>(a_Mob); + Byte SheepMetadata = static_cast<Byte>(Sheep.GetFurColor() & 0x0f); + if (Sheep.IsSheared()) { SheepMetadata |= 0x10; } - WriteByte(SheepMetadata); + a_Pkt.WriteBEUInt8(SheepMetadata); break; - } - - case mtEnderman: - { - WriteByte(0x10); - WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedBlock())); - WriteByte(0x11); - WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedMeta())); - WriteByte(0x12); - WriteByte(((const cEnderman &)a_Mob).IsScreaming() ? 1 : 0); - break; - } + } // case mtSheep case mtSkeleton: { - WriteByte(0x0d); - WriteByte(((const cSkeleton &)a_Mob).IsWither() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x0d); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cSkeleton &>(a_Mob).IsWither() ? 1 : 0); break; - } + } // case mtSkeleton - case mtWitch: + case mtSlime: { - WriteByte(0x15); - WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(static_cast<Byte>(reinterpret_cast<const cSlime &>(a_Mob).GetSize())); break; - } - - case mtWither: + } // case mtSlime + + case mtVillager: { - WriteByte(0x54); // Int at index 20 - WriteInt(static_cast<int>(((const cWither &)a_Mob).GetWitherInvulnerableTicks())); - WriteByte(0x66); // Float at index 6 - WriteFloat((float)(a_Mob.GetHealth())); + a_Pkt.WriteBEUInt8(0x50); + a_Pkt.WriteBEInt32(reinterpret_cast<const cVillager &>(a_Mob).GetVilType()); break; - } + } // case mtVillager - case mtSlime: + case mtWitch: { - WriteByte(0x10); - WriteByte(static_cast<Byte>(((const cSlime &)a_Mob).GetSize())); + a_Pkt.WriteBEUInt8(0x15); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cWitch &>(a_Mob).IsAngry() ? 1 : 0); break; - } - - case mtMagmaCube: + } // case mtWitch + + case mtWither: { - WriteByte(0x10); - WriteByte(static_cast<Byte>(((const cMagmaCube &)a_Mob).GetSize())); + a_Pkt.WriteBEUInt8(0x54); // Int at index 20 + a_Pkt.WriteBEInt32(static_cast<int>(reinterpret_cast<const cWither &>(a_Mob).GetWitherInvulnerableTicks())); + a_Pkt.WriteBEUInt8(0x66); // Float at index 6 + a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); break; - } + } // case mtWither - case mtHorse: + case mtWolf: { - const cHorse & Horse = (const cHorse &)a_Mob; - int Flags = 0; - if (Horse.IsTame()) - { - Flags |= 0x02; - } - if (Horse.IsSaddled()) - { - Flags |= 0x04; - } - if (Horse.IsChested()) - { - Flags |= 0x08; - } - if (Horse.IsBaby()) - { - Flags |= 0x10; - } - if (Horse.IsEating()) + auto & Wolf = reinterpret_cast<const cWolf &>(a_Mob); + Byte WolfStatus = 0; + if (Wolf.IsSitting()) { - Flags |= 0x20; + WolfStatus |= 0x1; } - if (Horse.IsRearing()) + if (Wolf.IsAngry()) { - Flags |= 0x40; + WolfStatus |= 0x2; } - if (Horse.IsMthOpen()) + if (Wolf.IsTame()) { - Flags |= 0x80; + WolfStatus |= 0x4; } - WriteByte(0x50); // Int at index 16 - WriteInt(Flags); - WriteByte(0x13); // Byte at index 19 - WriteByte(static_cast<Byte>(Horse.GetHorseType())); - WriteByte(0x54); // Int at index 20 - int Appearance = 0; - Appearance = Horse.GetHorseColor(); - Appearance |= Horse.GetHorseStyle() << 8; - WriteInt(Appearance); - WriteByte(0x56); // Int at index 22 - WriteInt(Horse.GetHorseArmour()); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(WolfStatus); + + a_Pkt.WriteBEUInt8(0x72); + a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); + a_Pkt.WriteBEUInt8(0x13); + a_Pkt.WriteBEUInt8(Wolf.IsBegging() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x14); + a_Pkt.WriteBEUInt8(static_cast<Byte>(Wolf.GetCollarColor())); break; - } + } // case mtWolf + + case mtZombie: + { + auto & Zombie = reinterpret_cast<const cZombie &>(a_Mob); + a_Pkt.WriteBEUInt8(0x0c); + a_Pkt.WriteBEUInt8(Zombie.IsBaby() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x0d); + a_Pkt.WriteBEUInt8(Zombie.IsVillagerZombie() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x0e); + a_Pkt.WriteBEUInt8(Zombie.IsConverting() ? 1 : 0); + break; + } // case mtZombie default: { @@ -3057,10 +3075,10 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) // Custom name: if (a_Mob.HasCustomName()) { - WriteByte(0x8a); - WriteString(a_Mob.GetCustomName()); - WriteByte(0x0b); - WriteByte(a_Mob.IsCustomNameAlwaysVisible() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x8a); + a_Pkt.WriteString(a_Mob.GetCustomName()); + a_Pkt.WriteBEUInt8(0x0b); + a_Pkt.WriteBEUInt8(a_Mob.IsCustomNameAlwaysVisible() ? 1 : 0); } } @@ -3068,20 +3086,20 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) -void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) +void cProtocol172::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) { if (!a_Entity.IsMob()) { // No properties for anything else than mobs - WriteInt(0); + a_Pkt.WriteBEInt32(0); return; } - // const cMonster & Mob = (const cMonster &)a_Entity; + // auto & Mob = reinterpret_cast<const cMonster &>(a_Entity); // TODO: Send properties and modifiers based on the mob type - WriteInt(0); // NumProperties + a_Pkt.WriteBEInt32(0); // NumProperties } @@ -3104,7 +3122,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) { // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet - Pkt.WriteVarInt(static_cast<UInt32>(a_Player.GetUniqueID())); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); if (a_Player.HasCustomName()) { @@ -3116,7 +3134,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) } const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); - Pkt.WriteVarInt(Properties.size()); + Pkt.WriteVarInt32(Properties.size()); for (Json::Value::iterator itr = Properties.begin(), end = Properties.end(); itr != end; ++itr) { @@ -3131,10 +3149,10 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) Pkt.WriteByteAngle(a_Player.GetYaw()); Pkt.WriteByteAngle(a_Player.GetPitch()); short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType; - Pkt.WriteShort(ItemType); - Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6 - Pkt.WriteFloat((float)a_Player.GetHealth()); - Pkt.WriteByte(0x7f); // Metadata: end + Pkt.WriteBEInt16(ItemType); + Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6 + Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth())); + Pkt.WriteBEUInt8(0x7f); // Metadata: end } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index f939bfb5e..1212cc325 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -63,7 +63,7 @@ public: /** 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 SendBlockBreakAnim (UInt32 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; @@ -140,89 +140,6 @@ public: protected: - /** Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed */ - class cPacketizer - { - public: - cPacketizer(cProtocol172 & a_Protocol, UInt32 a_PacketType) : - m_Protocol(a_Protocol), - m_Out(a_Protocol.m_OutPacketBuffer), - m_Lock(a_Protocol.m_CSPacket) - { - m_Out.WriteVarInt(a_PacketType); - } - - ~cPacketizer(); - - void WriteBool(bool a_Value) - { - m_Out.WriteBool(a_Value); - } - - void WriteByte(Byte a_Value) - { - m_Out.WriteByte(a_Value); - } - - void WriteChar(char a_Value) - { - m_Out.WriteChar(a_Value); - } - - void WriteShort(short a_Value) - { - m_Out.WriteBEShort(a_Value); - } - - void WriteInt(int a_Value) - { - m_Out.WriteBEInt(a_Value); - } - - void WriteInt64(Int64 a_Value) - { - m_Out.WriteBEInt64(a_Value); - } - - void WriteFloat(float a_Value) - { - m_Out.WriteBEFloat(a_Value); - } - - void WriteDouble(double a_Value) - { - m_Out.WriteBEDouble(a_Value); - } - - void WriteVarInt(UInt32 a_Value) - { - m_Out.WriteVarInt(a_Value); - } - - void WriteString(const AString & a_Value) - { - m_Out.WriteVarUTF8String(a_Value); - } - - void WriteBuf(const char * a_Data, size_t a_Size) - { - m_Out.Write(a_Data, a_Size); - } - - void WriteItem(const cItem & a_Item); - void WriteByteAngle(double a_Angle); // Writes the specified angle using a single byte - void WriteFPInt(double a_Value); // Writes the double value as a 27:5 fixed-point integer - void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f - void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob - void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field - void WriteBlockEntity(const cBlockEntity & a_BlockEntity); - - protected: - cProtocol172 & m_Protocol; - cByteBuffer & m_Out; - cCSLock m_Lock; - } ; - AString m_ServerAddress; UInt16 m_ServerPort; @@ -235,12 +152,6 @@ protected: /** Buffer for the received data */ cByteBuffer m_ReceivedData; - /** Buffer for composing the outgoing packets, through cPacketizer */ - cByteBuffer m_OutPacketBuffer; - - /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */ - cByteBuffer m_OutPacketLenBuffer; - bool m_IsEncrypted; cAesCfb128Decryptor m_Decryptor; @@ -297,11 +208,14 @@ protected: /** 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); + void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, UInt16 a_PayloadLength); /** Sends the data to the client, encrypting them if needed. */ virtual void SendData(const char * a_Data, size_t a_Size) override; + /** Sends the packet to the client. Called by the cPacketizer's destructor. */ + virtual void SendPacket(cPacketizer & a_Packet) override; + void SendCompass(const cWorld & a_World); /** Reads an item out of the received data, sets a_Item to the values read. Returns false if not enough received data */ @@ -312,6 +226,24 @@ protected: void StartEncryption(const Byte * a_Key); + /** Converts the BlockFace received by the protocol into eBlockFace constants. + If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */ + eBlockFace FaceIntToBlockFace(Int8 a_FaceInt); + + /** Writes the item data into a packet. */ + void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); + + /** Writes the metadata for the specified entity, not including the terminating 0x7f. */ + void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity); + + /** Writes the mob-specific metadata for the specified mob */ + void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob); + + /** Writes the entity properties for the specified entity, including the Count field. */ + void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); + + /** Writes the block entity data for the specified block entity into the packet. */ + void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); } ; diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index 22280f800..a1ca25200 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -13,6 +13,7 @@ Implements the 1.8.x protocol classes: #include "Protocol18x.h" #include "ChunkDataSerializer.h" #include "PolarSSL++/Sha1Checksum.h" +#include "Packetizer.h" #include "../ClientHandle.h" #include "../Root.h" @@ -49,6 +50,13 @@ Implements the 1.8.x protocol classes: +/** The slot number that the client uses to indicate "outside the window". */ +static const Int16 SLOT_NUM_OUTSIDE = -999; + + + + + #define HANDLE_READ(ByteBuf, Proc, Type, Var) \ Type Var; \ if (!ByteBuf.Proc(Var))\ @@ -98,8 +106,6 @@ cProtocol180::cProtocol180(cClientHandle * a_Client, const AString & a_ServerAdd m_ServerPort(a_ServerPort), m_State(a_State), m_ReceivedData(32 KiB), - m_OutPacketBuffer(64 KiB), - m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt m_IsEncrypted(false), m_LastSentDimension(dimNotSet) { @@ -155,8 +161,8 @@ void cProtocol180::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_ ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1b); // Attach Entity packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteInt((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0); Pkt.WriteBool(false); } @@ -169,24 +175,24 @@ void cProtocol180::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x24); // Block Action packet - Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ); - Pkt.WriteByte(a_Byte1); - Pkt.WriteByte(a_Byte2); - Pkt.WriteVarInt(a_BlockType); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); + Pkt.WriteBEInt8(a_Byte1); + Pkt.WriteBEInt8(a_Byte2); + Pkt.WriteVarInt32(a_BlockType); } -void cProtocol180::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) +void cProtocol180::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x25); // Block Break Animation packet - Pkt.WriteVarInt(a_EntityID); - Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ); - Pkt.WriteChar(a_Stage); + Pkt.WriteVarInt32(a_EntityID); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); + Pkt.WriteBEInt8(a_Stage); } @@ -198,8 +204,8 @@ void cProtocol180::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x23); // Block Change packet - Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ); - Pkt.WriteVarInt(((UInt32)a_BlockType << 4) | ((UInt32)a_BlockMeta & 15)); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); + Pkt.WriteVarInt32(((UInt32)a_BlockType << 4) | ((UInt32)a_BlockMeta & 15)); } @@ -211,14 +217,14 @@ void cProtocol180::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x22); // Multi Block Change packet - Pkt.WriteInt(a_ChunkX); - Pkt.WriteInt(a_ChunkZ); - Pkt.WriteVarInt((UInt32)a_Changes.size()); + Pkt.WriteBEInt32(a_ChunkX); + Pkt.WriteBEInt32(a_ChunkZ); + Pkt.WriteVarInt32((UInt32)a_Changes.size()); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { - short Coords = (short) (itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12)); - Pkt.WriteShort(Coords); - Pkt.WriteVarInt((itr->m_BlockType & 0xFFF) << 4 | (itr->m_BlockMeta & 0xF)); + Int16 Coords = static_cast<Int16>(itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12)); + Pkt.WriteBEInt16(Coords); + Pkt.WriteVarInt32((itr->m_BlockType & 0xFFF) << 4 | (itr->m_BlockMeta & 0xF)); } // for itr - a_Changes[] } @@ -232,7 +238,7 @@ void cProtocol180::SendChat(const AString & a_Message) cPacketizer Pkt(*this, 0x02); // Chat Message packet Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); - Pkt.WriteChar(0); + Pkt.WriteBEInt8(0); } @@ -249,7 +255,7 @@ void cProtocol180::SendChat(const cCompositeChat & a_Message) // Send the message to the client: cPacketizer Pkt(*this, 0x02); Pkt.WriteString(a_Message.CreateJsonString(ShouldUseChatPrefixes)); - Pkt.WriteChar(0); + Pkt.WriteBEInt8(0); } @@ -277,8 +283,8 @@ void cProtocol180::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0d); // Collect Item packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteVarInt(a_Player.GetUniqueID()); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); } @@ -290,8 +296,8 @@ void cProtocol180::SendDestroyEntity(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x13); // Destroy Entities packet - Pkt.WriteVarInt(1); - Pkt.WriteVarInt(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(1); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); } @@ -328,7 +334,7 @@ void cProtocol180::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet - Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); } @@ -340,10 +346,10 @@ void cProtocol180::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1D); // Entity Effect packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(a_EffectID); - Pkt.WriteByte(a_Amplifier); - Pkt.WriteVarInt((UInt32)a_Duration); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID)); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier)); + Pkt.WriteVarInt32((UInt32)a_Duration); Pkt.WriteBool(false); // Hide particles } @@ -356,9 +362,9 @@ void cProtocol180::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x04); // Entity Equipment packet - Pkt.WriteVarInt((UInt32)a_Entity.GetUniqueID()); - Pkt.WriteShort(a_SlotNum); - Pkt.WriteItem(a_Item); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt16(a_SlotNum); + WriteItem(Pkt, a_Item); } @@ -370,7 +376,7 @@ void cProtocol180::SendEntityHeadLook(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x19); // Entity Head Look packet - Pkt.WriteVarInt((UInt32)a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); } @@ -383,7 +389,7 @@ void cProtocol180::SendEntityLook(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x16); // Entity Look packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); Pkt.WriteBool(a_Entity.IsOnGround()); @@ -398,9 +404,9 @@ void cProtocol180::SendEntityMetadata(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteEntityMetadata(a_Entity); - Pkt.WriteByte(0x7f); // The termination byte + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityMetadata(Pkt, a_Entity); + Pkt.WriteBEUInt8(0x7f); // The termination byte } @@ -412,8 +418,8 @@ void cProtocol180::SendEntityProperties(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x20); // Entity Properties packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteEntityProperties(a_Entity); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityProperties(Pkt, a_Entity); } @@ -425,10 +431,10 @@ void cProtocol180::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(a_RelX); - Pkt.WriteByte(a_RelY); - Pkt.WriteByte(a_RelZ); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_RelX); + Pkt.WriteBEInt8(a_RelY); + Pkt.WriteBEInt8(a_RelZ); Pkt.WriteBool(a_Entity.IsOnGround()); } @@ -441,10 +447,10 @@ void cProtocol180::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(a_RelX); - Pkt.WriteByte(a_RelY); - Pkt.WriteByte(a_RelZ); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_RelX); + Pkt.WriteBEInt8(a_RelY); + Pkt.WriteBEInt8(a_RelZ); Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); Pkt.WriteBool(a_Entity.IsOnGround()); @@ -459,8 +465,8 @@ void cProtocol180::SendEntityStatus(const cEntity & a_Entity, char a_Status) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1a); // Entity Status packet - Pkt.WriteInt(a_Entity.GetUniqueID()); - Pkt.WriteChar(a_Status); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_Status); } @@ -472,11 +478,11 @@ void cProtocol180::SendEntityVelocity(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x12); // Entity Velocity packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); // 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick - Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400)); - Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400)); - Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400)); + Pkt.WriteBEInt16((short)(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16((short)(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16((short)(a_Entity.GetSpeedZ() * 400)); } @@ -488,20 +494,20 @@ void cProtocol180::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x27); // Explosion packet - Pkt.WriteFloat((float)a_BlockX); - Pkt.WriteFloat((float)a_BlockY); - Pkt.WriteFloat((float)a_BlockZ); - Pkt.WriteFloat((float)a_Radius); - Pkt.WriteInt((int)a_BlocksAffected.size()); + Pkt.WriteBEFloat(static_cast<float>(a_BlockX)); + Pkt.WriteBEFloat(static_cast<float>(a_BlockY)); + Pkt.WriteBEFloat(static_cast<float>(a_BlockZ)); + Pkt.WriteBEFloat(static_cast<float>(a_Radius)); + Pkt.WriteBEUInt32(static_cast<UInt32>(a_BlocksAffected.size())); for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr) { - Pkt.WriteChar((char)itr->x); - Pkt.WriteChar((char)itr->y); - Pkt.WriteChar((char)itr->z); + Pkt.WriteBEInt8(static_cast<Int8>(itr->x)); + Pkt.WriteBEInt8(static_cast<Int8>(itr->y)); + Pkt.WriteBEInt8(static_cast<Int8>(itr->z)); } // for itr - a_BlockAffected[] - Pkt.WriteFloat((float)a_PlayerMotion.x); - Pkt.WriteFloat((float)a_PlayerMotion.y); - Pkt.WriteFloat((float)a_PlayerMotion.z); + Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.x)); + Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.y)); + Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.z)); } @@ -513,8 +519,8 @@ void cProtocol180::SendGameMode(eGameMode a_GameMode) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2b); // Change Game State packet - Pkt.WriteByte(3); // Reason: Change game mode - Pkt.WriteFloat((float)a_GameMode); + Pkt.WriteBEUInt8(3); // Reason: Change game mode + Pkt.WriteBEFloat(static_cast<float>(a_GameMode)); // The protocol really represents the value with a float! } @@ -527,9 +533,9 @@ void cProtocol180::SendHealth(void) cPacketizer Pkt(*this, 0x06); // Update Health packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteFloat((float)Player->GetHealth()); - Pkt.WriteVarInt((UInt32)Player->GetFoodLevel()); - Pkt.WriteFloat((float)Player->GetFoodSaturationLevel()); + Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth())); + Pkt.WriteVarInt32((UInt32)Player->GetFoodLevel()); + Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel())); } @@ -541,9 +547,9 @@ void cProtocol180::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2f); // Set Slot packet - Pkt.WriteChar(a_WindowID); - Pkt.WriteShort(a_SlotNum); - Pkt.WriteItem(a_Item); + Pkt.WriteBEInt8(a_WindowID); + Pkt.WriteBEInt16(a_SlotNum); + WriteItem(Pkt, a_Item); } @@ -560,7 +566,7 @@ void cProtocol180::SendKeepAlive(int a_PingID) } cPacketizer Pkt(*this, 0x00); // Keep Alive packet - Pkt.WriteVarInt(a_PingID); + Pkt.WriteVarInt32(a_PingID); } @@ -573,11 +579,11 @@ void cProtocol180::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { cServer * Server = cRoot::Get()->GetServer(); cPacketizer Pkt(*this, 0x01); // Join Game packet - Pkt.WriteInt(a_Player.GetUniqueID()); - Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 - Pkt.WriteChar((char)a_World.GetDimension()); - Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte(Server->GetMaxPlayers()); + Pkt.WriteBEUInt32(a_Player.GetUniqueID()); + Pkt.WriteBEUInt8((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 + Pkt.WriteBEInt8((char)a_World.GetDimension()); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8(Server->GetMaxPlayers()); Pkt.WriteString("default"); // Level type - wtf? Pkt.WriteBool(false); // Reduced Debug Info - wtf? } @@ -586,13 +592,13 @@ void cProtocol180::SendLogin(const cPlayer & a_Player, const cWorld & a_World) // Send the spawn position: { cPacketizer Pkt(*this, 0x05); // Spawn Position packet - Pkt.WritePosition((int)a_World.GetSpawnX(), (int)a_World.GetSpawnY(), (int)a_World.GetSpawnZ()); + Pkt.WritePosition64((int)a_World.GetSpawnX(), (int)a_World.GetSpawnY(), (int)a_World.GetSpawnZ()); } // Send the server difficulty: { cPacketizer Pkt(*this, 0x41); - Pkt.WriteChar(1); + Pkt.WriteBEInt8(1); } // Send player abilities: @@ -609,7 +615,7 @@ void cProtocol180::SendLoginSuccess(void) // Enable compression: { cPacketizer Pkt(*this, 0x03); // Set compression packet - Pkt.WriteVarInt(256); + Pkt.WriteVarInt32(256); } m_State = 3; // State = Game @@ -632,19 +638,11 @@ void cProtocol180::SendPaintingSpawn(const cPainting & a_Painting) double PosY = a_Painting.GetPosY(); double PosZ = a_Painting.GetPosZ(); - switch (a_Painting.GetDirection()) - { - case 0: PosZ += 1; break; - case 1: PosX -= 1; break; - case 2: PosZ -= 1; break; - case 3: PosX += 1; break; - } - cPacketizer Pkt(*this, 0x10); // Spawn Painting packet - Pkt.WriteVarInt(a_Painting.GetUniqueID()); + Pkt.WriteVarInt32(a_Painting.GetUniqueID()); Pkt.WriteString(a_Painting.GetName().c_str()); - Pkt.WritePosition((int)PosX, (int)PosY, (int)PosZ); - Pkt.WriteChar(a_Painting.GetDirection()); + Pkt.WritePosition64((int)PosX, (int)PosY, (int)PosZ); + Pkt.WriteBEInt8(a_Painting.GetProtocolFacing()); } @@ -656,19 +654,19 @@ void cProtocol180::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x34); - Pkt.WriteVarInt(a_ID); - Pkt.WriteByte(m_Scale); + Pkt.WriteVarInt32(a_ID); + Pkt.WriteBEUInt8(m_Scale); - Pkt.WriteVarInt(0); - Pkt.WriteByte(1); - Pkt.WriteByte(a_Length); - Pkt.WriteByte(a_X); - Pkt.WriteByte(a_Y); + Pkt.WriteVarInt32(0); + Pkt.WriteBEUInt8(1); + Pkt.WriteBEUInt8(a_Length); + Pkt.WriteBEUInt8(a_X); + Pkt.WriteBEUInt8(a_Y); - Pkt.WriteVarInt(a_Length); + Pkt.WriteVarInt32(a_Length); for (unsigned int i = 0; i < a_Length; ++i) { - Pkt.WriteByte(a_Colors[i]); + Pkt.WriteBEUInt8(a_Colors[i]); } } @@ -681,18 +679,18 @@ void cProtocol180::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x34); - Pkt.WriteVarInt(a_ID); - Pkt.WriteByte(m_Scale); - Pkt.WriteVarInt(a_Decorators.size()); + Pkt.WriteVarInt32(a_ID); + Pkt.WriteBEUInt8(m_Scale); + Pkt.WriteVarInt32(a_Decorators.size()); for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) { - Pkt.WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf)); - Pkt.WriteByte(it->GetPixelX()); - Pkt.WriteByte(it->GetPixelZ()); + Pkt.WriteBEUInt8((it->GetType() << 4) | (it->GetRot() & 0xf)); + Pkt.WriteBEUInt8(it->GetPixelX()); + Pkt.WriteBEUInt8(it->GetPixelZ()); } - Pkt.WriteByte(0); + Pkt.WriteBEUInt8(0); } @@ -717,22 +715,22 @@ void cProtocol180::SendPickupSpawn(const cPickup & a_Pickup) { cPacketizer Pkt(*this, 0x0e); // Spawn Object packet - Pkt.WriteVarInt(a_Pickup.GetUniqueID()); - Pkt.WriteByte(2); // Type = Pickup + Pkt.WriteVarInt32(a_Pickup.GetUniqueID()); + Pkt.WriteBEUInt8(2); // Type = Pickup Pkt.WriteFPInt(a_Pickup.GetPosX()); Pkt.WriteFPInt(a_Pickup.GetPosY()); Pkt.WriteFPInt(a_Pickup.GetPosZ()); Pkt.WriteByteAngle(a_Pickup.GetYaw()); Pkt.WriteByteAngle(a_Pickup.GetPitch()); - Pkt.WriteInt(0); // No object data + Pkt.WriteBEInt32(0); // No object data } { cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet - Pkt.WriteVarInt(a_Pickup.GetUniqueID()); - Pkt.WriteByte((0x05 << 5) | 10); // Slot type + index 10 - Pkt.WriteItem(a_Pickup.GetItem()); - Pkt.WriteByte(0x7f); // End of metadata + Pkt.WriteVarInt32(a_Pickup.GetUniqueID()); + Pkt.WriteBEUInt8((0x05 << 5) | 10); // Slot type + index 10 + WriteItem(Pkt, a_Pickup.GetItem()); + Pkt.WriteBEUInt8(0x7f); // End of metadata } } @@ -760,9 +758,9 @@ void cProtocol180::SendPlayerAbilities(void) { Flags |= 0x04; } - Pkt.WriteByte(Flags); - Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed())); - Pkt.WriteFloat((float)(0.1 * Player->GetNormalMaxSpeed())); + Pkt.WriteBEUInt8(Flags); + Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed())); + Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed())); } @@ -774,8 +772,8 @@ void cProtocol180::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0b); // Animation packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteChar(a_Animation); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_Animation); } @@ -788,16 +786,16 @@ void cProtocol180::SendParticleEffect(const AString & a_ParticleName, float a_Sr int ParticleID = GetParticleID(a_ParticleName); cPacketizer Pkt(*this, 0x2A); - Pkt.WriteInt(ParticleID); + Pkt.WriteBEInt32(ParticleID); Pkt.WriteBool(false); - Pkt.WriteFloat(a_SrcX); - Pkt.WriteFloat(a_SrcY); - Pkt.WriteFloat(a_SrcZ); - Pkt.WriteFloat(a_OffsetX); - Pkt.WriteFloat(a_OffsetY); - Pkt.WriteFloat(a_OffsetZ); - Pkt.WriteFloat(a_ParticleData); - Pkt.WriteInt(a_ParticleAmount); + Pkt.WriteBEFloat(a_SrcX); + Pkt.WriteBEFloat(a_SrcY); + Pkt.WriteBEFloat(a_SrcZ); + Pkt.WriteBEFloat(a_OffsetX); + Pkt.WriteBEFloat(a_OffsetY); + Pkt.WriteBEFloat(a_OffsetZ); + Pkt.WriteBEFloat(a_ParticleData); + Pkt.WriteBEInt32(a_ParticleAmount); } @@ -809,13 +807,13 @@ void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x38); // Playerlist Item packet - Pkt.WriteVarInt(0); - Pkt.WriteVarInt(1); + Pkt.WriteVarInt32(0); + Pkt.WriteVarInt32(1); Pkt.WriteUUID(a_Player.GetUUID()); Pkt.WriteString(a_Player.GetPlayerListName()); const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); - Pkt.WriteVarInt(Properties.size()); + Pkt.WriteVarInt32(Properties.size()); for (Json::Value::iterator itr = Properties.begin(), end = Properties.end(); itr != end; ++itr) { Pkt.WriteString(((Json::Value)*itr).get("name", "").asString()); @@ -832,8 +830,8 @@ void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player) } } - Pkt.WriteVarInt((UInt32)a_Player.GetGameMode()); - Pkt.WriteVarInt((UInt32)a_Player.GetClientHandle()->GetPing()); + Pkt.WriteVarInt32((UInt32)a_Player.GetGameMode()); + Pkt.WriteVarInt32((UInt32)a_Player.GetClientHandle()->GetPing()); Pkt.WriteBool(false); } @@ -846,8 +844,8 @@ void cProtocol180::SendPlayerListRemovePlayer(const cPlayer & a_Player) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x38); // Playerlist Item packet - Pkt.WriteVarInt(4); - Pkt.WriteVarInt(1); + Pkt.WriteVarInt32(4); + Pkt.WriteVarInt32(1); Pkt.WriteUUID(a_Player.GetUUID()); } @@ -860,10 +858,10 @@ void cProtocol180::SendPlayerListUpdateGameMode(const cPlayer & a_Player) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x38); // Playerlist Item packet - Pkt.WriteVarInt(1); - Pkt.WriteVarInt(1); + Pkt.WriteVarInt32(1); + Pkt.WriteVarInt32(1); Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteVarInt((UInt32)a_Player.GetGameMode()); + Pkt.WriteVarInt32((UInt32)a_Player.GetGameMode()); } @@ -878,10 +876,10 @@ void cProtocol180::SendPlayerListUpdatePing(const cPlayer & a_Player) if (ClientHandle != nullptr) { cPacketizer Pkt(*this, 0x38); // Playerlist Item packet - Pkt.WriteVarInt(2); - Pkt.WriteVarInt(1); + Pkt.WriteVarInt32(2); + Pkt.WriteVarInt32(1); Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteVarInt(static_cast<UInt32>(ClientHandle->GetPing())); + Pkt.WriteVarInt32(static_cast<UInt32>(ClientHandle->GetPing())); } } @@ -894,8 +892,8 @@ void cProtocol180::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, con ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x38); // Playerlist Item packet - Pkt.WriteVarInt(3); - Pkt.WriteVarInt(1); + Pkt.WriteVarInt32(3); + Pkt.WriteVarInt32(1); Pkt.WriteUUID(a_Player.GetUUID()); if (a_CustomName.empty()) @@ -919,22 +917,22 @@ void cProtocol180::SendPlayerMaxSpeed(void) cPacketizer Pkt(*this, 0x20); // Entity Properties cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteVarInt(Player->GetUniqueID()); - Pkt.WriteInt(1); // Count + Pkt.WriteVarInt32(Player->GetUniqueID()); + Pkt.WriteBEInt32(1); // Count Pkt.WriteString("generic.movementSpeed"); // The default game speed is 0.1, multiply that value by the relative speed: - Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed()); + Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed()); if (Player->IsSprinting()) { - Pkt.WriteVarInt(1); // Modifier count - Pkt.WriteInt64(0x662a6b8dda3e4c1c); - Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier - Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); - Pkt.WriteByte(2); + Pkt.WriteVarInt32(1); // Modifier count + Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c); + Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier + Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); + Pkt.WriteBEUInt8(2); } else { - Pkt.WriteVarInt(0); // Modifier count + Pkt.WriteVarInt32(0); // Modifier count } } @@ -948,15 +946,15 @@ void cProtocol180::SendPlayerMoveLook(void) cPacketizer Pkt(*this, 0x08); // Player Position And Look packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteDouble(Player->GetPosX()); + Pkt.WriteBEDouble(Player->GetPosX()); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. - Pkt.WriteDouble(Player->GetPosY() + 0.001); + Pkt.WriteBEDouble(Player->GetPosY() + 0.001); - Pkt.WriteDouble(Player->GetPosZ()); - Pkt.WriteFloat((float)Player->GetYaw()); - Pkt.WriteFloat((float)Player->GetPitch()); - Pkt.WriteByte(0); + Pkt.WriteBEDouble(Player->GetPosZ()); + Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch())); + Pkt.WriteBEUInt8(0); } @@ -977,7 +975,7 @@ void cProtocol180::SendPlayerSpawn(const cPlayer & a_Player) { // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet - Pkt.WriteVarInt(a_Player.GetUniqueID()); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteUUID(cMojangAPI::MakeUUIDShort(a_Player.GetUUID())); Pkt.WriteFPInt(a_Player.GetPosX()); Pkt.WriteFPInt(a_Player.GetPosY() + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. @@ -985,12 +983,12 @@ void cProtocol180::SendPlayerSpawn(const cPlayer & a_Player) Pkt.WriteByteAngle(a_Player.GetYaw()); Pkt.WriteByteAngle(a_Player.GetPitch()); short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType; - Pkt.WriteShort(ItemType); - Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6 - Pkt.WriteFloat((float)a_Player.GetHealth()); - Pkt.WriteByte((4 << 5 | (2 & 0x1F)) & 0xFF); + Pkt.WriteBEInt16(ItemType); + Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6 + Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth())); + Pkt.WriteBEUInt8((4 << 5 | (2 & 0x1F)) & 0xFF); Pkt.WriteString(a_Player.GetName()); - Pkt.WriteByte(0x7f); // Metadata: end + Pkt.WriteBEUInt8(0x7f); // Metadata: end } @@ -1015,8 +1013,8 @@ void cProtocol180::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x1e); - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(a_EffectID); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(a_EffectID); } @@ -1033,9 +1031,9 @@ void cProtocol180::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimens cPacketizer Pkt(*this, 0x07); // Respawn packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteInt((int)a_Dimension); - Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte((Byte)Player->GetEffectiveGameMode()); + Pkt.WriteBEInt32((int)a_Dimension); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8((Byte)Player->GetEffectiveGameMode()); Pkt.WriteString("default"); m_LastSentDimension = a_Dimension; } @@ -1050,9 +1048,9 @@ void cProtocol180::SendExperience(void) cPacketizer Pkt(*this, 0x1f); // Experience Packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteFloat(Player->GetXpPercentage()); - Pkt.WriteVarInt((UInt32)Player->GetXpLevel()); - Pkt.WriteVarInt((UInt32)Player->GetCurrentXp()); + Pkt.WriteBEFloat(Player->GetXpPercentage()); + Pkt.WriteVarInt32((UInt32)Player->GetXpLevel()); + Pkt.WriteVarInt32((UInt32)Player->GetCurrentXp()); } @@ -1064,11 +1062,11 @@ void cProtocol180::SendExperienceOrb(const cExpOrb & a_ExpOrb) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x11); - Pkt.WriteVarInt(a_ExpOrb.GetUniqueID()); + Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID()); Pkt.WriteFPInt(a_ExpOrb.GetPosX()); Pkt.WriteFPInt(a_ExpOrb.GetPosY()); Pkt.WriteFPInt(a_ExpOrb.GetPosZ()); - Pkt.WriteShort(a_ExpOrb.GetReward()); + Pkt.WriteBEInt16(a_ExpOrb.GetReward()); } @@ -1081,7 +1079,7 @@ void cProtocol180::SendScoreboardObjective(const AString & a_Name, const AString cPacketizer Pkt(*this, 0x3b); Pkt.WriteString(a_Name); - Pkt.WriteByte(a_Mode); + Pkt.WriteBEUInt8(a_Mode); if ((a_Mode == 0) || (a_Mode == 2)) { Pkt.WriteString(a_DisplayName); @@ -1099,12 +1097,12 @@ void cProtocol180::SendScoreUpdate(const AString & a_Objective, const AString & cPacketizer Pkt(*this, 0x3c); Pkt.WriteString(a_Player); - Pkt.WriteByte(a_Mode); + Pkt.WriteBEUInt8(a_Mode); Pkt.WriteString(a_Objective); if (a_Mode != 1) { - Pkt.WriteVarInt((UInt32) a_Score); + Pkt.WriteVarInt32((UInt32) a_Score); } } @@ -1117,7 +1115,7 @@ void cProtocol180::SendDisplayObjective(const AString & a_Objective, cScoreboard ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x3d); - Pkt.WriteByte((int) a_Display); + Pkt.WriteBEUInt8((int) a_Display); Pkt.WriteString(a_Objective); } @@ -1131,11 +1129,11 @@ void cProtocol180::SendSoundEffect(const AString & a_SoundName, double a_X, doub cPacketizer Pkt(*this, 0x29); // Sound Effect packet Pkt.WriteString(a_SoundName); - Pkt.WriteInt((int)(a_X * 8.0)); - Pkt.WriteInt((int)(a_Y * 8.0)); - Pkt.WriteInt((int)(a_Z * 8.0)); - Pkt.WriteFloat(a_Volume); - Pkt.WriteByte((Byte)(a_Pitch * 63)); + Pkt.WriteBEInt32((int)(a_X * 8.0)); + Pkt.WriteBEInt32((int)(a_Y * 8.0)); + Pkt.WriteBEInt32((int)(a_Z * 8.0)); + Pkt.WriteBEFloat(a_Volume); + Pkt.WriteBEUInt8((Byte)(a_Pitch * 63)); } @@ -1147,9 +1145,9 @@ void cProtocol180::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x28); // Effect packet - Pkt.WriteInt(a_EffectID); - Pkt.WritePosition(a_SrcX, a_SrcY, a_SrcZ); - Pkt.WriteInt(a_Data); + Pkt.WriteBEInt32(a_EffectID); + Pkt.WritePosition64(a_SrcX, a_SrcY, a_SrcZ); + Pkt.WriteBEInt32(a_Data); Pkt.WriteBool(false); } @@ -1162,17 +1160,17 @@ void cProtocol180::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0e); // Spawn Object packet - Pkt.WriteVarInt(a_FallingBlock.GetUniqueID()); - Pkt.WriteByte(70); // Falling block + Pkt.WriteVarInt32(a_FallingBlock.GetUniqueID()); + Pkt.WriteBEUInt8(70); // Falling block Pkt.WriteFPInt(a_FallingBlock.GetPosX()); Pkt.WriteFPInt(a_FallingBlock.GetPosY()); Pkt.WriteFPInt(a_FallingBlock.GetPosZ()); Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); - Pkt.WriteInt(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 12)); - Pkt.WriteShort((short)(a_FallingBlock.GetSpeedX() * 400)); - Pkt.WriteShort((short)(a_FallingBlock.GetSpeedY() * 400)); - Pkt.WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400)); + Pkt.WriteBEInt32(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 12)); + Pkt.WriteBEInt16((short)(a_FallingBlock.GetSpeedX() * 400)); + Pkt.WriteBEInt16((short)(a_FallingBlock.GetSpeedY() * 400)); + Pkt.WriteBEInt16((short)(a_FallingBlock.GetSpeedZ() * 400)); } @@ -1184,19 +1182,19 @@ void cProtocol180::SendSpawnMob(const cMonster & a_Mob) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet - Pkt.WriteVarInt(a_Mob.GetUniqueID()); - Pkt.WriteByte((Byte)a_Mob.GetMobType()); + Pkt.WriteVarInt32(a_Mob.GetUniqueID()); + Pkt.WriteBEUInt8((Byte)a_Mob.GetMobType()); Pkt.WriteFPInt(a_Mob.GetPosX()); Pkt.WriteFPInt(a_Mob.GetPosY()); Pkt.WriteFPInt(a_Mob.GetPosZ()); Pkt.WriteByteAngle(a_Mob.GetPitch()); Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); - Pkt.WriteShort((short)(a_Mob.GetSpeedX() * 400)); - Pkt.WriteShort((short)(a_Mob.GetSpeedY() * 400)); - Pkt.WriteShort((short)(a_Mob.GetSpeedZ() * 400)); - Pkt.WriteEntityMetadata(a_Mob); - Pkt.WriteByte(0x7f); // Metadata terminator + Pkt.WriteBEInt16((short)(a_Mob.GetSpeedX() * 400)); + Pkt.WriteBEInt16((short)(a_Mob.GetSpeedY() * 400)); + Pkt.WriteBEInt16((short)(a_Mob.GetSpeedZ() * 400)); + WriteEntityMetadata(Pkt, a_Mob); + Pkt.WriteBEUInt8(0x7f); // Metadata terminator } @@ -1215,19 +1213,19 @@ void cProtocol180::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, } cPacketizer Pkt(*this, 0xe); // Spawn Object packet - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WriteByte(a_ObjectType); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(a_ObjectType); Pkt.WriteFPInt(PosX); Pkt.WriteFPInt(a_Entity.GetPosY()); Pkt.WriteFPInt(PosZ); Pkt.WriteByteAngle(a_Entity.GetPitch()); Pkt.WriteByteAngle(Yaw); - Pkt.WriteInt(a_ObjectData); + Pkt.WriteBEInt32(a_ObjectData); if (a_ObjectData != 0) { - Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400)); - Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400)); - Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400)); + Pkt.WriteBEInt16((short)(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16((short)(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16((short)(a_Entity.GetSpeedZ() * 400)); } } @@ -1240,19 +1238,19 @@ void cProtocol180::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0xe); // Spawn Object packet - Pkt.WriteVarInt(a_Vehicle.GetUniqueID()); - Pkt.WriteByte(a_VehicleType); + Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); + Pkt.WriteBEUInt8(a_VehicleType); Pkt.WriteFPInt(a_Vehicle.GetPosX()); Pkt.WriteFPInt(a_Vehicle.GetPosY()); Pkt.WriteFPInt(a_Vehicle.GetPosZ()); Pkt.WriteByteAngle(a_Vehicle.GetPitch()); Pkt.WriteByteAngle(a_Vehicle.GetYaw()); - Pkt.WriteInt(a_VehicleSubType); + Pkt.WriteBEInt32(a_VehicleSubType); if (a_VehicleSubType != 0) { - Pkt.WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); - Pkt.WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); - Pkt.WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + Pkt.WriteBEInt16((short)(a_Vehicle.GetSpeedX() * 400)); + Pkt.WriteBEInt16((short)(a_Vehicle.GetSpeedY() * 400)); + Pkt.WriteBEInt16((short)(a_Vehicle.GetSpeedZ() * 400)); } } @@ -1265,7 +1263,7 @@ void cProtocol180::SendStatistics(const cStatManager & a_Manager) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x37); - Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only + Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only for (size_t i = 0; i < (size_t)statCount; ++i) { @@ -1273,7 +1271,7 @@ void cProtocol180::SendStatistics(const cStatManager & a_Manager) const AString & StatName = cStatInfo::GetName((eStatistic) i); Pkt.WriteString(StatName); - Pkt.WriteVarInt(Value); + Pkt.WriteVarInt32(Value); } } @@ -1286,7 +1284,7 @@ void cProtocol180::SendTabCompletionResults(const AStringVector & a_Results) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet - Pkt.WriteVarInt((int)a_Results.size()); + Pkt.WriteVarInt32((int)a_Results.size()); for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr) { @@ -1303,7 +1301,7 @@ void cProtocol180::SendTeleportEntity(const cEntity & a_Entity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x18); - Pkt.WriteVarInt(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); Pkt.WriteFPInt(a_Entity.GetPosX()); Pkt.WriteFPInt(a_Entity.GetPosY()); Pkt.WriteFPInt(a_Entity.GetPosZ()); @@ -1321,8 +1319,8 @@ void cProtocol180::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet - Pkt.WriteVarInt(0); // EntityID = 0, always - Pkt.WriteByte(1); // Type = Thunderbolt + Pkt.WriteVarInt32(0); // EntityID = 0, always + Pkt.WriteBEUInt8(1); // Type = Thunderbolt Pkt.WriteFPInt(a_BlockX); Pkt.WriteFPInt(a_BlockY); Pkt.WriteFPInt(a_BlockZ); @@ -1342,8 +1340,8 @@ void cProtocol180::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_Do } cPacketizer Pkt(*this, 0x03); - Pkt.WriteInt64(a_WorldAge); - Pkt.WriteInt64(a_TimeOfDay); + Pkt.WriteBEInt64(a_WorldAge); + Pkt.WriteBEInt64(a_TimeOfDay); } @@ -1355,11 +1353,11 @@ void cProtocol180::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x21); // Chunk Data packet - Pkt.WriteInt(a_ChunkX); - Pkt.WriteInt(a_ChunkZ); + Pkt.WriteBEInt32(a_ChunkX); + Pkt.WriteBEInt32(a_ChunkZ); Pkt.WriteBool(true); - Pkt.WriteShort(0); // Primary bitmap - Pkt.WriteVarInt(0); // Data size + Pkt.WriteBEInt16(0); // Primary bitmap + Pkt.WriteVarInt32(0); // Data size } @@ -1370,7 +1368,7 @@ void cProtocol180::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x35); // Update tile entity packet - Pkt.WritePosition(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); + Pkt.WritePosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); Byte Action = 0; switch (a_BlockEntity.GetBlockType()) @@ -1382,9 +1380,9 @@ void cProtocol180::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; } - Pkt.WriteByte(Action); + Pkt.WriteBEUInt8(Action); - Pkt.WriteBlockEntity(a_BlockEntity); + WriteBlockEntity(Pkt, a_BlockEntity); } @@ -1396,7 +1394,7 @@ void cProtocol180::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x33); - Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); Json::StyledWriter JsonWriter; AString Lines[] = { a_Line1, a_Line2, a_Line3, a_Line4 }; @@ -1417,8 +1415,8 @@ void cProtocol180::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0a); - Pkt.WriteVarInt(a_Entity.GetUniqueID()); - Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); } @@ -1431,8 +1429,8 @@ void cProtocol180::SendWeather(eWeather a_Weather) { cPacketizer Pkt(*this, 0x2b); // Change Game State packet - Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain - Pkt.WriteFloat(0); // Unused for weather + Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain + Pkt.WriteBEFloat(0); // Unused for weather } // TODO: Fade effect, somehow @@ -1447,13 +1445,13 @@ void cProtocol180::SendWholeInventory(const cWindow & a_Window) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x30); // Window Items packet - Pkt.WriteChar(a_Window.GetWindowID()); - Pkt.WriteShort(a_Window.GetNumSlots()); + Pkt.WriteBEInt8(a_Window.GetWindowID()); + Pkt.WriteBEInt16(a_Window.GetNumSlots()); cItems Slots; a_Window.GetSlots(*(m_Client->GetPlayer()), Slots); for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr) { - Pkt.WriteItem(*itr); + WriteItem(Pkt, *itr); } // for itr - Slots[] } @@ -1466,7 +1464,7 @@ void cProtocol180::SendWindowClose(const cWindow & a_Window) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x2e); - Pkt.WriteChar(a_Window.GetWindowID()); + Pkt.WriteBEInt8(a_Window.GetWindowID()); } @@ -1484,7 +1482,7 @@ void cProtocol180::SendWindowOpen(const cWindow & a_Window) } cPacketizer Pkt(*this, 0x2d); - Pkt.WriteChar(a_Window.GetWindowID()); + Pkt.WriteBEInt8(a_Window.GetWindowID()); Pkt.WriteString(a_Window.GetWindowTypeName()); Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_Window.GetWindowTitle().c_str())); @@ -1494,19 +1492,19 @@ void cProtocol180::SendWindowOpen(const cWindow & a_Window) case cWindow::wtEnchantment: case cWindow::wtAnvil: { - Pkt.WriteChar(0); + Pkt.WriteBEInt8(0); break; } default: { - Pkt.WriteChar(a_Window.GetNumNonInventorySlots()); + Pkt.WriteBEInt8(a_Window.GetNumNonInventorySlots()); break; } } if (a_Window.GetWindowType() == cWindow::wtAnimalChest) { - Pkt.WriteInt(0); // TODO: The animal's EntityID + Pkt.WriteBEInt32(0); // TODO: The animal's EntityID } } @@ -1519,9 +1517,9 @@ void cProtocol180::SendWindowProperty(const cWindow & a_Window, short a_Property ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x31); // Window Property packet - Pkt.WriteChar(a_Window.GetWindowID()); - Pkt.WriteShort(a_Property); - Pkt.WriteShort(a_Value); + Pkt.WriteBEInt8(a_Window.GetWindowID()); + Pkt.WriteBEInt16(a_Property); + Pkt.WriteBEInt16(a_Value); } @@ -1540,7 +1538,10 @@ bool cProtocol180::CompressPacket(const AString & a_Packet, AString & a_Compress return false; } - int Status = compress2((Bytef*)CompressedData, &CompressedSize, (const Bytef*)a_Packet.data(), a_Packet.size(), Z_DEFAULT_COMPRESSION); + int Status = compress2( + reinterpret_cast<Bytef *>(CompressedData), &CompressedSize, + reinterpret_cast<const Bytef *>(a_Packet.data()), a_Packet.size(), Z_DEFAULT_COMPRESSION + ); if (Status != Z_OK) { return false; @@ -1548,12 +1549,12 @@ bool cProtocol180::CompressPacket(const AString & a_Packet, AString & a_Compress AString LengthData; cByteBuffer Buffer(20); - Buffer.WriteVarInt((UInt32)a_Packet.size()); + Buffer.WriteVarInt32(static_cast<UInt32>(a_Packet.size())); Buffer.ReadAll(LengthData); Buffer.CommitRead(); - Buffer.WriteVarInt(CompressedSize + LengthData.size()); - Buffer.WriteVarInt(a_Packet.size()); + Buffer.WriteVarInt32(CompressedSize + LengthData.size()); + Buffer.WriteVarInt32(static_cast<UInt32>(a_Packet.size())); Buffer.ReadAll(LengthData); Buffer.CommitRead(); @@ -1951,7 +1952,7 @@ void cProtocol180::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp); cPacketizer Pkt(*this, 0x01); // Ping packet - Pkt.WriteInt64(Timestamp); + Pkt.WriteBEInt64(Timestamp); } @@ -2088,10 +2089,10 @@ void cProtocol180::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) cPacketizer Pkt(*this, 0x01); Pkt.WriteString(Server->GetServerID()); const AString & PubKeyDer = Server->GetPublicKeyDER(); - Pkt.WriteVarInt((short)PubKeyDer.size()); + Pkt.WriteVarInt32((short)PubKeyDer.size()); Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); - Pkt.WriteVarInt(4); - Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) + Pkt.WriteVarInt32(4); + Pkt.WriteBEInt32((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) m_Client->SetUsername(Username); return; } @@ -2105,9 +2106,7 @@ void cProtocol180::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketAnimation(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Animation); - m_Client->HandleAnimation(Animation); + m_Client->HandleAnimation(1); // Packet exists solely for arm-swing notification } @@ -2116,16 +2115,16 @@ void cProtocol180::HandlePacketAnimation(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Status); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status); int BlockX, BlockY, BlockZ; - if (!a_ByteBuffer.ReadPosition(BlockX, BlockY, BlockZ)) + if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ)) { return; } - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Face); - m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), Status); + HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face); + m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), Status); } @@ -2135,24 +2134,20 @@ void cProtocol180::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer) { int BlockX, BlockY, BlockZ; - if (!a_ByteBuffer.ReadPosition(BlockX, BlockY, BlockZ)) + if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ)) { return; } - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Face); - if (Face == 255) - { - Face = 0; - } + HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face); cItem Item; ReadItem(a_ByteBuffer, Item, 3); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorX); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorY); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorZ); - m_Client->HandleRightClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ); + m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); } @@ -2172,10 +2167,10 @@ void cProtocol180::HandlePacketChatMessage(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ViewDistance); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatFlags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags); HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors); - HANDLE_READ(a_ByteBuffer, ReadChar, char, SkinFlags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinFlags); m_Client->SetLocale(Locale); m_Client->SetViewDistance(ViewDistance); @@ -2188,7 +2183,7 @@ void cProtocol180::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadChar, char, ActionID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID); switch (ActionID) { case 0: @@ -2220,13 +2215,13 @@ void cProtocol180::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); cItem Item; if (!ReadItem(a_ByteBuffer, Item)) { return; } - m_Client->HandleCreativeInventory(SlotNum, Item); + m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutside : caLeftClick); } @@ -2235,9 +2230,9 @@ void cProtocol180::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffe void cProtocol180::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID); - HANDLE_READ(a_ByteBuffer, ReadChar, char, Action); - HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost); + HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action); + HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost); switch (Action) { @@ -2256,7 +2251,7 @@ void cProtocol180::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, KeepAliveID); - m_Client->HandleKeepAlive((int)KeepAliveID); + m_Client->HandleKeepAlive(static_cast<int>(KeepAliveID)); } @@ -2275,10 +2270,11 @@ void cProtocol180::HandlePacketPlayer(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketPlayerAbilities(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Flags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed); + // COnvert the bitfield into individual boolean flags: bool IsFlying = false, CanFly = false; if ((Flags & 2) != 0) { @@ -2369,7 +2365,7 @@ void cProtocol180::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); m_Client->HandleSlotSelected(SlotNum); } @@ -2381,7 +2377,7 @@ void cProtocol180::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Forward); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways); - HANDLE_READ(a_ByteBuffer, ReadChar, char, Flags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags); if ((Flags & 0x2) != 0) { @@ -2400,7 +2396,7 @@ void cProtocol180::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketTabComplete(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Text); - HANDLE_READ(a_ByteBuffer, ReadBool, bool, HasPosition); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, HasPosition); if (HasPosition) { @@ -2417,7 +2413,7 @@ void cProtocol180::HandlePacketTabComplete(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketUpdateSign(cByteBuffer & a_ByteBuffer) { int BlockX, BlockY, BlockZ; - if (!a_ByteBuffer.ReadPosition(BlockX, BlockY, BlockZ)) + if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ)) { return; } @@ -2445,12 +2441,12 @@ void cProtocol180::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer) { case 0: { - m_Client->HandleUseEntity((int)EntityID, false); + m_Client->HandleUseEntity(EntityID, false); break; } case 1: { - m_Client->HandleUseEntity((int)EntityID, true); + m_Client->HandleUseEntity(EntityID, true); break; } case 2: @@ -2476,8 +2472,8 @@ void cProtocol180::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment); m_Client->HandleEnchantItem(WindowID, Enchantment); } @@ -2488,11 +2484,11 @@ void cProtocol180::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID); - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Button); - HANDLE_READ(a_ByteBuffer, ReadBEShort, short, TransactionID); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); + HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Button); + HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, TransactionID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode); cItem Item; ReadItem(a_ByteBuffer, Item); @@ -2500,8 +2496,8 @@ void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) eClickAction Action; switch ((Mode << 8) | Button) { - case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break; - case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break; + case 0x0000: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftClick : caLeftClickOutside; break; + case 0x0001: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightClick : caRightClickOutside; break; case 0x0100: Action = caShiftLeftClick; break; case 0x0101: Action = caShiftRightClick; break; case 0x0200: Action = caNumber1; break; @@ -2514,14 +2510,14 @@ void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) 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 0x0400: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutsideHoldNothing : caDropKey; break; + case 0x0401: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break; + case 0x0500: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintBegin : caUnknown; break; + case 0x0501: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftPaintProgress : caUnknown; break; + case 0x0502: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintEnd : caUnknown; break; + case 0x0504: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintBegin : caUnknown; break; + case 0x0505: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightPaintProgress : caUnknown; break; + case 0x0506: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintEnd : caUnknown; break; case 0x0600: Action = caDblClick; break; default: { @@ -2540,7 +2536,7 @@ void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); m_Client->HandleWindowClose(WindowID); } @@ -2552,14 +2548,14 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const { if (a_Channel == "MC|AdvCdm") { - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode) + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, 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, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); break; @@ -2567,7 +2563,7 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const default: { - m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %d", Mode), mtFailure); + m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %u (0x%02x)", Mode, Mode), mtFailure); LOG("Unhandled MC|AdvCdm packet mode."); return; } @@ -2584,8 +2580,8 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const } else if (a_Channel == "MC|Beacon") { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1); - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect1); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect2); m_Client->HandleBeaconSelection(Effect1, Effect2); return; } @@ -2597,7 +2593,7 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const } else if (a_Channel == "MC|TrSel") { - HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum); m_Client->HandleNPCTrade(SlotNum); return; } @@ -2639,7 +2635,7 @@ void cProtocol180::SendData(const char * a_Data, size_t a_Size) bool cProtocol180::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes) { - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemType); + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType); if (ItemType == -1) { // The item is empty, no more data follows @@ -2648,8 +2644,8 @@ bool cProtocol180::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a } a_Item.m_ItemType = ItemType; - HANDLE_PACKET_READ(a_ByteBuffer, ReadChar, char, ItemCount); - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemDamage); + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount); + HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage); a_Item.m_ItemCount = ItemCount; a_Item.m_ItemDamage = ItemDamage; if (ItemCount <= 0) @@ -2765,59 +2761,81 @@ void cProtocol180::StartEncryption(const Byte * a_Key) +eBlockFace cProtocol180::FaceIntToBlockFace(Int8 a_BlockFace) +{ + // Normalize the blockface values returned from the protocol + // Anything known gets mapped 1:1, everything else returns BLOCK_FACE_NONE + switch (a_BlockFace) + { + case BLOCK_FACE_XM: return BLOCK_FACE_XM; + case BLOCK_FACE_XP: return BLOCK_FACE_XP; + case BLOCK_FACE_YM: return BLOCK_FACE_YM; + case BLOCK_FACE_YP: return BLOCK_FACE_YP; + case BLOCK_FACE_ZM: return BLOCK_FACE_ZM; + case BLOCK_FACE_ZP: return BLOCK_FACE_ZP; + default: return BLOCK_FACE_NONE; + } +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cProtocol180::cPacketizer: -cProtocol180::cPacketizer::~cPacketizer() +void cProtocol180::SendPacket(cPacketizer & a_Pkt) { - UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace(); + UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace()); AString PacketData, CompressedPacket; - m_Out.ReadAll(PacketData); - m_Out.CommitRead(); + m_OutPacketBuffer.ReadAll(PacketData); + m_OutPacketBuffer.CommitRead(); - if ((m_Protocol.m_State == 3) && (PacketLen >= 256)) + if ((m_State == 3) && (PacketLen >= 256)) { + // Compress the packet payload: if (!cProtocol180::CompressPacket(PacketData, CompressedPacket)) { return; } } - else if (m_Protocol.m_State == 3) + else if (m_State == 3) { - m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen + 1); - m_Protocol.m_OutPacketLenBuffer.WriteVarInt(0); - + // The packet is not compressed, indicate this in the packet header: + m_OutPacketLenBuffer.WriteVarInt32(PacketLen + 1); + m_OutPacketLenBuffer.WriteVarInt32(0); AString LengthData; - m_Protocol.m_OutPacketLenBuffer.ReadAll(LengthData); - m_Protocol.SendData(LengthData.data(), LengthData.size()); + m_OutPacketLenBuffer.ReadAll(LengthData); + SendData(LengthData.data(), LengthData.size()); } else { - m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen); - + // Compression doesn't apply to this state, send raw data: + m_OutPacketLenBuffer.WriteVarInt32(PacketLen); AString LengthData; - m_Protocol.m_OutPacketLenBuffer.ReadAll(LengthData); - m_Protocol.SendData(LengthData.data(), LengthData.size()); + m_OutPacketLenBuffer.ReadAll(LengthData); + SendData(LengthData.data(), LengthData.size()); } + // Send the packet's payload, either direct or compressed: if (CompressedPacket.empty()) { - m_Protocol.m_OutPacketLenBuffer.CommitRead(); - m_Protocol.SendData(PacketData.data(), PacketData.size()); + m_OutPacketLenBuffer.CommitRead(); + SendData(PacketData.data(), PacketData.size()); } else { - m_Protocol.SendData(CompressedPacket.data(), CompressedPacket.size()); + SendData(CompressedPacket.data(), CompressedPacket.size()); } // Log the comm into logfile: - if (g_ShouldLogCommOut && m_Protocol.m_CommLogFile.IsOpen()) + if (g_ShouldLogCommOut && m_CommLogFile.IsOpen()) { AString Hex; ASSERT(PacketData.size() > 0); - CreateHexDump(Hex, PacketData.data() + 1, PacketData.size() - 1, 16); - m_Protocol.m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload:\n%s\n", - PacketData[0], PacketData[0], PacketLen, PacketLen, m_Protocol.m_State, Hex.c_str() + CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16); + m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload (incl. type):\n%s\n", + a_Pkt.GetPacketType(), a_Pkt.GetPacketType(), PacketLen, PacketLen, m_State, Hex.c_str() ); } } @@ -2826,30 +2844,7 @@ cProtocol180::cPacketizer::~cPacketizer() -void cProtocol180::cPacketizer::WriteUUID(const AString & a_UUID) -{ - if (a_UUID.length() != 32) - { - LOGWARNING("Attempt to send a bad uuid (length isn't 32): %s", a_UUID.c_str()); - ASSERT(!"Wrong uuid length!"); - return; - } - AString UUID_1 = a_UUID.substr(0, 16); - AString UUID_2 = a_UUID.substr(16); - - Int64 Value_1, Value_2; - sscanf(UUID_1.c_str(), "%llx", &Value_1); - sscanf(UUID_2.c_str(), "%llx", &Value_2); - - WriteInt64(Value_1); - WriteInt64(Value_2); -} - - - - - -void cProtocol180::cPacketizer::WriteItem(const cItem & a_Item) +void cProtocol180::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; ASSERT(ItemType >= -1); // Check validity of packets in debug runtime @@ -2861,17 +2856,17 @@ void cProtocol180::cPacketizer::WriteItem(const cItem & a_Item) if (a_Item.IsEmpty()) { - WriteShort(-1); + a_Pkt.WriteBEInt16(-1); return; } - WriteShort(ItemType); - WriteByte (a_Item.m_ItemCount); - WriteShort(a_Item.m_ItemDamage); + a_Pkt.WriteBEInt16(ItemType); + a_Pkt.WriteBEInt8(a_Item.m_ItemCount); + a_Pkt.WriteBEInt16(a_Item.m_ItemDamage); if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR)) { - WriteChar(0); + a_Pkt.WriteBEInt8(0); return; } @@ -2914,24 +2909,24 @@ void cProtocol180::cPacketizer::WriteItem(const cItem & a_Item) } if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) { - cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, (ENUM_ITEM_ID)a_Item.m_ItemType); + cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, static_cast<ENUM_ITEM_ID>(a_Item.m_ItemType)); } Writer.Finish(); AString Result = Writer.GetResult(); if (Result.size() == 0) { - WriteChar(0); + a_Pkt.WriteBEInt8(0); return; } - WriteBuf(Result.data(), Result.size()); + a_Pkt.WriteBuf(Result.data(), Result.size()); } -void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEntity) +void cProtocol180::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) { cFastNBTWriter Writer; @@ -2939,21 +2934,20 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt { case E_BLOCK_BEACON: { - cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity; - - Writer.AddInt("x", BeaconEntity.GetPosX()); - Writer.AddInt("y", BeaconEntity.GetPosY()); - Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); + auto & BeaconEntity = reinterpret_cast<const cBeaconEntity &>(a_BlockEntity); + Writer.AddInt("x", BeaconEntity.GetPosX()); + Writer.AddInt("y", BeaconEntity.GetPosY()); + Writer.AddInt("z", BeaconEntity.GetPosZ()); + Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); - Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); + Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_COMMAND_BLOCK: { - cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity; - + auto & CommandBlockEntity = reinterpret_cast<const cCommandBlockEntity &>(a_BlockEntity); Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); Writer.AddInt("x", CommandBlockEntity.GetPosX()); @@ -2965,20 +2959,16 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt // MCS doesn't have this, so just leave it @ '@'. (geddit?) Writer.AddString("CustomName", "@"); Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - if (!CommandBlockEntity.GetLastOutput().empty()) { - AString Output; - Printf(Output, "{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()); - - Writer.AddString("LastOutput", Output.c_str()); + Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); } break; } + case E_BLOCK_HEAD: { - cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity; - + auto & MobHeadEntity = reinterpret_cast<const cMobHeadEntity &>(a_BlockEntity); Writer.AddInt("x", MobHeadEntity.GetPosX()); Writer.AddInt("y", MobHeadEntity.GetPosY()); Writer.AddInt("z", MobHeadEntity.GetPosZ()); @@ -2988,10 +2978,10 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_FLOWER_POT: { - cFlowerPotEntity & FlowerPotEntity = (cFlowerPotEntity &)a_BlockEntity; - + auto & FlowerPotEntity = reinterpret_cast<const cFlowerPotEntity &>(a_BlockEntity); Writer.AddInt("x", FlowerPotEntity.GetPosX()); Writer.AddInt("y", FlowerPotEntity.GetPosY()); Writer.AddInt("z", FlowerPotEntity.GetPosZ()); @@ -3000,10 +2990,10 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } + case E_BLOCK_MOB_SPAWNER: { - cMobSpawnerEntity & MobSpawnerEntity = (cMobSpawnerEntity &)a_BlockEntity; - + auto & MobSpawnerEntity = reinterpret_cast<const cMobSpawnerEntity &>(a_BlockEntity); Writer.AddInt("x", MobSpawnerEntity.GetPosX()); Writer.AddInt("y", MobSpawnerEntity.GetPosY()); Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); @@ -3012,37 +3002,22 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddString("id", "MobSpawner"); break; } - default: break; + + default: + { + break; + } } Writer.Finish(); - WriteBuf(Writer.GetResult().data(), Writer.GetResult().size()); + a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size()); } -void cProtocol180::cPacketizer::WriteByteAngle(double a_Angle) -{ - WriteByte((char)(255 * a_Angle / 360)); -} - - - - - -void cProtocol180::cPacketizer::WriteFPInt(double a_Value) -{ - int Value = (int)(a_Value * 32); - WriteInt(Value); -} - - - - - -void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) +void cProtocol180::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) { // Common metadata: Byte Flags = 0; @@ -3066,21 +3041,21 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) { Flags |= 0x20; } - WriteByte(0); // Byte(0) + index 0 - WriteByte(Flags); + a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0 + a_Pkt.WriteBEUInt8(Flags); switch (a_Entity.GetEntityType()) { case cEntity::etPlayer: break; // TODO? case cEntity::etPickup: { - WriteByte((5 << 5) | 10); // Slot(5) + index 10 - WriteItem(((const cPickup &)a_Entity).GetItem()); + a_Pkt.WriteBEUInt8((5 << 5) | 10); // Slot(5) + index 10 + WriteItem(a_Pkt, reinterpret_cast<const cPickup &>(a_Entity).GetItem()); break; } case cEntity::etMinecart: { - WriteByte(0x51); + a_Pkt.WriteBEUInt8(0x51); // The following expression makes Minecarts shake more with less health or higher damage taken // It gets half the maximum health, and takes it away from the current health minus the half health: @@ -3089,71 +3064,82 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) Health: 3 | 3 - (3 - 3) = 3 Health: 1 | 3 - (1 - 3) = 5 */ - 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 + auto & Minecart = reinterpret_cast<const cMinecart &>(a_Entity); + a_Pkt.WriteBEInt32((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4); + a_Pkt.WriteBEUInt8(0x52); + a_Pkt.WriteBEInt32(1); // Shaking direction, doesn't seem to affect anything + a_Pkt.WriteBEUInt8(0x73); + a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10)); // Damage taken / shake effect multiplyer - if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone) + if (Minecart.GetPayload() == cMinecart::mpNone) { - cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity); + auto & RideableMinecart = reinterpret_cast<const cRideableMinecart &>(Minecart); const cItem & MinecartContent = RideableMinecart.GetContent(); if (!MinecartContent.IsEmpty()) { - WriteByte(0x54); + a_Pkt.WriteBEUInt8(0x54); int Content = MinecartContent.m_ItemType; Content |= MinecartContent.m_ItemDamage << 8; - WriteInt(Content); - WriteByte(0x55); - WriteInt(RideableMinecart.GetBlockHeight()); - WriteByte(0x56); - WriteByte(1); + a_Pkt.WriteBEInt32(Content); + a_Pkt.WriteBEUInt8(0x55); + a_Pkt.WriteBEInt32(RideableMinecart.GetBlockHeight()); + a_Pkt.WriteBEUInt8(0x56); + a_Pkt.WriteBEUInt8(1); } } - else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace) + else if (Minecart.GetPayload() == cMinecart::mpFurnace) { - WriteByte(0x10); - WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cMinecartWithFurnace &>(Minecart).IsFueled() ? 1 : 0); } break; - } + } // case etMinecart + case cEntity::etProjectile: { - cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity; + auto & Projectile = reinterpret_cast<const cProjectileEntity &>(a_Entity); switch (Projectile.GetProjectileKind()) { case cProjectileEntity::pkArrow: { - WriteByte(0x10); - WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(reinterpret_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0); break; } case cProjectileEntity::pkFirework: { - WriteByte(0xA8); - WriteItem(((const cFireworkEntity &)a_Entity).GetItem()); + a_Pkt.WriteBEUInt8(0xa8); + WriteItem(a_Pkt, reinterpret_cast<const cFireworkEntity &>(Projectile).GetItem()); + break; + } + default: + { break; } - default: break; } break; - } + } // case etProjectile + case cEntity::etMonster: { - WriteMobMetadata((const cMonster &)a_Entity); + WriteMobMetadata(a_Pkt, reinterpret_cast<const cMonster &>(a_Entity)); break; } + case cEntity::etItemFrame: { - cItemFrame & Frame = (cItemFrame &)a_Entity; - WriteByte(0xA8); - WriteItem(Frame.GetItem()); - WriteByte(0x09); - WriteByte(Frame.GetItemRotation()); + auto & Frame = reinterpret_cast<const cItemFrame &>(a_Entity); + a_Pkt.WriteBEUInt8(0xa8); + WriteItem(a_Pkt, Frame.GetItem()); + a_Pkt.WriteBEUInt8(0x09); + a_Pkt.WriteBEUInt8(Frame.GetItemRotation()); + break; + } // case etItemFrame + + default: + { break; } - default: break; } } @@ -3161,192 +3147,205 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) -void cProtocol180::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) +void cProtocol180::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) { switch (a_Mob.GetMobType()) { - case mtCreeper: - { - WriteByte(0x10); - WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); - WriteByte(0x11); - WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0); - break; - } - case mtBat: { - WriteByte(0x10); - WriteByte(((const cBat &)a_Mob).IsHanging() ? 1 : 0); - break; - } - - case mtPig: - { - WriteByte(0x10); - WriteByte(((const cPig &)a_Mob).IsSaddled() ? 1 : 0); + auto & Bat = reinterpret_cast<const cBat &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(Bat.IsHanging() ? 1 : 0); break; - } + } // case mtBat - case mtVillager: + case mtCreeper: { - WriteByte(0x50); - WriteInt(((const cVillager &)a_Mob).GetVilType()); + auto & Creeper = reinterpret_cast<const cCreeper &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(Creeper.IsBlowing() ? 1 : -1); + a_Pkt.WriteBEUInt8(0x11); + a_Pkt.WriteBEUInt8(Creeper.IsCharged() ? 1 : 0); break; - } + } // case mtCreeper - case mtZombie: + case mtEnderman: { - WriteByte(0x0c); - WriteByte(((const cZombie &)a_Mob).IsBaby() ? 1 : 0); - WriteByte(0x0d); - WriteByte(((const cZombie &)a_Mob).IsVillagerZombie() ? 1 : 0); - WriteByte(0x0e); - WriteByte(((const cZombie &)a_Mob).IsConverting() ? 1 : 0); + auto & Enderman = reinterpret_cast<const cEnderman &>(a_Mob); + a_Pkt.WriteBEUInt8(0x30); + a_Pkt.WriteBEInt16(static_cast<Byte>(Enderman.GetCarriedBlock())); + a_Pkt.WriteBEUInt8(0x11); + a_Pkt.WriteBEUInt8(static_cast<Byte>(Enderman.GetCarriedMeta())); + a_Pkt.WriteBEUInt8(0x12); + a_Pkt.WriteBEUInt8(Enderman.IsScreaming() ? 1 : 0); break; - } + } // case mtEnderman case mtGhast: { - WriteByte(0x10); - WriteByte(((const cGhast &)a_Mob).IsCharging()); + auto & Ghast = reinterpret_cast<const cGhast &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(Ghast.IsCharging()); break; - } + } // case mtGhast - case mtWolf: + case mtHorse: { - const cWolf & Wolf = (const cWolf &)a_Mob; - Byte WolfStatus = 0; - if (Wolf.IsSitting()) + auto & Horse = reinterpret_cast<const cHorse &>(a_Mob); + int Flags = 0; + if (Horse.IsTame()) { - WolfStatus |= 0x1; + Flags |= 0x02; } - if (Wolf.IsAngry()) + if (Horse.IsSaddled()) { - WolfStatus |= 0x2; + Flags |= 0x04; } - if (Wolf.IsTame()) + if (Horse.IsChested()) { - WolfStatus |= 0x4; + Flags |= 0x08; + } + if (Horse.IsBaby()) + { + Flags |= 0x10; + } + if (Horse.IsEating()) + { + Flags |= 0x20; + } + if (Horse.IsRearing()) + { + Flags |= 0x40; + } + if (Horse.IsMthOpen()) + { + Flags |= 0x80; } - WriteByte(0x10); - WriteByte(WolfStatus); - - WriteByte(0x72); - WriteFloat((float)(a_Mob.GetHealth())); - WriteByte(0x13); - WriteByte(Wolf.IsBegging() ? 1 : 0); - WriteByte(0x14); - WriteByte(Wolf.GetCollarColor()); + a_Pkt.WriteBEUInt8(0x50); // Int at index 16 + a_Pkt.WriteBEInt32(Flags); + a_Pkt.WriteBEUInt8(0x13); // Byte at index 19 + a_Pkt.WriteBEUInt8(Horse.GetHorseType()); + a_Pkt.WriteBEUInt8(0x54); // Int at index 20 + int Appearance = 0; + Appearance = Horse.GetHorseColor(); + Appearance |= Horse.GetHorseStyle() << 8; + a_Pkt.WriteBEInt32(Appearance); + a_Pkt.WriteBEUInt8(0x56); // Int at index 22 + a_Pkt.WriteBEInt32(Horse.GetHorseArmour()); break; - } + } // case mtHorse + + case mtMagmaCube: + { + auto & MagmaCube = reinterpret_cast<const cMagmaCube &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(MagmaCube.GetSize()); + break; + } // case mtMagmaCube + + case mtPig: + { + auto & Pig = reinterpret_cast<const cPig &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(Pig.IsSaddled() ? 1 : 0); + break; + } // case mtPig case mtSheep: { - WriteByte(0x10); + auto & Sheep = reinterpret_cast<const cSheep &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); Byte SheepMetadata = 0; - SheepMetadata = ((const cSheep &)a_Mob).GetFurColor(); - if (((const cSheep &)a_Mob).IsSheared()) + SheepMetadata = Sheep.GetFurColor(); + if (Sheep.IsSheared()) { SheepMetadata |= 0x10; } - WriteByte(SheepMetadata); + a_Pkt.WriteBEUInt8(SheepMetadata); break; - } - - case mtEnderman: - { - WriteByte(0x30); - WriteShort((Byte)(((const cEnderman &)a_Mob).GetCarriedBlock())); - WriteByte(0x11); - WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedMeta())); - WriteByte(0x12); - WriteByte(((const cEnderman &)a_Mob).IsScreaming() ? 1 : 0); - break; - } + } // case mtSheep case mtSkeleton: { - WriteByte(0x0d); - WriteByte(((const cSkeleton &)a_Mob).IsWither() ? 1 : 0); + auto & Skeleton = reinterpret_cast<const cSkeleton &>(a_Mob); + a_Pkt.WriteBEUInt8(0x0d); + a_Pkt.WriteBEUInt8(Skeleton.IsWither() ? 1 : 0); break; - } + } // case mtSkeleton - case mtWitch: + case mtSlime: { - WriteByte(0x15); - WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); + auto & Slime = reinterpret_cast<const cSlime &>(a_Mob); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(Slime.GetSize()); break; - } + } // case mtSlime - case mtWither: + case mtVillager: { - WriteByte(0x54); // Int at index 20 - WriteInt(((const cWither &)a_Mob).GetWitherInvulnerableTicks()); - WriteByte(0x66); // Float at index 6 - WriteFloat((float)(a_Mob.GetHealth())); + auto & Villager = reinterpret_cast<const cVillager &>(a_Mob); + a_Pkt.WriteBEUInt8(0x50); + a_Pkt.WriteBEInt32(Villager.GetVilType()); break; - } + } // case mtVillager - case mtSlime: + case mtWitch: { - WriteByte(0x10); - WriteByte(((const cSlime &)a_Mob).GetSize()); + auto & Witch = reinterpret_cast<const cWitch &>(a_Mob); + a_Pkt.WriteBEUInt8(0x15); + a_Pkt.WriteBEUInt8(Witch.IsAngry() ? 1 : 0); break; - } - - case mtMagmaCube: + } // case mtWitch + + case mtWither: { - WriteByte(0x10); - WriteByte(((const cMagmaCube &)a_Mob).GetSize()); + auto & Wither = reinterpret_cast<const cWither &>(a_Mob); + a_Pkt.WriteBEUInt8(0x54); // Int at index 20 + a_Pkt.WriteBEInt32(Wither.GetWitherInvulnerableTicks()); + a_Pkt.WriteBEUInt8(0x66); // Float at index 6 + a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); break; - } + } // case mtWither - case mtHorse: + case mtWolf: { - const cHorse & Horse = (const cHorse &)a_Mob; - int Flags = 0; - if (Horse.IsTame()) - { - Flags |= 0x02; - } - if (Horse.IsSaddled()) - { - Flags |= 0x04; - } - if (Horse.IsChested()) - { - Flags |= 0x08; - } - if (Horse.IsBaby()) - { - Flags |= 0x10; - } - if (Horse.IsEating()) + auto & Wolf = reinterpret_cast<const cWolf &>(a_Mob); + Byte WolfStatus = 0; + if (Wolf.IsSitting()) { - Flags |= 0x20; + WolfStatus |= 0x1; } - if (Horse.IsRearing()) + if (Wolf.IsAngry()) { - Flags |= 0x40; + WolfStatus |= 0x2; } - if (Horse.IsMthOpen()) + if (Wolf.IsTame()) { - Flags |= 0x80; + WolfStatus |= 0x4; } - WriteByte(0x50); // Int at index 16 - WriteInt(Flags); - WriteByte(0x13); // Byte at index 19 - WriteByte(Horse.GetHorseType()); - WriteByte(0x54); // Int at index 20 - int Appearance = 0; - Appearance = Horse.GetHorseColor(); - Appearance |= Horse.GetHorseStyle() << 8; - WriteInt(Appearance); - WriteByte(0x56); // Int at index 22 - WriteInt(Horse.GetHorseArmour()); + a_Pkt.WriteBEUInt8(0x10); + a_Pkt.WriteBEUInt8(WolfStatus); + + a_Pkt.WriteBEUInt8(0x72); + a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); + a_Pkt.WriteBEUInt8(0x13); + a_Pkt.WriteBEUInt8(Wolf.IsBegging() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x14); + a_Pkt.WriteBEUInt8(Wolf.GetCollarColor()); break; - } + } // case mtWolf + + case mtZombie: + { + auto & Zombie = reinterpret_cast<const cZombie &>(a_Mob); + a_Pkt.WriteBEUInt8(0x0c); + a_Pkt.WriteBEUInt8(Zombie.IsBaby() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x0d); + a_Pkt.WriteBEUInt8(Zombie.IsVillagerZombie() ? 1 : 0); + a_Pkt.WriteBEUInt8(0x0e); + a_Pkt.WriteBEUInt8(Zombie.IsConverting() ? 1 : 0); + break; + } // case mtZombie } // switch (a_Mob.GetType()) } @@ -3354,12 +3353,12 @@ void cProtocol180::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) -void cProtocol180::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) +void cProtocol180::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) { if (!a_Entity.IsMob()) { // No properties for anything else than mobs - WriteInt(0); + a_Pkt.WriteBEInt32(0); return; } @@ -3367,7 +3366,7 @@ void cProtocol180::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) // TODO: Send properties and modifiers based on the mob type - WriteInt(0); // NumProperties + a_Pkt.WriteBEInt32(0); // NumProperties } diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h index 92d9825ef..9aa5ed827 100644 --- a/src/Protocol/Protocol18x.h +++ b/src/Protocol/Protocol18x.h @@ -62,7 +62,7 @@ public: /** 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 SendBlockBreakAnim (UInt32 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; @@ -150,96 +150,6 @@ public: protected: - /** Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed */ - class cPacketizer - { - public: - cPacketizer(cProtocol180 & a_Protocol, UInt32 a_PacketType) : - m_Protocol(a_Protocol), - m_Out(a_Protocol.m_OutPacketBuffer), - m_Lock(a_Protocol.m_CSPacket) - { - m_Out.WriteVarInt(a_PacketType); - } - - ~cPacketizer(); - - void WriteBool(bool a_Value) - { - m_Out.WriteBool(a_Value); - } - - void WriteByte(Byte a_Value) - { - m_Out.WriteByte(a_Value); - } - - void WriteChar(char a_Value) - { - m_Out.WriteChar(a_Value); - } - - void WriteShort(short a_Value) - { - m_Out.WriteBEShort(a_Value); - } - - void WriteInt(int a_Value) - { - m_Out.WriteBEInt(a_Value); - } - - void WriteInt64(Int64 a_Value) - { - m_Out.WriteBEInt64(a_Value); - } - - void WriteFloat(float a_Value) - { - m_Out.WriteBEFloat(a_Value); - } - - void WriteDouble(double a_Value) - { - m_Out.WriteBEDouble(a_Value); - } - - void WriteVarInt(UInt32 a_Value) - { - m_Out.WriteVarInt(a_Value); - } - - void WriteString(const AString & a_Value) - { - m_Out.WriteVarUTF8String(a_Value); - } - - void WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ) - { - m_Out.WritePosition(a_BlockX, a_BlockY, a_BlockZ); - } - - void WriteUUID(const AString & a_UUID); - - void WriteBuf(const char * a_Data, size_t a_Size) - { - m_Out.Write(a_Data, a_Size); - } - - void WriteItem(const cItem & a_Item); - void WriteByteAngle(double a_Angle); // Writes the specified angle using a single byte - void WriteFPInt(double a_Value); // Writes the double value as a 27:5 fixed-point integer - void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f - void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob - void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field - void WriteBlockEntity(const cBlockEntity & a_BlockEntity); - - protected: - cProtocol180 & m_Protocol; - cByteBuffer & m_Out; - cCSLock m_Lock; - } ; - AString m_ServerAddress; UInt16 m_ServerPort; @@ -252,12 +162,6 @@ protected: /** Buffer for the received data */ cByteBuffer m_ReceivedData; - /** Buffer for composing the outgoing packets, through cPacketizer */ - cByteBuffer m_OutPacketBuffer; - - /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */ - cByteBuffer m_OutPacketLenBuffer; - bool m_IsEncrypted; cAesCfb128Decryptor m_Decryptor; @@ -320,6 +224,9 @@ protected: /** Sends the data to the client, encrypting them if needed. */ virtual void SendData(const char * a_Data, size_t a_Size) override; + /** Sends the packet to the client. Called by the cPacketizer's destructor. */ + virtual void SendPacket(cPacketizer & a_Packet) override; + void SendCompass(const cWorld & a_World); /** Reads an item out of the received data, sets a_Item to the values read. @@ -332,6 +239,24 @@ protected: void StartEncryption(const Byte * a_Key); + /** Converts the BlockFace received by the protocol into eBlockFace constants. + If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */ + eBlockFace FaceIntToBlockFace(Int8 a_FaceInt); + + /** Writes the item data into a packet. */ + void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); + + /** Writes the metadata for the specified entity, not including the terminating 0x7f. */ + void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity); + + /** Writes the mob-specific metadata for the specified mob */ + void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob); + + /** Writes the entity properties for the specified entity, including the Count field. */ + void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); + + /** Writes the block entity data for the specified block entity into the packet. */ + void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); } ; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index af9e0d1bc..36f8bc791 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -108,10 +108,10 @@ 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) +void cProtocolRecognizer::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { ASSERT(m_Protocol != nullptr); - m_Protocol->SendBlockBreakAnim(a_entityID, a_BlockX, a_BlockY, a_BlockZ, stage); + m_Protocol->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage); } @@ -911,13 +911,13 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema case PROTO_VERSION_1_7_2: { AString ServerAddress; - short ServerPort; + UInt16 ServerPort; UInt32 NextState; if (!m_Buffer.ReadVarUTF8String(ServerAddress)) { break; } - if (!m_Buffer.ReadBEShort(ServerPort)) + if (!m_Buffer.ReadBEUInt16(ServerPort)) { break; } @@ -926,19 +926,19 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema break; } m_Buffer.CommitRead(); - m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState); + m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState); return true; } case PROTO_VERSION_1_7_6: { AString ServerAddress; - short ServerPort; + UInt16 ServerPort; UInt32 NextState; if (!m_Buffer.ReadVarUTF8String(ServerAddress)) { break; } - if (!m_Buffer.ReadBEShort(ServerPort)) + if (!m_Buffer.ReadBEUInt16(ServerPort)) { break; } @@ -947,19 +947,19 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema break; } m_Buffer.CommitRead(); - m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState); + m_Protocol = new cProtocol176(m_Client, ServerAddress, ServerPort, NextState); return true; } case PROTO_VERSION_1_8_0: { AString ServerAddress; - short ServerPort; + UInt16 ServerPort; UInt32 NextState; if (!m_Buffer.ReadVarUTF8String(ServerAddress)) { break; } - if (!m_Buffer.ReadBEShort(ServerPort)) + if (!m_Buffer.ReadBEUInt16(ServerPort)) { break; } @@ -968,12 +968,12 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema break; } m_Buffer.CommitRead(); - m_Protocol = new cProtocol180(m_Client, ServerAddress, (UInt16)ServerPort, NextState); + m_Protocol = new cProtocol180(m_Client, ServerAddress, ServerPort, NextState); return true; } } - LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)", - m_Client->GetIPString().c_str(), ProtocolVersion + LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))", + m_Client->GetIPString().c_str(), ProtocolVersion, ProtocolVersion ); m_Client->Kick("Unsupported protocol version"); return false; @@ -982,3 +982,15 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema +void cProtocolRecognizer::SendPacket(cPacketizer & a_Pkt) +{ + // This function should never be called - it needs to exists so that cProtocolRecognizer can be instantiated, + // but the actual sending is done by the internal m_Protocol itself. + LOGWARNING("%s: This function shouldn't ever be called.", __FUNCTION__); + ASSERT(!"Function not to be called"); +} + + + + + diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index dcf653e75..d46d31cb1 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -50,7 +50,7 @@ public: /// 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 SendBlockBreakAnim (UInt32 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; @@ -136,9 +136,12 @@ protected: /** 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 - **/ + The number of bytes remaining in the packet is passed as a_PacketLengthRemaining. **/ bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining); + + /** Sends a single packet contained within the cPacketizer class. + The cPacketizer's destructor calls this to send the contained packet; protocol may transform the data (compression in 1.8 etc). */ + virtual void SendPacket(cPacketizer & a_Pkt) override; } ; diff --git a/src/Root.cpp b/src/Root.cpp index 27d87c717..87bc29627 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -84,7 +84,10 @@ void cRoot::InputThread(cRoot & a_Params) if (m_TerminateEventRaised || !std::cin.good()) { // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server: - a_Params.m_bStop = true; + if (m_RunAsService) // HACK: Dont kill if running as a service + { + a_Params.m_bStop = true; + } } } @@ -268,6 +271,13 @@ void cRoot::Start(void) +void cRoot::SetStopping(bool a_Stopping) +{ + m_bStop = a_Stopping; +} + + + void cRoot::LoadGlobalSettings() { diff --git a/src/Root.h b/src/Root.h index fdaf444bd..d552466dc 100644 --- a/src/Root.h +++ b/src/Root.h @@ -46,6 +46,7 @@ public: // tolua_end static bool m_TerminateEventRaised; + static bool m_RunAsService; cRoot(void); @@ -53,6 +54,9 @@ public: void Start(void); + // Added so the service handler can request a stop + void SetStopping(bool a_Stopping); + // tolua_begin cServer * GetServer(void) { return m_Server; } cWorld * GetDefaultWorld(void); diff --git a/src/Server.cpp b/src/Server.cpp index 3f61be378..df2c7deef 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -549,7 +549,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac } #endif - else if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output)) + else if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output, a_Cmd)) { a_Output.Finished(); return; diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 8456ed11d..0ee33a3bc 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -377,7 +377,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel if (BlockType == E_BLOCK_TNT) { m_World.SpawnPrimedTNT(AbsX, Y, AbsZ, 0); - Neighbour->SetBlock(X, a_RelY + Y, Z, E_BLOCK_AIR, 0); + Neighbour->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); return; } diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index bcd083294..a9481edb0 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -108,8 +108,9 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re { SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta); } + // If source creation is on, check for it here: - else if ( + if ( (m_NumNeighborsForSource > 0) && // Source creation is on (MyMeta == m_Falloff) && // Only exactly one block away from a source (fast bail-out) !IsPassableForFluid(Below) && // Only exactly 1 block deep diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 1cc5340dd..40be9c582 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -31,7 +31,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, { return; } - else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height)) + else if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) { return; } @@ -556,7 +556,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... { BLOCKTYPE Type = 0; - if (a_RelBlockY + 1 >= cChunkDef::Height) + if (a_RelBlockY >= cChunkDef::Height - 1) { continue; } diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 4eb2d48b6..4adc6a0a0 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -140,6 +140,54 @@ AStringVector StringSplit(const AString & str, const AString & delim) +AStringVector StringSplitWithQuotes(const AString & str, const AString & delim) +{ + AStringVector results; + + size_t cutAt = 0; + size_t Prev = 0; + size_t cutAtQuote = 0; + + while ((cutAt = str.find_first_of(delim, Prev)) != str.npos) + { + AString current = str.substr(Prev, cutAt - Prev); + if ((current.front() == '"') || (current.front() == '\'')) + { + Prev += 1; + cutAtQuote = str.find_first_of(current.front(), Prev); + if (cutAtQuote != str.npos) + { + current = str.substr(Prev, cutAtQuote - Prev); + cutAt = cutAtQuote + 1; + } + } + + results.push_back(std::move(current)); + Prev = cutAt + 1; + } + + if (Prev < str.length()) + { + AString current = str.substr(Prev); + + // If the remant is wrapped in matching quotes, remove them: + if ( + (current.length() >= 2) && + ((current.front() == '"') || (current.front() == '\'')) && + (current.front() == current.back()) + ) + { + current = current.substr(1, current.length() - 2); + } + + results.push_back(current); + } + + return results; +} + + + AStringVector StringSplitAndTrim(const AString & str, const AString & delim) { diff --git a/src/StringUtils.h b/src/StringUtils.h index bc3bb7a2c..785197763 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -41,6 +41,11 @@ extern AString & AppendPrintf (AString & a_Dst, const char * format, ...) FORMAT Return the splitted strings as a stringvector. */ extern AStringVector StringSplit(const AString & str, const AString & delim); +/** Split the string at any of the listed delimiters. Keeps quoted content together +Resolves issue #490 +Return the splitted strings as a stringvector. */ +extern AStringVector StringSplitWithQuotes(const AString & str, const AString & delim); + /** Split the string at any of the listed delimiters and trim each value. Returns the splitted strings as a stringvector. */ extern AStringVector StringSplitAndTrim(const AString & str, const AString & delim); diff --git a/src/UI/AnvilWindow.cpp b/src/UI/AnvilWindow.cpp new file mode 100644 index 000000000..daa35cf47 --- /dev/null +++ b/src/UI/AnvilWindow.cpp @@ -0,0 +1,83 @@ + +// AnvilWindow.cpp + +// Representing the UI window for the anvil block + +#include "Globals.h" +#include "AnvilWindow.h" +#include "SlotArea.h" + + + + +cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtAnvil, "Repair"), + m_RepairedItemName(""), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_AnvilSlotArea = new cSlotAreaAnvil(*this); + m_SlotAreas.push_back(m_AnvilSlotArea); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +AString cAnvilWindow::GetRepairedItemName(void) const +{ + return m_RepairedItemName; +} + + + + + +void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player) +{ + m_RepairedItemName = a_Name; + if (a_Player != nullptr) + { + m_AnvilSlotArea->UpdateResult(*a_Player); + } +} + + + + + +void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) +{ + a_PosX = m_BlockX; + a_PosY = m_BlockY; + a_PosZ = m_BlockZ; +} + + + + + +void cAnvilWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Anvil Slot + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* Anvil */ + } + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); +} + + + + diff --git a/src/UI/AnvilWindow.h b/src/UI/AnvilWindow.h new file mode 100644 index 000000000..e23c744fe --- /dev/null +++ b/src/UI/AnvilWindow.h @@ -0,0 +1,45 @@ + +// AnvilWindow.h + +// Representing the UI window for the anvil block + + + + + +#pragma once + +#include "Window.h" + + + + + +class cAnvilWindow : + public cWindow +{ + typedef cWindow super; + +public: + cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + + /** Gets the repaired item name. */ + AString GetRepairedItemName(void) const; + + /** Set the repaired item name. */ + void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player); + + /** Gets the Position from the Anvil */ + void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + +protected: + cSlotAreaAnvil * m_AnvilSlotArea; + AString m_RepairedItemName; + int m_BlockX, m_BlockY, m_BlockZ; +}; + + + + diff --git a/src/UI/BeaconWindow.cpp b/src/UI/BeaconWindow.cpp new file mode 100644 index 000000000..c1efa78ad --- /dev/null +++ b/src/UI/BeaconWindow.cpp @@ -0,0 +1,76 @@ + +// BeaconWindow.cpp + +// Representing the UI window for the beacon block + +#include "Globals.h" +#include "BeaconWindow.h" +#include "SlotArea.h" +#include "../BlockEntities/BeaconEntity.h" +#include "../Entities/Player.h" + + + + + +cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) : + cWindow(wtBeacon, "Beacon"), + m_Beacon(a_Beacon) +{ + m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cBeaconWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Beacon Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + if (cSlotAreaBeacon::IsPlaceableItem(a_ItemStack.m_ItemType) && (a_ItemStack.m_ItemCount == 1)) + { + AreasInOrder.push_back(m_SlotAreas[0]); /* Beacon */ + } + + if (a_ClickedArea == m_SlotAreas[1]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + else + { + // Hotbar Area + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + } + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + + +void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player) +{ + super::OpenedByPlayer(a_Player); + + a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect()); +} + + + + diff --git a/src/UI/BeaconWindow.h b/src/UI/BeaconWindow.h new file mode 100644 index 000000000..fa28b41ba --- /dev/null +++ b/src/UI/BeaconWindow.h @@ -0,0 +1,40 @@ + +// BeaconWindow.h + +// Representing the UI window for the beacon block + + + + + +#pragma once + +#include "Window.h" +#include "../Entities/Player.h" + + + + + +class cBeaconWindow : + public cWindow +{ + typedef cWindow super; + +public: + cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon); + + cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; } + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + + // cWindow Overrides: + virtual void OpenedByPlayer(cPlayer & a_Player) override; + +protected: + cBeaconEntity * m_Beacon; +}; + + + + diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt index 2b094ef1d..ef4afc40a 100644 --- a/src/UI/CMakeLists.txt +++ b/src/UI/CMakeLists.txt @@ -6,11 +6,32 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") SET (SRCS SlotArea.cpp - Window.cpp) + Window.cpp + AnvilWindow.cpp + BeaconWindow.cpp + ChestWindow.cpp + CraftingWindow.cpp + DropSpenserWindow.cpp + EnchantingWindow.cpp + EnderChestWindow.cpp + FurnaceWindow.cpp + HopperWindow.cpp + InventoryWindow.cpp) SET (HDRS SlotArea.h Window.h + AnvilWindow.h + BeaconWindow.h + ChestWindow.h + CraftingWindow.h + DropSpenserWindow.h + EnchantingWindow.h + EnderChestWindow.h + FurnaceWindow.h + HopperWindow.h + InventoryWindow.h + MinecartWithChestWindow.h WindowOwner.h) if(NOT MSVC) diff --git a/src/UI/ChestWindow.cpp b/src/UI/ChestWindow.cpp new file mode 100644 index 000000000..3766b132d --- /dev/null +++ b/src/UI/ChestWindow.cpp @@ -0,0 +1,141 @@ + +// ChestWindow.cpp + +// Representing the UI window for the chest block + +#include "Globals.h" +#include "ChestWindow.h" +#include "../BlockEntities/ChestEntity.h" +#include "../Entities/Player.h" + + + + + +cChestWindow::cChestWindow(cChestEntity * a_Chest) : + cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"), + m_World(a_Chest->GetWorld()), + m_BlockX(a_Chest->GetPosX()), + m_BlockY(a_Chest->GetPosY()), + m_BlockZ(a_Chest->GetPosZ()), + m_PrimaryChest(a_Chest), + m_SecondaryChest(nullptr) +{ + m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); + + // Play the opening sound: + m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); + + // Send out the chest-open packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType()); +} + + + + + +cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) : + cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"), + m_World(a_PrimaryChest->GetWorld()), + m_BlockX(a_PrimaryChest->GetPosX()), + m_BlockY(a_PrimaryChest->GetPosY()), + m_BlockZ(a_PrimaryChest->GetPosZ()), + m_PrimaryChest(a_PrimaryChest), + m_SecondaryChest(a_SecondaryChest) +{ + m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); + + // Play the opening sound: + m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); + + // Send out the chest-open packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType()); +} + + + + + +cChestWindow::~cChestWindow() +{ + // Send out the chest-close packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType()); + + m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); +} + + + + + +bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) +{ + int ChunkX, ChunkZ; + + m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1); + cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); + m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + + if (m_SecondaryChest != nullptr) + { + m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1); + cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); + m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + } + + cWindow::ClosedByPlayer(a_Player, a_CanRefuse); + return true; +} + + + + + +void cChestWindow::OpenedByPlayer(cPlayer & a_Player) +{ + int ChunkX, ChunkZ; + + m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1); + cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); + m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + + if (m_SecondaryChest != nullptr) + { + m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1); + cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); + m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + } + + cWindow::OpenedByPlayer(a_Player); +} + + + + + +void cChestWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Chest Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Hotbar or Inventory + AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/ChestWindow.h b/src/UI/ChestWindow.h new file mode 100644 index 000000000..a3b20cdd9 --- /dev/null +++ b/src/UI/ChestWindow.h @@ -0,0 +1,45 @@ + +// ChestWindow.h + +// Representing the UI window for the chest block + + + + + +#pragma once + +#include "Window.h" + + + + + +class cChestWindow : + public cWindow +{ + typedef cWindow super; + +public: + cChestWindow(cChestEntity * a_Chest); + + cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest); + + ~cChestWindow(); + + virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override; + + virtual void OpenedByPlayer(cPlayer & a_Player) override; + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + +protected: + cWorld * m_World; + int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet + cChestEntity * m_PrimaryChest; + cChestEntity * m_SecondaryChest; +}; + + + + diff --git a/src/UI/CraftingWindow.cpp b/src/UI/CraftingWindow.cpp new file mode 100644 index 000000000..ca44056f9 --- /dev/null +++ b/src/UI/CraftingWindow.cpp @@ -0,0 +1,61 @@ + +// CraftingWindow.cpp + +// Representing the UI window for the crafting block + +#include "Globals.h" +#include "CraftingWindow.h" +#include "SlotArea.h" + + + + +cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtWorkbench, "Crafting Table") +{ + m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cCraftingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Crafting Area + if (a_Slot == 0) + { + // Result Slot + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + } + else + { + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, (a_Slot == 0)); + } + else if (a_ClickedArea == m_SlotAreas[1]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + else + { + // Hotbar + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/CraftingWindow.h b/src/UI/CraftingWindow.h new file mode 100644 index 000000000..01b2da73a --- /dev/null +++ b/src/UI/CraftingWindow.h @@ -0,0 +1,31 @@ + +// CraftingWindow.h + +// Representing the UI window for the crafting block + + + + + +#pragma once + +#include "Window.h" + + + + + +class cCraftingWindow : + public cWindow +{ + typedef cWindow super; + +public: + cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; +}; + + + + diff --git a/src/UI/DropSpenserWindow.cpp b/src/UI/DropSpenserWindow.cpp new file mode 100644 index 000000000..aeb7c64b7 --- /dev/null +++ b/src/UI/DropSpenserWindow.cpp @@ -0,0 +1,46 @@ + +// DropSpenserWindow.cpp + +// Representing the UI window for the dropper/dispenser block + +#include "Globals.h" +#include "DropSpenserWindow.h" + + + + + +cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : + cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper") +{ + m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cDropSpenserWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // DropSpenser Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* DropSpenser */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/DropSpenserWindow.h b/src/UI/DropSpenserWindow.h new file mode 100644 index 000000000..edff936e5 --- /dev/null +++ b/src/UI/DropSpenserWindow.h @@ -0,0 +1,32 @@ + +// DropSpenserWindow.h + +// Representing the UI window for the dropper/dispenser block + + + + + +#pragma once + +#include "Window.h" +#include "../BlockEntities/DropSpenserEntity.h" + + + + + +class cDropSpenserWindow : + public cWindow +{ + typedef cWindow super; + +public: + cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; +}; + + + + diff --git a/src/UI/EnchantingWindow.cpp b/src/UI/EnchantingWindow.cpp new file mode 100644 index 000000000..fe21ee83d --- /dev/null +++ b/src/UI/EnchantingWindow.cpp @@ -0,0 +1,100 @@ + +// EnchantingWindow.cpp + +// Representing the UI window for the enchanting block + +#include "Globals.h" +#include "EnchantingWindow.h" +#include "SlotArea.h" + + + + + +cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtEnchantment, "Enchant"), + m_SlotArea(), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_SlotArea = new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ); + m_SlotAreas.push_back(m_SlotArea); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player) +{ + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return; + } + + m_PropertyValue[a_Property] = a_Value; + super::SetProperty(a_Property, a_Value, a_Player); +} + + + + + + +void cEnchantingWindow::SetProperty(short a_Property, short a_Value) +{ + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return; + } + + m_PropertyValue[a_Property] = a_Value; + super::SetProperty(a_Property, a_Value); +} + + + + + +short cEnchantingWindow::GetPropertyValue(short a_Property) +{ + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return 0; + } + + return m_PropertyValue[a_Property]; +} + + + + + +void cEnchantingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Enchanting Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* Enchanting */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/EnchantingWindow.h b/src/UI/EnchantingWindow.h new file mode 100644 index 000000000..bf805c6c8 --- /dev/null +++ b/src/UI/EnchantingWindow.h @@ -0,0 +1,44 @@ + +// EnchantingWindow.h + +// Representing the UI window for the enchanting block + + + + + +#pragma once + +#include "Window.h" + + + + + +class cEnchantingWindow : + public cWindow +{ + typedef cWindow super; + +public: + cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + + 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 */ + short GetPropertyValue(short a_Property); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + + cSlotArea * m_SlotArea; + +protected: + short m_PropertyValue[3]; + int m_BlockX, m_BlockY, m_BlockZ; +}; + + + + diff --git a/src/UI/EnderChestWindow.cpp b/src/UI/EnderChestWindow.cpp new file mode 100644 index 000000000..a5484468f --- /dev/null +++ b/src/UI/EnderChestWindow.cpp @@ -0,0 +1,71 @@ + +// EnderChestWindow.cpp + +// Representing the UI window for the enderchest block + +#include "Globals.h" +#include "../World.h" +#include "EnderChestWindow.h" +#include "SlotArea.h" + + + + + +cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) : + cWindow(wtChest, "Ender Chest"), + m_World(a_EnderChest->GetWorld()), + m_BlockX(a_EnderChest->GetPosX()), + m_BlockY(a_EnderChest->GetPosY()), + m_BlockZ(a_EnderChest->GetPosZ()) +{ + m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); + + // Play the opening sound: + m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); + + // Send out the chest-open packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST); +} + + + + + +cEnderChestWindow::~cEnderChestWindow() +{ + // Send out the chest-close packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST); + + // Play the closing sound + m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); +} + + + + + +void cEnderChestWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Chest Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Hotbar or Inventory + AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/EnderChestWindow.h b/src/UI/EnderChestWindow.h new file mode 100644 index 000000000..006a490bf --- /dev/null +++ b/src/UI/EnderChestWindow.h @@ -0,0 +1,38 @@ + +// EnderChestWindow.h + +// Representing the UI window for the enderchest block + + + + + +#pragma once + +#include "Window.h" +#include "../BlockEntities/EnderChestEntity.h" + + + + + +class cEnderChestWindow : + public cWindow +{ + typedef cWindow super; + +public: + cEnderChestWindow(cEnderChestEntity * a_EnderChest); + + ~cEnderChestWindow(); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + +protected: + cWorld * m_World; + int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet +}; + + + + diff --git a/src/UI/FurnaceWindow.cpp b/src/UI/FurnaceWindow.cpp new file mode 100644 index 000000000..132439ff3 --- /dev/null +++ b/src/UI/FurnaceWindow.cpp @@ -0,0 +1,74 @@ + +// FurnaceWindow.cpp + +// Representing the UI window for the furnace block + +#include "Globals.h" +#include "FurnaceWindow.h" +#include "SlotArea.h" +#include "../FurnaceRecipe.h" +#include "../Root.h" + + + + + +cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : + cWindow(wtFurnace, "Furnace") +{ + m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cFurnaceWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Furnace Area + if (a_Slot == 2) + { + // Result Slot + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Furnace Input/Fuel Slot + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } + else + { + cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe(); + if ((FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr) || (FurnaceRecipes->IsFuel(a_ItemStack))) + { + // The item is a valid input item or fuel + AreasInOrder.push_back(m_SlotAreas[0]); /* Furnace Area */ + } + else if (a_ClickedArea == m_SlotAreas[1]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + else + { + // Hotbar Area + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + } + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/FurnaceWindow.h b/src/UI/FurnaceWindow.h new file mode 100644 index 000000000..845505f8e --- /dev/null +++ b/src/UI/FurnaceWindow.h @@ -0,0 +1,32 @@ + +// FurnaceWindow.h + +// Representing the UI window for the furnace block + + + + + +#pragma once + +#include "Window.h" + + + + + +class cFurnaceWindow : + public cWindow +{ + typedef cWindow super; + +public: + cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + +}; + + + + diff --git a/src/UI/HopperWindow.cpp b/src/UI/HopperWindow.cpp new file mode 100644 index 000000000..79f0767e8 --- /dev/null +++ b/src/UI/HopperWindow.cpp @@ -0,0 +1,48 @@ + +// HopperWindow.cpp + +// Representing the UI window for the hopper block + +#include "Globals.h" +#include "../BlockEntities/HopperEntity.h" +#include "HopperWindow.h" +#include "../BlockEntities/DropperEntity.h" + + + + + +cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) : + super(wtHopper, "Hopper") +{ + m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cHopperWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Hopper Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* Hopper */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/HopperWindow.h b/src/UI/HopperWindow.h new file mode 100644 index 000000000..2dec08666 --- /dev/null +++ b/src/UI/HopperWindow.h @@ -0,0 +1,32 @@ + +// HopperWindow.h + +// Representing the UI window for the hopper block + + + + + +#pragma once + +#include "Window.h" + + + + + +class cHopperWindow : + public cWindow +{ + typedef cWindow super; + +public: + cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + +}; + + + + diff --git a/src/UI/InventoryWindow.cpp b/src/UI/InventoryWindow.cpp new file mode 100644 index 000000000..0f876e559 --- /dev/null +++ b/src/UI/InventoryWindow.cpp @@ -0,0 +1,73 @@ + +// InventoryWindow.cpp + +// Representing the UI window for the player inventory + +#include "Globals.h" +#include "InventoryWindow.h" +#include "SlotArea.h" + + + + + +cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : + cWindow(wtInventory, "Inventory"), + m_Player(a_Player) +{ + m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers + m_SlotAreas.push_back(new cSlotAreaArmor(*this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cInventoryWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +{ + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Crafting Area + if (a_Slot == 0) + { + // Result Slot + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + } + else + { + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + } + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, (a_Slot == 0)); + } + else if (a_ClickedArea == m_SlotAreas[1]) + { + // Armor Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + else if (a_ClickedArea == m_SlotAreas[2]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[1]); /* Armor */ + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + else + { + // Hotbar + AreasInOrder.push_back(m_SlotAreas[1]); /* Armor */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } +} + + + + diff --git a/src/UI/InventoryWindow.h b/src/UI/InventoryWindow.h new file mode 100644 index 000000000..10952d37f --- /dev/null +++ b/src/UI/InventoryWindow.h @@ -0,0 +1,34 @@ + +// InventoryWindow.h + +// Representing the UI window for the player inventory + + + + + +#pragma once + +#include "Window.h" + + + + + +class cInventoryWindow : + public cWindow +{ + typedef cWindow super; + +public: + cInventoryWindow(cPlayer & a_Player); + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; + +protected: + cPlayer & m_Player; +}; + + + + diff --git a/src/UI/MinecartWithChestWindow.h b/src/UI/MinecartWithChestWindow.h new file mode 100644 index 000000000..a2b5283a6 --- /dev/null +++ b/src/UI/MinecartWithChestWindow.h @@ -0,0 +1,67 @@ + +// MinecartWithChestWindow.h + +// Representing the UI window for the minecart chest entity + + + + + +#pragma once + +#include "Window.h" +#include "../Entities/Minecart.h" + + + + + +class cMinecartWithChestWindow : + public cWindow +{ + typedef cWindow super; + +public: + cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart) : + cWindow(wtChest, "Minecart with Chest"), + m_ChestCart(a_ChestCart) + { + 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); + } + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea* a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Chest Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Hotbar or Inventory + AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */ + super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } + + + ~cMinecartWithChestWindow() + { + m_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestclosed", m_ChestCart->GetPosX(), m_ChestCart->GetPosY(), m_ChestCart->GetPosZ(), 1, 1); + } + +private: + cMinecartWithChest * m_ChestCart; +}; + + + + diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index e784569d9..37683a8e5 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -1,3 +1,4 @@ + // SlotArea.cpp // Implements the cSlotArea class and its descendants @@ -12,6 +13,7 @@ #include "../BlockEntities/FurnaceEntity.h" #include "../Entities/Minecart.h" #include "../Items/ItemHandler.h" +#include "AnvilWindow.h" #include "Window.h" #include "../CraftingRecipes.h" #include "../Root.h" @@ -205,7 +207,7 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ { // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover: cItem Slot(*GetSlot(a_SlotNum, a_Player)); - m_ParentWindow.DistributeStack(Slot, a_Player, this, true); + m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true); if (Slot.IsEmpty()) { // Empty the slot completely, the client doesn't like left-over ItemType with zero count @@ -340,31 +342,31 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player) -void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { for (int i = 0; i < m_NumSlots; i++) { - const cItem * Slot = GetSlot(i, a_Player); + int SlotNum = (a_BackFill) ? (m_NumSlots - 1 - i) : i; + + const cItem * Slot = GetSlot(SlotNum, a_Player); if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) { // Different items continue; } - int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; if (NumFit <= 0) { // Full stack already continue; } - if (NumFit > a_ItemStack.m_ItemCount) - { - NumFit = a_ItemStack.m_ItemCount; - } + NumFit = std::min(NumFit, a_ItemStack.m_ItemCount); + if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; - SetSlot(i, a_Player, NewSlot); + SetSlot(SlotNum, a_Player, NewSlot); } a_ItemStack.m_ItemCount -= NumFit; if (a_ItemStack.IsEmpty()) @@ -589,12 +591,13 @@ void cSlotAreaCrafting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & -void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { UNUSED(a_ItemStack); UNUSED(a_Player); UNUSED(a_ShouldApply); UNUSED(a_KeepEmptySlots); + UNUSED(a_BackFill); } @@ -656,7 +659,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) { // Try distributing the result. If it fails, bail out: cItem ResultCopy(Result); - m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, false); + m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, false); if (!ResultCopy.IsEmpty()) { // Couldn't distribute all of it. Bail out @@ -665,7 +668,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) // Distribute the result, this time for real: ResultCopy = Result; - m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, true); + m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, true); // Remove the ingredients from the crafting grid and update the recipe: cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); @@ -769,7 +772,7 @@ void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Play //////////////////////////////////////////////////////////////////////////////// // cSlotAreaAnvil: -cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) : +cSlotAreaAnvil::cSlotAreaAnvil(cWindow & a_ParentWindow) : cSlotAreaTemporary(3, a_ParentWindow), m_MaximumCost(0), m_StackSizeToBeUsedInRepair(0) @@ -894,7 +897,7 @@ void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem return; } - m_ParentWindow.DistributeStack(Slot, a_Player, this, true); + m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true); if (Slot.IsEmpty()) { Slot.Empty(); @@ -910,31 +913,31 @@ void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem -void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { for (int i = 0; i < 2; i++) { - const cItem * Slot = GetSlot(i, a_Player); + int SlotNum = (a_BackFill) ? (2 - 1 - i) : i; + + const cItem * Slot = GetSlot(SlotNum, a_Player); if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) { // Different items continue; } - int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; if (NumFit <= 0) { // Full stack already continue; } - if (NumFit > a_ItemStack.m_ItemCount) - { - NumFit = a_ItemStack.m_ItemCount; - } + NumFit = std::min(NumFit, a_ItemStack.m_ItemCount); + if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; - SetSlot(i, a_Player, NewSlot); + SetSlot(SlotNum, a_Player, NewSlot); } a_ItemStack.m_ItemCount -= NumFit; if (a_ItemStack.IsEmpty()) @@ -1051,7 +1054,7 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player) cItem SecondInput(*GetSlot(1, a_Player)); cItem Output(*GetSlot(2, a_Player)); - if (Input.IsEmpty() && !Output.IsEmpty()) + if (Input.IsEmpty()) { Output.Empty(); SetSlot(2, a_Player, Output); @@ -1335,7 +1338,7 @@ void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ -void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { const cItem * Slot = GetSlot(0, a_Player); if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1)) @@ -1390,13 +1393,12 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) //////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnchanting: -cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) : +cSlotAreaEnchanting::cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) : cSlotAreaTemporary(1, a_ParentWindow), m_BlockX(a_BlockX), m_BlockY(a_BlockY), m_BlockZ(a_BlockZ) { - a_ParentWindow.m_SlotArea = this; } @@ -1503,7 +1505,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio -void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) +void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots, bool a_BackFill) { const cItem * Slot = GetSlot(0, a_Player); if (!Slot->IsEmpty()) @@ -1833,38 +1835,50 @@ void cSlotAreaFurnace::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a -void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { - for (int i = 0; i < 2; i++) + int SlotNum; + cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe(); + + if (FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr) { - const cItem * Slot = GetSlot(i, a_Player); - if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) - { - // Different items - continue; - } - int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; - if (NumFit <= 0) - { - // Full stack already - continue; - } - if (NumFit > a_ItemStack.m_ItemCount) - { - NumFit = a_ItemStack.m_ItemCount; - } - if (a_ShouldApply) - { - cItem NewSlot(a_ItemStack); - NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; - SetSlot(i, a_Player, NewSlot); - } - a_ItemStack.m_ItemCount -= NumFit; - if (a_ItemStack.IsEmpty()) - { - return; - } - } // for i - Slots + SlotNum = 0; + } + else if (FurnaceRecipes->IsFuel(a_ItemStack)) + { + SlotNum = 1; + } + else + { + return; + } + + const cItem * Slot = GetSlot(SlotNum, a_Player); + if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) + { + // Different items + return; + } + + char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + if (NumFit <= 0) + { + // Full stack already + return; + } + NumFit = std::min(NumFit, a_ItemStack.m_ItemCount); + + if (a_ShouldApply) + { + cItem NewSlot(a_ItemStack); + NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; + SetSlot(SlotNum, a_Player, NewSlot); + } + a_ItemStack.m_ItemCount -= NumFit; + if (a_ItemStack.IsEmpty()) + { + return; + } } @@ -2013,7 +2027,7 @@ void cSlotAreaInventoryBase::SetSlot(int a_SlotNum, cPlayer & a_Player, const cI //////////////////////////////////////////////////////////////////////////////// // cSlotAreaArmor: -void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { if (ItemCategory::IsHelmet(a_ItemStack.m_ItemType) && GetSlot(0, a_Player)->IsEmpty()) { diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 1eeeb9836..0e7ba2a50 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -17,12 +17,10 @@ class cWindow; class cPlayer; class cBeaconEntity; class cChestEntity; -class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cMinecartWithChest; class cCraftingRecipe; -class cEnchantingWindow; class cWorld; @@ -73,7 +71,7 @@ public: if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) If a_KeepEmptySlots is true, empty slots will be skipped and won't be filled */ - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots); + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill); /// Called on DblClicking to collect all stackable items into hand. /// The items are accumulated in a_Dragging and removed from the slots immediately. @@ -158,7 +156,7 @@ public: } /** Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) */ - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; /** Called when a player clicks in the window. Parameters taken from the click packet. */ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; @@ -246,32 +244,35 @@ public: virtual void SetSlot (int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; // Distributing items into this area is completely disabled - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; protected: - /// Maps player's EntityID -> current recipe; not a std::map because cCraftingGrid needs proper constructor params - typedef std::list<std::pair<int, cCraftingRecipe> > cRecipeMap; + /** Maps player's EntityID -> current recipe. + Not a std::map because cCraftingGrid needs proper constructor params. */ + typedef std::list<std::pair<UInt32, cCraftingRecipe> > cRecipeMap; int m_GridSize; cRecipeMap m_Recipes; - /// Handles a click in the result slot. Crafts using the current recipe, if possible + /** Handles a click in the result slot. + Crafts using the current recipe, if possible. */ void ClickedResult(cPlayer & a_Player); - /// Handles a shift-click in the result slot. Crafts using the current recipe until it changes or no more space for result. + /** Handles a shift-click in the result slot. + Crafts using the current recipe until it changes or no more space for result. */ void ShiftClickedResult(cPlayer & a_Player); /** Handles a drop-click in the result slot. */ void DropClickedResult(cPlayer & a_Player); - /// Updates the current recipe and result slot based on the ingredients currently in the crafting grid of the specified player + /** Updates the current recipe and result slot based on the ingredients currently in the crafting grid of the specified player. */ void UpdateRecipe(cPlayer & a_Player); - /// Retrieves the recipe for the specified player from the map, or creates one if not found + /** Retrieves the recipe for the specified player from the map, or creates one if not found. */ cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player); - /// Called after an item has been crafted to handle statistics e.t.c. + /** Called after an item has been crafted to handle statistics e.t.c. */ void HandleCraftItem(const cItem & a_Result, cPlayer & a_Player); } ; @@ -285,12 +286,12 @@ class cSlotAreaAnvil : typedef cSlotAreaTemporary super; public: - cSlotAreaAnvil(cAnvilWindow & a_ParentWindow); + cSlotAreaAnvil(cWindow & a_ParentWindow); // cSlotArea overrides: virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; // cSlotAreaTemporary overrides: virtual void OnPlayerRemoved(cPlayer & a_Player) override; @@ -326,10 +327,10 @@ public: cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow); virtual ~cSlotAreaBeacon(); - bool IsPlaceableItem(short a_ItemType); + static bool IsPlaceableItem(short a_ItemType); virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; 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; @@ -350,11 +351,11 @@ class cSlotAreaEnchanting : typedef cSlotAreaTemporary super; public: - cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ); + cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ); // cSlotArea overrides: virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; // cSlotAreaTemporary overrides: @@ -439,7 +440,7 @@ public: virtual ~cSlotAreaFurnace(); virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; 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; diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 1598dd3e7..bb2e2a807 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -32,7 +32,6 @@ cWindow::cWindow(WindowType a_WindowType, const AString & a_WindowTitle) : m_WindowType(a_WindowType), m_WindowTitle(a_WindowTitle), m_IsDestroyed(false), - m_ShouldDistributeToHotbarFirst(true), m_Owner(nullptr) { if (a_WindowType == wtInventory) @@ -392,43 +391,23 @@ bool cWindow::ForEachClient(cItemCallback<cClientHandle> & a_Callback) -void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply) +void cWindow::DistributeStackToAreas(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill) { - // Ask each slot area to take as much of the stack as it can. - // First ask only slots that already have the same kind of item - // Then ask any remaining slots - for (int Pass = 0; Pass < 2; ++Pass) + /* Ask each slot area to take as much of the stack as it can. + First ask only slots that already have the same kind of item + Then ask any remaining slots */ + for (size_t Pass = 0; Pass < 2; Pass++) { - if (m_ShouldDistributeToHotbarFirst) + for (auto SlotArea : a_AreasInOrder) { - // First distribute into the hotbar: - if (a_ExcludeArea != m_SlotAreas.back()) - { - m_SlotAreas.back()->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); - if (a_ItemStack.IsEmpty()) - { - // Distributed it all - return; - } - } - } - - // The distribute to all other areas: - cSlotAreas::iterator end = m_ShouldDistributeToHotbarFirst ? (m_SlotAreas.end() - 1) : m_SlotAreas.end(); - for (cSlotAreas::iterator itr = m_SlotAreas.begin(); itr != end; ++itr) - { - if (*itr == a_ExcludeArea) - { - continue; - } - (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); + SlotArea->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0), a_BackFill); if (a_ItemStack.IsEmpty()) { // Distributed it all return; } - } // for itr - m_SlotAreas[] - } // for Pass - repeat twice + } + } } @@ -779,401 +758,3 @@ void cWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player) - -//////////////////////////////////////////////////////////////////////////////// -// cInventoryWindow: - -cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : - cWindow(wtInventory, "Inventory"), - m_Player(a_Player) -{ - m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers - m_SlotAreas.push_back(new cSlotAreaArmor(*this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCraftingWindow: - -cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : - cWindow(wtWorkbench, "Crafting Table") -{ - m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cAnvilWindow: - -cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : - cWindow(wtAnvil, "Repair"), - m_RepairedItemName(""), - m_BlockX(a_BlockX), - m_BlockY(a_BlockY), - m_BlockZ(a_BlockZ) -{ - m_AnvilSlotArea = new cSlotAreaAnvil(*this); - m_SlotAreas.push_back(m_AnvilSlotArea); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player) -{ - m_RepairedItemName = a_Name; - - if (a_Player != nullptr) - { - m_AnvilSlotArea->UpdateResult(*a_Player); - } -} - - - - - -void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) -{ - a_PosX = m_BlockX; - a_PosY = m_BlockY; - a_PosZ = m_BlockZ; -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cBeaconWindow: - -cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) : - cWindow(wtBeacon, "Beacon"), - m_Beacon(a_Beacon) -{ - m_ShouldDistributeToHotbarFirst = true; - m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player) -{ - super::OpenedByPlayer(a_Player); - - a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel()); - a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect()); - a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect()); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cEnchantingWindow: - -cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : - cWindow(wtEnchantment, "Enchant"), - m_SlotArea(), - m_BlockX(a_BlockX), - m_BlockY(a_BlockY), - m_BlockZ(a_BlockZ) -{ - m_SlotAreas.push_back(new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -void cEnchantingWindow::SetProperty(short a_Property, short a_Value) -{ - if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) - { - ASSERT(!"a_Property is invalid"); - return; - } - - m_PropertyValue[a_Property] = a_Value; - super::SetProperty(a_Property, a_Value); -} - - - - - -void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player) -{ - if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) - { - ASSERT(!"a_Property is invalid"); - return; - } - - m_PropertyValue[a_Property] = a_Value; - super::SetProperty(a_Property, a_Value, a_Player); -} - - - - - -short cEnchantingWindow::GetPropertyValue(short a_Property) -{ - if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) - { - ASSERT(!"a_Property is invalid"); - return 0; - } - - return m_PropertyValue[a_Property]; -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cChestWindow: - -cChestWindow::cChestWindow(cChestEntity * a_Chest) : - cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"), - m_World(a_Chest->GetWorld()), - m_BlockX(a_Chest->GetPosX()), - m_BlockY(a_Chest->GetPosY()), - m_BlockZ(a_Chest->GetPosZ()), - m_PrimaryChest(a_Chest), - m_SecondaryChest(nullptr) -{ - m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); - - // Play the opening sound: - m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); - - // Send out the chest-open packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType()); -} - - - - - -cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) : - cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"), - m_World(a_PrimaryChest->GetWorld()), - m_BlockX(a_PrimaryChest->GetPosX()), - m_BlockY(a_PrimaryChest->GetPosY()), - m_BlockZ(a_PrimaryChest->GetPosZ()), - m_PrimaryChest(a_PrimaryChest), - m_SecondaryChest(a_SecondaryChest) -{ - m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); - - m_ShouldDistributeToHotbarFirst = false; - - // Play the opening sound: - m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); - - // Send out the chest-open packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType()); -} - - - - - -void cChestWindow::OpenedByPlayer(cPlayer & a_Player) -{ - int ChunkX, ChunkZ; - - m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1); - cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); - m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); - - if (m_SecondaryChest != nullptr) - { - m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1); - cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); - m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); - } - - cWindow::OpenedByPlayer(a_Player); -} - - - - - -bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) -{ - int ChunkX, ChunkZ; - - m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1); - cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); - m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); - - if (m_SecondaryChest != nullptr) - { - m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1); - cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); - m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); - } - - cWindow::ClosedByPlayer(a_Player, a_CanRefuse); - return true; -} - - - - - -cChestWindow::~cChestWindow() -{ - // Send out the chest-close packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType()); - - m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// 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) : - cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper") -{ - m_ShouldDistributeToHotbarFirst = false; - m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cEnderChestWindow: - -cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) : - cWindow(wtChest, "Ender Chest"), - m_World(a_EnderChest->GetWorld()), - m_BlockX(a_EnderChest->GetPosX()), - 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)); - - // Play the opening sound: - m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); - - // Send out the chest-open packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST); -} - - - - - -cEnderChestWindow::~cEnderChestWindow() -{ - // Send out the chest-close packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST); - - // Play the closing sound - m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cHopperWindow: - -cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) : - super(wtHopper, "Hopper") -{ - m_ShouldDistributeToHotbarFirst = false; - m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cFurnaceWindow: - -cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : - cWindow(wtFurnace, "Furnace") -{ - m_ShouldDistributeToHotbarFirst = false; - m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *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 e62176d50..9821aade1 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -19,7 +19,6 @@ class cPlayer; class cWindowOwner; class cClientHandle; class cChestEntity; -class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cHopperEntity; @@ -154,14 +153,19 @@ public: /** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed! if a_ShouldApply is true, the changes are written into the slots; + if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) */ + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) = 0; + + /** Called from DistributeStack() to distribute the stack into a_AreasInOrder; Modifies a_ItemStack as it is distributed! + If a_ShouldApply is true, the changes are written into the slots; if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) - */ - void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); + If a_BackFill is true, the areas will be filled from the back (right side). (Example: Empty Hotbar -> Item get in slot 8, not slot 0) */ + void DistributeStackToAreas(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill); - /// Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area. - /// The items are accumulated in a_Dragging and removed from the SlotAreas immediately. - /// If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting. - /// Returns true if full stack has been collected, false if there's space remaining to fill. + /** Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area. + The items are accumulated in a_Dragging and removed from the SlotAreas immediately. + If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting. + Returns true if full stack has been collected, false if there's space remaining to fill. */ bool CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks); /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea @@ -178,7 +182,6 @@ protected: cPlayerList m_OpenedBy; bool m_IsDestroyed; - bool m_ShouldDistributeToHotbarFirst; ///< If set (default), shift+click tries to distribute to hotbar first, then other areas. False for doublechests cWindowOwner * m_Owner; @@ -219,188 +222,3 @@ protected: - -class cCraftingWindow : - public cWindow -{ - typedef cWindow super; -public: - cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); -} ; - - - - - -class cAnvilWindow : - public cWindow -{ - typedef cWindow super; -public: - cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ); - - /** Gets the repaired item name. */ - AString GetRepairedItemName(void) const { return m_RepairedItemName; } - - /** Set the repaired item name. */ - void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player); - - /** Gets the Position from the Anvil */ - void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); - -protected: - cSlotAreaAnvil * m_AnvilSlotArea; - AString m_RepairedItemName; - int m_BlockX, m_BlockY, m_BlockZ; -} ; - - - - - -class cBeaconWindow : - public cWindow -{ - typedef cWindow super; -public: - cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon); - - cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; } - - // cWindow Overrides: - virtual void OpenedByPlayer(cPlayer & a_Player) override; - -protected: - cBeaconEntity * m_Beacon; -} ; - - - - - -class cEnchantingWindow : - public cWindow -{ - typedef cWindow super; -public: - cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); - 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 */ - short GetPropertyValue(short a_Property); - - cSlotArea * m_SlotArea; - -protected: - short m_PropertyValue[3]; - int m_BlockX, m_BlockY, m_BlockZ; -}; - - - - - -class cFurnaceWindow : - public cWindow -{ - typedef cWindow super; -public: - cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace); -} ; - - - - - -class cDropSpenserWindow : - public cWindow -{ - typedef cWindow super; -public: - cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_Dispenser); -} ; - - - - - -class cHopperWindow : - public cWindow -{ - typedef cWindow super; -public: - cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper); -} ; - - - - - -class cChestWindow : - public cWindow -{ -public: - cChestWindow(cChestEntity * a_Chest); - cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest); - ~cChestWindow(); - - virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override; - virtual void OpenedByPlayer(cPlayer & a_Player) override; - -protected: - cWorld * m_World; - int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet - cChestEntity * m_PrimaryChest; - cChestEntity * m_SecondaryChest; -} ; - - - - - -class cMinecartWithChestWindow : - public cWindow -{ -public: - cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart); - ~cMinecartWithChestWindow(); -private: - cMinecartWithChest * m_ChestCart; -}; - - - - - -class cEnderChestWindow : - public cWindow -{ -public: - cEnderChestWindow(cEnderChestEntity * a_EnderChest); - ~cEnderChestWindow(); - -protected: - cWorld * m_World; - int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet -}; - - - - - -class cInventoryWindow : - public cWindow -{ -public: - cInventoryWindow(cPlayer & a_Player); - -protected: - cPlayer & m_Player; - -} ; - - - - - diff --git a/src/WebAdmin.h b/src/WebAdmin.h index 86a8a9a4b..1e1a9bfa9 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -95,7 +95,9 @@ struct sWebAdminPage // tolua_begin class cWebAdmin : + // tolua_end public cHTTPServer::cCallbacks + // tolua_begin { public: // tolua_end diff --git a/src/World.cpp b/src/World.cpp index 474f77b81..4480013c3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -259,9 +259,9 @@ void cWorld::cTickThread::Execute(void) //////////////////////////////////////////////////////////////////////////////// // cWorld: -cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) : +cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_LinkedOverworldName) : m_WorldName(a_WorldName), - m_OverworldName(a_OverworldName), + m_LinkedOverworldName(a_LinkedOverworldName), m_IniFileName(m_WorldName + "/world.ini"), m_StorageSchema("Default"), #ifdef __arm__ @@ -604,12 +604,12 @@ void cWorld::Start(void) if (GetDimension() == dimOverworld) { - m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether"); - m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end"); + m_LinkedNetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether"); + m_LinkedEndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end"); } else { - m_OverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName()); + m_LinkedOverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName()); } // Adjust the enum-backed variables into their respective bounds: @@ -667,18 +667,23 @@ void cWorld::Start(void) void cWorld::GenerateRandomSpawn(void) { LOGD("Generating random spawnpoint..."); - + bool foundSpawnPoint = false; // Look for a spawn point at most 100 chunks away from map center: for (int i = 0; i < 100; i++) { EMCSBiome biome = GetBiomeAt((int)m_SpawnX, (int)m_SpawnZ); + if ( (biome != biOcean) && (biome != biFrozenOcean) && // The biome is acceptable (don't want a small ocean island) !IsBlockWaterOrIce(GetBlock((int)m_SpawnX, GetHeight((int)m_SpawnX, (int)m_SpawnZ), (int)m_SpawnZ)) // The terrain is acceptable (don't want to spawn inside a lake / river) ) { - // A good spawnpoint was found - break; + if (CheckPlayerSpawnPoint((int)m_SpawnX, GetHeight((int)m_SpawnX, (int)m_SpawnZ), (int)m_SpawnZ)) + { + // A good spawnpoint was found + foundSpawnPoint = true; + break; + } } // Try a neighboring chunk: if ((GetTickRandomNumber(4) % 2) == 0) // Randomise whether to increment X or Z coords @@ -692,8 +697,60 @@ void cWorld::GenerateRandomSpawn(void) } // for i - 100* m_SpawnY = (double)GetHeight((int)m_SpawnX, (int)m_SpawnZ) + 1.6f; // 1.6f to accomodate player height + if (foundSpawnPoint) + { + LOGINFO("Generated random spawnpoint position at {%i, %i, %i}", (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ); + } + else + { + LOGINFO("Did not find an acceptable spawnpoint. Generated a random spawnpoint position at {%i, %i, %i}", (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ); + } // Maybe widen the search instead? + +} + + + + + +bool cWorld::CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ) +{ + // Check that spawnblock and surrounding blocks are neither solid nor water / lava + static const struct + { + int x, z; + } Coords[] = + { + { 0, 0 }, + { -1, 0 }, + { 1, 0 }, + { 0, -1 }, + { 0, 1 }, + }; + for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) + { + BLOCKTYPE BlockType = GetBlock(a_PosX + Coords[i].x, a_PosY, a_PosZ + Coords[i].x); + if (cBlockInfo::IsSolid(BlockType) || IsBlockLiquid(BlockType)) + { + return false; + } + } // for i - Coords[] + + // Check that the block below is solid: + if (!cBlockInfo::IsSolid(GetBlock(a_PosX, a_PosY - 1, a_PosZ))) + { + return false; + } - LOGINFO("Generated random spawnpoint position {%i, %i, %i}", (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ); + // Check that all the blocks above the spawnpoint are not solid: + for (int i = a_PosY; i < cChunkDef::Height; i++) + { + BLOCKTYPE BlockType = GetBlock(a_PosX, i, a_PosZ); + if (cBlockInfo::IsSolid(BlockType)) + { + return false; + } + } + return true; } @@ -827,18 +884,18 @@ void cWorld::Stop(void) IniFile.ReadFile(m_IniFileName); if (GetDimension() == dimOverworld) { - IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_NetherWorldName); - IniFile.SetValue("LinkedWorlds", "EndWorldName", m_EndWorldName); + IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_LinkedNetherWorldName); + IniFile.SetValue("LinkedWorlds", "EndWorldName", m_LinkedEndWorldName); } else { - IniFile.SetValue("LinkedWorlds", "OverworldName", m_OverworldName); + IniFile.SetValue("LinkedWorlds", "OverworldName", m_LinkedOverworldName); } - IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel); + IniFile.SetValueI("Physics", "TNTShrapnelLevel", static_cast<int>(m_TNTShrapnelLevel)); IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled); - IniFile.SetValueI("General", "Weather", (int)m_Weather); + IniFile.SetValueI("General", "Weather", static_cast<int>(m_Weather)); IniFile.SetValueI("General", "TimeInTicks", GetTimeOfDay()); IniFile.WriteFile(m_IniFileName); @@ -1863,7 +1920,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double -int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta) +UInt32 cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta) { cFallingBlock * FallingBlock = new cFallingBlock(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); FallingBlock->Initialize(*this); @@ -1874,11 +1931,12 @@ int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NI -int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) +UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) { if (a_Reward < 1) { - return -1; + LOGWARNING("%s: Attempting to create an experience orb with non-positive reward!", __FUNCTION__); + return cEntity::INVALID_ID; } cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward); @@ -1890,7 +1948,7 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) -int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight) +UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight) { cMinecart * Minecart; switch (a_MinecartType) @@ -1902,7 +1960,7 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break; default: { - return -1; + return cEntity::INVALID_ID; } } // switch (a_MinecartType) Minecart->Initialize(*this); @@ -1913,7 +1971,7 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType -void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff) +UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff) { cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks); TNT->Initialize(*this); @@ -1922,6 +1980,7 @@ void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, a_InitialVelocityCoeff * 2, a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1) ); + return TNT->GetUniqueID(); } @@ -2012,7 +2071,7 @@ void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char -void cWorld::BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude) +void cWorld::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude) { m_ChunkMap->BroadcastBlockBreakAnimation(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage, a_Exclude); } @@ -2849,8 +2908,22 @@ bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ -bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) +bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback) { + // First check the entities-to-add: + { + cCSLock Lock(m_CSEntitiesToAdd); + for (auto & ent: m_EntitiesToAdd) + { + if (ent->GetUniqueID() == a_UniqueID) + { + a_Callback.Item(ent); + return true; + } + } // for ent - m_EntitiesToAdd[] + } + + // Then check the chunkmap: return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback); } @@ -3096,14 +3169,14 @@ void cWorld::SaveAllChunks(void) void cWorld::QueueSaveAllChunks(void) { - QueueTask(make_unique<cWorld::cTaskSaveAllChunks>()); + QueueTask(std::make_shared<cWorld::cTaskSaveAllChunks>()); } -void cWorld::QueueTask(std::unique_ptr<cTask> a_Task) +void cWorld::QueueTask(cTaskPtr a_Task) { cCSLock Lock(m_CSTasks); m_Tasks.push_back(std::move(a_Task)); @@ -3113,7 +3186,7 @@ void cWorld::QueueTask(std::unique_ptr<cTask> a_Task) -void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task) +void cWorld::ScheduleTask(int a_DelayTicks, cTaskPtr a_Task) { Int64 TargetTick = a_DelayTicks + std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count(); @@ -3123,11 +3196,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task) { if ((*itr)->m_TargetTick >= TargetTick) { - m_ScheduledTasks.insert(itr, make_unique<cScheduledTask>(TargetTick, a_Task)); + m_ScheduledTasks.insert(itr, cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task))); return; } } - m_ScheduledTasks.push_back(make_unique<cScheduledTask>(TargetTick, a_Task)); + m_ScheduledTasks.push_back(cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task))); } @@ -3144,7 +3217,7 @@ void cWorld::AddEntity(cEntity * a_Entity) -bool cWorld::HasEntity(int a_UniqueID) +bool cWorld::HasEntity(UInt32 a_UniqueID) { // Check if the entity is in the queue to be added to the world: { @@ -3261,15 +3334,16 @@ 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) +UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) { cMonster * Monster = nullptr; Monster = cMonster::NewMonsterFromType(a_MonsterType); - if (Monster != nullptr) + if (Monster == nullptr) { - Monster->SetPosition(a_PosX, a_PosY, a_PosZ); + return cEntity::INVALID_ID; } + Monster->SetPosition(a_PosX, a_PosY, a_PosZ); return SpawnMobFinalize(Monster); } @@ -3277,13 +3351,9 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a -int cWorld::SpawnMobFinalize(cMonster * a_Monster) +UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) { - // Invalid cMonster object. Bail out. - if (!a_Monster) - { - return -1; - } + ASSERT(a_Monster != nullptr); // Give the mob full health. a_Monster->SetHealth(a_Monster->GetMaxHealth()); @@ -3293,7 +3363,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster) { delete a_Monster; a_Monster = nullptr; - return -1; + return cEntity::INVALID_ID; } // Initialize the monster into the current world. @@ -3301,7 +3371,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster) { delete a_Monster; a_Monster = nullptr; - return -1; + return cEntity::INVALID_ID; } cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); @@ -3313,18 +3383,18 @@ 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) +UInt32 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 == nullptr) { - return -1; + return cEntity::INVALID_ID; } if (!Projectile->Initialize(*this)) { delete Projectile; Projectile = nullptr; - return -1; + return cEntity::INVALID_ID; } return Projectile->GetUniqueID(); } @@ -3578,7 +3648,7 @@ void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World) //////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskSendBlockTo +// cWorld::cTaskSendBlockToAllPlayers cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) : m_SendQueue(a_SendQueue) diff --git a/src/World.h b/src/World.h index 3cac71a36..1de241f60 100644 --- a/src/World.h +++ b/src/World.h @@ -106,7 +106,8 @@ public: virtual void Run(cWorld & a_World) = 0; } ; - typedef std::vector<std::unique_ptr<cTask>> cTasks; + typedef SharedPtr<cTask> cTaskPtr; + typedef std::vector<cTaskPtr> cTasks; class cTaskSaveAllChunks : @@ -215,7 +216,7 @@ public: // (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 = 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 BroadcastBlockBreakAnimation(UInt32 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 @@ -335,7 +336,9 @@ public: The entity is added lazily - this function only puts it in a queue that is then processed by the Tick thread. */ void AddEntity(cEntity * a_Entity); - bool HasEntity(int a_UniqueID); + /** Returns true if an entity with the specified UniqueID exists in the world. + Note: Only loaded chunks are considered. */ + bool HasEntity(UInt32 a_UniqueID); /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp @@ -348,8 +351,9 @@ public: If any chunk in the box is missing, ignores the entities in that chunk silently. */ bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /** 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 and callback returned false. */ - bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /** 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 and callback returned false. */ + bool DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp /** Compares clients of two chunks, calls the callback accordingly */ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); @@ -476,20 +480,25 @@ public: /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) override; - /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */ + /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified. */ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false) override; - /** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */ - int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta); + /** Spawns an falling block entity at the given position. + Returns the UniqueID of the spawned falling block, or cEntity::INVALID_ID on failure. */ + UInt32 SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta); - /** Spawns an minecart at the given coordinates. */ - int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1); + /** Spawns an minecart at the given coordinates. + Returns the UniqueID of the spawned minecart, or cEntity::INVALID_ID on failure. */ + UInt32 SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1); - /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */ - virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override; + /** Spawns an experience orb at the given location with the given reward. + Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */ + virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override; - /** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */ - void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1); + /** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. + Initial velocity is given based on the relative coefficient provided. + Returns the UniqueID of the created entity, or cEntity::INVALID_ID on failure. */ + UInt32 SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1); // tolua_end @@ -673,14 +682,14 @@ public: bool ShouldBroadcastAchievementMessages(void) const { return m_BroadcastAchievementMessages; } - AString GetNetherWorldName(void) const { return m_NetherWorldName; } - void SetNetherWorldName(const AString & a_Name) { m_NetherWorldName = a_Name; } + AString GetLinkedNetherWorldName(void) const { return m_LinkedNetherWorldName; } + void SetLinkedNetherWorldName(const AString & a_Name) { m_LinkedNetherWorldName = a_Name; } - AString GetEndWorldName(void) const { return m_EndWorldName; } - void SetEndWorldName(const AString & a_Name) { m_EndWorldName = a_Name; } + AString GetLinkedEndWorldName(void) const { return m_LinkedEndWorldName; } + void SetLinkedEndWorldName(const AString & a_Name) { m_LinkedEndWorldName = a_Name; } - AString GetLinkedOverworldName(void) const { return m_OverworldName; } - void SetLinkedOverworldName(const AString & a_Name) { m_OverworldName = a_Name; } + AString GetLinkedOverworldName(void) const { return m_LinkedOverworldName; } + void SetLinkedOverworldName(const AString & a_Name) { m_LinkedOverworldName = a_Name; } // tolua_end @@ -691,11 +700,10 @@ 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(std::unique_ptr<cTask> a_Task); // Exported in ManualBindings.cpp + void QueueTask(cTaskPtr 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 */ - void ScheduleTask(int a_DelayTicks, cTask * a_Task); + /** Queues a task onto the tick thread, with the specified delay. */ + void ScheduleTask(int a_DelayTicks, cTaskPtr a_Task); /** Returns the number of chunks loaded */ int GetNumChunks() const; // tolua_export @@ -796,14 +804,14 @@ public: bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ - virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) override; // tolua_export - int SpawnMobFinalize(cMonster* a_Monster); + /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, cEntity::INVALID_ID otherwise */ + virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) override; // tolua_export + + UInt32 SpawnMobFinalize(cMonster * a_Monster); - /** 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 = nullptr); // tolua_export + /** Creates a projectile of the specified type. Returns the projectile's UniqueID if successful, cEntity::INVALID_ID otherwise + Item parameter is currently used for Fireworks to correctly set entity metadata based on item metadata. */ + UInt32 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(int a_Range) { return (int)(m_TickRand.randInt(a_Range)); } @@ -867,20 +875,16 @@ private: { public: Int64 m_TargetTick; - cTask * m_Task; + cTaskPtr m_Task; /** Creates a new scheduled task; takes ownership of the task object passed to it. */ - cScheduledTask(Int64 a_TargetTick, cTask * a_Task) : + cScheduledTask(Int64 a_TargetTick, cTaskPtr a_Task) : m_TargetTick(a_TargetTick), m_Task(a_Task) { } - virtual ~cScheduledTask() - { - delete m_Task; - m_Task = nullptr; - } + virtual ~cScheduledTask() {} }; typedef std::unique_ptr<cScheduledTask> cScheduledTaskPtr; @@ -889,10 +893,9 @@ private: AString m_WorldName; - /** The name of the world that a portal in this world should link to - Only has effect if this world is a nether or end world, as it is used by entities to see which world to teleport to when in a portal - */ - AString m_OverworldName; + /** The name of the overworld that portals in this world should link to. + Only has effect if this world is a Nether or End world. */ + AString m_LinkedOverworldName; AString m_IniFileName; @@ -985,11 +988,13 @@ private: /** The maximum view distance that a player can have in this world. */ int m_MaxViewDistance; - /** Name of the nether world */ - AString m_NetherWorldName; + /** Name of the nether world - where Nether portals should teleport. + Only used when this world is an Overworld. */ + AString m_LinkedNetherWorldName; - /** Name of the end world */ - AString m_EndWorldName; + /** Name of the End world - where End portals should teleport. + Only used when this world is an Overworld. */ + AString m_LinkedEndWorldName; cChunkGenerator m_Generator; @@ -1049,7 +1054,7 @@ private: cSetChunkDataPtrs m_SetChunkDataQueue; - cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = ""); + cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_LinkedOverworldName = ""); virtual ~cWorld(); void Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec); @@ -1077,6 +1082,9 @@ private: /** <summary>Generates a random spawnpoint on solid land by walking chunks and finding their biomes</summary> */ void GenerateRandomSpawn(void); + /** Check if player starting point is acceptable **/ + bool CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ); + /** Chooses a reasonable transition from the current weather to a new weather **/ eWeather ChooseNewWeather(void); diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index c87397542..10231ae3b 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -36,20 +36,9 @@ #include "../Entities/ExpOrb.h" #include "../Entities/HangingEntity.h" #include "../Entities/ItemFrame.h" +#include "../Entities/Painting.h" -#include "../Mobs/Monster.h" -#include "../Mobs/Bat.h" -#include "../Mobs/Creeper.h" -#include "../Mobs/Enderman.h" -#include "../Mobs/Horse.h" -#include "../Mobs/MagmaCube.h" -#include "../Mobs/Sheep.h" -#include "../Mobs/Slime.h" -#include "../Mobs/Skeleton.h" -#include "../Mobs/Villager.h" -#include "../Mobs/Wither.h" -#include "../Mobs/Wolf.h" -#include "../Mobs/Zombie.h" +#include "../Mobs/IncludeAllMonsters.h" @@ -726,24 +715,10 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging) { - 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_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_YM: - case BLOCK_FACE_YP: - case BLOCK_FACE_NONE: - { - // These directions are invalid, but they may have been previously loaded, so keep them. - break; - } - } + m_Writer.AddInt("TileX", FloorC(a_Hanging->GetPosX())); + m_Writer.AddInt("TileY", FloorC(a_Hanging->GetPosY())); + m_Writer.AddInt("TileZ", FloorC(a_Hanging->GetPosZ())); + m_Writer.AddByte("Facing", a_Hanging->GetProtocolFacing()); } @@ -790,6 +765,19 @@ void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame) +void cNBTChunkSerializer::AddPaintingEntity(cPainting * a_Painting) +{ + m_Writer.BeginCompound(""); + AddBasicEntity(a_Painting, "Painting"); + AddHangingEntity(a_Painting); + m_Writer.AddString("Motive", a_Painting->GetName()); + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart) { m_Writer.BeginList("Items", TAG_Compound); @@ -888,7 +876,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity) case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break; case cEntity::etExpOrb: AddExpOrbEntity ((cExpOrb *) a_Entity); break; case cEntity::etItemFrame: AddItemFrameEntity ((cItemFrame *) a_Entity); break; - case cEntity::etPainting: /* TODO */ break; + case cEntity::etPainting: AddPaintingEntity (reinterpret_cast<cPainting *>(a_Entity)); break; case cEntity::etPlayer: return; // Players aren't saved into the world default: { diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 4c066b9af..f30cd59d5 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -48,6 +48,7 @@ class cTNTEntity; class cExpOrb; class cHangingEntity; class cItemFrame; +class cPainting; class cEntityEffect; @@ -123,6 +124,7 @@ protected: void AddTNTEntity (cTNTEntity * a_TNT); void AddExpOrbEntity (cExpOrb * a_ExpOrb); void AddItemFrameEntity (cItemFrame * a_ItemFrame); + void AddPaintingEntity (cPainting * a_Painting); void AddMinecartChestContents(cMinecartWithChest * a_Minecart); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index cc8b8d3f5..7244bcb73 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -50,6 +50,7 @@ #include "../Entities/ExpOrb.h" #include "../Entities/HangingEntity.h" #include "../Entities/ItemFrame.h" +#include "../Entities/Painting.h" #include "../Protocol/MojangAPI.h" #include "Server.h" @@ -1337,6 +1338,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a { LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } + else if (strncmp(a_IDTag, "Painting", a_IDTagLength) == 0) + { + LoadPaintingFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0) { LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx); @@ -1747,52 +1752,22 @@ void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT { // "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) + if (Facing < 0) { - Facing = (int)a_NBT.GetByte(Facing); - if ((Facing >= 2) && (Facing <= 5)) - { - a_Hanging.SetFacing(static_cast<eBlockFace>(Facing)); - } - } - else - { - Facing = a_NBT.FindChildByName(a_TagIdx, "Direction"); - if (Facing > 0) - { - switch ((int)a_NBT.GetByte(Facing)) - { - 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; - } - } - } + return; } + a_Hanging.SetProtocolFacing(a_NBT.GetByte(Facing)); + int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX"); int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY"); int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ"); if ((TileX > 0) && (TileY > 0) && (TileZ > 0)) { a_Hanging.SetPosition( - (double)a_NBT.GetInt(TileX), - (double)a_NBT.GetInt(TileY), - (double)a_NBT.GetInt(TileZ) + static_cast<double>(a_NBT.GetInt(TileX)), + static_cast<double>(a_NBT.GetInt(TileY)), + static_cast<double>(a_NBT.GetInt(TileZ)) ); } } @@ -1838,6 +1813,29 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT +void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + // Load painting name: + int MotiveTag = a_NBT.FindChildByName(a_TagIdx, "Motive"); + if ((MotiveTag < 0) || (a_NBT.GetType(MotiveTag) != TAG_String)) + { + return; + } + + std::unique_ptr<cPainting> Painting(new cPainting(a_NBT.GetString(MotiveTag), BLOCK_FACE_NONE, 0.0, 0.0, 0.0)); + if (!LoadEntityBaseFromNBT(*Painting.get(), a_NBT, a_TagIdx)) + { + return; + } + + LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx); + a_Entities.push_back(Painting.release()); +} + + + + + void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { std::unique_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 362796614..892645785 100755 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -166,6 +166,7 @@ protected: void LoadExpOrbFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadHangingFromNBT (cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx); void LoadItemFrameFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadPaintingFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); diff --git a/src/main.cpp b/src/main.cpp index 20609a2f8..da8eb75d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,8 @@ +/** Make the Root instance global, so it can be terminated from the worker threads */ +cRoot Root; /** If something has told the server to stop; checked periodically in cRoot */ @@ -29,8 +31,15 @@ bool g_ShouldLogCommIn; /** If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connection logfile */ bool g_ShouldLogCommOut; +/** If set to true, binary will attempt to run as a service on Windows */ +bool cRoot::m_RunAsService = false; +#if defined(_WIN32) +SERVICE_STATUS_HANDLE g_StatusHandle = NULL; +HANDLE g_ServiceThread = INVALID_HANDLE_VALUE; +#define SERVICE_NAME "MCServerService" +#endif /// If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window @@ -179,6 +188,165 @@ BOOL CtrlHandler(DWORD fdwCtrlType) +//////////////////////////////////////////////////////////////////////////////// +// universalMain - Main startup logic for both standard running and as a service + +void universalMain() +{ + #ifdef _WIN32 + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) + { + LOGERROR("Could not install the Windows CTRL handler!"); + } + #endif + + // Initialize logging subsystem: + cLogger::InitiateMultithreading(); + + // Initialize LibEvent: + cNetworkSingleton::Get(); + + #if !defined(ANDROID_NDK) + try + #endif + { + Root.Start(); + } + #if !defined(ANDROID_NDK) + catch (std::exception & e) + { + LOGERROR("Standard exception: %s", e.what()); + } + catch (...) + { + LOGERROR("Unknown exception!"); + } + #endif + + g_ServerTerminated = true; + + // Shutdown all of LibEvent: + cNetworkSingleton::Get().Terminate(); +} + + + + +#if defined(_WIN32) +//////////////////////////////////////////////////////////////////////////////// +// serviceWorkerThread: Keep the service alive + +DWORD WINAPI serviceWorkerThread(LPVOID lpParam) +{ + UNREFERENCED_PARAMETER(lpParam); + + // Do the normal startup + universalMain(); + + return ERROR_SUCCESS; +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// serviceSetState: Set the internal status of the service + +void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode) +{ + SERVICE_STATUS serviceStatus; + ZeroMemory(&serviceStatus, sizeof(SERVICE_STATUS)); + serviceStatus.dwCheckPoint = 0; + serviceStatus.dwControlsAccepted = acceptedControls; + serviceStatus.dwCurrentState = newState; + serviceStatus.dwServiceSpecificExitCode = 0; + serviceStatus.dwServiceType = SERVICE_WIN32; + serviceStatus.dwWaitHint = 0; + serviceStatus.dwWin32ExitCode = exitCode; + + if (SetServiceStatus(g_StatusHandle, &serviceStatus) == FALSE) + { + LOGERROR("SetServiceStatus() failed\n"); + } +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// serviceCtrlHandler: Handle stop events from the Service Control Manager + +void WINAPI serviceCtrlHandler(DWORD CtrlCode) +{ + switch (CtrlCode) + { + case SERVICE_CONTROL_STOP: + { + Root.SetStopping(true); + serviceSetState(0, SERVICE_STOP_PENDING, 0); + break; + } + + default: + { + break; + } + } +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// serviceMain: Startup logic for running as a service + +void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) +{ + #if defined(_DEBUG) && defined(DEBUG_SERVICE_STARTUP) + Sleep(10000); + #endif + + char applicationFilename[MAX_PATH]; + char applicationDirectory[MAX_PATH]; + + GetModuleFileName(NULL, applicationFilename, MAX_PATH); // This binaries fill path. + + // GetModuleFileName() returns the path and filename. Strip off the filename. + strncpy(applicationDirectory, applicationFilename, (strrchr(applicationFilename, '\\') - applicationFilename)); + applicationDirectory[strlen(applicationDirectory)] = '\0'; // Make sure new path is null terminated + + // Services are run by the SCM, and inherit its working directory - usually System32. + // Set the working directory to the same location as the binary. + SetCurrentDirectory(applicationDirectory); + + g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler); + + if (g_StatusHandle == NULL) + { + OutputDebugString("RegisterServiceCtrlHandler() failed\n"); + serviceSetState(0, SERVICE_STOPPED, GetLastError()); + return; + } + + serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0); + + g_ServiceThread = CreateThread(NULL, 0, serviceWorkerThread, NULL, 0, NULL); + if (g_ServiceThread == NULL) + { + OutputDebugString("CreateThread() failed\n"); + serviceSetState(0, SERVICE_STOPPED, GetLastError()); + return; + } + WaitForSingleObject(g_ServiceThread, INFINITE); // Wait here for a stop signal. + + CloseHandle(g_ServiceThread); + + serviceSetState(0, SERVICE_STOPPED, 0); +} +#endif + + + //////////////////////////////////////////////////////////////////////////////// // main: @@ -219,13 +387,6 @@ int main( int argc, char **argv) #endif // _WIN32 && !_WIN64 // End of dump-file magic - #ifdef _WIN32 - if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) - { - LOGERROR("Could not install the Windows CTRL handler!"); - } - #endif - #if defined(_DEBUG) && defined(_MSC_VER) _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); @@ -280,38 +441,39 @@ int main( int argc, char **argv) { setvbuf(stdout, nullptr, _IONBF, 0); } + else if (NoCaseCompare(Arg, "/service") == 0) + { + cRoot::m_RunAsService = true; + } } // for i - argv[] - - cLogger::InitiateMultithreading(); - - #if !defined(ANDROID_NDK) - try - #endif - { - cRoot Root; - Root.Start(); - } - #if !defined(ANDROID_NDK) - catch (std::exception & e) + + #if defined(_WIN32) + // Attempt to run as a service + if (cRoot::m_RunAsService) { - LOGERROR("Standard exception: %s", e.what()); + SERVICE_TABLE_ENTRY ServiceTable[] = + { + { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, + { NULL, NULL } + }; + + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) + { + LOGERROR("Attempted, but failed, service startup."); + return GetLastError(); + } } - catch (...) + else + #endif { - LOGERROR("Unknown exception!"); + // Not running as a service, do normal startup + universalMain(); } - #endif - #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) DeinitLeakFinder(); #endif - g_ServerTerminated = true; - - // Shutdown all of LibEvent: - cNetworkSingleton::Get().Terminate(); - return EXIT_SUCCESS; } |