diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index dc04d3e81..2bede6323 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -364,8 +364,8 @@ g_APIDesc = }, Constants = { - Color = { Notes = "The first character of the color-code-sequence, §" }, - Delimiter = { Notes = "The first character of the color-code-sequence, §" }, + Color = { Notes = "The first character of the color-code-sequence, §" }, + Delimiter = { Notes = "The first character of the color-code-sequence, §" }, Random = { Notes = "Random letters and symbols animate instead of the text" }, Plain = { Notes = "Resets all formatting to normal" }, }, @@ -546,7 +546,7 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(), Desc = [[ This class is used to represent a crafting recipe, either a built-in one, or one created dynamically in a plugin. It is used only as a parameter for {{OnCraftingNoRecipe|OnCraftingNoRecipe}}, {{OnPostCrafting|OnPostCrafting}} and {{OnPreCrafting|OnPreCrafting}} hooks. Plugins may use it to inspect or modify a crafting recipe that a player views in their crafting window, either at a crafting table or the survival inventory screen.

-

Internally, the class contains a {{cItem|cItem}} for the result. +

Internally, the class contains a {{cCraftingGrid}} for the ingredients and a {{cItem}} for the result. ]], Functions = { @@ -2029,14 +2029,14 @@ World:ForEachEntity( GetTime = {Return = "number", Notes = "Returns the current OS time, as a unix time stamp (number of seconds since Jan 1, 1970)"}, IsValidBlock = {Params = "BlockType", Return = "bool", Notes = "Returns true if BlockType is a known block type"}, IsValidItem = {Params = "ItemType", Return = "bool", Notes = "Returns true if ItemType is a known item type"}, - ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format “ItemTypeText:ItemDamage * Count”"}, + ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format “ItemTypeText:ItemDamage * Count”"}, ItemToString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item type"}, ItemTypeToString = {Params = "ItemType", Return = "string", Notes = "Returns the string representation of ItemType "}, - LOG = {Params = "string", Notes = "Logs a text into the server console using “normal” severity (gray text) "}, - LOGERROR = {Params = "string", Notes = "Logs a text into the server console using “error” severity (black text on red background)"}, - LOGINFO = {Params = "string", Notes = "Logs a text into the server console using “info” severity (yellow text)"}, - LOGWARN = {Params = "string", Notes = "Logs a text into the server console using “warning” severity (red text); OBSOLETE"}, - LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using “warning” severity (red text)"}, + LOG = {Params = "string", Notes = "Logs a text into the server console using “normal” severity (gray text) "}, + LOGERROR = {Params = "string", Notes = "Logs a text into the server console using “error” severity (black text on red background)"}, + LOGINFO = {Params = "string", Notes = "Logs a text into the server console using “info” severity (yellow text)"}, + LOGWARN = {Params = "string", Notes = "Logs a text into the server console using “warning” severity (red text); OBSOLETE"}, + LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using “warning” severity (red text)"}, NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"}, ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"}, StringSplit = {Params = "string, Seperator", Return = "list", Notes = "Seperates string into multiple by splitting every time Seperator is encountered."}, @@ -2136,6 +2136,921 @@ end; the second value is not provided, the original message is used. ]], }, -- HOOK_CHAT + + HOOK_CHUNK_AVAILABLE = + { + CalledWhen = "A chunk has just been added to world, either generated or loaded. ", + DefaultFnName = "OnChunkAvailable", -- also used as pagename + Desc = [[ + This hook is called after a chunk is either generated or loaded from the disk. The chunk is + already available for manipulation using the {{cWorld}} API. This is a notification-only callback, + there is no behavior that plugins could override. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk belongs" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_CHUNK_AVAILABLE + + HOOK_CHUNK_GENERATED = + { + CalledWhen = "After a chunk was generated. Notification only.", + DefaultFnName = "OnChunkGenerated", -- also used as pagename + Desc = [[ + This hook is called when world generator finished its work on a chunk. The chunk data has already + been generated and is about to be stored in the {{cWorld|world}}. A plugin may provide some + last-minute finishing touches to the generated data. Note that the chunk is not yet stored in the + world, so regular {{cWorld}} block API will not work! Instead, use the {{cChunkDesc}} object + received as the parameter.

+

+ See also the {{OnChunkGenerating|HOOK_CHUNK_GENERATING}} hook. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk will be added" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + { Name = "ChunkDesc", Type = "{{cChunkDesc}}", Notes = "Generated chunk data. Plugins may still modify the chunk data contained." }, + }, + Returns = [[ + If the plugin returns false or no value, MCServer will call other plugins' callbacks for this event. + If a plugin returns true, no other callback is called for this event.

+

+ In either case, MCServer will then store the data from ChunkDesc as the chunk's contents in the world. + ]], + CodeExamples = + { + { + Title = "Generate emerald ore", + Desc = "This example callback function generates one block of emerald ore in each chunk, under the condition that the randomly chosen location is in an ExtremeHills biome.", + Code = [[ +function OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc) + -- Generate a psaudorandom value that is always the same for the same X/Z pair, but is otherwise random enough: + -- This is actually similar to how MCServer does its noise functions + local PseudoRandom = (a_ChunkX * 57 + a_ChunkZ) * 57 + 19785486 + PseudoRandom = PseudoRandom * 8192 + PseudoRandom; + PseudoRandom = ((PseudoRandom * (PseudoRandom * PseudoRandom * 15731 + 789221) + 1376312589) % 0x7fffffff; + PseudoRandom = PseudoRandom / 7; + + -- Based on the PseudoRandom value, choose a location for the ore: + local OreX = PseudoRandom % 16; + local OreY = 2 + ((PseudoRandom / 16) % 20); + local OreZ = (PseudoRandom / 320) % 16; + + -- Check if the location is in ExtremeHills: + if (a_ChunkDesc:GetBiome(OreX, OreZ) ~= biExtremeHills) then + return false; + end + + -- Only replace allowed blocks with the ore: + local CurrBlock = a_ChunDesc:GetBlockType(OreX, OreY, OreZ); + if ( + (CurrBlock == E_BLOCK_STONE) or + (CurrBlock == E_BLOCK_DIRT) or + (CurrBlock == E_BLOCK_GRAVEL) + ) then + a_ChunkDesc:SetBlockTypeMeta(OreX, OreY, OreZ, E_BLOCK_EMERALD_ORE, 0); + end +end; + ]], + }, + } , -- CodeExamples + }, -- HOOK_CHUNK_GENERATED + + HOOK_CHUNK_GENERATING = + { + CalledWhen = "A chunk is about to be generated. Plugin can override the built-in generator.", + DefaultFnName = "OnChunkGenerating", -- also used as pagename + Desc = [[ + This hook is called before the world generator starts generating a chunk. The plugin may provide + some or all parts of the generation, by-passing the built-in generator. The function is given access + to the {{cChunkDesc|ChunkDesc}} object representing the contents of the chunk. It may override parts + of the built-in generator by using the object's SetUseDefaultXXX(false) functions. After all + the callbacks for a chunk have been processed, the server will generate the chunk based on the + {{cChunkDesc|ChunkDesc}} description - those parts that are set for generating (by default + everything) are generated, the rest are read from the ChunkDesc object.

+

+ See also the {{OnChunkGenerated|HOOK_CHUNK_GENERATED}} hook. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk will be added" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + { Name = "ChunkDesc", Type = "{{cChunkDesc}}", Notes = "Generated chunk data." }, + }, + Returns = [[ + If this function returns true, the server will not call any other plugin with the same chunk. If + this function returns false, the server will call the rest of the plugins with the same chunk, + possibly overwriting the ChunkDesc's contents. + ]], + }, -- HOOK_CHUNK_GENERATING + + HOOK_CHUNK_UNLOADED = + { + CalledWhen = "A chunk has been unloaded from the memory.", + DefaultFnName = "OnChunkUnloaded", -- also used as pagename + Desc = [[ + This hook is called when a chunk is unloaded from the memory. Though technically still in memory, + the plugin should behave as if the chunk was already not present. In particular, {{cWorld}} block + API should not be used in the area of the specified chunk. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the chunk is unloading" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. There is no behavior that plugins could + override. + ]], + }, -- HOOK_CHUNK_UNLOADED + + HOOK_CHUNK_UNLOADING = + { + CalledWhen = " A chunk is about to be unloaded from the memory. Plugins may refuse the unload.", + DefaultFnName = "OnChunkUnloading", -- also used as pagename + Desc = [[ + MCServer calls this function when a chunk is about to be unloaded from the memory. A plugin may + force MCServer to keep the chunk in memory by returning true.

+

+ FIXME: The return value should be used only for event propagation stopping, not for the actual + decision whether to unload. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the chunk is unloading" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called and finally MCServer + unloads the chunk. If the function returns true, no other callback is called for this event and the + chunk is left in the memory. + ]], + }, -- HOOK_CHUNK_UNLOADING + + HOOK_COLLECTING_PICKUP = + { + CalledWhen = "Player is about to collect a pickup. Plugin can refuse / override behavior. ", + DefaultFnName = "OnCollectingPickup", -- also used as pagename + Desc = [[ + This hook is called when a player is about to collect a pickup. Plugins may refuse the action.

+

+ Pickup collection happens within the world tick, so if the collecting is refused, it will be tried + again in the next world tick, as long as the player is within reach of the pickup.

+

+ FIXME: There is no OnCollectedPickup() callback.

+

+ FIXME: This callback is called even if the pickup doesn't fit into the player's inventory.

+ ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who's collecting the pickup" }, + { Name = "Pickup", Type = "{{cPickup}}", Notes = "The pickup being collected" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks and finally the + pickup is collected. If the function returns true, no other plugins are called for this event and + the pickup is not collected. + ]], + }, -- HOOK_COLLECTING_PICKUP + + HOOK_CRAFTING_NO_RECIPE = + { + CalledWhen = " No built-in crafting recipe is found. Plugin may provide a recipe.", + DefaultFnName = "OnCraftingNoRecipe", -- also used as pagename + Desc = [[ + This callback is called when a player places items in their {{cCraftingGrid|crafting grid}} and + MCServer cannot find a built-in {{cCraftingRecipe|recipe}} for the combination. Plugins may provide + a recipe for the ingredients given. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose crafting is reported in this hook" }, + { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "Contents of the player's crafting grid" }, + { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that will be used (can be filled by plugins)" }, + }, + Returns = [[ + If the function returns false or no value, no recipe will be used. If the function returns true, no + other plugin will have their callback called for this event and MCServer will use the crafting + recipe in Recipe.

+

+ FIXME: To allow plugins give suggestions and overwrite other plugins' suggestions, we should change + the behavior with returning false, so that the recipe will still be used, but fill the recipe with + empty values by default. + ]], + }, -- HOOK_CRAFTING_NO_RECIPE + + HOOK_DISCONNECT = + { + CalledWhen = "A player has explicitly disconnected.", + DefaultFnName = "OnDisconnect", -- also used as pagename + Desc = [[ + This hook is called when a client sends the disconnect packet and is about to be disconnected from + the server.

+

+ Note that this callback is not called if the client drops the connection or is kicked by the + server.

+

+ FIXME: There is no callback for "client destroying" that would be called in all circumstances.

+ ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has disconnected" }, + { Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks for this event + and finally broadcasts a disconnect message to the player's world. If the function returns true, no + other plugins are called for this event and the disconnect message is not broadcast. In either case, + the player is disconnected. + ]], + }, -- HOOK_DISCONNECT + + HOOK_EXECUTE_COMMAND = + { + CalledWhen = "A player executes an in-game command, or the admin issues a console command. Note that built-in console commands are exempt to this hook - they are always performed and the hook is not called.", + DefaultFnName = "OnExecuteCommand", -- also used as pagename + Desc = [[ + A plugin may implement a callback for this hook to intercept both in-game commands executed by the + players and console commands executed by the server admin. The function is called for every in-game + command sent from any player and for those server console commands that are not built in in the + server.

+

+ If the command is in-game, the first parameter to the hook function is the {{cPlayer|player}} who's + executing the command. If the command comes from the server console, the first parameter is nil. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "For in-game commands, the player who has sent the message. For console commands, nil" }, + { Name = "Command", Type = "table of strings", Notes = "The command and its parameters, broken into a table by spaces" }, + }, + Returns = [[ + If the plugin returns true, the command will be blocked and none of the remaining hook handlers will + be called. If the plugin returns false, MCServer calls all the remaining hook handlers and finally + the command will be executed. + ]], + }, -- HOOK_EXECUTE_COMMAND + + HOOK_EXPLODED = + { + CalledWhen = "An explosion has happened", + DefaultFnName = "OnExploded", -- also used as pagename + Desc = [[ + This hook is called after an explosion has been processed in a world.

+

+ See also {{OnHookExploding|HOOK_EXPLODING}} for a similar hook called before the explosion.

+

+ The explosion carries with it the type of its source - whether it's a creeper exploding, or TNT, + etc. It also carries the identification of the actual source. The exact type of the identification + depends on the source kind: + + + + + + + + + + + + +
SourceSourceData TypeNotes
esPrimedTNT{{cTNTEntity}}An exploding primed TNT entity
esCreeper{{cCreeper}}An exploding creeper or charged creeper
esBed{{Vector3i}}A bed exploding in the Nether or in the End. The bed coords are given.
esEnderCrystal{{Vector3i}}An ender crystal exploding upon hit. The block coords are given.
esGhastFireball{{cGhastFireballEntity}}A ghast fireball hitting ground or an {{cEntity|entity}}.
esWitherSkullBlackTBDA black wither skull hitting ground or an {{cEntity|entity}}.
esWitherSkullBlueTBDA blue wither skull hitting ground or an {{cEntity|entity}}.
esWitherBirthTBDA wither boss being created
esOtherTBDAny other previously unspecified type.
esPluginobjectAn explosion created by a plugin. The plugin may specify any kind of data.

+ ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world where the explosion happened" }, + { Name = "ExplosionSize", Type = "number", Notes = "The relative explosion size" }, + { Name = "CanCauseFire", Type = "bool", Notes = "True if the explosion has turned random air blocks to fire (such as a ghast fireball)" }, + { Name = "X", Type = "number", Notes = "X-coord of the explosion center" }, + { Name = "Y", Type = "number", Notes = "Y-coord of the explosion center" }, + { Name = "Z", Type = "number", Notes = "Z-coord of the explosion center" }, + { Name = "Source", Type = "eExplosionSource", Notes = "Source of the explosion. See the table above." }, + { Name = "SourceData", Type = "varies", Notes = "Additional data for the source. The exact type varies by the source. See the table above." }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. There is no overridable behaviour. + ]], + }, -- HOOK_EXPLODED + + HOOK_EXPLODING = + { + CalledWhen = "An explosion is about to be processed", + DefaultFnName = "OnExploding", -- also used as pagename + Desc = [[ + This hook is called before an explosion has been processed in a world.

+

+ See also {{OnHookExploded|HOOK_EXPLODED}} for a similar hook called after the explosion.

+

+ The explosion carries with it the type of its source - whether it's a creeper exploding, or TNT, + etc. It also carries the identification of the actual source. The exact type of the identification + depends on the source kind: + + + + + + + + + + + + +
SourceSourceData TypeNotes
esPrimedTNT{{cTNTEntity}}An exploding primed TNT entity
esCreeper{{cCreeper}}An exploding creeper or charged creeper
esBed{{Vector3i}}A bed exploding in the Nether or in the End. The bed coords are given.
esEnderCrystal{{Vector3i}}An ender crystal exploding upon hit. The block coords are given.
esGhastFireball{{cGhastFireballEntity}}A ghast fireball hitting ground or an {{cEntity|entity}}.
esWitherSkullBlackTBDA black wither skull hitting ground or an {{cEntity|entity}}.
esWitherSkullBlueTBDA blue wither skull hitting ground or an {{cEntity|entity}}.
esWitherBirthTBDA wither boss being created
esOtherTBDAny other previously unspecified type.
esPluginobjectAn explosion created by a plugin. The plugin may specify any kind of data.

+ ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world where the explosion happens" }, + { Name = "ExplosionSize", Type = "number", Notes = "The relative explosion size" }, + { Name = "CanCauseFire", Type = "bool", Notes = "True if the explosion will turn random air blocks to fire (such as a ghast fireball)" }, + { Name = "X", Type = "number", Notes = "X-coord of the explosion center" }, + { Name = "Y", Type = "number", Notes = "Y-coord of the explosion center" }, + { Name = "Z", Type = "number", Notes = "Z-coord of the explosion center" }, + { Name = "Source", Type = "eExplosionSource", Notes = "Source of the explosion. See the table above." }, + { Name = "SourceData", Type = "varies", Notes = "Additional data for the source. The exact type varies by the source. See the table above." }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called, and finally + MCServer will process the explosion - destroy blocks and push + hurt entities. If the function + returns true, no other callback is called for this event and the explosion will not occur. + ]], + }, -- HOOK_EXPLODING + + HOOK_HANDSHAKE = + { + CalledWhen = "A client is connecting.", + DefaultFnName = "OnHandshake", -- also used as pagename + Desc = [[ + This hook is called when a client sends the Handshake packet. At this stage, only the client IP and + (unverified) username are known. Plugins may refuse access to the server based on this + information.

+

+ Note that the username is not authenticated - the authentication takes place only after this hook is + processed. + ]], + Params = + { + { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client handle representing the connection. Note that there's no {{cPlayer}} object for this client yet." }, + { Name = "UserName", Type = "string", Notes = "The username presented in the packet. Note that this username is unverified." }, + }, + Returns = [[ + If the function returns false, the user is let in to the server. If the function returns true, no + other plugin's callback is called, the user is kicked and the connection is closed. + ]], + }, -- HOOK_HANDSHAKE + + HOOK_HOPPER_PULLING_ITEM = + { + CalledWhen = "A hopper is pulling an item from another block entity.", + DefaultFnName = "OnHopperPullingItem", -- also used as pagename + Desc = [[ + This callback is called whenever a {{cHopperEntity|hopper}} transfers an {{cItem|item}} from another + block entity into its own internal storage. A plugin may decide to disallow the move by returning + true. Note that in such a case, the hook may be called again for the same hopper, with different + slot numbers. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World where the hopper resides" }, + { Name = "Hopper", Type = "{{cHopperEntity}}", Notes = "The hopper that is pulling the item" }, + { Name = "DstSlot", Type = "number", Notes = "The destination slot in the hopper's {{cItemGrid|internal storage}}" }, + { Name = "SrcBlockEntity", Type = "{{cBlockEntityWithItems}}", Notes = "The block entity that is losing the item" }, + { Name = "SrcSlot", Type = "number", Notes = "Slot in SrcBlockEntity from which the item will be pulled" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event and the hopper will not pull the item. + ]], + }, -- HOOK_HOPPER_PULLING_ITEM + + HOOK_HOPPER_PUSHING_ITEM = + { + CalledWhen = "A hopper is pushing an item into another block entity. ", + DefaultFnName = "OnHopperPushingItem", -- also used as pagename + Desc = [[ + This hook is called whenever a {{cHopperEntity|hopper}} transfers an {{cItem|item}} from its own + internal storage into another block entity. A plugin may decide to disallow the move by returning + true. Note that in such a case, the hook may be called again for the same hopper and block, with + different slot numbers. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World where the hopper resides" }, + { Name = "Hopper", Type = "{{cHopperEntity}}", Notes = "The hopper that is pushing the item" }, + { Name = "SrcSlot", Type = "number", Notes = "Slot in the hopper that will lose the item" }, + { Name = "DstBlockEntity", Type = "{{cBlockEntityWithItems}}", Notes = " The block entity that will receive the item" }, + { Name = "DstSlot", Type = "number", Notes = " Slot in DstBlockEntity's internal storage where the item will be stored" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event and the hopper will not push the item. + ]], + }, -- HOOK_HOPPER_PUSHING_ITEM + + HOOK_KILLING = + { + CalledWhen = "A player or a mob is dying.", + DefaultFnName = "OnKilling", -- also used as pagename + Desc = [[ + This hook is called whenever a {{cPawn|pawn}}'s (a player's or a mob's) health reaches zero. This + means that the pawn is about to be killed, unless a plugin "revives" them by setting their health + back to a positive value.

+

+ FIXME: There is no HOOK_KILLED notification hook yet; this is deliberate because HOOK_KILLED has + been recently renamed to HOOK_KILLING, and plugins need to be updated. Once updated, the HOOK_KILLED + notification will be implemented. + ]], + Params = + { + { Name = "Victim", Type = "{{cPawn}}", Notes = "The player or mob that is about to be killed" }, + { Name = "Killer", Type = "{{cEntity}}", Notes = "The entity that has caused the victim to lose the last point of health. May be nil for environment damage" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins with this event. If the + function returns true, no other plugin is called for this event.

+

+ In either case, the victim's health is then re-checked and if it is greater than zero, the victim is + "revived" with that health amount. If the health is less or equal to zero, the victim is killed. + ]], + }, -- HOOK_KILLING + + HOOK_LOGIN = + { + CalledWhen = "Right after player authentication. If auth is disabled, right after the player sends their name.", + DefaultFnName = "OnLogin", -- also used as pagename + Desc = [[ + This hook is called whenever a client logs in. It is called right before the client's name is sent + to be authenticated. Plugins may refuse the client from accessing the server. Note that when this + callback is called, the {{cPlayer}} object for this client doesn't exist yet - the client has no + representation in any world. To process new players when their world is known, use a later callback, + such as {{OnPlayerJoined|HOOK_PLAYER_JOINED}} or {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}. + ]], + Params = + { + { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client handle representing the connection" }, + { Name = "ProtocolVersion", Type = "number", Notes = "Versio of the protocol that the client is talking" }, + { Name = "UserName", Type = "string", Notes = "The name that the client has presented for authentication. This name will be given to the {{cPlayer}} object when it is created for this client." }, + }, + Returns = [[ + If the function returns true, no other plugins are called for this event and the client is kicked. + If the function returns false or no value, MCServer calls other plugins' callbacks and finally + sends an authentication request for the client's username to the auth server. If the auth server + is disabled in the server settings, the player object is immediately created. + ]], + }, -- HOOK_LOGIN + + HOOK_PLAYER_ANIMATION = + { + CalledWhen = "A client has sent an Animation packet (0x12)", + DefaultFnName = "OnPlayerAnimation", -- also used as pagename + Desc = [[ + This hook is called when the server receives an Animation packet (0x12) from the client.

+

+ For the list of animations that are sent by the client, see the + Protocol wiki. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player from whom the packet was received" }, + { Name = "Animation", Type = "number", Notes = "The kind of animation" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. Afterwards, the + server broadcasts the animation packet to all nearby clients. If the function returns true, no other + callback is called for this event and the packet is not broadcasted. + ]], + }, -- HOOK_PLAYER_ANIMATION + + HOOK_PLAYER_BREAKING_BLOCK = + { + CalledWhen = "Just before a player breaks a block. Plugin may override / refuse. ", + DefaultFnName = "OnPlayerBreakingBlock", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} breaks a block, before the block is actually broken in + the {{cWorld|World}}. Plugins may refuse the breaking.

+

+ See also the {{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}} hook for a similar hook called after + the block is broken. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is digging the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player is acting. One of the BLOCK_FACE_ constants" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block being broken" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block being broken " }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called, and then the block + is broken. If the function returns true, no other plugin's callback is called and the block breaking + is cancelled. The server re-sends the block back to the player to replace it (the player's client + already thinks the block was broken). + ]], + }, -- HOOK_PLAYER_BREAKING_BLOCK + + HOOK_PLAYER_BROKEN_BLOCK = + { + CalledWhen = "After a player has broken a block. Notification only.", + DefaultFnName = "OnPlayerBrokenBlock", -- also used as pagename + Desc = [[ + This function is called after a {{cPlayer|player}} breaks a block. The block is already removed + from the {{cWorld|world}} and {{cPickup|pickups}} have been spawned. To get the world in which the + block has been dug, use the {{cPlayer}}:GetWorld() function.

+

+ See also the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}} hook for a similar hook called + before the block is broken. To intercept the creation of pickups, see the + {{OnBlockToPickups|HOOK_BLOCK_TO_PICKUPS}} hook. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who broke the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_PLAYER_BROKEN_BLOCK + + HOOK_PLAYER_EATING = + { + CalledWhen = "When the player starts eating", + DefaultFnName = "OnPlayerEating", -- also used as pagename + Desc = [[ + This hook gets called when the {{cPlayer|player}} starts eating, after the server checks that the + player can indeed eat (is not satiated and is holding food). Plugins may still refuse the eating by + returning true. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who started eating" }, + }, + Returns = [[ + If the function returns false or no value, the server calls the next plugin handler, and finally + lets the player eat. If the function returns true, the server doesn't call any more callbacks for + this event and aborts the eating. A "disallow" packet is sent to the client. + ]], + }, -- HOOK_PLAYER_EATING + + HOOK_PLAYER_JOINED = + { + CalledWhen = "After Login and before Spawned, before being added to world. ", + DefaultFnName = "OnPlayerJoined", -- also used as pagename + Desc = [[ + This hook is called whenever a {{cPlayer|player}} has completely logged in. If authentication is + enabled, this function is called after their name has been authenticated. It is called after + {{OnLogin|HOOK_LOGIN}} and before {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}, right after the player's + entity is created, but not added to the world yet. The player is not yet visible to other players. + This is a notification-only event, plugins wishing to refuse player's entry should kick the player + using the {{cPlayer}}:Kick() function. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has joined the game" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. Either way the player is let in. + ]], + }, -- HOOK_PLAYER_JOINED + + HOOK_PLAYER_LEFT_CLICK = + { + CalledWhen = "A left-click packet is received from the client. Plugin may override / refuse.", + DefaultFnName = "OnPlayerLeftClick", -- also used as pagename + Desc = [[ + This hook is called when MCServer receives a left-click packet from the {{cClientHandle|client}}. It + is called before any processing whatsoever is performed on the packet, meaning that hacked / + malicious clients may be trigerring this event very often and with unchecked parameters. Therefore + plugin authors are advised to use extreme caution with this callback.

+

+ Plugins may refuse the default processing for the packet, causing MCServer to behave as if the + packet has never arrived. This may, however, create inconsistencies in the client - the client may + think that they broke a block, while the server didn't process the breaking, etc. For this reason, + if a plugin refuses the processing, MCServer sends the block specified in the packet back to the + client (as if placed anew), if the status code specified a block-break action. For other actions, + plugins must rectify the situation on their own.

+

+ The client sends the left-click packet for several other occasions, such as dropping the held item + (Q keypress) or shooting an arrow. This is reflected in the Status code. Consult the + protocol documentation for details on the actions. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose client sent the packet" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + { Name = "Action", Type = "number", Notes = "Action to be performed on the block (\"status\" in the protocol docs)" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks and finally sends + the packet for further processing.

+

+ If the function returns true, no other plugins are called, processing is halted. If the action was a + block dig, MCServer sends the block specified in the coords back to the client. The packet is + dropped. + ]], + }, -- HOOK_PLAYER_LEFT_CLICK + + HOOK_PLAYER_MOVING = + { + CalledWhen = "Player tried to move in the tick being currently processed. Plugin may refuse movement.", + DefaultFnName = "OnPlayerMoving", -- also used as pagename + Desc = [[ + This function is called in each server tick for each {{cPlayer|player}} that has sent any of the + player-move packets. Plugins may refuse the movement. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has moved. The object already has the new position stored in it." }, + }, + Returns = [[ + If the function returns true, movement is prohibited. FIXME: The player's client is not informed.

+

+ If the function returns false or no value, other plugins' callbacks are called and finally the new + position is permanently stored in the cPlayer object.

+ ]], + }, -- HOOK_PLAYER_MOVING + + HOOK_PLAYER_PLACED_BLOCK = + { + CalledWhen = "After a player has placed a block. Notification only.", + DefaultFnName = "OnPlayerPlacedBlock", -- also used as pagename + Desc = [[ + This hook is called after a {{cPlayer|player}} has placed a block in the {{cWorld|world}}. The block + is already added to the world and the corresponding item removed from player's + {{cInventory|inventory}}.

+

+ Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.

+

+ See also the {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook for a similar hook called + before the placement. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who placed the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, + }, + Returns = [[ + If this function returns false or no value, MCServer calls other plugins with the same event. If + this function returns true, no other plugin is called for this event. + ]], + }, -- HOOK_PLAYER_PLACED_BLOCK + + HOOK_PLAYER_PLACING_BLOCK = + { + CalledWhen = "Just before a player places a block. Plugin may override / refuse.", + DefaultFnName = "OnPlayerPlacingBlock", -- also used as pagename + Desc = [[ + This hook is called just before a {{cPlayer|player}} places a block in the {{cWorld|world}}. The + block is not yet placed, plugins may choose to override the default behavior or refuse the placement + at all.

+

+ Note that the client already expects that the block has been placed. For that reason, if a plugin + refuses the placement, MCServer sends the old block at the provided coords to the client.

+

+ Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.

+

+ See also the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook for a similar hook called after + the placement. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is placing the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player is interacting. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, + }, + Returns = [[ + If this function returns false or no value, MCServer calls other plugins with the same event and + finally places the block and removes the corresponding item from player's inventory. If this + function returns true, no other plugin is called for this event, MCServer sends the old block at + the specified coords to the client and drops the packet. + ]], + }, -- HOOK_PLAYER_PLACING_BLOCK + + HOOK_PLAYER_RIGHT_CLICK = + { + CalledWhen = "A right-click packet is received from the client. Plugin may override / refuse.", + DefaultFnName = "OnPlayerRightClick", -- also used as pagename + Desc = [[ + This hook is called when MCServer receives a right-click packet from the {{cClientHandle|client}}. It + is called before any processing whatsoever is performed on the packet, meaning that hacked / + malicious clients may be trigerring this event very often and with unchecked parameters. Therefore + plugin authors are advised to use extreme caution with this callback.

+

+ Plugins may refuse the default processing for the packet, causing MCServer to behave as if the + packet has never arrived. This may, however, create inconsistencies in the client - the client may + think that they placed a block, while the server didn't process the placing, etc. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose client sent the packet" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks and finally sends + the packet for further processing.

+

+ If the function returns true, no other plugins are called, processing is halted. + ]], + }, -- HOOK_PLAYER_RIGHT_CLICK + + HOOK_POST_CRAFTING = + { + CalledWhen = "After the built-in recipes are checked and a recipe was found.", + DefaultFnName = "OnPostCrafting", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} changes contents of their + {{cCraftingGrid|crafting grid}}, after the recipe has been established by MCServer. Plugins may use + this to modify the resulting recipe or provide an alternate recipe.

+

+ If a plugin implements custom recipes, it should do so using the {{OnPreCrafting|HOOK_PRE_CRAFTING}} + hook, because that will save the server from going through the built-in recipes. The + HOOK_POST_CRAFTING hook is intended as a notification, with a chance to tweak the result.

+

+ Note that this hook is not called if a built-in recipe is not found; + {{OnCraftingNoRecipe|HOOK_CRAFTING_NO_RECIPE}} is called instead in such a case. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has changed their crafting grid contents" }, + { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "The new crafting grid contents" }, + { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that MCServer has decided to use (can be tweaked by plugins)" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. In either case, MCServer uses the value + of Recipe as the recipe to be presented to the player. + ]], + }, -- HOOK_POST_CRAFTING + + HOOK_PRE_CRAFTING = + { + CalledWhen = "Before the built-in recipes are checked.", + DefaultFnName = "OnPreCrafting", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} changes contents of their + {{cCraftingGrid|crafting grid}}, before the built-in recipes are searched for a match by MCServer. + Plugins may use this hook to provide a custom recipe.

+

+ If you intend to tweak built-in recipes, use the {{OnPostCrafting|HOOK_POST_CRAFTING}} hook, because + that will be called once the built-in recipe is matched.

+

+ Also note a third hook, {{OnCraftingNoRecipe|HOOK_CRAFTING_NO_RECIPE}}, that is called when MCServer + cannot find any built-in recipe for the given ingredients. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has changed their crafting grid contents" }, + { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "The new crafting grid contents" }, + { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that MCServer will use. Modify this object to change the recipe" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called and then MCServer + searches the built-in recipes. The Recipe output parameter is ignored in this case.

+

+ If the function returns true, no other callbacks are called for this event and MCServer uses the + recipe stored in the Recipe output parameter. + ]], + }, -- HOOK_PRE_CRAFTING + + HOOK_SPAWNED_ENTITY = + { + CalledWhen = "After an entity is spawned in the world.", + DefaultFnName = "OnSpawnedEntity", -- also used as pagename + Desc = [[ + This hook is called after the server spawns an {{cEntity|entity}}. This is an information-only + callback, the entity is already spawned by the time it is called. If the entity spawned is a + {{cMonster|monster}}, the {{OnSpawnedMonster|HOOK_SPAWNED_MONSTER}} hook is called before this + hook.

+

+ See also the {{OnSpawningEntity|HOOK_SPAWNING_ENTITY}} hook for a similar hook called before the + entity is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity has spawned" }, + { Name = "Entity", Type = "{{cEntity}} descentant", Notes = "The entity that has spawned" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_SPAWNED_ENTITY + + HOOK_SPAWNED_MONSTER = + { + CalledWhen = "After a monster is spawned in the world", + DefaultFnName = "OnSpawnedMonster", -- also used as pagename + Desc = [[ + This hook is called after the server spawns a {{cMonster|monster}}. This is an information-only + callback, the monster is already spawned by the time it is called. After this hook is called, the + {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} is called for the monster entity.

+

+ See also the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook for a similar hook called before the + monster is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the monster has spawned" }, + { Name = "Monster", Type = "{{cMonster}} descendant", Notes = "The monster that has spawned" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_SPAWNED_MONSTER + + HOOK_SPAWNING_ENTITY = + { + CalledWhen = "Before an entity is spawned in the world.", + DefaultFnName = "OnSpawningEntity", -- also used as pagename + Desc = [[ + This hook is called before the server spawns an {{cEntity|entity}}. The plugin can either modify the + entity before it is spawned, or disable the spawning altogether. If the entity spawning is a + monster, the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook is called before this hook.

+

+ See also the {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} hook for a similar hook called after the + entity is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity will spawn" }, + { Name = "Entity", Type = "{{cEntity}} descentant", Notes = "The entity that will spawn" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. Finally, the server + spawns the entity with whatever parameters have been set on the {{cEntity}} object by the callbacks. + If the function returns true, no other callback is called for this event and the entity is not + spawned. + ]], + }, -- HOOK_SPAWNING_ENTITY + + HOOK_SPAWNING_MONSTER = + { + CalledWhen = "Before a monster is spawned in the world.", + DefaultFnName = "OnSpawningMonster", -- also used as pagename + Desc = [[ + This hook is called before the server spawns a {{cMonster|monster}}. The plugins may modify the + monster's parameters in the {{cMonster}} class, or disallow the spawning altogether. This hook is + called before the {{OnSpawningEntity|HOOK_SPAWNING_ENTITY}} is called for the monster entity.

+

+ See also the {{OnSpawnedMonster|HOOK_SPAWNED_MONSTER}} hook for a similar hook called after the + monster is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity will spawn" }, + { Name = "Monster", Type = "{{cMonster}} descentant", Notes = "The monster that will spawn" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. Finally, the server + spawns the monster with whatever parameters the plugins set in the cMonster parameter.

+

+ If the function returns true, no other callback is called for this event and the monster won't + spawn. + ]], + }, -- HOOK_SPAWNING_MONSTER + }, -- Hooks[] diff --git a/MCServer/Plugins/APIDump/main.lua b/MCServer/Plugins/APIDump/main.lua index 3827668e3..163c505b2 100644 --- a/MCServer/Plugins/APIDump/main.lua +++ b/MCServer/Plugins/APIDump/main.lua @@ -180,7 +180,12 @@ function DumpAPIHtml() -- Extract hook constants: for name, obj in pairs(cPluginManager) do - if (type(obj) == "number") and (name:match("HOOK_.*")) then + if ( + (type(obj) == "number") and + name:match("HOOK_.*") and + (name ~= "HOOK_MAX") and + (name ~= "HOOK_NUM_HOOKS") + ) then table.insert(Hooks, { Name = name }); end end @@ -327,10 +332,18 @@ function DumpAPIHtml() f:write("\t\t" .. hook .. " =\n\t\t{\n"); f:write("\t\t\tCalledWhen = \"\",\n"); f:write("\t\t\tDefaultFnName = \"On\", -- also used as pagename\n"); - f:write("\t\t\tDesc = [[]],\n"); + f:write("\t\t\tDesc = [[\n\t\t\t\t\n\t\t\t]],\n"); f:write("\t\t\tParams =\n\t\t\t{\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n\t\t\t},\n"); - f:write("\t\t\tReturns = [[]],\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t},\n"); + f:write("\t\t\tReturns = [[\n\t\t\t\t\n\t\t\t]],\n"); f:write("\t\t}, -- " .. hook .. "\n"); end end @@ -604,8 +617,39 @@ end -- Make a link out of anything with the special linkifying syntax {{link|title}} function LinkifyString(a_String) - local txt = a_String:gsub("{{([^|}]*)|([^}]*)}}", "%2") -- {{link|title}} - txt = txt:gsub("{{([^|}]*)}}", "%1") -- {{LinkAndTitle}} + local function CreateLink(Link, Title) + if (Link:sub(1, 7) == "http://") then + -- The link is a full absolute URL, do not modify, do not track: + return "" .. Title .. ""; + end + local idxHash = Link:find("#"); + if (idxHash ~= nil) then + -- The link contains an anchor: + if (idxHash == 1) then + -- Anchor in the current page, no need to track: + return "" .. Title .. ""; + end + -- Anchor in another page: + -- TODO: track this link + return "" .. Title .. ""; + end + -- Link without anchor: + -- TODO; track this link + return "" .. Title .. ""; + end + + local txt = a_String:gsub("{{([^|}]*)|([^}]*)}}", CreateLink) -- {{link|title}} + + txt = txt:gsub("{{([^|}]*)}}", -- {{LinkAndTitle}} + function(LinkAndTitle) + local idxHash = LinkAndTitle:find("#"); + if (idxHash ~= nil) then + -- The LinkAndTitle contains a hash, remove the hashed part from the title: + return CreateLink(LinkAndTitle, LinkAndTitle:sub(1, idxHash - 1)); + end + return CreateLink(LinkAndTitle, LinkAndTitle); + end + ); return txt; end diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt index 6140ca3a6..5132bf436 100644 --- a/MCServer/crafting.txt +++ b/MCServer/crafting.txt @@ -96,7 +96,11 @@ BrickStairs, 4 = BrickBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 SandstoneStairs, 4 = Sandstone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 SandstoneStairs, 4 = Sandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 NetherBrickStairs, 4 = NetherBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +NetherBrickStairs, 4 = NetherBrick, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 quartzstairs, 4 = QuartzBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +quartzstairs, 4 = QuartzBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +StoneBrickStairs, 4 = StoneBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +StoneBrickStairs, 4 = StoneBrick, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2 ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2 BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2 diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 7c3fa0b8e..177652a46 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -1,4 +1,3 @@ - // BlockID.cpp // Implements the helper functions for converting Block ID string to int etc. @@ -930,6 +929,7 @@ public: g_BlockIsTorchPlaceable[E_BLOCK_STAINED_CLAY] = true; g_BlockIsTorchPlaceable[E_BLOCK_WOOL] = true; g_BlockIsTorchPlaceable[E_BLOCK_STONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_STONE_BRICKS] = true; } } BlockPropertiesInitializer; diff --git a/source/HTTPServer/HTTPFormParser.cpp b/source/HTTPServer/HTTPFormParser.cpp index 7db7b4e6d..596db424e 100644 --- a/source/HTTPServer/HTTPFormParser.cpp +++ b/source/HTTPServer/HTTPFormParser.cpp @@ -52,6 +52,18 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba +cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks) : + m_Callbacks(a_Callbacks), + m_Kind(a_Kind), + m_IsValid(true) +{ + Parse(a_Data, a_Size); +} + + + + + void cHTTPFormParser::Parse(const char * a_Data, int a_Size) { if (!m_IsValid) diff --git a/source/HTTPServer/HTTPFormParser.h b/source/HTTPServer/HTTPFormParser.h index b92ef9d3c..a554ca5a4 100644 --- a/source/HTTPServer/HTTPFormParser.h +++ b/source/HTTPServer/HTTPFormParser.h @@ -26,6 +26,13 @@ class cHTTPFormParser : public cMultipartParser::cCallbacks { public: + enum eKind + { + fpkURL, ///< The form has been transmitted as parameters to a GET request + fpkFormUrlEncoded, ///< The form has been POSTed or PUT, with Content-Type of "application/x-www-form-urlencoded" + fpkMultipart, ///< The form has been POSTed or PUT, with Content-Type of "multipart/form-data" + } ; + class cCallbacks { public: @@ -40,8 +47,12 @@ public: } ; + /// Creates a parser that is tied to a request and notifies of various events using a callback mechanism cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callbacks); + /// Creates a parser with the specified content type that reads data from a string + cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks); + /// Adds more data into the parser, as the request body is received void Parse(const char * a_Data, int a_Size); @@ -54,12 +65,6 @@ public: static bool HasFormData(const cHTTPRequest & a_Request); protected: - enum eKind - { - fpkURL, ///< The form has been transmitted as parameters to a GET request - fpkFormUrlEncoded, ///< The form has been POSTed or PUT, with Content-Type of "application/x-www-form-urlencoded" - fpkMultipart, ///< The form has been POSTed or PUT, with Content-Type of "multipart/form-data" - }; /// The callbacks to call for incoming file data cCallbacks & m_Callbacks; diff --git a/source/Mobs/Cow.cpp b/source/Mobs/Cow.cpp index 8e9b87d27..431a6916d 100644 --- a/source/Mobs/Cow.cpp +++ b/source/Mobs/Cow.cpp @@ -7,10 +7,6 @@ -// TODO: Milk Cow - - - cCow::cCow(void) : @@ -28,6 +24,18 @@ void cCow::GetDrops(cItems & a_Drops, cEntity * a_Killer) AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_STEAK : E_ITEM_RAW_BEEF); } +void cCow::OnRightClicked(cPlayer & a_Player) +{ + if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_BUCKET)) + { + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + a_Player.GetInventory().AddItem(E_ITEM_MILK) + } + + } +} diff --git a/source/Mobs/Cow.h b/source/Mobs/Cow.h index b90cb170e..0391d4a31 100644 --- a/source/Mobs/Cow.h +++ b/source/Mobs/Cow.h @@ -18,6 +18,7 @@ public: CLASS_PROTODEF(cCow); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void OnRightClicked(cPlayer & a_Player) override; } ; diff --git a/source/Mobs/Horse.cpp b/source/Mobs/Horse.cpp index 46e7969cc..c2a8f6ed0 100644 --- a/source/Mobs/Horse.cpp +++ b/source/Mobs/Horse.cpp @@ -107,6 +107,18 @@ void cHorse::OnRightClicked(cPlayer & a_Player) m_TameAttemptTimes++; a_Player.AttachTo(this); + + if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE) + { + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + + // Set saddle state & broadcast metadata + m_bIsSaddled = true; + m_World->BroadcastEntityMetadata(*this); + } } diff --git a/source/WebAdmin.cpp b/source/WebAdmin.cpp index 08817139a..316513f11 100644 --- a/source/WebAdmin.cpp +++ b/source/WebAdmin.cpp @@ -79,8 +79,14 @@ bool cWebAdmin::Init(void) return false; } - AString PortsIPv4 = m_IniFile.GetValue("WebAdmin", "Port", "8080"); - AString PortsIPv6 = m_IniFile.GetValue("WebAdmin", "PortsIPv6", ""); + if (!m_IniFile.GetValueSetB("WebAdmin", "Enabled", true)) + { + // WebAdmin is disabled, bail out faking a success + return true; + } + + AString PortsIPv4 = m_IniFile.GetValueSet("WebAdmin", "Port", "8080"); + AString PortsIPv6 = m_IniFile.GetValueSet("WebAdmin", "PortsIPv6", ""); if (!m_HTTPServer.Initialize(PortsIPv4, PortsIPv6)) { @@ -185,8 +191,19 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque HTTPfd.Name = itr->first; TemplateRequest.Request.FormData[itr->first] = HTTPfd; TemplateRequest.Request.PostParams[itr->first] = itr->second; - TemplateRequest.Request.Params[itr->first] = itr->second; } // for itr - Data->m_Form[] + + // Parse the URL into individual params: + size_t idxQM = a_Request.GetURL().find('?'); + if (idxQM != AString::npos) + { + cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, a_Request.GetURL().c_str() + idxQM + 1, a_Request.GetURL().length() - idxQM - 1, *Data); + URLParams.Finish(); + for (cHTTPFormParser::const_iterator itr = URLParams.begin(), end = URLParams.end(); itr != end; ++itr) + { + TemplateRequest.Request.Params[itr->first] = itr->second; + } // for itr - URLParams[] + } } // Try to get the template from the Lua template script diff --git a/source/WebAdmin.h b/source/WebAdmin.h index 16b5dd4dc..72c77ddfb 100644 --- a/source/WebAdmin.h +++ b/source/WebAdmin.h @@ -56,8 +56,14 @@ struct HTTPRequest AString Path; AString Username; // tolua_end + + /// Parameters given in the URL, after the questionmark StringStringMap Params; // >> EXPORTED IN MANUALBINDINGS << + + /// Parameters posted as a part of a form - either in the URL (GET method) or in the body (POST method) StringStringMap PostParams; // >> EXPORTED IN MANUALBINDINGS << + + /// Same as PostParams FormDataMap FormData; // >> EXPORTED IN MANUALBINDINGS << } ; // tolua_export