summaryrefslogtreecommitdiffstats
path: root/MCServer/Plugins
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--MCServer/Plugins/.gitignore3
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua884
-rw-r--r--MCServer/Plugins/APIDump/APIDump.deproj3
-rw-r--r--MCServer/Plugins/APIDump/Classes/BlockEntities.lua20
-rw-r--r--MCServer/Plugins/APIDump/Classes/Geometry.lua332
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua40
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua16
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnPlayerDestroyed.lua27
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua8
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua7
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua24
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua25
-rw-r--r--MCServer/Plugins/APIDump/SettingUpZeroBrane.html46
-rw-r--r--MCServer/Plugins/APIDump/Static/zbs_logo.pngbin0 -> 1306 bytes
-rw-r--r--MCServer/Plugins/APIDump/Static/zbs_workspace.pngbin0 -> 72631 bytes
-rw-r--r--MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html50
-rw-r--r--MCServer/Plugins/APIDump/main_APIDump.lua966
-rw-r--r--MCServer/Plugins/ChunkWorx/chunkworx_main.lua2
-rw-r--r--MCServer/Plugins/ChunkWorx/chunkworx_web.lua2
m---------MCServer/Plugins/Core0
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua383
-rw-r--r--MCServer/Plugins/DumpInfo/Init.lua49
-rw-r--r--MCServer/Plugins/InfoDump.lua449
-rw-r--r--MCServer/Plugins/InfoReg.lua198
-rw-r--r--MCServer/Plugins/MagicCarpet/coremessaging.lua19
-rw-r--r--MCServer/Plugins/MagicCarpet/plugin.lua8
26 files changed, 2632 insertions, 929 deletions
diff --git a/MCServer/Plugins/.gitignore b/MCServer/Plugins/.gitignore
new file mode 100644
index 000000000..8553945b5
--- /dev/null
+++ b/MCServer/Plugins/.gitignore
@@ -0,0 +1,3 @@
+*.txt
+*.md
+*/
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 347299a50..233bdbc46 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -104,13 +104,18 @@ g_APIDesc =
DumpToRawFile = { Params = "FileName", Return = "", Notes = "Dumps the raw data into a file. For debugging purposes only." },
Expand = { Params = "SubMinX, AddMaxX, SubMinY, AddMaxY, SubMinZ, AddMaxZ", Return = "", Notes = "Expands the specified number of blocks from each border. Modifies the size of this blockarea object. New blocks created with this operation are filled with zeroes." },
Fill = { Params = "DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Fills the entire block area with the same values, specified. Uses the DataTypes param to determine which content types are modified." },
- FillRelCuboid = { Params = "MinRelX, MaxRelX, MinRelY, MaxRelY, MinRelZ, MaxRelZ, DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Fills the specified cuboid with the same values (like Fill() )." },
+ FillRelCuboid =
+ {
+ { Params = "{{cCuboid|RelCuboid}}, DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Fills the specified cuboid (in relative coords) with the same values (like Fill() )." },
+ { Params = "MinRelX, MaxRelX, MinRelY, MaxRelY, MinRelZ, MaxRelZ, DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Fills the specified cuboid with the same values (like Fill() )." },
+ },
GetBlockLight = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the blocklight at the specified absolute coords" },
GetBlockMeta = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the block meta at the specified absolute coords" },
GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified absolute coords" },
GetBlockType = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified absolute coords" },
GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified absolute coords" },
- GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the objectis currently holding" },
+ GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the object is currently holding" },
+ GetOrigin = { Params = "", Return = "OriginX, OriginY, OriginZ", Notes = "Returns the origin coords of where the area was read from." },
GetOriginX = { Params = "", Return = "number", Notes = "Returns the origin x-coord" },
GetOriginY = { Params = "", Return = "number", Notes = "Returns the origin y-coord" },
GetOriginZ = { Params = "", Return = "number", Notes = "Returns the origin z-coord" },
@@ -118,41 +123,72 @@ g_APIDesc =
GetRelBlockMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the block meta at the specified relative coords" },
GetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified relative coords" },
GetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified relative coords" },
- GetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the block type and meta at the specified relative coords" },
+ GetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified relative coords" },
+ GetSize = { Params = "", Return = "SizeX, SizeY, SizeZ", Notes = "Returns the size of the area in all 3 axes." },
GetSizeX = { Params = "", Return = "number", Notes = "Returns the size of the held data in the x-axis" },
GetSizeY = { Params = "", Return = "number", Notes = "Returns the size of the held data in the y-axis" },
GetSizeZ = { Params = "", Return = "number", Notes = "Returns the size of the held data in the z-axis" },
+ GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the area - the total number of blocks stored within." },
+ GetWEOffset = { Params = "", Return = "{{Vector3i}}", Notes = "Returns the WE offset, a data value sometimes stored in the schematic files. MCServer doesn't use this value, but provides access to it using this method. The default is {0, 0, 0}."},
HasBlockLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include blocklight" },
HasBlockMetas = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block metas" },
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
HasBlockTypes = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block types" },
LoadFromSchematicFile = { Params = "FileName", Return = "", Notes = "Clears current content and loads new content from the specified schematic file. Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
- Merge = { Params = "BlockAreaSrc, RelX, RelY, RelZ, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
+ LoadFromSchematicString = { Params = "SchematicData", Return = "", Notes = "Clears current content and loads new content from the specified string (assumed to contain .schematic data). Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
+ Merge =
+ {
+ { Params = "BlockAreaSrc, {{Vector3i|RelMinCoords}}, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
+ { Params = "BlockAreaSrc, RelX, RelY, RelZ, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
+ },
MirrorXY = { Params = "", Return = "", Notes = "Mirrors this block area around the XY plane. Modifies blocks' metas (if present) to match (i. e. furnaces facing the opposite direction)." },
MirrorXYNoMeta = { Params = "", Return = "", Notes = "Mirrors this block area around the XY plane. Doesn't modify blocks' metas." },
MirrorXZ = { Params = "", Return = "", Notes = "Mirrors this block area around the XZ plane. Modifies blocks' metas (if present)" },
MirrorXZNoMeta = { Params = "", Return = "", Notes = "Mirrors this block area around the XZ plane. Doesn't modify blocks' metas." },
MirrorYZ = { Params = "", Return = "", Notes = "Mirrors this block area around the YZ plane. Modifies blocks' metas (if present)" },
MirrorYZNoMeta = { Params = "", Return = "", Notes = "Mirrors this block area around the YZ plane. Doesn't modify blocks' metas." },
- Read = { Params = "World, MinX, MaxX, MinY, MaxY, MinZ, MaxZ, DataTypes", Return = "bool", Notes = "Reads the area from World, returns true if successful" },
- RelLine = { Params = "RelX1, RelY1, RelZ1, RelX2, RelY2, RelZ2, DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Draws a line between the two specified points. Sets only datatypes specified by DataTypes." },
+ Read =
+ {
+ { Params = "World, {{cCuboid|Cuboid}}, DataTypes", Return = "bool", Notes = "Reads the area from World, returns true if successful" },
+ { Params = "World, {{Vector3i|Point1}}, {{Vector3i|Point2}}, DataTypes", Return = "bool", Notes = "Reads the area from World, returns true if successful" },
+ { Params = "World, X1, X2, Y1, Y2, Z1, Z2, DataTypes", Return = "bool", Notes = "Reads the area from World, returns true if successful" },
+ },
+ RelLine =
+ {
+ { Params = "{{Vector3i|RelPoint1}}, {{Vector3i|RelPoint2}}, DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Draws a line between the two specified points. Sets only datatypes specified by DataTypes (baXXX constants)." },
+ { Params = "RelX1, RelY1, RelZ1, RelX2, RelY2, RelZ2, DataTypes, BlockType, [BlockMeta], [BlockLight], [BlockSkyLight]", Return = "", Notes = "Draws a line between the two specified points. Sets only datatypes specified by DataTypes (baXXX constants)." },
+ },
RotateCCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, counter-clockwise (east -> north). Modifies blocks' metas (if present) to match." },
RotateCCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, counter-clockwise (east -> north). Doesn't modify blocks' metas." },
RotateCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Modifies blocks' metas (if present) to match." },
RotateCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Doesn't modify blocks' metas." },
SaveToSchematicFile = { Params = "FileName", Return = "", Notes = "Saves the current contents to a schematic file. Returns true if successful." },
+ SaveToSchematicString = { Params = "", Return = "string", Notes = "Saves the current contents to a string (in a .schematic file format). Returns the data if successful, nil if failed." },
SetBlockLight = { Params = "BlockX, BlockY, BlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified absolute coords" },
SetBlockMeta = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified absolute coords" },
SetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified absolute coords" },
SetBlockType = { Params = "BlockX, BlockY, BlockZ, BlockType", Return = "", Notes = "Sets the block type at the specified absolute coords" },
SetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block type and meta at the specified absolute coords" },
- SetOrigin = { Params = "OriginX, OriginY, OriginZ", Return = "", Notes = "Resets the origin for the absolute coords. Only affects how absolute coords are translated into relative coords." },
+ SetOrigin =
+ {
+ { Params = "{{Vector3i|Origin}}", Return = "", Notes = "Resets the origin for the absolute coords. Only affects how absolute coords are translated into relative coords." },
+ { Params = "OriginX, OriginY, OriginZ", Return = "", Notes = "Resets the origin for the absolute coords. Only affects how absolute coords are translated into relative coords." },
+ },
SetRelBlockLight = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified relative coords" },
SetRelBlockMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified relative coords" },
SetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified relative coords" },
SetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType", Return = "", Notes = "Sets the block type at the specified relative coords" },
SetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block type and meta at the specified relative coords" },
- Write = { Params = "World, MinX, MinY, MinZ, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" },
+ SetWEOffset =
+ {
+ { Params = "{{Vector3i|Offset}}", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
+ { Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
+ },
+ Write =
+ {
+ { Params = "World, {{Vector3i|MinPoint}}, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" },
+ { Params = "World, MinX, MinY, MinZ, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" },
+ },
},
Constants =
{
@@ -164,6 +200,8 @@ g_APIDesc =
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" },
msLake = { Notes = "Special mode for merging lake images" },
+ msSpongePrint = { Notes = "Similar to msImprint, sponge block doesn't overwrite anything, all other blocks overwrite everything"},
+ msMask = { Notes = "The blocks that are exactly the same are kept in Dst, all differing blocks are replaced by air"},
},
ConstantGroups =
{
@@ -211,6 +249,9 @@ g_APIDesc =
<tr>
<td> A </td><td> B </td><td> B </td><td> A </td><td> B </td>
</tr>
+ <tr>
+ <td> A </td><td> A </td><td> A </td><td> A </td><td> A </td>
+ </td>
</tbody></table>
<p>
@@ -222,12 +263,24 @@ g_APIDesc =
</ol>
</p>
+ <h3>Special strategies</h3>
+ <p>For each strategy, evaluate the table rows from top downwards, the first match wins.</p>
+
<p>
- Special strategies:
+ <strong>msDifference</strong> - changes all the blocks which are the same to air. Otherwise the source block gets placed.
</p>
-
+ <table><tbody<tr>
+ <th colspan="2"> area block </th><th> </th><th> Notes </th>
+ </tr><tr>
+ <td> * </td><td> B </td><td> B </td><td> The blocks are different so we use block B </td>
+ </tr><tr>
+ <td> B </td><td> B </td><td> Air </td><td> The blocks are the same so we get air. </td>
+ </tr>
+ </tbody></table>
+
+
<p>
- <strong>msLake</strong> (evaluate top-down, first match wins):
+ <strong>msLake</strong> - used for merging areas with lava and water lakes, in the appropriate generator.
</p>
<table><tbody><tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
@@ -257,49 +310,74 @@ g_APIDesc =
<td> A </td><td> * </td><td> A </td><td> Everything else is left as it is </td>
</tr>
</tbody></table>
- ]],
+
+ <p>
+ <strong>msSpongePrint</strong> - used for most prefab-generators to merge the prefabs. Similar to
+ msImprint, but uses the sponge block as the NOP block instead, so that the prefabs may carve out air
+ pockets, too.
+ </p>
+ <table><tbody><tr>
+ <th colspan="2"> area block </th><th> </th><th> Notes </th>
+ </tr><tr>
+ <th> this </th><th> Src </th><th> result </th><th> </th>
+ </tr><tr>
+ <td> A </td><td> sponge </td><td> A </td><td> Sponge is the NOP block </td>
+ </tr><tr>
+ <td> * </td><td> B </td><td> B </td><td> Everything else overwrites anything </td>
+ </tr>
+ </tbody></table>
+
+ <p>
+ <strong>msMask</strong> - the blocks that are the same in the other area are kept, all the
+ differing blocks are replaced with air. Meta is used in the comparison, too, two blocks of the
+ same type but different meta are considered different and thus replaced with air.
+ </p>
+ <table><tbody><tr>
+ <th colspan="2"> area block </th><th> </th><th> Notes </th>
+ </tr><tr>
+ <th> this </th><th> Src </th><th> result </th><th> </th>
+ </tr><tr>
+ <td> A </td><td> A </td><td> A </td><td> Same blocks are kept </td>
+ </tr><tr>
+ <td> A </td><td> non-A </td><td> air </td><td> Differing blocks are replaced with air </td>
+ </tr>
+ </tbody></table>
+]],
}, -- Merge strategies
}, -- AdditionalInfo
}, -- cBlockArea
- cBoundingBox =
+ cBlockInfo =
{
Desc = [[
- Represents two sets of coordinates, minimum and maximum for each direction; thus defining an
- axis-aligned cuboid with floating-point boundaries. It supports operations changing the size and
- position of the box, as well as querying whether a point or another BoundingBox is inside the box.</p>
- <p>
- All the points within the coordinate limits (inclusive the edges) are considered "inside" the box.
- However, for intersection purposes, if the intersection is "sharp" in any coord (min1 == max2, i. e.
- zero volume), the boxes are considered non-intersecting.</p>
+ This class is used to query and register block properties.
]],
Functions =
{
- constructor =
- {
- { Params = "MinX, MaxX, MinY, MaxY, MinZ, MaxZ", Return = "cBoundingBox", Notes = "Creates a new bounding box with the specified edges" },
- { Params = "{{Vector3d|Min}}, {{Vector3d|Max}}", Return = "cBoundingBox", Notes = "Creates a new bounding box with the coords specified as two vectors" },
- { Params = "{{Vector3d|Pos}}, Radius, Height", Return = "cBoundingBox", Notes = "Creates a new bounding box from the position given and radius (X/Z) and height. Radius is added from X/Z to calculate the maximum coords and subtracted from X/Z to get the minimum; minimum Y is set to Pos.y and maxumim Y to Pos.y plus Height. This corresponds with how {{cEntity|entities}} are represented in Minecraft." },
- { Params = "OtherBoundingBox", Return = "cBoundingBox", Notes = "Creates a new copy of the given bounding box. Same result can be achieved by using a simple assignment." },
- },
- CalcLineIntersection = { Params = "{{Vector3d|LineStart}}, {{Vector3d|LinePt2}}", Return = "DoesIntersect, LineCoeff, Face", Notes = "Calculates the intersection of a ray (half-line), given by two of its points, with the bounding box. Returns false if the line doesn't intersect the bounding box, or true, together with coefficient of the intersection (how much of the difference between the two ray points is needed to reach the intersection), and the face of the box which is intersected.<br /><b>TODO</b>: Lua binding for this function is wrong atm." },
- DoesIntersect = { Params = "OtherBoundingBox", Return = "bool", Notes = "Returns true if the two bounding boxes have an intersection of nonzero volume." },
- Expand = { Params = "ExpandX, ExpandY, ExpandZ", Return = "", Notes = "Expands this bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each axis)." },
- IsInside =
- {
- { Params = "{{Vector3d|Point}}", Return = "bool", Notes = "Returns true if the specified point is inside (including on the edge) of the box." },
- { Params = "PointX, PointY, PointZ", Return = "bool", Notes = "Returns true if the specified point is inside (including on the edge) of the box." },
- { Params = "OtherBoundingBox", Return = "bool", Notes = "Returns true if OtherBoundingBox is inside of this box." },
- { Params = "{{Vector3d|OtherBoxMin}}, {{Vector3d|OtherBoxMax}}", Return = "bool", Notes = "Returns true if the other bounding box, specified by its 2 corners, is inside of this box." },
- },
- Move =
- {
- { Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Moves the bounding box by the specified offset in each axis" },
- { Params = "{{Vector3d|Offset}}", Return = "", Notes = "Moves the bounding box by the specified offset in each axis" },
- },
- Union = { Params = "OtherBoundingBox", Return = "cBoundingBox", Notes = "Returns the smallest bounding box that contains both OtherBoundingBox and this bounding box. Note that unlike the strict geometrical meaning of \"union\", this operation actually returns a cBoundingBox." },
+ 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." },
+ 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." },
+ IsSnowable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block can hold snow atop." },
+ IsSolid = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block is solid." },
+ IsTransparent = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block is transparent." },
+ RequiresSpecialTool = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block requires a special tool to drop." },
},
- },
+ Variables =
+ {
+ 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_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(?))" },
+ },
+ }, -- cBlockInfo
cChatColor =
{
@@ -394,6 +472,7 @@ g_APIDesc =
SetUseDefaultFinish = { Params = "bool", Return = "", Notes = "Sets the chunk to use default finishers or not" },
SetUseDefaultHeight = { Params = "bool", Return = "", Notes = "Sets the chunk to use default height generator or not" },
SetUseDefaultStructures = { Params = "bool", Return = "", Notes = "Sets the chunk to use default structures or not" },
+ UpdateHeightmap = { Params = "", Return = "", Notes = "Updates the heightmap to match current contents. The plugins should do that if they modify the contents and don't modify the heightmap accordingly; MCServer expects (and checks in Debug mode) that the heightmap matches the contents when the cChunkDesc is returned from a plugin." },
WriteBlockArea = { Params = "{{cBlockArea|BlockArea}}, MinRelX, MinRelY, MinRelZ", Return = "", Notes = "Writes data from the block area into the chunk" },
},
AdditionalInfo =
@@ -443,13 +522,16 @@ end
Functions =
{
+ GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" },
GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" },
+ HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" },
SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." },
+ SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." },
SetUsername = { Params = "Name", Return = "", Notes = "Sets the username" },
SetViewDistance = { Params = "ViewDistance", Return = "", Notes = "Sets the viewdistance (number of chunks loaded for the player in each direction)" },
SendBlockChange = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sends a BlockChange packet to the client. This can be used to create fake blocks only for that player." },
@@ -461,6 +543,74 @@ end
},
}, -- cClientHandle
+ cCompositeChat =
+ {
+ Desc = [[
+ Encapsulates a chat message that can contain various formatting, URLs, commands executed on click
+ and commands suggested on click. The chat message can be sent by the regular chat-sending functions,
+ {{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p>
+ <p>
+ Note that most of the functions in this class are so-called modifiers - they modify the object and
+ then return the object itself, so that they can be chained one after another. See the Chaining
+ example below for details.</p>
+ <p>
+ Each part of the composite chat message takes a "Style" parameter, this is a string that describes
+ the formatting. It uses the following strings, concatenated together:
+ <table>
+ <tr><th>String</th><th>Style</th></tr>
+ <tr><td>b</td><td>Bold text</td></tr>
+ <tr><td>i</td><td>Italic text</td></tr>
+ <tr><td>u</td><td>Underlined text</td></tr>
+ <tr><td>s</td><td>Strikethrough text</td></tr>
+ <tr><td>o</td><td>Obfuscated text</td></tr>
+ <tr><td>@X</td><td>color X (X is 0 - 9 or a - f, same as dye meta</td></tr>
+ </table>
+ The following picture, taken from MineCraft Wiki, illustrates the color codes:</p>
+ <img src="http://hydra-media.cursecdn.com/minecraft.gamepedia.com/4/4c/Colors.png?version=34a0f56789a95326e1f7d82047b12232" />
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "", Return = "", Notes = "Creates an empty chat message" },
+ { Params = "Text", Return = "", Notes = "Creates a chat message containing the specified text, parsed by the ParseText() function. This allows easy migration from old chat messages." },
+ },
+ AddRunCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, runs the specified command. Chaining." },
+ AddSuggestCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, puts the specified command into the player's chat input area. Chaining." },
+ AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." },
+ AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." },
+ Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" },
+ ExtractText = { Params = "", Return = "string", Notes = "Returns the text from the parts that comprises the human-readable data. Used for older protocols that don't support composite chat and for console-logging." },
+ GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" },
+ ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." },
+ SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." },
+ UnderlineUrls = { Params = "", Return = "self", Notes = "Makes all URL parts contained in the message underlined. Doesn't affect parts added in the future. Chaining." },
+ },
+
+ AdditionalInfo =
+ {
+ {
+ Header = "Chaining example",
+ Contents = [[
+ Sending a chat message that is composed of multiple different parts has been made easy thanks to
+ chaining. Consider the following example that shows how a message containing all kinds of parts
+ is sent (adapted from the Debuggers plugin):
+<pre class="prettyprint lang-lua">
+function OnPlayerJoined(a_Player)
+ -- Send an example composite chat message to the player:
+ a_Player:SendMessage(cCompositeChat()
+ :AddTextPart("Hello, ")
+ :AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2") -- Colored underlined link
+ :AddSuggestCommandPart(", and welcome.", "/help", "u") -- Underlined suggest-command
+ :AddRunCommandPart(" SetDay", "/time set 0") -- Regular text that will execute command when clicked
+ :SetMessageType(mtJoin) -- It is a join-message
+ )
+end</pre>
+ ]],
+ },
+ }, -- AdditionalInfo
+ }, -- cCompositeChat
+
cCraftingGrid =
{
Desc = [[
@@ -520,48 +670,6 @@ end
},
}, -- cCraftingRecipe
- cCuboid =
- {
- Desc = [[
- cCuboid offers some native support for integral-boundary cuboids. A cuboid internally consists of
- two {{Vector3i}}s. By default the cuboid doesn't make any assumptions about the defining points,
- but for most of the operations in the cCuboid class, the p1 member variable is expected to be the
- minima and the p2 variable the maxima. The Sort() function guarantees this condition.</p>
- <p>
- The Cuboid considers both its edges inclusive.</p>
- ]],
- Functions =
- {
- constructor =
- {
- { Params = "OtheCuboid", Return = "cCuboid", Notes = "Creates a new Cuboid object as a copy of OtherCuboid" },
- { Params = "{{Vector3i|Point1}}, {{Vector3i|Point2}}", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
- { Params = "X, Y, Z", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified point as both its corners (the cuboid has a size of 1 in each direction)." },
- { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
- },
- Assign = { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "", Notes = "Assigns all the coords stored in the cuboid. Sort-state is ignored." },
- DifX = { Params = "", Return = "number", Notes = "Returns the difference between the two X coords (X-size minus 1). Assumes sorted." },
- DifY = { Params = "", Return = "number", Notes = "Returns the difference between the two Y coords (Y-size minus 1). Assumes sorted." },
- DifZ = { Params = "", Return = "number", Notes = "Returns the difference between the two Z coords (Z-size minus 1). Assumes sorted." },
- DoesIntersect = { Params = "OtherCuboid", Return = "bool", Notes = "Returns true if this cuboid has at least one voxel in common with OtherCuboid. Note that edges are considered inclusive. Assumes both sorted." },
- IsCompletelyInside = { Params = "OuterCuboid", Return = "bool", Notes = "Returns true if this cuboid is completely inside (in all directions) in OuterCuboid. Assumes both sorted." },
- IsInside =
- {
- { Params = "X, Y, Z", Return = "bool", Notes = "Returns true if the specified point (integral coords) is inside this cuboid. Assumes sorted." },
- { Params = "{{Vector3i|Point}}", Return = "bool", Notes = "Returns true if the specified point (integral coords) is inside this cuboid. Assumes sorted." },
- { Params = "{{Vector3d|Point}}", Return = "bool", Notes = "Returns true if the specified point (floating-point coords) is inside this cuboid. Assumes sorted." },
- },
- IsSorted = { Params = "", Return = "bool", Notes = "Returns true if this cuboid is sorted" },
- Move = { Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Adds the specified offsets to each respective coord, effectively moving the Cuboid. Sort-state is ignored." },
- Sort = { Params = "", Return = "" , Notes = "Sorts the internal representation so that p1 contains the lesser coords and p2 contains the greater coords." },
- },
- Variables =
- {
- p1 = { Type = "{{Vector3i}}", Notes = "The first corner. Usually the lesser of the two coords in each set" },
- p2 = { Type = "{{Vector3i}}", Notes = "The second corner. Usually the larger of the two coords in each set" },
- },
- }, -- cCuboid
-
cEnchantments =
{
Desc = [[
@@ -685,15 +793,14 @@ end
GetMass = { Params = "", Return = "number", Notes = "Returns the mass of the entity. Currently unused." },
GetMaxHealth = { Params = "", Return = "number", Notes = "Returns the maximum number of hitpoints this entity is allowed to have." },
GetParentClass = { Params = "", Return = "string", Notes = "Returns the name of the direct parent class for this entity" },
- GetPitch = { Params = "", Return = "number", Notes = "Returns the pitch (nose-down rotation) of the entity" },
+ GetPitch = { Params = "", Return = "number", Notes = "Returns the pitch (nose-down rotation) of the entity. Measured in degrees, normal values range from -90 to +90. +90 means looking down, 0 means looking straight ahead, -90 means looking up." },
GetPosition = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the entity's pivot position as a 3D vector" },
GetPosX = { Params = "", Return = "number", Notes = "Returns the X-coord of the entity's pivot" },
GetPosY = { Params = "", Return = "number", Notes = "Returns the Y-coord of the entity's pivot" },
GetPosZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the entity's pivot" },
GetRawDamageAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the raw damage that this entity's equipment would cause when attacking the ReceiverEntity. This includes this entity's weapon {{cEnchantments|enchantments}}, but excludes the receiver's armor or potion effects. See {{TakeDamageInfo}} for more information on attack damage." },
GetRoll = { Params = "", Return = "number", Notes = "Returns the roll (sideways rotation) of the entity. Currently unused." },
- GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the entire rotation vector (Yaw, Pitch, Roll)" },
- GetRotation = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. OBSOLETE, use GetYaw() instead." },
+ GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "(OBSOLETE) Returns the entire rotation vector (Yaw, Pitch, Roll)" },
GetSpeed = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the complete speed vector of the entity" },
GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" },
GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" },
@@ -701,7 +808,7 @@ end
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity within the running server. Note that this ID is not persisted to the data files." },
GetWidth = { Params = "", Return = "number", Notes = "Returns the width (X and Z size) of the entity." },
GetWorld = { Params = "", Return = "{{cWorld}}", Notes = "Returns the world where the entity resides" },
- GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity." },
+ GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. Measured in degrees, values range from -180 to +180. 0 means ZP, 90 means XM, -180 means ZM, -90 means XP." },
Heal = { Params = "Hitpoints", Return = "", Notes = "Heals the specified number of hitpoints. Hitpoints is expected to be a positive number." },
IsA = { Params = "ClassName", Return = "bool", Notes = "Returns true if the entity class is a descendant of the specified class name, or the specified class itself" },
IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." },
@@ -714,14 +821,18 @@ end
IsMinecart = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cMinecart|minecart}}" },
IsMob = { Params = "", Return = "bool", Notes = "Returns true if the entity represents any {{cMonster|mob}}." },
IsOnFire = { Params = "", Return = "bool", Notes = "Returns true if the entity is on fire" },
+ IsPainting = { Params = "", Return = "bool", Notes = "Returns if this entity is a painting." },
IsPickup = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPickup|pickup}}." },
IsPlayer = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPlayer|player}}" },
IsProjectile = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cProjectileEntity}} descendant." },
IsRclking = { Params = "", Return = "bool", Notes = "Currently unimplemented" },
IsRiding = { Params = "", Return = "bool", Notes = "Returns true if the entity is attached to (riding) another entity." },
IsSprinting = { Params = "", Return = "bool", Notes = "Returns true if the entity is sprinting. Entities that cannot sprint return always false" },
+ IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is submerged in water (head is in a water block). Note, this function is only updated with mobs or players." },
+ IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is swimming in water (feet are in a water block). Note, this function is only updated with mobs or players." },
IsTNT = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cTNTEntity|TNT entity}}" },
KilledBy = { Notes = "FIXME: Remove this from API" },
+ GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." },
SetGravity = { Params = "Gravity", Return = "", Notes = "Sets the number that is used as the gravity for physics simulation. 1G (9.78) by default." },
SetHeadYaw = { Params = "HeadPitch", Return = "", Notes = "Sets the head pitch (FIXME: Rename to SetHeadPitch() )." },
SetHealth = { Params = "Hitpoints", Return = "", Notes = "Sets the entity's health to the specified amount of hitpoints. Doesn't broadcast any hurt animation. Doesn't kill the entity if health drops below zero. Use the TakeDamage() function instead for taking damage." },
@@ -740,8 +851,7 @@ end
SetPosZ = { Params = "number", Return = "", Notes = "Sets the Z-coord of the entity's pivot" },
SetRoll = { Params = "number", Return = "", Notes = "Sets the roll (sideways rotation) of the entity. Currently unused." },
SetRot = { Params = "{{Vector3f|Rotation}}", Return = "", Notes = "Sets the entire rotation vector (Yaw, Pitch, Roll)" },
- SetRotation = { Params = "number", Return = "", Notes = "Sets the yaw (direction) of the entity. OBSOLETE, use SetYaw() instead." },
- SetRotationFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" },
+ SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" },
SetSpeed =
{
{ Params = "SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Sets the current speed of the entity" },
@@ -778,6 +888,7 @@ end
etPickup = { Notes = "The entity is a {{cPickup}}" },
etProjectile = { Notes = "The entity is a {{cProjectileEntity}} descendant" },
etTNT = { Notes = "The entity is a {{cTNTEntity}}" },
+ etPainting = { Notes = "The entity is a {{cPainting}}" },
},
ConstantGroups =
{
@@ -813,6 +924,20 @@ cFile:Delete("/usr/bin/virus.exe");
},
}, -- cFile
+ cFloater =
+ {
+ Desc = [[
+ When a player uses his/her fishing rod it creates a floater entity. This class manages it.
+ ]],
+ Functions =
+ {
+ CanPickup = { Params = "", Return = "bool", Notes = "Returns true if the floater gives an item when the player right clicks." },
+ GetAttachedMobID = { Params = "", Return = "EntityID", Notes = "A floater can get attached to an mob. When it is and this functions gets called it returns the mob ID. If it isn't attached to a mob it returns -1" },
+ GetOwnerID = { Params = "", Return = "EntityID", Notes = "Returns the EntityID of the player who owns the floater." },
+ },
+ Inherits = "cEntity",
+ },
+
cGroup =
{
Desc = [[
@@ -826,7 +951,6 @@ cFile:Delete("/usr/bin/virus.exe");
SetColor = { Return = "" },
GetColor = { Return = "string" },
AddCommand = { Return = "" },
- HasCommand = { Return = "bool" },
AddPermission = { Return = "" },
InheritFrom = { Return = "" },
},
@@ -1089,10 +1213,13 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
GetMaxStackSize = { Params = "", Return = "number", Notes = "Returns the maximum stack size for this item." },
IsDamageable = { Params = "", Return = "bool", Notes = "Returns true if this item does account for its damage" },
IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if this object represents an empty item (zero count or invalid ID)" },
- IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage and enchantments)" },
+ IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage, lore, name and enchantments)" },
+ IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
- IsStackableWith = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is stackable with the one stored in the object. Two items with different enchantments cannot be stacked" },
+ IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." },
+ IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." },
+ IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." },
},
Variables =
{
@@ -1100,6 +1227,8 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
m_ItemCount = { Type = "number", Notes = "Number of items in this stack" },
m_ItemDamage = { Type = "number", Notes = "The damage of the item. Zero means no damage. Maximum damage can be queried with GetMaxDamage()" },
m_ItemType = { Type = "number", Notes = "The item type. One of E_ITEM_ or E_BLOCK_ constants" },
+ m_CustomName = { Type = "string", Notes = "The custom name for an item." },
+ m_Lore = { Type = "string", Notes = "The lore for an item. Line breaks are represented by the ` character." },
},
AdditionalInfo =
{
@@ -1144,6 +1273,53 @@ local Item5 = cItem(E_ITEM_DIAMOND_CHESTPLATE, 1, 0, "thorns=1;unbreaking=3");
},
}, -- cItem
+ cObjective =
+ {
+ Desc = [[
+ This class represents a single scoreboard objective.
+ ]],
+ Functions =
+ {
+ AddScore = { Params = "string, number", Return = "Score", Notes = "Adds a value to the score of the specified player and returns the new value." },
+ GetDisplayName = { Params = "", Return = "string", Notes = "Returns the display name of the objective. This name will be shown to the connected players." },
+ GetName = { Params = "", Return = "string", Notes = "Returns the internal name of the objective." },
+ GetScore = { Params = "string", Return = "Score", Notes = "Returns the score of the specified player." },
+ GetType = { Params = "", Return = "eType", Notes = "Returns the type of the objective. (i.e what is being tracked)" },
+ Reset = { Params = "", Return = "", Notes = "Resets the scores of the tracked players." },
+ ResetScore = { Params = "string", Return = "", Notes = "Reset the score of the specified player." },
+ SetDisplayName = { Params = "string", Return = "", Notes = "Sets the display name of the objective." },
+ SetScore = { Params = "string, Score", Return = "", Notes = "Sets the score of the specified player." },
+ SubScore = { Params = "string, number", Return = "Score", Notes = "Subtracts a value from the score of the specified player and returns the new value." },
+ },
+ Constants =
+ {
+ otAchievement = { Notes = "" },
+ otDeathCount = { Notes = "" },
+ otDummy = { Notes = "" },
+ otHealth = { Notes = "" },
+ otPlayerKillCount = { Notes = "" },
+ otStat = { Notes = "" },
+ otStatBlockMine = { Notes = "" },
+ otStatEntityKill = { Notes = "" },
+ otStatEntityKilledBy = { Notes = "" },
+ otStatItemBreak = { Notes = "" },
+ otStatItemCraft = { Notes = "" },
+ otStatItemUse = { Notes = "" },
+ otTotalKillCount = { Notes = "" },
+ },
+ }, -- cObjective
+
+ cPainting =
+ {
+ Desc = "This class represents a painting in the world. These paintings are special and different from Vanilla in that they can be critical-hit.",
+ Functions =
+ {
+ GetDirection = { Params = "", Return = "number", Notes = "Returns the direction the painting faces. Directions: ZP - 0, ZM - 2, XM - 1, XP - 3. Note that these are not the BLOCK_FACE constants." },
+ GetName = { Params = "", Return = "string", Notes = "Returns the name of the painting" },
+ },
+
+ }, -- cPainting
+
cItemGrid =
{
Desc = [[This class represents a 2D array of items. It is used as the underlying storage and API for all cases that use a grid of items:
@@ -1278,95 +1454,6 @@ end
},
}, -- cItems
- cLineBlockTracer =
- {
- Desc = [[Objects of this class provide an easy-to-use interface to tracing lines through individual
-blocks in the world. It will call the provided callbacks according to what events it encounters along the
-way.</p>
-<p>
-For the Lua API, there's only one function exported that takes all the parameters necessary to do the
-tracing. The Callbacks parameter is a table containing all the functions that will be called upon the
-various events. See below for further information.
- ]],
- Functions =
- {
- Trace = { Params = "{{cWorld}}, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ", Return = "bool", Notes = "(STATIC) Performs the trace on the specified line. Returns true if the entire trace was processed (no callback returned true)" },
- },
-
- AdditionalInfo =
- {
- {
- Header = "Callbacks",
- Contents = [[
-The Callbacks in the Trace() function is a table that contains named functions. MCServer will call
-individual functions from that table for the events that occur on the line - hitting a block, going out of
-valid world data etc. The following table lists all the available callbacks. If the callback function is
-not defined, MCServer skips it. Each function can return a bool value, if it returns true, the tracing is
-aborted and Trace() returns false.</p>
-<p>
-<table><tr><th>Name</th><th>Parameters</th><th>Notes</th></tr>
-<tr><td>OnNextBlock</td><td>BlockX, BlockY, BlockZ, BlockType, BlockMeta, EntryFace</td>
- <td>Called when the ray hits a new valid block. The block type and meta is given. EntryFace is one of the
- BLOCK_FACE_ constants indicating which "side" of the block got hit by the ray.</td></tr>
-<tr><td>OnNextBlockNoData</td><td>BlockX, BlockY, BlockZ, EntryFace</td>
- <td>Called when the ray hits a new block, but the block is in an unloaded chunk - no valid data is
- available. Only the coords and the entry face are given.</td></tr>
-<tr><td>OnOutOfWorld</td><td>X, Y, Z</td>
- <td>Called when the ray goes outside of the world (Y-wise); the coords specify the exact exit point. Note
- that for other paths than lines (considered for future implementations) the path may leave the world and
- go back in again later, in such a case this callback is followed by OnIntoWorld() and further
- OnNextBlock() calls.</td></tr>
-<tr><td>OnIntoWorld</td><td>X, Y, Z</td>
- <td>Called when the ray enters the world (Y-wise); the coords specify the exact entry point.</td></tr>
-<tr><td>OnNoMoreHits</td><td>&nbsp;</td>
- <td>Called when the path is sure not to hit any more blocks. This is the final callback, no more
- callbacks are called after this function. Unlike the other callbacks, this function doesn't have a return
- value.</td></tr>
-<tr><td>OnNoChunk</td><td>&nbsp;</td>
- <td>Called when the ray enters a chunk that is not loaded. This usually means that the tracing is aborted.
- Unlike the other callbacks, this function doesn't have a return value.</td></tr>
-</table>
- ]],
- },
- {
- Header = "Example",
- Contents = [[
-<p>The following example is taken from the Debuggers plugin. It is a command handler function for the
-"/spidey" command that creates a line of cobweb blocks from the player's eyes up to 50 blocks away in
-the direction they're looking, but only through the air.
-<pre class="prettyprint lang-lua">
-function HandleSpideyCmd(a_Split, a_Player)
- local World = a_Player:GetWorld();
-
- local Callbacks = {
- OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta)
- if (a_BlockType ~= E_BLOCK_AIR) then
- -- abort the trace
- return true;
- end
- World:SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COBWEB, 0);
- end
- };
-
- local EyePos = a_Player:GetEyePosition();
- local LookVector = a_Player:GetLookVector();
- LookVector:Normalize(); -- Make the vector 1 m long
-
- -- Start cca 2 blocks away from the eyes
- local Start = EyePos + LookVector + LookVector;
- local End = EyePos + LookVector * 50;
-
- cLineBlockTracer.Trace(World, Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z);
-
- return true;
-end
-</pre>
-</p>
- ]],
- },
- }, -- AdditionalInfo
- }, -- cLineBlockTracer
-
cLuaWindow =
{
Desc = [[This class is used by plugins wishing to display a custom window to the player, unrelated to block entities or entities near the player. The window can be of any type and have any contents that the plugin defines. Callbacks for when the player modifies the window contents and when the player closes the window can be set.
@@ -1451,6 +1538,68 @@ a_Player:OpenWindow(Window);
Inherits = "cWindow",
}, -- cLuaWindow
+ cMap =
+ {
+ Desc = [[
+ This class encapsulates a single in-game colored map.</p>
+ <p>
+ The contents (i.e. pixel data) of a cMap are dynamically updated by each
+ tracked {{cPlayer}} instance. Furthermore, a cMap maintains and periodically
+ updates a list of map decorators, which are objects drawn on the map that
+ can freely move (e.g. Player and item frame pointers).
+ ]],
+ Functions =
+ {
+ EraseData = { Params = "", Return = "", Notes = "Erases all pixel data." },
+ GetCenterX = { Params = "", Return = "number", Notes = "Returns the X coord of the map's center." },
+ GetCenterZ = { Params = "", Return = "number", Notes = "Returns the Y coord of the map's center." },
+ GetDimension = { Params = "", Return = "eDimension", Notes = "Returns the dimension of the associated world." },
+ GetHeight = { Params = "", Return = "number", Notes = "Returns the height of the map." },
+ GetID = { Params = "", Return = "number", Notes = "Returns the numerical ID of the map. (The item damage value)" },
+ GetName = { Params = "", Return = "string", Notes = "Returns the name of the map." },
+ GetNumPixels = { Params = "", Return = "number", Notes = "Returns the number of pixels in this map." },
+ GetPixel = { Params = "PixelX, PixelZ", Return = "ColorID", Notes = "Returns the color of the specified pixel." },
+ GetPixelWidth = { Params = "", Return = "number", Notes = "Returns the width of a single pixel in blocks." },
+ GetScale = { Params = "", Return = "number", Notes = "Returns the scale of the map. Range: [0,4]" },
+ GetWidth = { Params = "", Return = "number", Notes = "Returns the width of the map." },
+ GetWorld = { Params = "", Return = "cWorld", Notes = "Returns the associated world." },
+ Resize = { Params = "Width, Height", Return = "", Notes = "Resizes the map. WARNING: This will erase the pixel data." },
+ SetPixel = { Params = "PixelX, PixelZ, ColorID", Return = "bool", Notes = "Sets the color of the specified pixel. Returns false on error (Out of range)." },
+ SetPosition = { Params = "CenterX, CenterZ", Return = "", Notes = "Relocates the map. The pixel data will not be modified." },
+ SetScale = { Params = "number", Return = "", Notes = "Rescales the map. The pixel data will not be modified." },
+ },
+ Constants =
+ {
+ E_BASE_COLOR_BLUE = { Notes = "" },
+ E_BASE_COLOR_BROWN = { Notes = "" },
+ E_BASE_COLOR_DARK_BROWN = { Notes = "" },
+ E_BASE_COLOR_DARK_GRAY = { Notes = "" },
+ E_BASE_COLOR_DARK_GREEN = { Notes = "" },
+ E_BASE_COLOR_GRAY_1 = { Notes = "" },
+ E_BASE_COLOR_GRAY_2 = { Notes = "" },
+ E_BASE_COLOR_LIGHT_BROWN = { Notes = "" },
+ E_BASE_COLOR_LIGHT_GRAY = { Notes = "" },
+ E_BASE_COLOR_LIGHT_GREEN = { Notes = "" },
+ E_BASE_COLOR_PALE_BLUE = { Notes = "" },
+ E_BASE_COLOR_RED = { Notes = "" },
+ E_BASE_COLOR_TRANSPARENT = { Notes = "" },
+ E_BASE_COLOR_WHITE = { Notes = "" },
+ },
+ }, -- cMap
+
+ cMapManager =
+ {
+ Desc = [[
+ This class is associated with a single {{cWorld}} instance and manages a list of maps.
+ ]],
+ Functions =
+ {
+ DoWithMap = { Params = "ID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If a map with the specified ID exists, calls the CallbackFunction for that map. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cMap|Map}}, [CallbackData])</pre> Returns true if the map was found and the callback called, false if map not found." },
+ GetNumMaps = { Params = "", Return = "number", Notes = "Returns the number of registered maps." },
+ },
+
+ }, -- cMapManager
+
cMonster =
{
Desc = [[
@@ -1465,6 +1614,7 @@ a_Player:OpenWindow(Window);
GetMobType = { Params = "", Return = "{{cMonster#MobType|MobType}}", Notes = "Returns the type of this mob ({{cMonster#MobType|mtXXX}} constant)" },
GetSpawnDelay = { Params = "{{cMonster#MobFamily|MobFamily}}", Return = "number", Notes = "(STATIC) Returns the spawn delay - the number of game ticks between spawn attempts - for the specified mob family." },
MobTypeToString = { Params = "{{cMonster#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{cMonster#MobType|mtXXX}} constant), or empty string if unknown type." },
+ MoveToPosition = { Params = "Position", Return = "", Notes = "Moves mob to the specified position" },
StringToMobType = { Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{cMonster#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." },
},
Constants =
@@ -1550,7 +1700,6 @@ a_Player:OpenWindow(Window);
]],
Functions =
{
- constructor = { Params = "PosX, PosY, PosZ, {{cItem|Item}}, IsPlayerCreated, [SpeedX, SpeedY, SpeedZ]", Return = "cPickup", Notes = "Creates a new pickup at the specified coords. If IsPlayerCreated is true, the pickup has a longer initial collection interval." },
CollectedBy = { Params = "{{cPlayer}}", Return = "bool", Notes = "Tries to make the player collect the pickup. Returns true if the pickup was collected, at least partially." },
GetAge = { Params = "", Return = "number", Notes = "Returns the number of ticks that the pickup has existed." },
GetItem = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item represented by this pickup" },
@@ -1573,36 +1722,35 @@ a_Player:OpenWindow(Window);
AddToGroup = { Params = "GroupName", Return = "", Notes = "Temporarily adds the player to the specified group. The assignment is lost when the player disconnects." },
CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "(STATIC) Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." },
CanFly = { Return = "bool", Notes = "Returns if the player is able to fly." },
- CanUseCommand = { Params = "Command", Return = "bool", Notes = "Returns true if the player is allowed to use the specified command." },
CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." },
CloseWindowIfID = { Params = "WindowID, [CanRefuse]", Return = "", Notes = "Closes the currently open UI window if its ID matches the given ID. If CanRefuse is true (default), the window may refuse the closing." },
DeltaExperience = { Params = "DeltaXP", Return = "", Notes = "Adds or removes XP from the current XP amount. Won't allow XP to go negative. Returns the new experience, -1 on error (XP overflow)." },
Feed = { Params = "AddFood, AddSaturation", Return = "bool", Notes = "Tries to add the specified amounts to food level and food saturation level (only positive amounts expected). Returns true if player was hungry and the food was consumed, false if too satiated." },
FoodPoison = { Params = "NumTicks", Return = "", Notes = "Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two" },
ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." },
- GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left)." },
GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." },
GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." },
GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" },
- GetEffectiveGameMode = { Params = "", Return = "{{eGameMode|GameMode}}", Notes = "Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions." },
+ GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." },
GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." },
GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" },
GetEyePosition = { Return = "{{Vector3d|EyePositionVector}}", Notes = "Returns the position of the player's eyes, as a {{Vector3d}}" },
GetFloaterID = { Params = "", Return = "number", Notes = "Returns the Entity ID of the fishing hook floater that belongs to the player. Returns -1 if no floater is associated with the player. FIXME: Undefined behavior when the player has used multiple fishing rods simultanously." },
+ GetFlyingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the maximum flying speed, relative to the default game flying speed. Defaults to 1, but plugins may modify it for faster or slower flying." },
GetFoodExhaustionLevel = { Params = "", Return = "number", Notes = "Returns the food exhaustion level" },
GetFoodLevel = { Params = "", Return = "number", Notes = "Returns the food level (number of half-drumsticks on-screen)" },
GetFoodPoisonedTicksRemaining = { Params = "", Return = "", Notes = "Returns the number of ticks left for the food posoning effect" },
GetFoodSaturationLevel = { Params = "", Return = "number", Notes = "Returns the food saturation (overcharge of the food level, is depleted before food level)" },
GetFoodTickTimer = { Params = "", Return = "", Notes = "Returns the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." },
- GetGameMode = { Return = "{{eGameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."},
+ GetGameMode = { Return = "{{Globals#GameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."},
GetGroups = { Return = "array-table of {{cGroup}}", Notes = "Returns all the groups that this player is member of, as a table. The groups are stored in the array part of the table, beginning with index 1."},
GetIP = { Return = "string", Notes = "Returns the IP address of the player, if available. Returns an empty string if there's no IP to report."},
GetInventory = { Return = "{{cInventory|Inventory}}", Notes = "Returns the player's inventory"},
- GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed (as reported by the 1.6.1+ protocols)" },
+ GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status." },
GetName = { Return = "string", Notes = "Returns the player's name" },
- GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed (as reported by the 1.6.1+ protocols)" },
+ GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed, relative to the game default speed. Defaults to 1, but plugins may modify it for faster or slower walking." },
GetResolvedPermissions = { Return = "array-table of string", Notes = "Returns all the player's permissions, as a table. The permissions are stored in the array part of the table, beginning with index 1." },
- GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed (as reported by the 1.6.1+ protocols)" },
+ GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed, relative to the game default speed. Defaults to 1.3, but plugins may modify it for faster or slower sprinting." },
GetStance = { Return = "number", Notes = "Returns the player's stance (Y-pos of player's eyes)" },
GetThrowSpeed = { Params = "SpeedCoeff", Return = "{{Vector3d}}", Notes = "Returns the speed vector for an object thrown with the specified speed coeff. Basically returns the normalized look vector multiplied by the coeff, with a slight random variation." },
GetThrowStartPos = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the position where the projectiles should start when thrown by this player." },
@@ -1621,8 +1769,6 @@ a_Player:OpenWindow(Window);
IsInGroup = { Params = "GroupNameString", Return = "bool", Notes = "Returns true if the player is a member of the specified group." },
IsOnGround = { Params = "", Return = "bool", Notes = "Returns true if the player is on ground (not falling, not jumping, not flying)" },
IsSatiated = { Params = "", Return = "bool", Notes = "Returns true if the player is satiated (cannot eat)." },
- IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the player is submerged in water (the player's head is in a water block)" },
- IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the player is swimming in water (the player's feet are in a water block)" },
IsVisible = { Params = "", Return = "bool", Notes = "Returns true if the player is visible to other players" },
LoadPermissionsFromDisk = { Params = "", Return = "", Notes = "Reloads the player's permissions from the disk. This loses any temporary changes made to the player's groups." },
MoveTo = { Params = "{{Vector3d|NewPosition}}", Return = "Tries to move the player into the specified position." },
@@ -1630,31 +1776,35 @@ a_Player:OpenWindow(Window);
OpenWindow = { Params = "{{cWindow|Window}}", Return = "", Notes = "Opens the specified UI window for the player." },
RemoveFromGroup = { Params = "GroupName", Return = "", Notes = "Temporarily removes the player from the specified group. This change is lost when the player disconnects." },
Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." },
- SendMessage = { Params = "MessageString", Return = "", Notes = "Sends the specified message to the player." },
+ SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." },
+ SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." },
+ SendMessageFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For something serious, such as a plugin crash, etc." },
+ SendMessageInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Informational message, such as command usage, etc." },
+ SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." },
+ SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." },
+ SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." },
SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." },
SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." },
SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." },
SetFlying = { Params = "IsFlying", Notes = "Sets if the player is flying or not." },
+ SetFlyingMaxSpeed = { Params = "FlyingMaxSpeed", Return = "", Notes = "Sets the flying maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client." },
SetFoodExhaustionLevel = { Params = "ExhaustionLevel", Return = "", Notes = "Sets the food exhaustion to the specified level." },
SetFoodLevel = { Params = "FoodLevel", Return = "", Notes = "Sets the food level (number of half-drumsticks on-screen)" },
SetFoodPoisonedTicksRemaining = { Params = "FoodPoisonedTicksRemaining", Return = "", Notes = "Sets the number of ticks remaining for food poisoning. Doesn't send foodpoisoning effect to the client, use FoodPoison() for that." },
SetFoodSaturationLevel = { Params = "FoodSaturationLevel", Return = "", Notes = "Sets the food saturation (overcharge of the food level)." },
SetFoodTickTimer = { Params = "FoodTickTimer", Return = "", Notes = "Sets the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." },
- SetGameMode = { Params = "{{eGameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." },
+ SetGameMode = { Params = "{{Globals#GameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." },
SetIsFishing = { Params = "IsFishing, [FloaterEntityID]", Return = "", Notes = "Sets the 'IsFishing' flag for the player. The floater entity ID is expected for the true variant, it can be omitted when IsFishing is false. FIXME: Undefined behavior when multiple fishing rods are used simultanously" },
SetName = { Params = "Name", Return = "", Notes = "Sets the player name. This rename will NOT be visible to any players already in the server who are close enough to see this player." },
- SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed (as reported by the 1.6.1+ protocols)" },
+ SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client, if appropriate." },
SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." },
- SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed (as reported by the 1.6.1+ protocols)" },
+ SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed, relative to the game default speed. The default value is 1.3. Sends the updated speed to the client, if appropriate." },
SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" },
- TossItem = { Params = "DraggedItem, [Amount], [CreateType], [CreateDamage]", Return = "", Notes = "FIXME: This function will be rewritten, avoid it. It tosses an item, either from the inventory, dragged in hand (while in UI window) or a newly created one." },
XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." },
},
Constants =
{
- DROWNING_TICKS = { Notes = "Number of ticks per heart of damage when drowning (zero AirLevel)" },
EATING_TICKS = { Notes = "Number of ticks required for consuming an item." },
- MAX_AIR_LEVEL = { Notes = "The maximum air level value. AirLevel gets reset to this value when the player exits water." },
MAX_FOOD_LEVEL = { Notes = "The maximum food level value. When the food level is at this value, the player cannot eat." },
MAX_HEALTH = { Notes = "The maximum health value" },
},
@@ -1667,7 +1817,7 @@ a_Player:OpenWindow(Window);
]],
Functions =
{
- Call = { Params = "Function name, [All the parameters divided with commas]", Notes = "This function allows you to call a function from another plugin. It can only use pass: integers, booleans, strings and usertypes (cPlayer, cEntity, cCuboid, etc.)." },
+ Call = { Params = "Function name, [All the parameters divided with commas]", Notes = "(<b>OBSOLETE</b>) This function allows you to call a function from another plugin. It can only use pass: integers, booleans, strings and usertypes (cPlayer, cEntity, cCuboid, etc.).<br /><br /><b>This function is obsolete and unsafe, use {{cPluginManager}}:CallPlugin() instead!</b>" },
GetDirectory = { Return = "string", Notes = "Returns the name of the folder where the plugin's files are. (APIDump)" },
GetLocalDirectory = { Notes = "OBSOLETE use GetLocalFolder instead." },
GetLocalFolder = { Return = "string", Notes = "Returns the path where the plugin's files are. (Plugins/APIDump)" },
@@ -1711,14 +1861,15 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
BindCommand =
{
- { Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
- { Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
+ { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
+ { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
},
BindConsoleCommand =
{
- { Params = "Command, Callback, HelpString", Return = "", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
- { Params = "Command, Callback, HelpString", Return = "", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
+ { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
+ { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
},
+ CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." },
DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." },
ExecuteCommand = { Params = "{{cPlayer|Player}}, CommandStr", Return = "bool", Notes = "Executes the command as if given by the specified Player. Checks permissions. Returns true if executed." },
FindPlugins = { Params = "", Return = "", Notes = "Refreshes the list of plugins to include all folders inside the Plugins folder (potentially new disabled plugins)" },
@@ -1730,14 +1881,17 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
GetCommandPermission = { Params = "Command", Return = "Permission", Notes = "Returns the permission needed for executing the specified command" },
GetCurrentPlugin = { Params = "", Return = "{{cPlugin}}", Notes = "Returns the {{cPlugin}} object for the calling plugin. This is the same object that the Initialize function receives as the argument." },
GetNumPlugins = { Params = "", Return = "number", Notes = "Returns the number of plugins, including the disabled ones" },
- GetPlugin = { Params = "PluginName", Return = "{{cPlugin}}", Notes = "Returns a plugin handle of the specified plugin" },
+ GetPlugin = { Params = "PluginName", Return = "{{cPlugin}}", Notes = "(<b>DEPRECATED, UNSAFE</b>) Returns a plugin handle of the specified plugin, or nil if such plugin is not loaded. Note thatdue to multithreading the handle is not guaranteed to be safe for use when stored - a single-plugin reload may have been triggered in the mean time for the requested plugin." },
+ GetPluginsPath = { Params = "", Return = "string", Notes = "Returns the path where the individual plugin folders are located. Doesn't include the path separator at the end of the returned string." },
IsCommandBound = { Params = "Command", Return = "bool", Notes = "Returns true if in-game Command is already bound (by any plugin)" },
IsConsoleCommandBound = { Params = "Command", Return = "bool", Notes = "Returns true if console Command is already bound (by any plugin)" },
LoadPlugin = { Params = "PluginFolder", Return = "", Notes = "(<b>DEPRECATED</b>) Loads a plugin from the specified folder. NOTE: Loading plugins may be an unsafe operation and may result in a deadlock or a crash. This API is deprecated and might be removed." },
+ LogStackTrace = { Params = "", Return = "", Notes = "(STATIC) Logs a current stack trace of the Lua engine to the server console log. Same format as is used when the plugin fails." },
ReloadPlugins = { Params = "", Return = "", Notes = "Reloads all active plugins" },
},
Constants =
{
+ HOOK_BLOCK_SPREAD = { Notes = "Called when a block spreads based on world conditions" },
HOOK_BLOCK_TO_PICKUPS = { Notes = "Called when a block has been dug and is being converted to pickups. The server has provided the default pickups and the plugins may modify them." },
HOOK_CHAT = { Notes = "Called when a client sends a chat message that is not a command. The plugin may modify the chat message" },
HOOK_CHUNK_AVAILABLE = { Notes = "Called when a chunk is loaded or generated and becomes available in the {{cWorld|world}}." },
@@ -1808,7 +1962,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
Functions =
{
Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." },
- BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server." },
+ BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server. No formatting is done by the server." },
+ BroadcastChatFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." },
+ BroadcastChatFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." },
+ BroadcastChatInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." },
+ BroadcastChatSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." },
+ BroadcastChatWarning = { Params = "Message", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." },
+ CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil." },
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for the given player." },
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
@@ -1857,6 +2017,36 @@ end
},
}, -- cRoot
+ cScoreboard =
+ {
+ Desc = [[
+ This class manages the objectives and teams of a single world.
+ ]],
+ Functions =
+ {
+ AddPlayerScore = { Params = "Name, Type, Value", Return = "", Notes = "Adds a value to all player scores of the specified objective type." },
+ ForEachObjective = { Params = "CallBackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each objective in the scoreboard. Returns true if all objectives have been processed (including when there are zero objectives), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cObjective|Objective}}, [CallbackData])</pre> The callback should return false or no value to continue with the next objective, or true to abort the enumeration." },
+ ForEachTeam = { Params = "CallBackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each team in the scoreboard. Returns true if all teams have been processed (including when there are zero teams), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cObjective|Objective}}, [CallbackData])</pre> The callback should return false or no value to continue with the next team, or true to abort the enumeration." },
+ GetNumObjectives = { Params = "", Return = "number", Notes = "Returns the nuber of registered objectives." },
+ GetNumTeams = { Params = "", Return = "number", Notes = "Returns the number of registered teams." },
+ GetObjective = { Params = "string", Return = "{{cObjective}}", Notes = "Returns the objective with the specified name." },
+ GetObjectiveIn = { Params = "DisplaySlot", Return = "{{cObjective}}", Notes = "Returns the objective in the specified display slot. Can be nil." },
+ GetTeam = { Params = "string", Return = "{{cTeam}}", Notes = "Returns the team with the specified name." },
+ RegisterObjective = { Params = "Name, DisplayName, Type", Return = "{{cObjective}}", Notes = "Registers a new scoreboard objective. Returns the {{cObjective}} instance, nil on error." },
+ RegisterTeam = { Params = "Name, DisplayName, Prefix, Suffix", Return = "{{cTeam}}", Notes = "Registers a new team. Returns the {{cTeam}} instance, nil on error." },
+ RemoveObjective = { Params = "string", Return = "bool", Notes = "Removes the objective with the specified name. Returns true if operation was successful." },
+ RemoveTeam = { Params = "string", Return = "bool", Notes = "Removes the team with the specified name. Returns true if operation was successful." },
+ SetDisplay = { Params = "Name, DisplaySlot", Return = "", Notes = "Updates the currently displayed objective." },
+ },
+ Constants =
+ {
+ dsCount = { Notes = "" },
+ dsList = { Notes = "" },
+ dsName = { Notes = "" },
+ dsSidebar = { Notes = "" },
+ },
+ }, -- cScoreboard
+
cServer =
{
Desc = [[
@@ -1877,32 +2067,44 @@ end
},
}, -- cServer
+ cTeam =
+ {
+ Desc = [[
+ This class manages a single player team.
+ ]],
+ Functions =
+ {
+ AddPlayer = { Params = "string", Returns = "bool", Notes = "Adds a player to this team. Returns true if the operation was successful." },
+ AllowsFriendlyFire = { Params = "", Return = "bool", Notes = "Returns whether team friendly fire is allowed." },
+ CanSeeFriendlyInvisible = { Params = "", Return = "bool", Notes = "Returns whether players can see invisible teammates." },
+ HasPlayer = { Params = "string", Returns = "bool", Notes = "Returns whether the specified player is a member of this team." },
+ GetDisplayName = { Params = "", Return = "string", Notes = "Returns the display name of the team." },
+ GetName = { Params = "", Return = "string", Notes = "Returns the internal name of the team." },
+ GetNumPlayers = { Params = "", Return = "number", Notes = "Returns the number of registered players." },
+ GetPrefix = { Params = "", Return = "string", Notes = "Returns the prefix prepended to the names of the members of this team." },
+ RemovePlayer = { Params = "string", Returns = "bool", Notes = "Removes the player with the specified name from this team. Returns true if the operation was successful." },
+ Reset = { Params = "", Returns = "", Notes = "Removes all players from this team." },
+ GetSuffix = { Params = "", Return = "string", Notes = "Returns the suffix appended to the names of the members of this team." },
+ SetCanSeeFriendlyInvisible = { Params = "bool", Return = "", Notes = "Set whether players can see invisible teammates." },
+ SetDisplayName = { Params = "string", Return = "", Notes = "Sets the display name of this team. (i.e. what will be shown to the players)" },
+ SetFriendlyFire = { Params = "bool", Return = "", Notes = "Sets whether team friendly fire is allowed." },
+ SetPrefix = { Params = "string", Return = "", Notes = "Sets the prefix prepended to the names of the members of this team." },
+ SetSuffix = { Params = "string", Return = "", Notes = "Sets the suffix appended to the names of the members of this team." },
+ },
+ }, -- cTeam
+
cTNTEntity =
{
Desc = "This class manages a TNT entity.",
Functions =
{
- GetCounterTime = { Return = "number", Notes = "Returns the time until the entity explodes." },
- GetMaxFuseTime = { Return = "number", Notes = "Returns how long the fuse was." },
+ Explode = { Return = "", Notes = "Explode the tnt." },
+ GetFuseTicks = { Return = "number", Notes = "Returns the fuse ticks until the tnt will explode." },
+ SetFuseTicks = { Return = "number", Notes = "Set the fuse ticks until the tnt will explode." },
},
Inherits = "cEntity",
},
- cTracer =
- {
- Desc = [[
- A cTracer object is used to trace lines in the world. One thing you can use the cTracer for, is
- tracing what block a player is looking at, but you can do more with it if you want.</p>
- <p>
- The cTracer is still a work in progress.</p>
- <p>
- See also the {{cLineBlockTracer}} class for an alternative approach using callbacks.
- ]],
- Functions =
- {
- },
- }, -- cTracer
-
cWebAdmin =
{
Desc = "",
@@ -1999,22 +2201,34 @@ end
Functions =
{
+ AreCommandBlocksEnabled = { Params = "", Return = "bool", Notes = "Returns whether command blocks are enabled on the (entire) server" },
BroadcastBlockAction = { Params = "BlockX, BlockY, BlockZ, ActionByte1, ActionByte2, BlockType, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Broadcasts the BlockAction packet to all clients who have the appropriate chunk loaded (except ExcludeClient). The contents of the packet are specified by the parameters for the call, the blocktype needn't match the actual block that is present in the world data at the specified location." },
- BroadcastChat = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the Message to all players in this world, except the optional ExceptClient" },
+ BroadcastChat = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the Message to all players in this world, except the optional ExcludeClient. No formatting is done by the server." },
+ BroadcastChatDeath = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Gray [DEATH] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For when a player dies." },
+ BroadcastChatFailure = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." },
+ BroadcastChatFatal = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." },
+ 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." },
+ 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" },
CastThunderbolt = { Params = "X, Y, Z", Return = "", Notes = "Creates a thunderbolt at the specified coords" },
ChangeWeather = { Params = "", Return = "", Notes = "Forces the weather to change in the next game tick. Weather is changed according to the normal rules: wSunny <-> wRain <-> wStorm" },
- CreateProjectile = { Params = "X, Y, Z, {{cProjectileEntity|ProjectileKind}}, {{cEntity|Creator}}, [{{Vector3d|Speed}}]", Return = "", Notes = "Creates a new projectile of the specified kind at the specified coords. The projectile's creator is set to Creator (may be nil). Optional speed indicates the initial speed for the projectile." },
+ ChunkStay = { Params = "ChunkCoordTable, OnChunkAvailable, OnAllChunksAvailable", Return = "", Notes = "Queues the specified chunks to be loaded or generated and calls the specified callbacks once they are loaded. ChunkCoordTable is an arra-table of chunk coords, each coord being a table of 2 numbers: { {Chunk1x, Chunk1z}, {Chunk2x, Chunk2z}, ...}. When any of those chunks are made available (including being available at the start of this call), the OnChunkAvailable() callback is called. When all the chunks are available, the OnAllChunksAvailable() callback is called. The function signatures are: <pre class=\"prettyprint lang-lua\">function OnChunkAvailable(ChunkX, ChunkZ)\nfunction OnAllChunksAvailable()</pre> All return values from the callbacks are ignored." },
+ CreateProjectile = { Params = "X, Y, Z, {{cProjectileEntity|ProjectileKind}}, {{cEntity|Creator}}, {{cItem|Originating Item}}, [{{Vector3d|Speed}}]", Return = "", Notes = "Creates a new projectile of the specified kind at the specified coords. The projectile's creator is set to Creator (may be nil). The item that created the projectile entity, commonly the {{cPlayer|player}}'s currently equipped item, is used at present for fireworks to correctly set their entity metadata. It is not used for any other projectile. Optional speed indicates the initial speed for the projectile." },
DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." },
DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." },
DoWithBlockEntityAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
DoWithChestAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a chest at the specified coords, calls the CallbackFunction with the {{cChestEntity}} parameter representing the chest. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The function returns false if there is no chest, or if there is, it returns the bool value that the callback has returned." },
+ DoWithCommandBlockAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a command block at the specified coords, calls the CallbackFunction with the {{cCommandBlockEntity}} parameter representing the command block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cCommandBlockEntity|CommandBlockEntity}}, [CallbackData])</pre> The function returns false if there is no command block, or if there is, it returns the bool value that the callback has returned." },
DoWithDispenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dispenser at the specified coords, calls the CallbackFunction with the {{cDispenserEntity}} parameter representing the dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDispenserEntity|DispenserEntity}}, [CallbackData])</pre> The function returns false if there is no dispenser, or if there is, it returns the bool value that the callback has returned." },
DoWithDropSpenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper or a dispenser at the specified coords, calls the CallbackFunction with the {{cDropSpenserEntity}} parameter representing the dropper or dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropSpenserEntity|DropSpenserEntity}}, [CallbackData])</pre> Note that this can be used to access both dispensers and droppers in a similar way. The function returns false if there is neither dispenser nor dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithDropperAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper at the specified coords, calls the CallbackFunction with the {{cDropperEntity}} parameter representing the dropper. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropperEntity|DropperEntity}}, [CallbackData])</pre> The function returns false if there is no dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithEntityByID = { Params = "EntityID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If an entity with the specified ID exists, calls the callback with the {{cEntity}} parameter representing the entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The function returns false if the entity was not found, and it returns the same bool value that the callback has returned if the entity was found." },
+ DoWithFlowerPotAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a flower pot at the specified coords, calls the CallbackFunction with the {{cFlowerPotEntity}} parameter representing the flower pot. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFlowerPotEntity|FlowerPotEntity}}, [CallbackData])</pre> The function returns false if there is no flower pot, or if there is, it returns the bool value that the callback has returned." },
DoWithFurnaceAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a furnace at the specified coords, calls the CallbackFunction with the {{cFurnaceEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The function returns false if there is no furnace, or if there is, it returns the bool value that the callback has returned." },
+ DoWithMobHeadAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a mob head at the specified coords, calls the CallbackFunction with the {{cMobHeadEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cMobHeadEntity|MobHeadEntity}}, [CallbackData])</pre> The function returns false if there is no mob head, or if there is, it returns the bool value that the callback has returned." },
DoWithNoteBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a note block at the specified coords, calls the CallbackFunction with the {{cNoteEntity}} parameter representing the note block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cNoteEntity|NoteEntity}}, [CallbackData])</pre> The function returns false if there is no note block, or if there is, it returns the bool value that the callback has returned." },
DoWithPlayer = { Params = "PlayerName, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of the specified name (exact match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
FastSetBlock =
@@ -2050,11 +2264,13 @@ end
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." },
+ GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
+ 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." },
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. " },
GetSignLines = { Params = "BlockX, BlockY, BlockZ", Return = "IsValid, [Line1, Line2, Line3, Line4]", Notes = "Returns true and the lines of a sign at the specified coords, or false if there is no sign at the coords." },
GetSpawnX = { Params = "", Return = "number", Notes = "Returns the X coord of the default spawn" },
GetSpawnY = { Params = "", Return = "number", Notes = "Returns the Y coord of the default spawn" },
@@ -2086,9 +2302,15 @@ end
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." },
QueueTask = { Params = "TaskFunction", Return = "", Notes = "Queues the specified function to be executed in the tick thread. This is the primary means of interaction with a cWorld from the WebAdmin page handlers (see {{WebWorldThreads}}). The function signature is <pre class=\"pretty-print lang-lua\">function()</pre>All return values from the function are ignored. Note that this function is actually called *after* the QueueTask() function returns. Note that it is unsafe to store references to MCServer objects, such as entities, across from the caller to the task handler function; store the EntityID instead." },
+ QueueUnloadUnusedChunks = { Params = "", Return = "", Notes = "Queues a cTask that unloads chunks that are no longer needed and are saved." },
RegenerateChunk = { Params = "ChunkX, ChunkZ", Return = "", Notes = "Queues the specified chunk to be re-generated, overwriting the current data. To queue a chunk for generating only if it doesn't exist, use the GenerateChunk() instead." },
ScheduleTask = { Params = "DelayTicks, TaskFunction", Return = "", Notes = "Queues the specified function to be executed in the world's tick thread after a the specified number of ticks. This enables operations to be queued for execution in the future. The function signature is <pre class=\"pretty-print lang-lua\">function({{cWorld|World}})</pre>All return values from the function are ignored. Note that it is unsafe to store references to MCServer objects, such as entities, across from the caller to the task handler function; store the EntityID instead." },
SendBlockTo = { Params = "BlockX, BlockY, BlockZ, {{cPlayer|Player}}", Return = "", Notes = "Sends the block at the specified coords to the specified player's client, as an UpdateBlock packet." },
+ SetAreaBiome = {
+ { Params = "MinX, MaxX, MinZ, MaxZ, EMCSBiome", Return = "bool", Notes = "Sets the biome in the rectangular area specified. Returns true if successful, false if any of the chunks were unloaded." },
+ { Params = "{{cCuboid|Cuboid}}, EMCSBiome", Return = "bool", Notes = "Sets the biome in the cuboid specified. Returns true if successful, false if any of the chunks were unloaded. The cuboid needn't be sorted." },
+ },
+ SetBiomeAt = { Params = "BlockX, BlockZ, EMCSBiome", Return = "bool", Notes = "Sets the biome at the specified block coords. Returns true if successful, false otherwise." },
SetBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, replaces the block entities for the previous block type, creates a new block entity for the new block, if appropriate, and wakes up the simulators. This is the preferred way to set blocks, as opposed to FastSetBlock(), which is only to be used under special circumstances." },
SetBlockMeta =
{
@@ -2096,6 +2318,10 @@ end
{ Params = "{{Vector3i|BlockCoords}}, BlockMeta", Return = "", Notes = "Sets the meta for the block at the specified coords." },
},
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." },
+ SetShouldUseChatPrefixes = { Params = "", Return = "ShouldUse (bool)", Notes = "Sets whether coloured chat prefixes such as [INFO] is used with the SendMessageXXX() or BroadcastChatXXX(), or simply the entire message is coloured in the respective colour." },
+ ShouldUseChatPrefixes = { Params = "", Return = "bool", Notes = "Returns whether coloured chat prefixes are prepended to chat messages or the entire message is simply coloured." },
SetSignLines = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as UpdateSign()." },
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." },
@@ -2109,9 +2335,8 @@ end
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" },
- SpawnPrimedTNT = { Params = "X, Y, Z, FuseTimeSecs, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse time. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
+ SpawnPrimedTNT = { Params = "X, Y, Z, FuseTicks, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse ticks. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." },
- UnloadUnusedChunks = { Params = "", Return = "", Notes = "Unloads chunks that are no longer needed, and are saved. NOTE: This API is deprecated and will be removed soon." },
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as SetSignLiens()" },
UseBlockEntity = { Params = "{{cPlayer|Player}}, BlockX, BlockY, BlockZ", Return = "", Notes = "Makes the specified Player use the block entity at the specified coords (open chest UI, etc.) If the cords are in an unloaded chunk or there's no block entity, ignores the call." },
WakeUpSimulators = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Wakes up the simulators for the specified block." },
@@ -2464,122 +2689,6 @@ end
} -- AdditionalInfo
}, -- tolua
- Vector3d =
- {
- Desc = [[
- A Vector3d object uses double precision floating point values to describe a point in 3D space.</p>
- <p>
- See also {{Vector3f}} for single-precision floating point 3D coords and {{Vector3i}} for integer
- 3D coords.
- ]],
- Functions =
- {
- constructor =
- {
- { Params = "{{Vector3f}}", Return = "Vector3d", Notes = "Creates a new Vector3d object by copying the coords from the given Vector3f." },
- { Params = "", Return = "Vector3d", Notes = "Creates a new Vector3d object with all its coords set to 0." },
- { Params = "X, Y, Z", Return = "Vector3d", Notes = "Creates a new Vector3d object with its coords set to the specified values." },
- },
- operator_div = { Params = "number", Return = "Vector3d", Notes = "Returns a new Vector3d with each coord divided by the specified number." },
- operator_mul = { Params = "number", Return = "Vector3d", Notes = "Returns a new Vector3d with each coord multiplied." },
- operator_sub = { Params = "Vector3d", Return = "Vector3d", Notes = "Returns a new Vector3d containing the difference between this object and the specified vector." },
- operator_plus = {Params = "Vector3d", Return = "Vector3d", Notes = "Returns a new Vector3d containing the sum of this vector and the specified vector" },
- Cross = { Params = "Vector3d", Return = "Vector3d", Notes = "Returns a new Vector3d that is a {{http://en.wikipedia.org/wiki/Cross_product|cross product}} of this vector and the specified vector." },
- Dot = { Params = "Vector3d", Return = "number", Notes = "Returns the dot product of this vector and the specified vector." },
- Equals = { Params = "Vector3d", Return = "bool", Notes = "Returns true if this vector is exactly equal to the specified vector." },
- Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of the vector." },
- LineCoeffToXYPlane = { Params = "Vector3d, Z", Return = "number", Notes = "Returns the coefficient for the line from the specified vector through this vector to reach the specified Z coord. The result satisfies the following equation: (this + Result * (Param - this)).z = Z. Returns the NO_INTERSECTION constant if there's no intersection." },
- LineCoeffToXZPlane = { Params = "Vector3d, Y", Return = "number", Notes = "Returns the coefficient for the line from the specified vector through this vector to reach the specified Y coord. The result satisfies the following equation: (this + Result * (Param - this)).y = Y. Returns the NO_INTERSECTION constant if there's no intersection." },
- LineCoeffToYZPlane = { Params = "Vector3d, X", Return = "number", Notes = "Returns the coefficient for the line from the specified vector through this vector to reach the specified X coord. The result satisfies the following equation: (this + Result * (Param - this)).x = X. Returns the NO_INTERSECTION constant if there's no intersection." },
- Normalize = { Params = "", Return = "", Notes = "Changes this vector so that it keeps current direction but is exactly 1 unit long. FIXME: Fails for a zero vector." },
- NormalizeCopy = { Params = "", Return = "Vector3d", Notes = "Returns a new vector that has the same directino as this but is exactly 1 unit long. FIXME: Fails for a zero vector." },
- Set = { Params = "X, Y, Z", Return = "", Notes = "Sets all the coords in this object." },
- SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison. " },
- },
- Constants =
- {
- EPS = { Notes = "The max difference between two coords for which the coords are assumed equal (in LineCoeffToXYPlane() et al)." },
- NO_INTERSECTION = { Notes = "Special return value for the LineCoeffToXYPlane() et al meaning that there's no intersectino with the plane." },
- },
- Variables =
- {
- x = { Type = "number", Notes = "The X coord of the vector." },
- y = { Type = "number", Notes = "The Y coord of the vector." },
- z = { Type = "number", Notes = "The Z coord of the vector." },
- },
- }, -- Vector3d
-
- Vector3f =
- {
- Desc = [[
- A Vector3f object uses floating point values to describe a point in space.</p>
- <p>
- See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3i}} for integer
- 3D coords.
- ]],
- Functions =
- {
- constructor =
- {
- { Params = "", Return = "Vector3f", Notes = "Creates a new Vector3f object with zero coords" },
- { Params = "x, y, z", Return = "Vector3f", Notes = "Creates a new Vector3f object with the specified coords" },
- { Params = "Vector3f", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified vector" },
- { Params = "{{Vector3d}}", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified {{Vector3d}}" },
- { Params = "{{Vector3i}}", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified {{Vector3i}}" },
- },
- operator_mul =
- {
- { Params = "number", Return = "Vector3f", Notes = "Returns a new Vector3f object that has each of its coords multiplied by the specified number" },
- { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that has each of its coords multiplied by the respective coord of the specified vector." },
- },
- operator_plus = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the vector sum of this vector and the specified vector." },
- operator_sub = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the vector differrence between this vector and the specified vector." },
- Cross = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the cross product of this vector and the specified vector." },
- Dot = { Params = "Vector3f", Return = "number", Notes = "Returns the dot product of this vector and the specified vector." },
- Equals = { Params = "Vector3f", Return = "bool", Notes = "Returns true if the specified vector is exactly equal to this vector." },
- Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector" },
- Normalize = { Params = "", Return = "", Notes = "Normalizes this vector (makes it 1 unit long while keeping the direction). FIXME: Fails for zero vectors." },
- NormalizeCopy = { Params = "", Return = "Vector3f", Notes = "Returns a copy of this vector that is normalized (1 unit long while keeping the same direction). FIXME: Fails for zero vectors." },
- Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once." },
- SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
- },
- Variables =
- {
- x = { Type = "number", Notes = "The X coord of the vector." },
- y = { Type = "number", Notes = "The Y coord of the vector." },
- z = { Type = "number", Notes = "The Z coord of the vector." },
- },
- }, -- Vector3f
-
- Vector3i =
- {
- Desc = [[
- A Vector3i object uses integer values to describe a point in space.</p>
- <p>
- See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3f}} for
- single-precision floating point 3D coords.
- ]],
- Functions =
- {
- constructor =
- {
- { Params = "", Return = "Vector3i", Notes = "Creates a new Vector3i object with zero coords." },
- { Params = "x, y, z", Return = "Vector3i", Notes = "Creates a new Vector3i object with the specified coords." },
- { Params = "{{Vector3d}}", Return = "Vector3i", Notes = "Creates a new Vector3i object with coords copied and floor()-ed from the specified {{Vector3d}}." },
- },
- Equals = { Params = "Vector3i", Return = "bool", Notes = "Returns true if this vector is exactly the same as the specified vector." },
- Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector." },
- Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once" },
- SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
- },
- Variables =
- {
- x = { Type = "number", Notes = "The X coord of the vector." },
- y = { Type = "number", Notes = "The Y coord of the vector." },
- z = { Type = "number", Notes = "The Z coord of the vector." },
- },
- }, -- Vector3i
-
Globals =
{
Desc = [[
@@ -2588,7 +2697,8 @@ end
]],
Functions =
{
- AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFace|face}}"},
+ AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFaces|face}}"},
+ BlockFaceToString = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "string", Notes = "Returns the string representation of the {{Globals#BlockFaces|eBlockFace}} constant. Uses the axis-direction-based names, such as BLOCK_FACE_XP." },
BlockStringToType = {Params = "BlockTypeString", Return = "BLOCKTYPE", Notes = "Returns the block type parsed from the given string"},
ClickActionToString = {Params = "{{Globals#ClickAction|ClickAction}}", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"},
DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "},
@@ -2602,14 +2712,37 @@ end
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, use LOGWARNING() instead"},
- 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)"},
+ {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console. The severity is converted from the CompositeChat's MessageType."},
+ },
+ LOGERROR =
+ {
+ {Params = "string", Notes = "Logs a text into the server console using 'error' severity (black text on red background)"},
+ {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable 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)"},
+ {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable 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, use LOGWARNING() instead"},
+ {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"},
+ },
+ LOGWARNING =
+ {
+ {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"},
+ {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'warning' severity (red text)"},
+ },
+ MirrorBlockFaceY = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after mirroring it around the Y axis (or rotating 180 degrees around it)." },
NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"},
NormalizeAngleDegrees = { Params = "AngleDegrees", Return = "AngleDegrees", Notes = "Returns the angle, wrapped into the [-180, +180) range." },
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"},
+ RotateBlockFaceCCW = { 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 counter-clockwise." },
+ 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)"},
StringToBiome = {Params = "string", Return = "{{Globals#BiomeTypes|BiomeType}}", Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value"},
@@ -2656,7 +2789,13 @@ end
Include = "^BLOCK_FACE_.*",
TextBefore = [[
These constants are used to describe individual faces of the block. They are used when the
- client is interacting with a block, or when the {{cLineBlockTracer}} hits a block, etc.
+ client is interacting with a block in the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}},
+ {{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}}, {{OnPlayerLeftClick|HOOK_PLAYER_LEFT_CLICK}},
+ {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}}, {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}},
+ {{OnPlayerRightClick|HOOK_PLAYER_RIGHT_CLICK}}, {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}},
+ {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}}, {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}},
+ and {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} hooks, or when the {{cLineBlockTracer}} hits a
+ block, etc.
]],
},
ClickAction =
@@ -2714,6 +2853,14 @@ end
data provided with the explosions, such as the exploding {{cCreeper|creeper}} entity or the
{{Vector3i|coords}} of the exploding bed.
]],
+ },
+ SpreadSource =
+ {
+ Include = "^ss.*",
+ TextBefore = [[
+ 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.
+ ]],
}
},
}, -- Globals
@@ -2722,16 +2869,16 @@ end
IgnoreClasses =
{
- "coroutine",
- "debug",
- "io",
- "math",
- "package",
- "os",
- "string",
- "table",
- "g_Stats",
- "g_TrackedPages",
+ "^coroutine$",
+ "^debug$",
+ "^io$",
+ "^math$",
+ "^package$",
+ "^os$",
+ "^string$",
+ "^table$",
+ "^g_Stats$",
+ "^g_TrackedPages$",
},
IgnoreFunctions =
@@ -2741,11 +2888,11 @@ end
"Globals.xpcall",
"Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace
"sqlite3.__newindex",
- "%a+\.__%a+", -- AnyClass.__Anything
- "%a+\.\.collector", -- AnyClass..collector
- "%a+\.new", -- AnyClass.new
- "%a+.new_local", -- AnyClass.new_local
- "%a+.delete", -- AnyClass.delete
+ "%a+%.__%a+", -- AnyClass.__Anything
+ "%a+%.%.collector", -- AnyClass..collector
+ "%a+%.new", -- AnyClass.new
+ "%a+%.new_local", -- AnyClass.new_local
+ "%a+%.delete", -- AnyClass.delete
-- Functions global in the APIDump plugin:
"CreateAPITables",
@@ -2783,6 +2930,7 @@ end
-- No sorting is provided for these, they will be output in the same order as defined here
{ FileName = "Writing-a-MCServer-plugin.html", Title = "Writing a MCServer plugin" },
{ FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" },
+ { FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" },
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
}
} ;
diff --git a/MCServer/Plugins/APIDump/APIDump.deproj b/MCServer/Plugins/APIDump/APIDump.deproj
index e78974901..0e6fcd325 100644
--- a/MCServer/Plugins/APIDump/APIDump.deproj
+++ b/MCServer/Plugins/APIDump/APIDump.deproj
@@ -7,6 +7,9 @@
<filename>Classes\BlockEntities.lua</filename>
</file>
<file>
+ <filename>Classes\Geometry.lua</filename>
+ </file>
+ <file>
<filename>Hooks\OnBlockToPickups.lua</filename>
</file>
<file>
diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
index cf258160c..de42f66df 100644
--- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
+++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
@@ -196,9 +196,11 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
Inherits = "cBlockEntity",
Functions =
{
- EjectRecord = { Params = "", Return = "", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0)" },
+ EjectRecord = { Params = "", Return = "bool", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0). Returns true if pickup ejected." },
GetRecord = { Params = "", Return = "number", Notes = "Returns the record currently present. Zero for no record, E_ITEM_*_DISC for records." },
- PlayRecord = { Params = "", Return = "", Notes = "Plays the currently present record. No action if there's no current record." },
+ IsPlayingRecord = { Params = "", Return = "bool", Notes = "Returns true if the jukebox is playing a record." },
+ IsRecordItem = { Params = "ItemType", Return = "bool", Notes = "Returns true if the specified item is a record that can be played." },
+ PlayRecord = { Params = "RecordItemType", Return = "bool", Notes = "Plays the specified Record. Return false if the parameter isn't a playable Record (E_ITEM_XXX_DISC). If there is a record already playing, ejects it first." },
SetRecord = { Params = "number", Return = "", Notes = "Sets the currently present record. Use zero for no record, or E_ITEM_*_DISC for records." },
},
}, -- cJukeboxEntity
@@ -236,6 +238,20 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
Inherits = "cBlockEntity";
}, -- cSignEntity
+
+ cFlowerPotEntity =
+ {
+ Desc = [[
+ This class represents a flower pot entity in the world.
+ ]],
+ Functions =
+ {
+ IsItemInPot = { Params = "", Return = "bool", Notes = "Is a flower in the pot?" },
+ GetItem = { Params = "", Return = "{{cItem|Item}}", Notes = "Returns the item in the flower pot." },
+ SetItem = { Params = "{{cItem|Item}}", Return = "", Notes = "Set the item in the flower pot" },
+ },
+ Inherits = "cBlockEntity";
+ }, -- cFlowerPotEntity
}
diff --git a/MCServer/Plugins/APIDump/Classes/Geometry.lua b/MCServer/Plugins/APIDump/Classes/Geometry.lua
new file mode 100644
index 000000000..9887bfb89
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Classes/Geometry.lua
@@ -0,0 +1,332 @@
+
+-- Geometry.lua
+
+-- Defines the documentation for geometry-related classes:
+-- cBoundingBox, cCuboid, cLineBlockTracer, cTracer, Vector3X
+
+
+
+
+return
+{
+ cBoundingBox =
+ {
+ Desc = [[
+ Represents two sets of coordinates, minimum and maximum for each direction; thus defining an
+ axis-aligned cuboid with floating-point boundaries. It supports operations changing the size and
+ position of the box, as well as querying whether a point or another BoundingBox is inside the box.</p>
+ <p>
+ All the points within the coordinate limits (inclusive the edges) are considered "inside" the box.
+ However, for intersection purposes, if the intersection is "sharp" in any coord (min1 == max2, i. e.
+ zero volume), the boxes are considered non-intersecting.</p>
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "MinX, MaxX, MinY, MaxY, MinZ, MaxZ", Return = "cBoundingBox", Notes = "Creates a new bounding box with the specified edges" },
+ { Params = "{{Vector3d|Min}}, {{Vector3d|Max}}", Return = "cBoundingBox", Notes = "Creates a new bounding box with the coords specified as two vectors" },
+ { Params = "{{Vector3d|Pos}}, Radius, Height", Return = "cBoundingBox", Notes = "Creates a new bounding box from the position given and radius (X/Z) and height. Radius is added from X/Z to calculate the maximum coords and subtracted from X/Z to get the minimum; minimum Y is set to Pos.y and maxumim Y to Pos.y plus Height. This corresponds with how {{cEntity|entities}} are represented in Minecraft." },
+ { Params = "OtherBoundingBox", Return = "cBoundingBox", Notes = "Creates a new copy of the given bounding box. Same result can be achieved by using a simple assignment." },
+ },
+ CalcLineIntersection = { Params = "{{Vector3d|LineStart}}, {{Vector3d|LinePt2}}", Return = "DoesIntersect, LineCoeff, Face", Notes = "Calculates the intersection of a ray (half-line), given by two of its points, with the bounding box. Returns false if the line doesn't intersect the bounding box, or true, together with coefficient of the intersection (how much of the difference between the two ray points is needed to reach the intersection), and the face of the box which is intersected.<br /><b>TODO</b>: Lua binding for this function is wrong atm." },
+ DoesIntersect = { Params = "OtherBoundingBox", Return = "bool", Notes = "Returns true if the two bounding boxes have an intersection of nonzero volume." },
+ Expand = { Params = "ExpandX, ExpandY, ExpandZ", Return = "", Notes = "Expands this bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each axis)." },
+ IsInside =
+ {
+ { Params = "{{Vector3d|Point}}", Return = "bool", Notes = "Returns true if the specified point is inside (including on the edge) of the box." },
+ { Params = "PointX, PointY, PointZ", Return = "bool", Notes = "Returns true if the specified point is inside (including on the edge) of the box." },
+ { Params = "OtherBoundingBox", Return = "bool", Notes = "Returns true if OtherBoundingBox is inside of this box." },
+ { Params = "{{Vector3d|OtherBoxMin}}, {{Vector3d|OtherBoxMax}}", Return = "bool", Notes = "Returns true if the other bounding box, specified by its 2 corners, is inside of this box." },
+ },
+ Move =
+ {
+ { Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Moves the bounding box by the specified offset in each axis" },
+ { Params = "{{Vector3d|Offset}}", Return = "", Notes = "Moves the bounding box by the specified offset in each axis" },
+ },
+ Union = { Params = "OtherBoundingBox", Return = "cBoundingBox", Notes = "Returns the smallest bounding box that contains both OtherBoundingBox and this bounding box. Note that unlike the strict geometrical meaning of \"union\", this operation actually returns a cBoundingBox." },
+ },
+ }, -- cBoundingBox
+
+
+ cCuboid =
+ {
+ Desc = [[
+ cCuboid offers some native support for integral-boundary cuboids. A cuboid internally consists of
+ two {{Vector3i}}-s. By default the cuboid doesn't make any assumptions about the defining points,
+ but for most of the operations in the cCuboid class, the p1 member variable is expected to be the
+ minima and the p2 variable the maxima. The Sort() function guarantees this condition.</p>
+ <p>
+ The Cuboid considers both its edges inclusive.</p>
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "", Return = "cCuboid", Notes = "Creates a new Cuboid object with all-zero coords" },
+ { Params = "OtherCuboid", Return = "cCuboid", Notes = "Creates a new Cuboid object as a copy of OtherCuboid" },
+ { Params = "{{Vector3i|Point1}}, {{Vector3i|Point2}}", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
+ { Params = "X, Y, Z", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified point as both its corners (the cuboid has a size of 1 in each direction)." },
+ { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
+ },
+ Assign =
+ {
+ { Params = "SrcCuboid", Return = "", Notes = "Copies all the coords from the src cuboid to this cuboid. Sort-state is ignored." },
+ { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "", Notes = "Assigns all the coords to the specified values. Sort-state is ignored." },
+ },
+ ClampX = { Params = "MinX, MaxX", Return = "", Notes = "Clamps both X coords into the range provided. Sortedness-agnostic." },
+ ClampY = { Params = "MinY, MaxY", Return = "", Notes = "Clamps both Y coords into the range provided. Sortedness-agnostic." },
+ ClampZ = { Params = "MinZ, MaxZ", Return = "", Notes = "Clamps both Z coords into the range provided. Sortedness-agnostic." },
+ DifX = { Params = "", Return = "number", Notes = "Returns the difference between the two X coords (X-size minus 1). Assumes sorted." },
+ DifY = { Params = "", Return = "number", Notes = "Returns the difference between the two Y coords (Y-size minus 1). Assumes sorted." },
+ DifZ = { Params = "", Return = "number", Notes = "Returns the difference between the two Z coords (Z-size minus 1). Assumes sorted." },
+ DoesIntersect = { Params = "OtherCuboid", Return = "bool", Notes = "Returns true if this cuboid has at least one voxel in common with OtherCuboid. Note that edges are considered inclusive. Assumes both sorted." },
+ Engulf = { Params = "{{Vector3i|Point}}", Return = "", Notes = "If needed, expands the cuboid to include the specified point. Doesn't shrink. Assumes sorted. " },
+ Expand = { Params = "SubMinX, AddMaxX, SubMinY, AddMaxY, SubMinZ, AddMaxZ", Return = "", Notes = "Expands the cuboid by the specified amount in each direction. Works on unsorted cuboids as well. NOTE: this function doesn't check for underflows." },
+ GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the cuboid, in blocks. Note that the volume considers both coords inclusive. Works on unsorted cuboids, too." },
+ IsCompletelyInside = { Params = "OuterCuboid", Return = "bool", Notes = "Returns true if this cuboid is completely inside (in all directions) in OuterCuboid. Assumes both sorted." },
+ IsInside =
+ {
+ { Params = "X, Y, Z", Return = "bool", Notes = "Returns true if the specified point (integral coords) is inside this cuboid. Assumes sorted." },
+ { Params = "{{Vector3i|Point}}", Return = "bool", Notes = "Returns true if the specified point (integral coords) is inside this cuboid. Assumes sorted." },
+ { Params = "{{Vector3d|Point}}", Return = "bool", Notes = "Returns true if the specified point (floating-point coords) is inside this cuboid. Assumes sorted." },
+ },
+ IsSorted = { Params = "", Return = "bool", Notes = "Returns true if this cuboid is sorted" },
+ Move = { Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Adds the specified offsets to each respective coord, effectively moving the Cuboid. Sort-state is ignored and preserved." },
+ Sort = { Params = "", Return = "" , Notes = "Sorts the internal representation so that p1 contains the lesser coords and p2 contains the greater coords." },
+ },
+ Variables =
+ {
+ p1 = { Type = "{{Vector3i}}", Notes = "The first corner. Usually the lesser of the two coords in each set" },
+ p2 = { Type = "{{Vector3i}}", Notes = "The second corner. Usually the larger of the two coords in each set" },
+ },
+ }, -- cCuboid
+
+
+ cLineBlockTracer =
+ {
+ Desc = [[This class provides an easy-to-use interface for tracing lines through individual
+blocks in the world. It will call the provided callbacks according to what events it encounters along the
+way.</p>
+<p>
+For the Lua API, there's only one static function exported that takes all the parameters necessary to do
+the tracing. The Callbacks parameter is a table containing all the functions that will be called upon the
+various events. See below for further information.
+ ]],
+ Functions =
+ {
+ Trace = { Params = "{{cWorld}}, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ", Return = "bool", Notes = "(STATIC) Performs the trace on the specified line. Returns true if the entire trace was processed (no callback returned true)" },
+ },
+
+ AdditionalInfo =
+ {
+ {
+ Header = "Callbacks",
+ Contents = [[
+The Callbacks in the Trace() function is a table that contains named functions. MCServer will call
+individual functions from that table for the events that occur on the line - hitting a block, going out of
+valid world data etc. The following table lists all the available callbacks. If the callback function is
+not defined, MCServer skips it. Each function can return a bool value, if it returns true, the tracing is
+aborted and Trace() returns false.</p>
+<p>
+<table><tr><th>Name</th><th>Parameters</th><th>Notes</th></tr>
+<tr><td>OnNextBlock</td><td>BlockX, BlockY, BlockZ, BlockType, BlockMeta, EntryFace</td>
+ <td>Called when the ray hits a new valid block. The block type and meta is given. EntryFace is one of the
+ BLOCK_FACE_ constants indicating which "side" of the block got hit by the ray.</td></tr>
+<tr><td>OnNextBlockNoData</td><td>BlockX, BlockY, BlockZ, EntryFace</td>
+ <td>Called when the ray hits a new block, but the block is in an unloaded chunk - no valid data is
+ available. Only the coords and the entry face are given.</td></tr>
+<tr><td>OnOutOfWorld</td><td>X, Y, Z</td>
+ <td>Called when the ray goes outside of the world (Y-wise); the coords specify the exact exit point. Note
+ that for other paths than lines (considered for future implementations) the path may leave the world and
+ go back in again later, in such a case this callback is followed by OnIntoWorld() and further
+ OnNextBlock() calls.</td></tr>
+<tr><td>OnIntoWorld</td><td>X, Y, Z</td>
+ <td>Called when the ray enters the world (Y-wise); the coords specify the exact entry point.</td></tr>
+<tr><td>OnNoMoreHits</td><td>&nbsp;</td>
+ <td>Called when the path is sure not to hit any more blocks. This is the final callback, no more
+ callbacks are called after this function. Unlike the other callbacks, this function doesn't have a return
+ value.</td></tr>
+<tr><td>OnNoChunk</td><td>&nbsp;</td>
+ <td>Called when the ray enters a chunk that is not loaded. This usually means that the tracing is aborted.
+ Unlike the other callbacks, this function doesn't have a return value.</td></tr>
+</table>
+ ]],
+ },
+ {
+ Header = "Example",
+ Contents = [[
+<p>The following example is taken from the Debuggers plugin. It is a command handler function for the
+"/spidey" command that creates a line of cobweb blocks from the player's eyes up to 50 blocks away in
+the direction they're looking, but only through the air.
+<pre class="prettyprint lang-lua">
+function HandleSpideyCmd(a_Split, a_Player)
+ local World = a_Player:GetWorld();
+
+ local Callbacks = {
+ OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta)
+ if (a_BlockType ~= E_BLOCK_AIR) then
+ -- abort the trace
+ return true;
+ end
+ World:SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COBWEB, 0);
+ end
+ };
+
+ local EyePos = a_Player:GetEyePosition();
+ local LookVector = a_Player:GetLookVector();
+ LookVector:Normalize(); -- Make the vector 1 m long
+
+ -- Start cca 2 blocks away from the eyes
+ local Start = EyePos + LookVector + LookVector;
+ local End = EyePos + LookVector * 50;
+
+ cLineBlockTracer.Trace(World, Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z);
+
+ return true;
+end
+</pre>
+</p>
+ ]],
+ },
+ }, -- AdditionalInfo
+ }, -- cLineBlockTracer
+
+
+ cTracer =
+ {
+ Desc = [[
+ A cTracer object is used to trace lines in the world. One thing you can use the cTracer for, is
+ tracing what block a player is looking at, but you can do more with it if you want.</p>
+ <p>
+ The cTracer is still a work in progress.</p>
+ <p>
+ See also the {{cLineBlockTracer}} class for an alternative approach using callbacks.
+ ]],
+ Functions =
+ {
+ },
+ }, -- cTracer
+
+
+ Vector3d =
+ {
+ Desc = [[
+ A Vector3d object uses double precision floating point values to describe a point in 3D space.</p>
+ <p>
+ See also {{Vector3f}} for single-precision floating point 3D coords and {{Vector3i}} for integer
+ 3D coords.
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "{{Vector3f}}", Return = "Vector3d", Notes = "Creates a new Vector3d object by copying the coords from the given Vector3f." },
+ { Params = "", Return = "Vector3d", Notes = "Creates a new Vector3d object with all its coords set to 0." },
+ { Params = "X, Y, Z", Return = "Vector3d", Notes = "Creates a new Vector3d object with its coords set to the specified values." },
+ },
+ operator_div = { Params = "number", Return = "Vector3d", Notes = "Returns a new Vector3d with each coord divided by the specified number." },
+ operator_mul = { Params = "number", Return = "Vector3d", Notes = "Returns a new Vector3d with each coord multiplied." },
+ operator_sub = { Params = "Vector3d", Return = "Vector3d", Notes = "Returns a new Vector3d containing the difference between this object and the specified vector." },
+ operator_plus = {Params = "Vector3d", Return = "Vector3d", Notes = "Returns a new Vector3d containing the sum of this vector and the specified vector" },
+ Cross = { Params = "Vector3d", Return = "Vector3d", Notes = "Returns a new Vector3d that is a {{http://en.wikipedia.org/wiki/Cross_product|cross product}} of this vector and the specified vector." },
+ Dot = { Params = "Vector3d", Return = "number", Notes = "Returns the dot product of this vector and the specified vector." },
+ Equals = { Params = "Vector3d", Return = "bool", Notes = "Returns true if this vector is exactly equal to the specified vector." },
+ Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of the vector." },
+ LineCoeffToXYPlane = { Params = "Vector3d, Z", Return = "number", Notes = "Returns the coefficient for the line from the specified vector through this vector to reach the specified Z coord. The result satisfies the following equation: (this + Result * (Param - this)).z = Z. Returns the NO_INTERSECTION constant if there's no intersection." },
+ LineCoeffToXZPlane = { Params = "Vector3d, Y", Return = "number", Notes = "Returns the coefficient for the line from the specified vector through this vector to reach the specified Y coord. The result satisfies the following equation: (this + Result * (Param - this)).y = Y. Returns the NO_INTERSECTION constant if there's no intersection." },
+ LineCoeffToYZPlane = { Params = "Vector3d, X", Return = "number", Notes = "Returns the coefficient for the line from the specified vector through this vector to reach the specified X coord. The result satisfies the following equation: (this + Result * (Param - this)).x = X. Returns the NO_INTERSECTION constant if there's no intersection." },
+ Normalize = { Params = "", Return = "", Notes = "Changes this vector so that it keeps current direction but is exactly 1 unit long. FIXME: Fails for a zero vector." },
+ NormalizeCopy = { Params = "", Return = "Vector3d", Notes = "Returns a new vector that has the same directino as this but is exactly 1 unit long. FIXME: Fails for a zero vector." },
+ Set = { Params = "X, Y, Z", Return = "", Notes = "Sets all the coords in this object." },
+ SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison. " },
+ },
+ Constants =
+ {
+ EPS = { Notes = "The max difference between two coords for which the coords are assumed equal (in LineCoeffToXYPlane() et al)." },
+ NO_INTERSECTION = { Notes = "Special return value for the LineCoeffToXYPlane() et al meaning that there's no intersectino with the plane." },
+ },
+ Variables =
+ {
+ x = { Type = "number", Notes = "The X coord of the vector." },
+ y = { Type = "number", Notes = "The Y coord of the vector." },
+ z = { Type = "number", Notes = "The Z coord of the vector." },
+ },
+ }, -- Vector3d
+
+ Vector3f =
+ {
+ Desc = [[
+ A Vector3f object uses floating point values to describe a point in space.</p>
+ <p>
+ See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3i}} for integer
+ 3D coords.
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "", Return = "Vector3f", Notes = "Creates a new Vector3f object with zero coords" },
+ { Params = "x, y, z", Return = "Vector3f", Notes = "Creates a new Vector3f object with the specified coords" },
+ { Params = "Vector3f", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified vector" },
+ { Params = "{{Vector3d}}", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified {{Vector3d}}" },
+ { Params = "{{Vector3i}}", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified {{Vector3i}}" },
+ },
+ operator_mul =
+ {
+ { Params = "number", Return = "Vector3f", Notes = "Returns a new Vector3f object that has each of its coords multiplied by the specified number" },
+ { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that has each of its coords multiplied by the respective coord of the specified vector." },
+ },
+ operator_plus = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the vector sum of this vector and the specified vector." },
+ operator_sub = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the vector differrence between this vector and the specified vector." },
+ Cross = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the cross product of this vector and the specified vector." },
+ Dot = { Params = "Vector3f", Return = "number", Notes = "Returns the dot product of this vector and the specified vector." },
+ Equals = { Params = "Vector3f", Return = "bool", Notes = "Returns true if the specified vector is exactly equal to this vector." },
+ Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector" },
+ Normalize = { Params = "", Return = "", Notes = "Normalizes this vector (makes it 1 unit long while keeping the direction). FIXME: Fails for zero vectors." },
+ NormalizeCopy = { Params = "", Return = "Vector3f", Notes = "Returns a copy of this vector that is normalized (1 unit long while keeping the same direction). FIXME: Fails for zero vectors." },
+ Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once." },
+ SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
+ },
+ Variables =
+ {
+ x = { Type = "number", Notes = "The X coord of the vector." },
+ y = { Type = "number", Notes = "The Y coord of the vector." },
+ z = { Type = "number", Notes = "The Z coord of the vector." },
+ },
+ }, -- Vector3f
+
+ Vector3i =
+ {
+ Desc = [[
+ A Vector3i object uses integer values to describe a point in space.</p>
+ <p>
+ See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3f}} for
+ single-precision floating point 3D coords.
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "", Return = "Vector3i", Notes = "Creates a new Vector3i object with zero coords." },
+ { Params = "x, y, z", Return = "Vector3i", Notes = "Creates a new Vector3i object with the specified coords." },
+ { Params = "{{Vector3d}}", Return = "Vector3i", Notes = "Creates a new Vector3i object with coords copied and floor()-ed from the specified {{Vector3d}}." },
+ },
+ Equals = { Params = "Vector3i", Return = "bool", Notes = "Returns true if this vector is exactly the same as the specified vector." },
+ Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector." },
+ Move = { Params = "X, Y, Z", Return = "", Notes = "Moves the vector by the specified amount in each axis direction." },
+ Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once" },
+ SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
+ },
+ Variables =
+ {
+ x = { Type = "number", Notes = "The X coord of the vector." },
+ y = { Type = "number", Notes = "The Y coord of the vector." },
+ z = { Type = "number", Notes = "The Z coord of the vector." },
+ },
+ }, -- Vector3i
+}
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua b/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua
new file mode 100644
index 000000000..ed0b5f46f
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua
@@ -0,0 +1,40 @@
+return
+{
+ HOOK_BLOCK_SPREAD =
+ {
+ CalledWhen = "Called when a block spreads based on world conditions",
+ DefaultFnName = "OnBlockSpread", -- also used as pagename
+ Desc = [[
+ This hook is called when a block spreads.</p>
+ <p>
+ The spread carries with it the type of its source - whether it's a block spreads.
+ It also carries the identification of the actual source. The exact type of the identification
+ depends on the source kind:
+ <table>
+ <tr><th>Source</th><th>Notes</th></tr>
+ <tr><td>ssFireSpread</td><td>Fire spreading</td></tr>
+ <tr><td>ssGrassSpread</td><td>Grass spreading</td></tr>
+ <tr><td>ssMushroomSpread</td><td>Mushroom spreading</td></tr>
+ <tr><td>ssMycelSpread</td><td>Mycel spreading</td></tr>
+ <tr><td>ssVineSpread</td><td>Vine spreading</td></tr>
+ </table></p>
+ ]],
+ Params =
+ {
+ { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the block resides" },
+ { 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 = "Source", Type = "eSpreadSource", Notes = "Source of the spread. 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 spread. If the function
+ returns true, no other callback is called for this event and the spread will not occur.
+ ]],
+ }, -- HOOK_BLOCK_SPREAD
+}
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua
index 496e0d751..a3301a8c6 100644
--- a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua
+++ b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua
@@ -5,13 +5,10 @@ return
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.</p>
- <p>
- Note that this callback is not called if the client drops the connection or is kicked by the
- server.</p>
- <p>
- FIXME: There is no callback for "client destroying" that would be called in all circumstances.</p>
+ This hook is called when a client is about to be disconnected from the server, for whatever reason.
+
+ <p><b>Note that this hook will be removed after <1.7 protocol support is removed, as it was originally a hook for
+ the client sending the server a disconnect packet, which no longer happens.</b></p>
]],
Params =
{
@@ -19,9 +16,8 @@ return
{ 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,
+ If the function returns false or no value, MCServer calls other plugins' callbacks for this event.
+ If the function returns true, no other plugins are called for this event. In either case,
the player is disconnected.
]],
}, -- HOOK_DISCONNECT
diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerDestroyed.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerDestroyed.lua
new file mode 100644
index 000000000..dc033197a
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerDestroyed.lua
@@ -0,0 +1,27 @@
+return
+{
+ HOOK_PLAYER_DESTROYED =
+ {
+ CalledWhen = "A player object is about to be destroyed.",
+ DefaultFnName = "OnPlayerDestroyed", -- also used as pagename
+ Desc = [[
+ This function is called before a {{cPlayer|player}} is about to be destroyed.
+ The player has disconnected for whatever reason and is no longer in the server.
+ If a plugin returns true, a leave message is not broadcast, and vice versa.
+ However, whatever the return value, the player object is removed from memory.
+ ]],
+ Params =
+ {
+ { Name = "Player", Type = "{{cPlayer}}", Notes = "The destroyed player" },
+ },
+ Returns = [[
+ If the function returns false or no value, other plugins' callbacks are called and a leave message is broadcast.
+ If the function returns true, no other callbacks are called for this event and no leave message appears. Either way the player is removed internally.
+ ]],
+ }, -- HOOK_PLAYER_DESTROYED
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua
index 00805af7e..dcd16ed00 100644
--- a/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua
+++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua
@@ -9,16 +9,16 @@ return
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.
+ Returning true will block a join message from being broadcast, but otherwise, the player is still allowed to join.
+ 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.
+ If the function returns false or no value, other plugins' callbacks are called and a join message is broadcast. If the function
+ returns true, no other callbacks are called for this event and a join message is not sent. Either way the player is let in.
]],
}, -- HOOK_PLAYER_JOINED
}
diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua
index 85c943721..82d5bb390 100644
--- a/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua
+++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua
@@ -5,7 +5,7 @@ return
CalledWhen = "A player is tossing an item. Plugin may override / refuse.",
DefaultFnName = "OnPlayerTossingItem", -- also used as pagename
Desc = [[
- This hook is called when a {{cPlayer|player}} has tossed an item (Q keypress). The
+ This hook is called when a {{cPlayer|player}} has tossed an item. The
{{cPickup|pickup}} has not been spawned yet. Plugins may disallow the tossing, but in that case they
need to clean up - the player's client already thinks the item has been tossed so the
{{cInventory|inventory}} needs to be re-sent to the player.</p>
@@ -18,8 +18,9 @@ return
},
Returns = [[
If the function returns false or no value, other plugins' callbacks are called and finally MCServer
- creates the pickup for the item and tosses it, using {{cPlayer}}:TossItem. If the function returns
- true, no other callbacks are called for this event and MCServer doesn't toss the item.
+ creates the pickup for the item and tosses it, using {{cPlayer}}:TossHeldItem, {{cPlayer}}:TossEquippedItem,
+ or {{cPlayer}}:TossPickup. If the function returns true, no other callbacks are called for this event
+ and MCServer doesn't toss the item.
]],
}, -- HOOK_PLAYER_TOSSING_ITEM
}
diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua
new file mode 100644
index 000000000..1588d420c
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua
@@ -0,0 +1,24 @@
+return
+{
+ HOOK_PROJECTILE_HIT_BLOCK =
+ {
+ CalledWhen = "A projectile hits a solid block.",
+ DefaultFnName = "OnProjectileHitBlock", -- also used as pagename
+ Desc = [[
+ This hook is called when a {{cProjectileEntity|projectile}} hits a solid block..
+ ]],
+ Params =
+ {
+ { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
+ },
+ 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 projectile flies through block..
+ ]],
+ }, -- HOOK_PROJECTILE_HIT_BLOCK
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua
new file mode 100644
index 000000000..dd949fb46
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua
@@ -0,0 +1,25 @@
+return
+{
+ HOOK_PROJECTILE_HIT_ENTITY =
+ {
+ CalledWhen = "A projectile hits another entity.",
+ DefaultFnName = "OnProjectileHitEntity", -- also used as pagename
+ Desc = [[
+ This hook is called when a {{cProjectileEntity|projectile}} hits another entity.
+ ]],
+ Params =
+ {
+ { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
+ { Name = "Entity", Type = "{{cEntity}}", Notes = "The entity wich was hit." },
+ },
+ 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 projectile flies through the entity.
+ ]],
+ }, -- HOOK_PROJECTILE_HIT_ENTITY
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/SettingUpZeroBrane.html b/MCServer/Plugins/APIDump/SettingUpZeroBrane.html
new file mode 100644
index 000000000..4ebbcb6e6
--- /dev/null
+++ b/MCServer/Plugins/APIDump/SettingUpZeroBrane.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>MCServer - Setting up ZeroBrane Studio</title>
+ <link rel="stylesheet" type="text/css" href="main.css" />
+ <link rel="stylesheet" type="text/css" href="prettify.css" />
+ <script src="prettify.js"></script>
+ <script src="lang-lua.js"></script>
+ <meta charset="UTF-8">
+ </head>
+ <body>
+ <div id="content">
+ <h1>Setting up the ZeroBrane Studio IDE</h1>
+ <p>
+ This article will explain how to set up ZeroBrane Studio, an IDE for writing Lua code, so that you can develop MCServer plugins with the comfort of an IDE.</p>
+
+ <h2><img src="Static/zbs_logo.png" /> About ZeroBrane Studio</h2>
+
+ <p>To quickly introduce ZeroBrane Studio, it is an IDE for writing Lua code. It has the basic features expected of an IDE - it allows you to manage groups of files as a project, you can edit multiple files in a tabbed editor, the code is syntax-highlighted. Code completion, symbol browsing, and more. It also features a Lua debugger that allows you to debug your Lua code within any application that uses Lua and can load Lua packages. It is written using the multiplatform WxWidgets toolkit, and runs on multiple platforms, including Windows, Linux and MacOS.</p>
+ <p>Here's a screenshot of a default ZBS window with the debugger stepping through the code (scaled down):<br />
+ <img src="Static/zbs_workspace.png" /></p>
+ <p>As you can see, you can set breakpoints in the code, inspect variables' values, view the Lua call-stacks.</p>
+ <p>ZBS is open-source, the sources are on GitHub: <a href="https://github.com/pkulchenko/ZeroBraneStudio">https://github.com/pkulchenko/ZeroBraneStudio</a>. The project's homepage is at <a href="http://studio.zerobrane.com/">http://studio.zerobrane.com/</a>.
+
+ <h2><img src="Static/zbs_logo.png" /> First-time setup</h2>
+ <p>Since ZBS is a universal Lua IDE, you need to first set it up so that it is ready for MCS plugin development. For that, you need to download one file, <a href="https://raw.githubusercontent.com/pkulchenko/ZeroBranePackage/master/mcserver.lua">mcserver.lua</a> from the <a href="https://github.com/pkulchenko/ZeroBranePackage">ZBS's plugin repository</a>. Place that file in the "packages" folder inside your ZBS's folder. Note that there are other useful plugins in the repository and you may want to have a look there later on to further customize your ZBS. To install them, simply save them into the same folder.</p>
+ <p>Next you should install the code-completion support specific for MCServer. You should repeat this step from time to time, because the API evolves in time so new functions and classes are added to it quite often. You should have an APIDump plugin in your MCServer installation. Enable the APIDump plugin in the server settings, it's very cheap to keep it enabled and it doesn't cost any performance during normal gameplay. To generate the code-completion support file, enter the <code style="background: #ddd; border: 1px solid #aaa">api</code> command into the server console. This will create a new file, "mcserver_api.lua", next to the MCS executable. Move that file into the "api/lua" subfolder inside your ZBS's folder.</p>
+ <p>After you download the mcserver.lua file and install the completion support, you need to restart ZBS in order for the plugin to load. If there are no errors, you should see two new items in the Project -> Lua Interpreter submenu: "MCServer - debug mode" and "MCServer - release mode". The only difference between the two is which filename they use to launch MCServer - mcserver_debug(.exe) for the debug option and "mcserver(.exe)" for the release option. If you built your own MCServer executable and you built it in debug mode, you should select the debug mode option. In all other cases, including if you downloaded the already-compiled MCServer executable from the internet, you should select the release mode option.</p>
+ <p>For a first time user, it might be a bit overwhelming that there are no GUI settings in the ZBS, yet the IDE is very configurable. There are two files that you edit in order to change settings, either system-wide (all users of the computer share those settings) or user-wide (the settings are only for a specific user of the computer). Those files are regular Lua sources and you can quickly locate them and edit them from within the IDE itself, select Edit -> Preferences -> Settings: XYZ from the menu, with XYZ being either System or User.</p>
+ <p>There is a documentation on most of the settings on ZBS's webpage, have a look at <a href="http://studio.zerobrane.com/documentation.html">http://studio.zerobrane.com/documentation.html</a>, especially the Preferences section. Personally I recommend setting editor.usetabs to true and possibly adjusting the editor.tabwidth, turn off the editor.smartindent feature and for debugging the option debugger.alloweditting should be set to true unless you feel like punishing yourself.</p>
+
+ <h2><img src="Static/zbs_logo.png" /> Project management</h2>
+ <p>ZBS works with projects, it considers all files and subfolder in a specific folder to be a project. There's no need for a special project file nor for adding individual files to the workspace, all files are added automatically. To open a MCS plugin as the project, click the triple-dot button in the Project pane, or select Project -> Project directory -> Choose... from the menu. Browse and select the MCS plugin's folder. ZBS will load all the files in the plugin's folder and you can start editting code.</p>
+ <p>Note that although ZBS allows you to work with subfolders in your plugins (and you should, especially with larger plugins), the current mcserver ZBS plugin will not be able to start debugging unless you have a file open in the editor that is at the root level of the MCS plugin's folder.</p>
+
+ <h2><img src="Static/zbs_logo.png" /> Debugging</h2>
+ <p>You are now ready to debug your code. Before doing that, though, don't forget to save your project files. If you haven't done so already, enable your plugin in the settings.ini file. If you want the program to break at a certain line, it is best to set the breakpoint before starting the program. Set the cursor on the line and hit F9 (or use menu Project -> Toggle Breakpoint) to toggle a breakpoint on that line. Finally, hit F5, or select menu Project -> Start Debugging to launch MCServer under the debugger. The MCServer window comes up and loads your plugin. If the window doesn't come up, inspect the Output pane in ZBS, there are usually two reasons for failure:<ul>
+ <li>Your code in the currently open file has a hard syntax error. These are reported as "Compilation error" in the Output pane, double-click the line to go to the error</li>
+ <li>ZBS cannot find the MCServer executable. Make sure you are editting a file two levels down the folder hierarchy from the MCS executable and that the MCS executable is named properly (mcserver[.exe] or mcserver_debug[.exe]). Also make sure you have selected the right Interpreter (menu Project -> Lua Interpreter).</li>
+ </ul></p>
+ <p>Once running, if the execution hits a breakpoint, the ZBS window will come up and a green arrow is displayed next to the breakpoint line. You can step through the code using F10 (Step Into) and Shift+F10 (Step Over). You can also use the Watch window to inspect variable values, or simply hover your mouse over a variable to display its value in the tooltip. Use the Remote console pane to execute commands directly *inside* the MCServer's plugin context.</p>
+ <p>You can also use the Project -> Break menu item to break into the debugger as soon as possible. You can also set breakpoints while the MCS plugin is running. Note that due to the way in which the debugger is implemented, MCS may execute some more Lua code before the break / breakpoint comes into effect. If MCS is not executing any Lua code in your plugin, it will not break until the plugin code kicks in again. This may result in missed breakpoints and delays before the Break command becomes effective. Therefore it's best to set breakpoints before running the program, or while the program is waiting in another breakpoint.</p>
+ </div>
+ </body>
+</html>
diff --git a/MCServer/Plugins/APIDump/Static/zbs_logo.png b/MCServer/Plugins/APIDump/Static/zbs_logo.png
new file mode 100644
index 000000000..c8d6d6278
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Static/zbs_logo.png
Binary files differ
diff --git a/MCServer/Plugins/APIDump/Static/zbs_workspace.png b/MCServer/Plugins/APIDump/Static/zbs_workspace.png
new file mode 100644
index 000000000..9ce17e35a
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Static/zbs_workspace.png
Binary files differ
diff --git a/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html b/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html
index 0e07cebdf..35c880b00 100644
--- a/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html
+++ b/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html
@@ -20,13 +20,7 @@
<p>
Let us begin. In order to begin development, we must firstly obtain a compiled copy
of MCServer, and make sure that the Core plugin is within the Plugins folder, and activated.
- Core handles much of the MCServer end-user experience and is a necessary component of
- plugin development, as necessary plugin components depend on sone of its functions.
- </p>
- <p>
- Next, we must obtain a copy of CoreMessaging.lua. This can be found
- <a href="https://raw.github.com/mc-server/MCServer/master/MCServer/Plugins/MagicCarpet/coremessaging.lua">here.</a>
- This is used to provide messaging support that is compliant with MCServer standards.
+ Core handles much of the MCServer end-user experience and gameplay will be very bland without it.
</p>
<h2>Creating the basic template</h2>
<p>
@@ -35,18 +29,17 @@
Format it like so:
</p>
<pre class="prettyprint lang-lua">
-local PLUGIN
+PLUGIN = nil
function Initialize(Plugin)
- Plugin:SetName("DerpyPlugin")
+ Plugin:SetName("NewPlugin")
Plugin:SetVersion(1)
- PLUGIN = Plugin
-
-- Hooks
-
- local PluginManager = cPluginManager:Get()
- -- Command bindings
+
+ PLUGIN = Plugin -- NOTE: only needed if you want OnDisable() to use GetName() or something like that
+
+ -- Command Bindings
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
return true
@@ -63,7 +56,8 @@ end
<li><b>Plugin:SetName</b> sets the name of the plugin.</li>
<li><b>Plugin:SetVersion</b> sets the revision number of the plugin. This must be an integer.</li>
<li><b>LOG</b> logs to console a message, in this case, it prints that the plugin was initialised.</li>
- <li>The <b>PLUGIN</b> variable just stores this plugin's object, so GetName() can be called in OnDisable (as no Plugin parameter is passed there, contrary to Initialize).</li>
+ <li>The <b>PLUGIN</b> variable just stores this plugin's object, so GetName() can be called in OnDisable (as no Plugin parameter is passed there, contrary to Initialize).
+ This global variable is only needed if you want to know the plugin details (name, etc.) when shutting down.</li>
<li><b>function OnDisable</b> is called when the plugin is disabled, commonly when the server is shutting down. Perform cleanup and logging here.</li>
</ul>
Be sure to return true for this function, else MCS thinks you plugin had failed to initialise and prints a stacktrace with an error message.
@@ -84,7 +78,7 @@ end
To register a hook, insert the following code template into the "-- Hooks" area in the previous code example.
</p>
<pre class="prettyprint lang-lua">
-cPluginManager:AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
+cPluginManager.AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
</pre>
<p>
What does this code do?
@@ -102,10 +96,7 @@ function Initialize(Plugin)
Plugin:SetName("DerpyPlugin")
Plugin:SetVersion(1)
- cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
-
- local PluginManager = cPluginManager:Get()
- -- Command bindings
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
return true
@@ -127,10 +118,10 @@ end
</p>
<pre class="prettyprint lang-lua">
-- ADD THIS IF COMMAND DOES NOT REQUIRE A PARAMETER (/explode)
-PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " - Description of command")
+cPluginManager.BindCommand("/commandname", "permissionnode", FunctionToCall, " - Description of command")
-- ADD THIS IF COMMAND DOES REQUIRE A PARAMETER (/explode Notch)
-PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
+cPluginManager.BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
</pre>
<p>
What does it do, and why are there two?
@@ -167,21 +158,23 @@ PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " ~
a message. Again, see the API documentation for fuller details. But, you ask, how <i>do</i> we send a message to the client?
</p>
<p>
- Remember that copy of CoreMessaging.lua that we downloaded earlier? Make sure that file is in your plugin folder, along with the main.lua file you are typing
- your code in. Since MCS brings all the files together on JIT compile, we don't need to worry about requiring any files or such. Simply follow the below examples:
+ There are dedicated functions used for sending a player formatted messages. By format, I refer to coloured prefixes/coloured text (depending on configuration)
+ that clearly categorise what type of message a player is being sent. For example, an informational message has a yellow coloured [INFO] prefix, and a warning message
+ has a rose coloured [WARNING] prefix. A few of the most used functions are listed here, but see the API docs for more details. Look in the cRoot, cWorld, and cPlayer sections
+ for functions that broadcast to the entire server, the whole world, and a single player, respectively.
</p>
<pre class="prettyprint lang-lua">
-- Format: §yellow[INFO] §white%text% (yellow [INFO], white text following it)
-- Use: Informational message, such as instructions for usage of a command
-SendMessage(Player, "Usage: /explode [player]")
+Player:SendMessageInfo("Usage: /explode [player]")
-- Format: §green[INFO] §white%text% (green [INFO] etc.)
-- Use: Success message, like when a command executes successfully
-SendMessageSuccess(Player, "Notch was blown up!")
+Player:SendMessageSuccess("Notch was blown up!")
-- Format: §rose[INFO] §white%text% (rose coloured [INFO] etc.)
-- Use: Failure message, like when a command was entered correctly but failed to run, such as when the destination player wasn't found in a /tp command
-SendMessageFailure(Player, "Player Salted was not found")
+Player:SendMessageFailure("Player Salted was not found")
</pre>
<p>
Those are the basics. If you want to output text to the player for a reason other than the three listed above, and you want to colour the text, simply concatenate
@@ -197,8 +190,7 @@ function Initialize(Plugin)
Plugin:SetName("DerpyPluginThatBlowsPeopleUp")
Plugin:SetVersion(9001)
- local PluginManager = cPluginManager:Get()
- PluginManager:BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
+ cPluginManager.BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
cPluginManager:AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup)
diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua
index bd509dcb6..52199740b 100644
--- a/MCServer/Plugins/APIDump/main_APIDump.lua
+++ b/MCServer/Plugins/APIDump/main_APIDump.lua
@@ -7,68 +7,22 @@
-- Global variables:
-g_Plugin = nil;
-g_PluginFolder = "";
-g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
-g_Stats = -- Statistics about the documentation
-{
- NumTotalClasses = 0,
- NumUndocumentedClasses = 0,
- NumTotalFunctions = 0,
- NumUndocumentedFunctions = 0,
- NumTotalConstants = 0,
- NumUndocumentedConstants = 0,
- NumTotalVariables = 0,
- NumUndocumentedVariables = 0,
- NumTotalHooks = 0,
- NumUndocumentedHooks = 0,
- NumTrackedLinks = 0,
- NumInvalidLinks = 0,
-}
+local g_Plugin = nil
+local g_PluginFolder = ""
+local g_Stats = {}
+local g_TrackedPages = {}
-function Initialize(Plugin)
- g_Plugin = Plugin;
-
- Plugin:SetName("APIDump");
- Plugin:SetVersion(1);
-
- LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
-
- g_PluginFolder = Plugin:GetLocalFolder();
-
- -- Load the API descriptions from the Classes and Hooks subfolders:
- if (g_APIDesc.Classes == nil) then
- g_APIDesc.Classes = {};
- end
- if (g_APIDesc.Hooks == nil) then
- g_APIDesc.Hooks = {};
- end
- LoadAPIFiles("/Classes/", g_APIDesc.Classes);
- LoadAPIFiles("/Hooks/", g_APIDesc.Hooks);
-
- -- dump all available API functions and objects:
- -- DumpAPITxt();
-
- -- Dump all available API object in HTML format into a subfolder:
- DumpAPIHtml();
-
- LOG("APIDump finished");
+local function LoadAPIFiles(a_Folder, a_DstTable)
+ assert(type(a_Folder) == "string")
+ assert(type(a_DstTable) == "table")
- return true
-end
-
-
-
-
-
-function LoadAPIFiles(a_Folder, a_DstTable)
local Folder = g_PluginFolder .. a_Folder;
- for idx, fnam in ipairs(cFile:GetFolderContents(Folder)) do
+ for _, fnam in ipairs(cFile:GetFolderContents(Folder)) do
local FileName = Folder .. fnam;
-- We only want .lua files from the folder:
if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then
@@ -89,45 +43,7 @@ end
-function DumpAPITxt()
- LOG("Dumping all available functions to API.txt...");
- function dump (prefix, a, Output)
- for i, v in pairs (a) do
- if (type(v) == "table") then
- if (GetChar(i, 1) ~= ".") then
- if (v == _G) then
- -- LOG(prefix .. i .. " == _G, CYCLE, ignoring");
- elseif (v == _G.package) then
- -- LOG(prefix .. i .. " == _G.package, ignoring");
- else
- dump(prefix .. i .. ".", v, Output)
- end
- end
- elseif (type(v) == "function") then
- if (string.sub(i, 1, 2) ~= "__") then
- table.insert(Output, prefix .. i .. "()");
- end
- end
- end
- end
-
- local Output = {};
- dump("", _G, Output);
-
- table.sort(Output);
- local f = io.open("API.txt", "w");
- for i, n in ipairs(Output) do
- f:write(n, "\n");
- end
- f:close();
- LOG("API.txt written.");
-end
-
-
-
-
-
-function CreateAPITables()
+local function CreateAPITables()
--[[
We want an API table of the following shape:
local API = {
@@ -194,7 +110,7 @@ function CreateAPITables()
-- Member variables:
local SetField = a_ClassObj[".set"] or {};
if ((a_ClassObj[".get"] ~= nil) and (type(a_ClassObj[".get"]) == "table")) then
- for k, v in pairs(a_ClassObj[".get"]) do
+ for k in pairs(a_ClassObj[".get"]) do
if (SetField[k] == nil) then
-- It is a read-only variable, add it as a constant:
table.insert(res.Constants, {Name = k, Value = ""});
@@ -235,7 +151,7 @@ local function WriteArticles(f)
<p>The following articles provide various extra information on plugin development</p>
<ul>
]]);
- for i, extra in ipairs(g_APIDesc.ExtraPages) do
+ for _, extra in ipairs(g_APIDesc.ExtraPages) do
local SrcFileName = g_PluginFolder .. "/" .. extra.FileName;
if (cFile:Exists(SrcFileName)) then
local DstFileName = "API/" .. extra.FileName;
@@ -255,20 +171,125 @@ end
-local function WriteClasses(f, a_API, a_ClassMenu)
- f:write([[
- <a name="classes"><h2>Class index</h2></a>
- <p>The following classes are available in the MCServer Lua scripting language:
- <ul>
- ]]);
- for i, cls in ipairs(a_API) do
- f:write("<li><a href=\"", cls.Name, ".html\">", cls.Name, "</a></li>\n");
- WriteHtmlClass(cls, a_API, a_ClassMenu);
+-- Make a link out of anything with the special linkifying syntax {{link|title}}
+local function LinkifyString(a_String, a_Referrer)
+ assert(a_Referrer ~= nil);
+ assert(a_Referrer ~= "");
+
+ --- Adds a page to the list of tracked pages (to be checked for existence at the end)
+ local function AddTrackedPage(a_PageName)
+ local Pg = (g_TrackedPages[a_PageName] or {});
+ table.insert(Pg, a_Referrer);
+ g_TrackedPages[a_PageName] = Pg;
end
- f:write([[
- </ul></p>
+
+ --- Creates the HTML for the specified link and title
+ 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 "<a href=\"" .. Link .. "\">" .. Title .. "</a>";
+ 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 "<a href=\"" .. Link .. "\">" .. Title .. "</a>";
+ end
+ -- Anchor in another page:
+ local PageName = Link:sub(1, idxHash - 1);
+ AddTrackedPage(PageName);
+ return "<a href=\"" .. PageName .. ".html#" .. Link:sub(idxHash + 1) .. "\">" .. Title .. "</a>";
+ end
+ -- Link without anchor:
+ AddTrackedPage(Link);
+ return "<a href=\"" .. Link .. ".html\">" .. Title .. "</a>";
+ end
+
+ -- Linkify the strings using the CreateLink() function:
+ 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
+
+
+
+
+
+local function WriteHtmlHook(a_Hook, a_HookNav)
+ local fnam = "API/" .. a_Hook.DefaultFnName .. ".html";
+ local f, error = io.open(fnam, "w");
+ if (f == nil) then
+ LOG("Cannot write \"" .. fnam .. "\": \"" .. error .. "\".");
+ return;
+ end
+ local HookName = a_Hook.DefaultFnName;
+
+ f:write([[<!DOCTYPE html><html>
+ <head>
+ <title>MCServer API - ]], HookName, [[ Hook</title>
+ <link rel="stylesheet" type="text/css" href="main.css" />
+ <link rel="stylesheet" type="text/css" href="prettify.css" />
+ <script src="prettify.js"></script>
+ <script src="lang-lua.js"></script>
+ </head>
+ <body>
+ <div id="content">
+ <header>
+ <h1>]], a_Hook.Name, [[</h1>
<hr />
+ </header>
+ <table><tr><td style="vertical-align: top;">
+ Index:<br />
+ <a href='index.html#articles'>Articles</a><br />
+ <a href='index.html#classes'>Classes</a><br />
+ <a href='index.html#hooks'>Hooks</a><br />
+ <br />
+ Quick navigation:<br />
]]);
+ f:write(a_HookNav);
+ f:write([[
+ </td><td style="vertical-align: top;"><p>
+ ]]);
+ f:write(LinkifyString(a_Hook.Desc, HookName));
+ f:write("</p>\n<hr /><h1>Callback function</h1>\n<p>The default name for the callback function is ");
+ f:write(a_Hook.DefaultFnName, ". It has the following signature:\n");
+ f:write("<pre class=\"prettyprint lang-lua\">function ", HookName, "(");
+ if (a_Hook.Params == nil) then
+ a_Hook.Params = {};
+ end
+ for i, param in ipairs(a_Hook.Params) do
+ if (i > 1) then
+ f:write(", ");
+ end
+ f:write(param.Name);
+ end
+ f:write(")</pre>\n<hr /><h1>Parameters:</h1>\n<table><tr><th>Name</th><th>Type</th><th>Notes</th></tr>\n");
+ for _, param in ipairs(a_Hook.Params) do
+ f:write("<tr><td>", param.Name, "</td><td>", LinkifyString(param.Type, HookName), "</td><td>", LinkifyString(param.Notes, HookName), "</td></tr>\n");
+ end
+ f:write("</table>\n<p>" .. (a_Hook.Returns or "") .. "</p>\n\n");
+ f:write([[<hr /><h1>Code examples</h1><h2>Registering the callback</h2>]]);
+ f:write("<pre class=\"prettyprint lang-lua\">\n");
+ f:write([[cPluginManager:AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]);
+ f:write("</pre>\n\n");
+ local Examples = a_Hook.CodeExamples or {};
+ for _, example in ipairs(Examples) do
+ f:write("<h2>", (example.Title or "<i>missing Title</i>"), "</h2>\n");
+ f:write("<p>", (example.Desc or "<i>missing Desc</i>"), "</p>\n");
+ f:write("<pre class=\"prettyprint lang-lua\">", (example.Code or "<i>missing Code</i>"), "\n</pre>\n\n");
+ end
+ f:write([[</td></tr></table></div><script>prettyPrint();</script></body></html>]]);
+ f:close();
end
@@ -294,7 +315,7 @@ local function WriteHooks(f, a_Hooks, a_UndocumentedHooks, a_HookNav)
<th>Called when</th>
</tr>
]]);
- for i, hook in ipairs(a_Hooks) do
+ for _, hook in ipairs(a_Hooks) do
if (hook.DefaultFnName == nil) then
-- The hook is not documented yet
f:write(" <tr>\n <td>" .. hook.Name .. "</td>\n <td><i>(No documentation yet)</i></td>\n </tr>\n");
@@ -314,162 +335,13 @@ end
-function DumpAPIHtml()
- LOG("Dumping all available functions and constants to API subfolder...");
-
- LOG("Copying static files..");
- cFile:CreateFolder("API/Static");
- local localFolder = g_Plugin:GetLocalFolder();
- for idx, fnam in ipairs(cFile:GetFolderContents(localFolder .. "/Static")) do
- cFile:Delete("API/Static/" .. fnam);
- cFile:Copy(localFolder .. "/Static/" .. fnam, "API/Static/" .. fnam);
- end
-
- LOG("Creating API tables...");
- local API, Globals = CreateAPITables();
- local Hooks = {};
- local UndocumentedHooks = {};
-
- -- Sort the classes by name:
- LOG("Sorting...");
- table.sort(API,
- function (c1, c2)
- return (string.lower(c1.Name) < string.lower(c2.Name));
- end
- );
-
- g_Stats.NumTotalClasses = #API;
-
- -- Add Globals into the API:
- Globals.Name = "Globals";
- table.insert(API, Globals);
-
- -- Extract hook constants:
- for name, obj in pairs(cPluginManager) do
- 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
- table.sort(Hooks,
- function(Hook1, Hook2)
- return (Hook1.Name < Hook2.Name);
- end
- );
-
- -- Read in the descriptions:
- LOG("Reading descriptions...");
- ReadDescriptions(API);
- ReadHooks(Hooks);
-
- -- Create the output folder
- if not(cFile:IsFolder("API")) then
- cFile:CreateFolder("API");
- end
-
- -- Create a "class index" file, write each class as a link to that file,
- -- then dump class contents into class-specific file
- LOG("Writing HTML files...");
- local f = io.open("API/index.html", "w");
- if (f == nil) then
- LOGINFO("Cannot output HTML API: " .. err);
- return;
- end
-
- -- Create a class navigation menu that will be inserted into each class file for faster navigation (#403)
- local ClassMenuTab = {};
- for idx, cls in ipairs(API) do
- table.insert(ClassMenuTab, "<a href='");
- table.insert(ClassMenuTab, cls.Name);
- table.insert(ClassMenuTab, ".html'>");
- table.insert(ClassMenuTab, cls.Name);
- table.insert(ClassMenuTab, "</a><br />");
- end
- local ClassMenu = table.concat(ClassMenuTab, "");
-
- -- Create a hook navigation menu that will be inserted into each hook file for faster navigation(#403)
- local HookNavTab = {};
- for idx, hook in ipairs(Hooks) do
- table.insert(HookNavTab, "<a href='");
- table.insert(HookNavTab, hook.DefaultFnName);
- table.insert(HookNavTab, ".html'>");
- table.insert(HookNavTab, (hook.Name:gsub("^HOOK_", ""))); -- remove the "HOOK_" part of the name
- table.insert(HookNavTab, "</a><br />");
- end
- local HookNav = table.concat(HookNavTab, "");
-
- -- Write the HTML file:
- f:write([[<!DOCTYPE html>
- <html>
- <head>
- <title>MCServer API - Index</title>
- <link rel="stylesheet" type="text/css" href="main.css" />
- </head>
- <body>
- <div id="content">
- <header>
- <h1>MCServer API - Index</h1>
- <hr />
- </header>
- <p>The API reference is divided into the following sections:</p>
- <ul>
- <li><a href="#articles">Articles</a></li>
- <li><a href="#classes">Class index</a></li>
- <li><a href="#hooks">Hooks</a></li>
- <li><a href="#docstats">Documentation statistics</a></li>
- </ul>
- <hr />
- ]]);
-
- WriteArticles(f);
- WriteClasses(f, API, ClassMenu);
- WriteHooks(f, Hooks, UndocumentedHooks, HookNav);
-
- -- Copy the static files to the output folder:
- local StaticFiles =
- {
- "main.css",
- "prettify.js",
- "prettify.css",
- "lang-lua.js",
- };
- for idx, fnam in ipairs(StaticFiles) do
- cFile:Delete("API/" .. fnam);
- cFile:Copy(g_Plugin:GetLocalFolder() .. "/" .. fnam, "API/" .. fnam);
- end
-
- -- List the documentation problems:
- LOG("Listing leftovers...");
- ListUndocumentedObjects(API, UndocumentedHooks);
- ListUnexportedObjects();
- ListMissingPages();
-
- WriteStats(f);
-
- f:write([[ </ul>
- </div>
- </body>
-</html>]]);
- f:close();
-
- LOG("API subfolder written");
-end
-
-
-
-
-
-function ReadDescriptions(a_API)
+local function ReadDescriptions(a_API)
-- Returns true if the class of the specified name is to be ignored
local function IsClassIgnored(a_ClsName)
if (g_APIDesc.IgnoreClasses == nil) then
return false;
end
- for i, name in ipairs(g_APIDesc.IgnoreClasses) do
+ for _, name in ipairs(g_APIDesc.IgnoreClasses) do
if (a_ClsName:match(name)) then
return true;
end
@@ -487,7 +359,7 @@ function ReadDescriptions(a_API)
return false;
end
local FnName = a_ClassName .. "." .. a_FnName;
- for i, name in ipairs(g_APIDesc.IgnoreFunctions) do
+ for _, name in ipairs(g_APIDesc.IgnoreFunctions) do
if (FnName:match(name)) then
return true;
end
@@ -500,7 +372,7 @@ function ReadDescriptions(a_API)
if (g_APIDesc.IgnoreConstants == nil) then
return false;
end;
- for i, name in ipairs(g_APIDesc.IgnoreConstants) do
+ for _, name in ipairs(g_APIDesc.IgnoreConstants) do
if (a_CnName:match(name)) then
return true;
end
@@ -513,7 +385,7 @@ function ReadDescriptions(a_API)
if (g_APIDesc.IgnoreVariables == nil) then
return false;
end;
- for i, name in ipairs(g_APIDesc.IgnoreVariables) do
+ for _, name in ipairs(g_APIDesc.IgnoreVariables) do
if (a_VarName:match(name)) then
return true;
end
@@ -523,7 +395,7 @@ function ReadDescriptions(a_API)
-- Remove ignored classes from a_API:
local APICopy = {};
- for i, cls in ipairs(a_API) do
+ for _, cls in ipairs(a_API) do
if not(IsClassIgnored(cls.Name)) then
table.insert(APICopy, cls);
end
@@ -533,14 +405,14 @@ function ReadDescriptions(a_API)
end;
-- Process the documentation for each class:
- for i, cls in ipairs(a_API) do
+ for _, cls in ipairs(a_API) do
-- Initialize default values for each class:
cls.ConstantGroups = {};
cls.NumConstantsInGroups = 0;
cls.NumConstantsInGroupsForDescendants = 0;
-- Rename special functions:
- for j, fn in ipairs(cls.Functions) do
+ for _, fn in ipairs(cls.Functions) do
if (fn.Name == ".call") then
fn.DocID = "constructor";
fn.Name = "() <i>(constructor)</i>";
@@ -570,7 +442,7 @@ function ReadDescriptions(a_API)
-- Process inheritance:
if (APIDesc.Inherits ~= nil) then
- for j, icls in ipairs(a_API) do
+ for _, icls in ipairs(a_API) do
if (icls.Name == APIDesc.Inherits) then
table.insert(icls.Descendants, cls);
cls.Inherits = icls;
@@ -590,7 +462,7 @@ function ReadDescriptions(a_API)
if (APIDesc.Functions ~= nil) then
-- Assign function descriptions:
- for j, func in ipairs(cls.Functions) do
+ for _, func in ipairs(cls.Functions) do
local FnName = func.DocID or func.Name;
local FnDesc = APIDesc.Functions[FnName];
if (FnDesc == nil) then
@@ -606,7 +478,7 @@ function ReadDescriptions(a_API)
AddFunction(func.Name, FnDesc.Params, FnDesc.Return, FnDesc.Notes);
else
-- Multiple function overloads
- for k, desc in ipairs(FnDesc) do
+ for _, desc in ipairs(FnDesc) do
AddFunction(func.Name, desc.Params, desc.Return, desc.Notes);
end -- for k, desc - FnDesc[]
end
@@ -617,7 +489,7 @@ function ReadDescriptions(a_API)
-- Replace functions with their described and overload-expanded versions:
cls.Functions = DoxyFunctions;
else -- if (APIDesc.Functions ~= nil)
- for j, func in ipairs(cls.Functions) do
+ for _, func in ipairs(cls.Functions) do
local FnName = func.DocID or func.Name;
if not(IsFunctionIgnored(cls.Name, FnName)) then
table.insert(cls.UndocumentedFunctions, FnName);
@@ -627,7 +499,7 @@ function ReadDescriptions(a_API)
if (APIDesc.Constants ~= nil) then
-- Assign constant descriptions:
- for j, cons in ipairs(cls.Constants) do
+ for _, cons in ipairs(cls.Constants) do
local CnDesc = APIDesc.Constants[cons.Name];
if (CnDesc == nil) then
-- Not documented
@@ -640,7 +512,7 @@ function ReadDescriptions(a_API)
end
end -- for j, cons
else -- if (APIDesc.Constants ~= nil)
- for j, cons in ipairs(cls.Constants) do
+ for _, cons in ipairs(cls.Constants) do
if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then
table.insert(cls.UndocumentedConstants, cons.Name);
end
@@ -649,7 +521,7 @@ function ReadDescriptions(a_API)
-- Assign member variables' descriptions:
if (APIDesc.Variables ~= nil) then
- for j, var in ipairs(cls.Variables) do
+ for _, var in ipairs(cls.Variables) do
local VarDesc = APIDesc.Variables[var.Name];
if (VarDesc == nil) then
-- Not documented
@@ -664,7 +536,7 @@ function ReadDescriptions(a_API)
end
end -- for j, var
else -- if (APIDesc.Variables ~= nil)
- for j, var in ipairs(cls.Variables) do
+ for _, var in ipairs(cls.Variables) do
if not(IsVariableIgnored(cls.Name .. "." .. var.Name)) then
table.insert(cls.UndocumentedVariables, var.Name);
end
@@ -682,8 +554,8 @@ function ReadDescriptions(a_API)
group.Include = { group.Include };
end
local NumInGroup = 0;
- for idx, incl in ipairs(group.Include or {}) do
- for cidx, cons in ipairs(cls.Constants) do
+ for _, incl in ipairs(group.Include or {}) do
+ for _, cons in ipairs(cls.Constants) do
if ((cons.Group == nil) and cons.Name:match(incl)) then
cons.Group = group;
table.insert(group.Constants, cons);
@@ -709,7 +581,7 @@ function ReadDescriptions(a_API)
-- Remove grouped constants from the normal list:
local NewConstants = {};
- for idx, cons in ipairs(cls.Constants) do
+ for _, cons in ipairs(cls.Constants) do
if (cons.Group == nil) then
table.insert(NewConstants, cons);
end
@@ -725,18 +597,18 @@ function ReadDescriptions(a_API)
cls.UndocumentedVariables = {};
cls.Variables = cls.Variables or {};
g_Stats.NumUndocumentedClasses = g_Stats.NumUndocumentedClasses + 1;
- for j, func in ipairs(cls.Functions) do
+ for _, func in ipairs(cls.Functions) do
local FnName = func.DocID or func.Name;
if not(IsFunctionIgnored(cls.Name, FnName)) then
table.insert(cls.UndocumentedFunctions, FnName);
end
end -- for j, func - cls.Functions[]
- for j, cons in ipairs(cls.Constants) do
+ for _, cons in ipairs(cls.Constants) do
if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then
table.insert(cls.UndocumentedConstants, cons.Name);
end
end -- for j, cons - cls.Constants[]
- for j, var in ipairs(cls.Variables) do
+ for _, var in ipairs(cls.Variables) do
if not(IsConstantIgnored(cls.Name .. "." .. var.Name)) then
table.insert(cls.UndocumentedVariables, var.Name);
end
@@ -745,7 +617,7 @@ function ReadDescriptions(a_API)
-- Remove ignored functions:
local NewFunctions = {};
- for j, fn in ipairs(cls.Functions) do
+ for _, fn in ipairs(cls.Functions) do
if (not(IsFunctionIgnored(cls.Name, fn.Name))) then
table.insert(NewFunctions, fn);
end
@@ -768,7 +640,7 @@ function ReadDescriptions(a_API)
-- Remove ignored constants:
local NewConstants = {};
- for j, cn in ipairs(cls.Constants) do
+ for _, cn in ipairs(cls.Constants) do
if (not(IsFunctionIgnored(cls.Name, cn.Name))) then
table.insert(NewConstants, cn);
end
@@ -784,7 +656,7 @@ function ReadDescriptions(a_API)
-- Remove ignored member variables:
local NewVariables = {};
- for j, var in ipairs(cls.Variables) do
+ for _, var in ipairs(cls.Variables) do
if (not(IsVariableIgnored(cls.Name .. "." .. var.Name))) then
table.insert(NewVariables, var);
end
@@ -800,7 +672,7 @@ function ReadDescriptions(a_API)
end -- for i, cls
-- Sort the descendants lists:
- for i, cls in ipairs(a_API) do
+ for _, cls in ipairs(a_API) do
table.sort(cls.Descendants,
function(c1, c2)
return (c1.Name < c2.Name);
@@ -813,7 +685,7 @@ end
-function ReadHooks(a_Hooks)
+local function ReadHooks(a_Hooks)
--[[
a_Hooks = {
{ Name = "HOOK_1"},
@@ -822,7 +694,7 @@ function ReadHooks(a_Hooks)
};
We want to add hook descriptions to each hook in this array
--]]
- for i, hook in ipairs(a_Hooks) do
+ for _, hook in ipairs(a_Hooks) do
local HookDesc = g_APIDesc.Hooks[hook.Name];
if (HookDesc ~= nil) then
for key, val in pairs(HookDesc) do
@@ -837,63 +709,10 @@ end
--- Make a link out of anything with the special linkifying syntax {{link|title}}
-function LinkifyString(a_String, a_Referrer)
- assert(a_Referrer ~= nil);
- assert(a_Referrer ~= "");
-
- --- Adds a page to the list of tracked pages (to be checked for existence at the end)
- local function AddTrackedPage(a_PageName)
- local Pg = (g_TrackedPages[a_PageName] or {});
- table.insert(Pg, a_Referrer);
- g_TrackedPages[a_PageName] = Pg;
- end
-
- --- Creates the HTML for the specified link and title
- 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 "<a href=\"" .. Link .. "\">" .. Title .. "</a>";
- 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 "<a href=\"" .. Link .. "\">" .. Title .. "</a>";
- end
- -- Anchor in another page:
- local PageName = Link:sub(1, idxHash - 1);
- AddTrackedPage(PageName);
- return "<a href=\"" .. PageName .. ".html#" .. Link:sub(idxHash + 1) .. "\">" .. Title .. "</a>";
- end
- -- Link without anchor:
- AddTrackedPage(Link);
- return "<a href=\"" .. Link .. ".html\">" .. Title .. "</a>";
- end
-
- -- Linkify the strings using the CreateLink() function:
- 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
-
-
-
-
-
-function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
+local function WriteHtmlClass(a_ClassAPI, a_ClassMenu)
local cf, err = io.open("API/" .. a_ClassAPI.Name .. ".html", "w");
if (cf == nil) then
+ LOGINFO("Cannot write HTML API for class " .. a_ClassAPI.Name .. ": " .. err)
return;
end
@@ -907,7 +726,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
cf:write("<h2>Functions inherited from ", a_InheritedName, "</h2>\n");
end
cf:write("<table>\n<tr><th>Name</th><th>Parameters</th><th>Return value</th><th>Notes</th></tr>\n");
- for i, func in ipairs(a_Functions) do
+ for _, func in ipairs(a_Functions) do
cf:write("<tr><td>", func.Name, "</td>\n");
cf:write("<td>", LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)), "</td>\n");
cf:write("<td>", LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)), "</td>\n");
@@ -918,7 +737,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
local function WriteConstantTable(a_Constants, a_Source)
cf:write("<table>\n<tr><th>Name</th><th>Value</th><th>Notes</th></tr>\n");
- for i, cons in ipairs(a_Constants) do
+ for _, cons in ipairs(a_Constants) do
cf:write("<tr><td>", cons.Name, "</td>\n");
cf:write("<td>", cons.Value, "</td>\n");
cf:write("<td>", LinkifyString(cons.Notes or "", a_Source), "</td></tr>\n");
@@ -941,7 +760,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
WriteConstantTable(a_Constants, Source);
end
- for k, group in pairs(a_ConstantGroups) do
+ for _, group in pairs(a_ConstantGroups) do
if ((a_InheritedName == nil) or group.ShowInDescendants) then
cf:write("<a name='", group.Name, "'><p>");
cf:write(LinkifyString(group.TextBefore or "", Source));
@@ -961,7 +780,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
end
cf:write("<table><tr><th>Name</th><th>Type</th><th>Notes</th></tr>\n");
- for i, var in ipairs(a_Variables) do
+ for _, var in ipairs(a_Variables) do
cf:write("<tr><td>", var.Name, "</td>\n");
cf:write("<td>", LinkifyString(var.Type or "<i>(undocumented)</i>", a_InheritedName or a_ClassAPI.Name), "</td>\n");
cf:write("<td>", LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name), "</td>\n </tr>\n");
@@ -974,7 +793,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
return;
end
cf:write("<ul>");
- for i, desc in ipairs(a_Descendants) do
+ for _, desc in ipairs(a_Descendants) do
cf:write("<li><a href=\"", desc.Name, ".html\">", desc.Name, "</a>");
WriteDescendants(desc.Descendants);
cf:write("</li>\n");
@@ -1025,7 +844,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
local HasConstants = (#a_ClassAPI.Constants > 0) or (a_ClassAPI.NumConstantsInGroups > 0);
local HasFunctions = (#a_ClassAPI.Functions > 0);
local HasVariables = (#a_ClassAPI.Variables > 0);
- for idx, cls in ipairs(InheritanceChain) do
+ for _, cls in ipairs(InheritanceChain) do
HasConstants = HasConstants or (#cls.Constants > 0) or (cls.NumConstantsInGroupsForDescendants > 0);
HasFunctions = HasFunctions or (#cls.Functions > 0);
HasVariables = HasVariables or (#cls.Variables > 0);
@@ -1064,7 +883,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
cf:write("<hr /><a name=\"inherits\"><h1>Inheritance</h1></a>\n");
if (#InheritanceChain > 0) then
cf:write("<p>This class inherits from the following parent classes:<ul>\n");
- for i, cls in ipairs(InheritanceChain) do
+ for _, cls in ipairs(InheritanceChain) do
cf:write("<li><a href=\"", cls.Name, ".html\">", cls.Name, "</a></li>\n");
end
cf:write("</ul></p>\n");
@@ -1081,7 +900,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
cf:write("<a name=\"constants\"><hr /><h1>Constants</h1></a>\n");
WriteConstants(a_ClassAPI.Constants, a_ClassAPI.ConstantGroups, a_ClassAPI.NumConstantsInGroups, nil);
g_Stats.NumTotalConstants = g_Stats.NumTotalConstants + #a_ClassAPI.Constants + (a_ClassAPI.NumConstantsInGroups or 0);
- for i, cls in ipairs(InheritanceChain) do
+ for _, cls in ipairs(InheritanceChain) do
WriteConstants(cls.Constants, cls.ConstantGroups, cls.NumConstantsInGroupsForDescendants, cls.Name);
end;
end;
@@ -1091,7 +910,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
cf:write("<a name=\"variables\"><hr /><h1>Member variables</h1></a>\n");
WriteVariables(a_ClassAPI.Variables, nil);
g_Stats.NumTotalVariables = g_Stats.NumTotalVariables + #a_ClassAPI.Variables;
- for i, cls in ipairs(InheritanceChain) do
+ for _, cls in ipairs(InheritanceChain) do
WriteVariables(cls.Variables, cls.Name);
end;
end
@@ -1101,7 +920,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
cf:write("<a name=\"functions\"><hr /><h1>Functions</h1></a>\n");
WriteFunctions(a_ClassAPI.Functions, nil);
g_Stats.NumTotalFunctions = g_Stats.NumTotalFunctions + #a_ClassAPI.Functions;
- for i, cls in ipairs(InheritanceChain) do
+ for _, cls in ipairs(InheritanceChain) do
WriteFunctions(cls.Functions, cls.Name);
end
end
@@ -1122,71 +941,20 @@ end
-function WriteHtmlHook(a_Hook, a_HookNav)
- local fnam = "API/" .. a_Hook.DefaultFnName .. ".html";
- local f, error = io.open(fnam, "w");
- if (f == nil) then
- LOG("Cannot write \"" .. fnam .. "\": \"" .. error .. "\".");
- return;
- end
- local HookName = a_Hook.DefaultFnName;
-
- f:write([[<!DOCTYPE html><html>
- <head>
- <title>MCServer API - ]], HookName, [[ Hook</title>
- <link rel="stylesheet" type="text/css" href="main.css" />
- <link rel="stylesheet" type="text/css" href="prettify.css" />
- <script src="prettify.js"></script>
- <script src="lang-lua.js"></script>
- </head>
- <body>
- <div id="content">
- <header>
- <h1>]], a_Hook.Name, [[</h1>
- <hr />
- </header>
- <table><tr><td style="vertical-align: top;">
- Index:<br />
- <a href='index.html#articles'>Articles</a><br />
- <a href='index.html#classes'>Classes</a><br />
- <a href='index.html#hooks'>Hooks</a><br />
- <br />
- Quick navigation:<br />
- ]]);
- f:write(a_HookNav);
+local function WriteClasses(f, a_API, a_ClassMenu)
f:write([[
- </td><td style="vertical-align: top;"><p>
+ <a name="classes"><h2>Class index</h2></a>
+ <p>The following classes are available in the MCServer Lua scripting language:
+ <ul>
]]);
- f:write(LinkifyString(a_Hook.Desc, HookName));
- f:write("</p>\n<hr /><h1>Callback function</h1>\n<p>The default name for the callback function is ");
- f:write(a_Hook.DefaultFnName, ". It has the following signature:\n");
- f:write("<pre class=\"prettyprint lang-lua\">function ", HookName, "(");
- if (a_Hook.Params == nil) then
- a_Hook.Params = {};
- end
- for i, param in ipairs(a_Hook.Params) do
- if (i > 1) then
- f:write(", ");
- end
- f:write(param.Name);
- end
- f:write(")</pre>\n<hr /><h1>Parameters:</h1>\n<table><tr><th>Name</th><th>Type</th><th>Notes</th></tr>\n");
- for i, param in ipairs(a_Hook.Params) do
- f:write("<tr><td>", param.Name, "</td><td>", LinkifyString(param.Type, HookName), "</td><td>", LinkifyString(param.Notes, HookName), "</td></tr>\n");
- end
- f:write("</table>\n<p>" .. (a_Hook.Returns or "") .. "</p>\n\n");
- f:write([[<hr /><h1>Code examples</h1><h2>Registering the callback</h2>]]);
- f:write("<pre class=\"prettyprint lang-lua\">\n");
- f:write([[cPluginManager:AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]);
- f:write("</pre>\n\n");
- local Examples = a_Hook.CodeExamples or {};
- for i, example in ipairs(Examples) do
- f:write("<h2>", (example.Title or "<i>missing Title</i>"), "</h2>\n");
- f:write("<p>", (example.Desc or "<i>missing Desc</i>"), "</p>\n");
- f:write("<pre class=\"prettyprint lang-lua\">", (example.Code or "<i>missing Code</i>"), "\n</pre>\n\n");
+ for _, cls in ipairs(a_API) do
+ f:write("<li><a href=\"", cls.Name, ".html\">", cls.Name, "</a></li>\n");
+ WriteHtmlClass(cls, a_ClassMenu);
end
- f:write([[</td></tr></table></div><script>prettyPrint();</script></body></html>]]);
- f:close();
+ f:write([[
+ </ul></p>
+ <hr />
+ ]]);
end
@@ -1194,12 +962,12 @@ end
--- Writes a list of undocumented objects into a file
-function ListUndocumentedObjects(API, UndocumentedHooks)
+local function ListUndocumentedObjects(API, UndocumentedHooks)
f = io.open("API/_undocumented.lua", "w");
if (f ~= nil) then
f:write("\n-- This is the list of undocumented API objects, automatically generated by APIDump\n\n");
f:write("g_APIDesc =\n{\n\tClasses =\n\t{\n");
- for i, cls in ipairs(API) do
+ for _, cls in ipairs(API) do
local HasFunctions = ((cls.UndocumentedFunctions ~= nil) and (#cls.UndocumentedFunctions > 0));
local HasConstants = ((cls.UndocumentedConstants ~= nil) and (#cls.UndocumentedConstants > 0));
local HasVariables = ((cls.UndocumentedVariables ~= nil) and (#cls.UndocumentedVariables > 0));
@@ -1216,7 +984,7 @@ function ListUndocumentedObjects(API, UndocumentedHooks)
if (HasFunctions) then
f:write("\t\t\tFunctions =\n\t\t\t{\n");
table.sort(cls.UndocumentedFunctions);
- for j, fn in ipairs(cls.UndocumentedFunctions) do
+ for _, fn in ipairs(cls.UndocumentedFunctions) do
f:write("\t\t\t\t" .. fn .. " = { Params = \"\", Return = \"\", Notes = \"\" },\n");
end -- for j, fn - cls.UndocumentedFunctions[]
f:write("\t\t\t},\n\n");
@@ -1225,7 +993,7 @@ function ListUndocumentedObjects(API, UndocumentedHooks)
if (HasConstants) then
f:write("\t\t\tConstants =\n\t\t\t{\n");
table.sort(cls.UndocumentedConstants);
- for j, cn in ipairs(cls.UndocumentedConstants) do
+ for _, cn in ipairs(cls.UndocumentedConstants) do
f:write("\t\t\t\t" .. cn .. " = { Notes = \"\" },\n");
end -- for j, fn - cls.UndocumentedConstants[]
f:write("\t\t\t},\n\n");
@@ -1234,7 +1002,7 @@ function ListUndocumentedObjects(API, UndocumentedHooks)
if (HasVariables) then
f:write("\t\t\tVariables =\n\t\t\t{\n");
table.sort(cls.UndocumentedVariables);
- for j, vn in ipairs(cls.UndocumentedVariables) do
+ for _, vn in ipairs(cls.UndocumentedVariables) do
f:write("\t\t\t\t" .. vn .. " = { Type = \"\", Notes = \"\" },\n");
end -- for j, fn - cls.UndocumentedVariables[]
f:write("\t\t\t},\n\n");
@@ -1282,7 +1050,7 @@ end
--- Lists the API objects that are documented but not available in the API:
-function ListUnexportedObjects()
+local function ListUnexportedObjects()
f = io.open("API/_unexported-documented.txt", "w");
if (f ~= nil) then
for clsname, cls in pairs(g_APIDesc.Classes) do
@@ -1314,7 +1082,7 @@ end
-function ListMissingPages()
+local function ListMissingPages()
local MissingPages = {};
local NumLinks = 0;
for PageName, Referrers in pairs(g_TrackedPages) do
@@ -1344,7 +1112,7 @@ function ListMissingPages()
LOGWARNING("Cannot open _missingPages.txt for writing: '" .. err .. "'. There are " .. #MissingPages .. " pages missing.");
return;
end
- for idx, pg in ipairs(MissingPages) do
+ for _, pg in ipairs(MissingPages) do
f:write(pg.Name .. ":\n");
-- Sort and output the referrers:
table.sort(pg.Refs);
@@ -1360,7 +1128,7 @@ end
--- Writes the documentation statistics (in g_Stats) into the given HTML file
-function WriteStats(f)
+local function WriteStats(f)
local function ExportMeter(a_Percent)
local Color;
if (a_Percent > 99) then
@@ -1428,3 +1196,361 @@ end
+
+local function DumpAPIHtml(a_API)
+ LOG("Dumping all available functions and constants to API subfolder...");
+
+ -- Create the output folder
+ if not(cFile:IsFolder("API")) then
+ cFile:CreateFolder("API");
+ end
+
+ LOG("Copying static files..");
+ cFile:CreateFolder("API/Static");
+ local localFolder = g_Plugin:GetLocalFolder();
+ for _, fnam in ipairs(cFile:GetFolderContents(localFolder .. "/Static")) do
+ cFile:Delete("API/Static/" .. fnam);
+ cFile:Copy(localFolder .. "/Static/" .. fnam, "API/Static/" .. fnam);
+ end
+
+ -- Extract hook constants:
+ local Hooks = {};
+ local UndocumentedHooks = {};
+ for name, obj in pairs(cPluginManager) do
+ 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
+ table.sort(Hooks,
+ function(Hook1, Hook2)
+ return (Hook1.Name < Hook2.Name);
+ end
+ );
+ ReadHooks(Hooks);
+
+ -- Create a "class index" file, write each class as a link to that file,
+ -- then dump class contents into class-specific file
+ LOG("Writing HTML files...");
+ local f, err = io.open("API/index.html", "w");
+ if (f == nil) then
+ LOGINFO("Cannot output HTML API: " .. err);
+ return;
+ end
+
+ -- Create a class navigation menu that will be inserted into each class file for faster navigation (#403)
+ local ClassMenuTab = {};
+ for _, cls in ipairs(a_API) do
+ table.insert(ClassMenuTab, "<a href='");
+ table.insert(ClassMenuTab, cls.Name);
+ table.insert(ClassMenuTab, ".html'>");
+ table.insert(ClassMenuTab, cls.Name);
+ table.insert(ClassMenuTab, "</a><br />");
+ end
+ local ClassMenu = table.concat(ClassMenuTab, "");
+
+ -- Create a hook navigation menu that will be inserted into each hook file for faster navigation(#403)
+ local HookNavTab = {};
+ for _, hook in ipairs(Hooks) do
+ table.insert(HookNavTab, "<a href='");
+ table.insert(HookNavTab, hook.DefaultFnName);
+ table.insert(HookNavTab, ".html'>");
+ table.insert(HookNavTab, (hook.Name:gsub("^HOOK_", ""))); -- remove the "HOOK_" part of the name
+ table.insert(HookNavTab, "</a><br />");
+ end
+ local HookNav = table.concat(HookNavTab, "");
+
+ -- Write the HTML file:
+ f:write([[<!DOCTYPE html>
+ <html>
+ <head>
+ <title>MCServer API - Index</title>
+ <link rel="stylesheet" type="text/css" href="main.css" />
+ </head>
+ <body>
+ <div id="content">
+ <header>
+ <h1>MCServer API - Index</h1>
+ <hr />
+ </header>
+ <p>The API reference is divided into the following sections:</p>
+ <ul>
+ <li><a href="#articles">Articles</a></li>
+ <li><a href="#classes">Class index</a></li>
+ <li><a href="#hooks">Hooks</a></li>
+ <li><a href="#docstats">Documentation statistics</a></li>
+ </ul>
+ <hr />
+ ]]);
+
+ WriteArticles(f);
+ WriteClasses(f, a_API, ClassMenu);
+ WriteHooks(f, Hooks, UndocumentedHooks, HookNav);
+
+ -- Copy the static files to the output folder:
+ local StaticFiles =
+ {
+ "main.css",
+ "prettify.js",
+ "prettify.css",
+ "lang-lua.js",
+ };
+ for _, fnam in ipairs(StaticFiles) do
+ cFile:Delete("API/" .. fnam);
+ cFile:Copy(g_Plugin:GetLocalFolder() .. "/" .. fnam, "API/" .. fnam);
+ end
+
+ -- List the documentation problems:
+ LOG("Listing leftovers...");
+ ListUndocumentedObjects(a_API, UndocumentedHooks);
+ ListUnexportedObjects();
+ ListMissingPages();
+
+ WriteStats(f);
+
+ f:write([[ </ul>
+ </div>
+ </body>
+</html>]]);
+ f:close();
+
+ LOG("API subfolder written");
+end
+
+
+
+
+
+--- Returns the string with extra tabs and CR/LFs removed
+local function CleanUpDescription(a_Desc)
+ -- Get rid of indent and newlines, normalize whitespace:
+ local res = a_Desc:gsub("[\n\t]", "")
+ res = a_Desc:gsub("%s%s+", " ")
+
+ -- Replace paragraph marks with newlines:
+ res = res:gsub("<p>", "\n")
+ res = res:gsub("</p>", "")
+
+ -- Replace list items with dashes:
+ res = res:gsub("</?ul>", "")
+ res = res:gsub("<li>", "\n - ")
+ res = res:gsub("</li>", "")
+
+ return res
+end
+
+
+
+
+
+--- Writes a list of methods into the specified file in ZBS format
+local function WriteZBSMethods(f, a_Methods)
+ for _, func in ipairs(a_Methods or {}) do
+ f:write("\t\t\t[\"", func.Name, "\"] =\n")
+ f:write("\t\t\t{\n")
+ f:write("\t\t\t\ttype = \"method\",\n")
+ if ((func.Notes ~= nil) and (func.Notes ~= "")) then
+ f:write("\t\t\t\tdescription = [[", CleanUpDescription(func.Notes or ""), " ]],\n")
+ end
+ f:write("\t\t\t},\n")
+ end
+end
+
+
+
+
+
+--- Writes a list of constants into the specified file in ZBS format
+local function WriteZBSConstants(f, a_Constants)
+ for _, cons in ipairs(a_Constants or {}) do
+ f:write("\t\t\t[\"", cons.Name, "\"] =\n")
+ f:write("\t\t\t{\n")
+ f:write("\t\t\t\ttype = \"value\",\n")
+ if ((cons.Desc ~= nil) and (cons.Desc ~= "")) then
+ f:write("\t\t\t\tdescription = [[", CleanUpDescription(cons.Desc or ""), " ]],\n")
+ end
+ f:write("\t\t\t},\n")
+ end
+end
+
+
+
+
+
+--- Writes one MCS class definition into the specified file in ZBS format
+local function WriteZBSClass(f, a_Class)
+ assert(type(a_Class) == "table")
+
+ -- Write class header:
+ f:write("\t", a_Class.Name, " =\n\t{\n")
+ f:write("\t\ttype = \"class\",\n")
+ f:write("\t\tdescription = [[", CleanUpDescription(a_Class.Desc or ""), " ]],\n")
+ f:write("\t\tchilds =\n")
+ f:write("\t\t{\n")
+
+ -- Export methods and constants:
+ WriteZBSMethods(f, a_Class.Functions)
+ WriteZBSConstants(f, a_Class.Constants)
+
+ -- Finish the class definition:
+ f:write("\t\t},\n")
+ f:write("\t},\n\n")
+end
+
+
+
+
+
+--- Dumps the entire API table into a file in the ZBS format
+local function DumpAPIZBS(a_API)
+ LOG("Dumping ZBS API description...")
+ local f, err = io.open("mcserver_api.lua", "w")
+ if (f == nil) then
+ LOG("Cannot open mcserver_lua.lua for writing, ZBS API will not be dumped. " .. err)
+ return
+ end
+
+ -- Write the file header:
+ f:write("-- This is a MCServer API file automatically generated by the APIDump plugin\n")
+ f:write("-- Note that any manual changes will be overwritten by the next dump\n\n")
+ f:write("return {\n")
+
+ -- Export each class except Globals, store those aside:
+ local Globals
+ for _, cls in ipairs(a_API) do
+ if (cls.Name ~= "Globals") then
+ WriteZBSClass(f, cls)
+ else
+ Globals = cls
+ end
+ end
+
+ -- Export the globals:
+ if (Globals) then
+ WriteZBSMethods(f, Globals.Functions)
+ WriteZBSConstants(f, Globals.Constants)
+ end
+
+ -- Finish the file:
+ f:write("}\n")
+ f:close()
+ LOG("ZBS API dumped...")
+end
+
+
+
+
+
+local function DumpApi()
+ LOG("Dumping the API...")
+
+ -- Load the API descriptions from the Classes and Hooks subfolders:
+ -- This needs to be done each time the command is invoked because the export modifies the tables' contents
+ dofile(g_PluginFolder .. "/APIDesc.lua")
+ if (g_APIDesc.Classes == nil) then
+ g_APIDesc.Classes = {};
+ end
+ if (g_APIDesc.Hooks == nil) then
+ g_APIDesc.Hooks = {};
+ end
+ LoadAPIFiles("/Classes/", g_APIDesc.Classes);
+ LoadAPIFiles("/Hooks/", g_APIDesc.Hooks);
+
+ -- Reset the stats:
+ g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
+ g_Stats = -- Statistics about the documentation
+ {
+ NumTotalClasses = 0,
+ NumUndocumentedClasses = 0,
+ NumTotalFunctions = 0,
+ NumUndocumentedFunctions = 0,
+ NumTotalConstants = 0,
+ NumUndocumentedConstants = 0,
+ NumTotalVariables = 0,
+ NumUndocumentedVariables = 0,
+ NumTotalHooks = 0,
+ NumUndocumentedHooks = 0,
+ NumTrackedLinks = 0,
+ NumInvalidLinks = 0,
+ }
+
+ -- Create the API tables:
+ local API, Globals = CreateAPITables();
+
+ -- Sort the classes by name:
+ table.sort(API,
+ function (c1, c2)
+ return (string.lower(c1.Name) < string.lower(c2.Name));
+ end
+ );
+ g_Stats.NumTotalClasses = #API;
+
+ -- Add Globals into the API:
+ Globals.Name = "Globals";
+ table.insert(API, Globals);
+
+ -- Read in the descriptions:
+ LOG("Reading descriptions...");
+ ReadDescriptions(API);
+
+ -- Dump all available API objects in HTML format into a subfolder:
+ DumpAPIHtml(API);
+
+ -- Dump all available API objects in format used by ZeroBraneStudio API descriptions:
+ DumpAPIZBS(API)
+
+ LOG("APIDump finished");
+ return true
+end
+
+
+
+
+
+local function HandleWebAdminDump(a_Request)
+ if (a_Request.PostParams["Dump"] ~= nil) then
+ DumpApi()
+ end
+ return
+ [[
+ <p>Pressing the button will generate the API dump on the server. Note that this can take some time.</p>
+ <form method="POST"><input type="submit" name="Dump" value="Dump the API"/></form>
+ ]]
+end
+
+
+
+
+
+local function HandleCmdApi(a_Split)
+ DumpApi()
+ return true
+end
+
+
+
+
+
+function Initialize(Plugin)
+ g_Plugin = Plugin;
+ g_PluginFolder = Plugin:GetLocalFolder();
+
+ LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
+
+ -- Bind a console command to dump the API:
+ cPluginManager:BindConsoleCommand("api", HandleCmdApi, "Dumps the Lua API docs into the API/ subfolder")
+
+ -- Add a WebAdmin tab that has a Dump button
+ g_Plugin:AddWebTab("APIDump", HandleWebAdminDump)
+
+ return true
+end
+
+
+
+
+
diff --git a/MCServer/Plugins/ChunkWorx/chunkworx_main.lua b/MCServer/Plugins/ChunkWorx/chunkworx_main.lua
index f74c4ea2d..88ecb3979 100644
--- a/MCServer/Plugins/ChunkWorx/chunkworx_main.lua
+++ b/MCServer/Plugins/ChunkWorx/chunkworx_main.lua
@@ -122,7 +122,7 @@ function OnTick( DeltaTime )
end
end
WW_instance:QueueSaveAllChunks()
- WW_instance:UnloadUnusedChunks()
+ WW_instance:QueueUnloadUnusedChunks()
end
end
end \ No newline at end of file
diff --git a/MCServer/Plugins/ChunkWorx/chunkworx_web.lua b/MCServer/Plugins/ChunkWorx/chunkworx_web.lua
index 44993f81c..6c5eab676 100644
--- a/MCServer/Plugins/ChunkWorx/chunkworx_web.lua
+++ b/MCServer/Plugins/ChunkWorx/chunkworx_web.lua
@@ -44,7 +44,7 @@ function HandleRequest_Generation( Request )
if (Request.PostParams["AGHRRRR"] ~= nil) then
GENERATION_STATE = 0
WW_instance:SaveAllChunks()
- WW_instance:UnloadUnusedChunks()
+ WW_instance:QueueUnloadUnusedChunks()
LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works ABORTED by admin")
end
--Content = Content .. "<head><meta http-equiv=\"refresh\" content=\"2;\"></head>"
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core
-Subproject 759cf48ba3f1409e6d7b60cb821ee17e589bdef
+Subproject 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be5
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index 2d2d2736d..064d5d772 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -19,18 +19,21 @@ function Initialize(Plugin)
cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick2);
--]]
- cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_USING_BLOCK, OnPlayerUsingBlock);
- cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_USING_ITEM, OnPlayerUsingItem);
- cPluginManager:AddHook(cPluginManager.HOOK_TAKE_DAMAGE, OnTakeDamage);
- cPluginManager:AddHook(cPluginManager.HOOK_TICK, OnTick);
- cPluginManager:AddHook(cPluginManager.HOOK_CHAT, OnChat);
- cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
- cPluginManager:AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
- cPluginManager:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
- cPluginManager:AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded);
- cPluginManager:AddHook(cPluginManager.HOOK_PLUGIN_MESSAGE, OnPluginMessage);
-
- PM = cRoot:Get():GetPluginManager();
+ local PM = cPluginManager;
+ PM:AddHook(cPluginManager.HOOK_PLAYER_USING_BLOCK, OnPlayerUsingBlock);
+ PM:AddHook(cPluginManager.HOOK_PLAYER_USING_ITEM, OnPlayerUsingItem);
+ PM:AddHook(cPluginManager.HOOK_TAKE_DAMAGE, OnTakeDamage);
+ PM:AddHook(cPluginManager.HOOK_TICK, OnTick);
+ PM:AddHook(cPluginManager.HOOK_CHAT, OnChat);
+ PM:AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
+ PM:AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
+ PM:AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded);
+ PM:AddHook(cPluginManager.HOOK_PLUGIN_MESSAGE, OnPluginMessage);
+ PM:AddHook(cPluginManager.HOOK_PLAYER_JOINED, OnPlayerJoined)
+
+ -- _X: Disabled so that the normal operation doesn't interfere with anything
+ -- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
+
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool");
@@ -53,18 +56,36 @@ function Initialize(Plugin)
PM:BindCommand("/fr", "debuggers", HandleFurnaceRecipe, "- Shows the furnace recipe for the currently held item");
PM:BindCommand("/ff", "debuggers", HandleFurnaceFuel, "- Shows how long the currently held item would burn in a furnace");
PM:BindCommand("/sched", "debuggers", HandleSched, "- Schedules a simple countdown using cWorld:ScheduleTask()");
+ PM:BindCommand("/cs", "debuggers", HandleChunkStay, "- Tests the ChunkStay Lua integration for the specified chunk coords");
+ PM:BindCommand("/compo", "debuggers", HandleCompo, "- Tests the cCompositeChat bindings")
+ PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one")
+ PM:BindCommand("/wesel", "debuggers", HandleWESel, "- Expands the current WE selection by 1 block in X/Z")
- Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers);
+ Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
+ Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
-- Enable the following line for BlockArea / Generator interface testing:
-- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
- -- TestBlockAreas();
- -- TestSQLiteBindings();
- -- TestExpatBindings();
+ -- TestBlockAreas()
+ -- TestSQLiteBindings()
+ -- TestExpatBindings()
+ -- TestPluginCalls()
+
+ TestBlockAreasString()
+ TestStringBase64()
+ --[[
+ -- Test cCompositeChat usage in console-logging:
+ LOGINFO(cCompositeChat("This is a simple message with some @2 color formatting @4 and http://links.to .")
+ :AddSuggestCommandPart("(Suggested command)", "cmd")
+ :AddRunCommandPart("(Run command)", "cmd")
+ :SetMessageType(mtInfo)
+ )
+ --]]
+
return true
end;
@@ -72,6 +93,38 @@ end;
+function TestPluginCalls()
+ -- In order to test the inter-plugin communication, we're going to call Core's ReturnColorFromChar() function
+ -- It is a rather simple function that doesn't need any tables as its params and returns a value, too
+ -- Note the signature: function ReturnColorFromChar( Split, char ) ... return cChatColog.Gray ... end
+ -- The Split parameter should be a table, but it is not used in that function anyway,
+ -- so we can get away with passing nil to it.
+
+ -- Use the old, deprecated and unsafe method:
+ local Core = cPluginManager:Get():GetPlugin("Core")
+ if (Core ~= nil) then
+ LOGINFO("Calling Core::ReturnColorFromChar() the old-fashioned way...")
+ local Gray = Core:Call("ReturnColorFromChar", nil, "8")
+ if (Gray ~= cChatColor.Gray) then
+ LOGWARNING("Call failed, exp " .. cChatColor.Gray .. ", got " .. (Gray or "<nil>"))
+ else
+ LOGINFO("Call succeeded")
+ end
+ end
+
+ -- Use the new method:
+ LOGINFO("Calling Core::ReturnColorFromChar() the recommended way...")
+ local Gray = cPluginManager:CallPlugin("Core", "ReturnColorFromChar", nil, "8")
+ if (Gray ~= cChatColor.Gray) then
+ LOGWARNING("Call failed, exp " .. cChatColor.Gray .. ", got " .. (Gray or "<nil>"))
+ else
+ LOGINFO("Call succeeded")
+ end
+end
+
+
+
+
function TestBlockAreas()
LOG("Testing block areas...");
@@ -164,6 +217,60 @@ end
+function TestBlockAreasString()
+ -- Write one area to string, then to file:
+ local BA1 = cBlockArea()
+ BA1:Create(5, 5, 5, cBlockArea.baTypes + cBlockArea.baMetas)
+ BA1:Fill(cBlockArea.baTypes, E_BLOCK_DIAMOND_BLOCK)
+ BA1:FillRelCuboid(1, 3, 1, 3, 1, 3, cBlockArea.baTypes, E_BLOCK_GOLD_BLOCK)
+ local Data = BA1:SaveToSchematicString()
+ if ((type(Data) ~= "string") or (Data == "")) then
+ LOG("Cannot save schematic to string")
+ return
+ end
+ cFile:CreateFolder("schematics")
+ local f = io.open("schematics/StringTest.schematic", "wb")
+ f:write(Data)
+ f:close()
+
+ -- Load a second area from that file:
+ local BA2 = cBlockArea()
+ if not(BA2:LoadFromSchematicFile("schematics/StringTest.schematic")) then
+ LOG("Cannot read schematic from string test file")
+ return
+ end
+ BA2:Clear()
+
+ -- Load another area from a string in that file:
+ f = io.open("schematics/StringTest.schematic", "rb")
+ Data = f:read("*all")
+ if not(BA2:LoadFromSchematicString(Data)) then
+ LOG("Cannot load schematic from string")
+ end
+end
+
+
+
+
+
+function TestStringBase64()
+ -- Create a binary string:
+ local s = ""
+ for i = 0, 255 do
+ s = s .. string.char(i)
+ end
+
+ -- Roundtrip through Base64:
+ local Base64 = Base64Encode(s)
+ local UnBase64 = Base64Decode(Base64)
+
+ assert(UnBase64 == s)
+end
+
+
+
+
+
function TestSQLiteBindings()
LOG("Testing SQLite bindings...");
@@ -1004,6 +1111,68 @@ end
+local g_Counter = 0
+local g_JavaScript =
+[[
+<script>
+function createXHR()
+{
+ var request = false;
+ try {
+ request = new ActiveXObject('Msxml2.XMLHTTP');
+ }
+ catch (err2)
+ {
+ try
+ {
+ request = new ActiveXObject('Microsoft.XMLHTTP');
+ }
+ catch (err3)
+ {
+ try
+ {
+ request = new XMLHttpRequest();
+ }
+ catch (err1)
+ {
+ request = false;
+ }
+ }
+ }
+ return request;
+}
+
+function RefreshCounter()
+{
+ var xhr = createXHR();
+ xhr.onreadystatechange = function()
+ {
+ if (xhr.readyState == 4)
+ {
+ document.getElementById("cnt").innerHTML = xhr.responseText;
+ }
+ };
+ xhr.open("POST", "/~webadmin/Debuggers/StressTest", true);
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ xhr.send("counter=true");
+}
+
+setInterval(RefreshCounter, 10)
+</script>
+]]
+
+function HandleRequest_StressTest(a_Request)
+ if (a_Request.PostParams["counter"]) then
+ g_Counter = g_Counter + 1
+ return tostring(g_Counter)
+ end
+ return g_JavaScript .. "<p>The counter below should be reloading as fast as possible</p><div id='cnt'>0</div>"
+end
+
+
+
+
+
function OnPluginMessage(a_Client, a_Channel, a_Message)
LOGINFO("Received a plugin message from client " .. a_Client:GetUsername() .. ": channel '" .. a_Channel .. "', message '" .. a_Message .. "'");
@@ -1028,3 +1197,185 @@ end
+
+function HandleChunkStay(a_Split, a_Player)
+ -- As an example of using ChunkStay, this call will load 3x3 chunks around the specified chunk coords,
+ -- then build an obsidian pillar in the middle of each one.
+ -- Once complete, the player will be teleported to the middle pillar
+
+ if (#a_Split ~= 3) then
+ a_Player:SendMessageInfo("Usage: /cs <ChunkX> <ChunkZ>")
+ return true
+ end
+
+ local ChunkX = tonumber(a_Split[2])
+ local ChunkZ = tonumber(a_Split[3])
+ if ((ChunkX == nil) or (ChunkZ == nil)) then
+ a_Player:SendMessageFailure("Invalid chunk coords.")
+ return true
+ end
+
+ local World = a_Player:GetWorld()
+ local PlayerID = a_Player:GetUniqueID()
+ a_Player:SendMessageInfo("Loading chunks, stand by...");
+
+ -- Set the wanted chunks:
+ local Chunks = {}
+ for z = -1, 1 do for x = -1, 1 do
+ table.insert(Chunks, {ChunkX + x, ChunkZ + z})
+ end end
+
+ -- The function that is called when all chunks are available
+ -- Will perform the actual action with all those chunks
+ -- Note that the player needs to be referenced using their EntityID - in case they disconnect before the chunks load
+ local OnAllChunksAvailable = function()
+ LOGINFO("ChunkStay all chunks now available")
+ -- Build something on the neighboring chunks, to verify:
+ for z = -1, 1 do for x = -1, 1 do
+ local BlockX = (ChunkX + x) * 16 + 8
+ local BlockZ = (ChunkZ + z) * 16 + 8
+ for y = 20, 80 do
+ World:SetBlock(BlockX, y, BlockZ, E_BLOCK_OBSIDIAN, 0)
+ end
+ end end
+
+ -- Teleport the player there for visual inspection:
+ World:DoWithEntityByID(PlayerID,
+ function (a_CallbackPlayer)
+ a_CallbackPlayer:TeleportToCoords(ChunkX * 16 + 8, 85, ChunkZ * 16 + 8)
+ a_CallbackPlayer:SendMessageSuccess("ChunkStay fully available")
+ end
+ )
+ end
+
+ -- This function will be called for each chunk that is made available
+ -- Note that the player needs to be referenced using their EntityID - in case they disconnect before the chunks load
+ local OnChunkAvailable = function(a_ChunkX, a_ChunkZ)
+ LOGINFO("ChunkStay now has chunk [" .. a_ChunkX .. ", " .. a_ChunkZ .. "]")
+ World:DoWithEntityByID(PlayerID,
+ function (a_CallbackPlayer)
+ a_CallbackPlayer:SendMessageInfo("ChunkStay now has chunk [" .. a_ChunkX .. ", " .. a_ChunkZ .. "]")
+ end
+ )
+ end
+
+ -- Process the ChunkStay:
+ World:ChunkStay(Chunks, OnChunkAvailable, OnAllChunksAvailable)
+ return true
+end
+
+
+
+
+
+function HandleCompo(a_Split, a_Player)
+ -- Send one composite message to self:
+ local msg = cCompositeChat()
+ msg:AddTextPart("Hello! ", "b@e") -- bold yellow
+ msg:AddUrlPart("MCServer", "http://mc-server.org")
+ msg:AddTextPart(" rules! ")
+ msg:AddRunCommandPart("Set morning", "/time set 0")
+ a_Player:SendMessage(msg)
+
+ -- Broadcast another one to the world:
+ local msg2 = cCompositeChat()
+ msg2:AddSuggestCommandPart(a_Player:GetName(), "/tell " .. a_Player:GetName() .. " ")
+ msg2:AddTextPart(" knows how to use cCompositeChat!");
+ a_Player:GetWorld():BroadcastChat(msg2)
+
+ return true
+end
+
+
+
+
+
+function HandleSetBiome(a_Split, a_Player)
+ local Biome = biJungle
+ local Size = 20
+ local SplitSize = #a_Split
+ if (SplitSize > 3) then
+ a_Player:SendMessage("Too many parameters. Usage: " .. a_Split[1] .. " <BiomeType>")
+ return true
+ end
+
+ if (SplitSize >= 2) then
+ Biome = StringToBiome(a_Split[2])
+ if (Biome == biInvalidBiome) then
+ a_Player:SendMessage("Unknown biome: '" .. a_Split[2] .. "'. Command ignored.")
+ return true
+ end
+ end
+ if (SplitSize >= 3) then
+ Size = tostring(a_Split[3])
+ if (Size == nil) then
+ a_Player:SendMessage("Unknown size: '" .. a_Split[3] .. "'. Command ignored.")
+ return true
+ end
+ end
+
+ local BlockX = math.floor(a_Player:GetPosX())
+ local BlockZ = math.floor(a_Player:GetPosZ())
+ a_Player:GetWorld():SetAreaBiome(BlockX - Size, BlockX + Size, BlockZ - Size, BlockZ + Size, Biome)
+ a_Player:SendMessage(
+ "Blocks {" .. (BlockX - Size) .. ", " .. (BlockZ - Size) ..
+ "} - {" .. (BlockX + Size) .. ", " .. (BlockZ + Size) ..
+ "} set to biome #" .. tostring(Biome) .. "."
+ )
+ return true
+end
+
+
+
+
+
+function HandleWESel(a_Split, a_Player)
+ -- Check if the selection is a cuboid:
+ local IsCuboid = cPluginManager:CallPlugin("WorldEdit", "IsPlayerSelectionCuboid")
+ if (IsCuboid == nil) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit is not loaded"))
+ return true
+ elseif (IsCuboid == false) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, the selection is not a cuboid"))
+ return true
+ end
+
+ -- Get the selection:
+ local SelCuboid = cCuboid()
+ local IsSuccess = cPluginManager:CallPlugin("WorldEdit", "GetPlayerCuboidSelection", a_Player, SelCuboid)
+ if not(IsSuccess) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit reported failure while getting current selection"))
+ return true
+ end
+
+ -- Adjust the selection:
+ local NumBlocks = tonumber(a_Split[2] or "1") or 1
+ SelCuboid:Expand(NumBlocks, NumBlocks, 0, 0, NumBlocks, NumBlocks)
+
+ -- Set the selection:
+ local IsSuccess = cPluginManager:CallPlugin("WorldEdit", "SetPlayerCuboidSelection", a_Player, SelCuboid)
+ if not(IsSuccess) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit reported failure while setting new selection"))
+ return true
+ end
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtInformation):AddTextPart("Successfully adjusted the selection by " .. NumBlocks .. " block(s)"))
+ return true
+end
+
+
+
+
+
+function OnPlayerJoined(a_Player)
+ -- Test composite chat chaining:
+ a_Player:SendMessage(cCompositeChat()
+ :AddTextPart("Hello, ")
+ :AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
+ :AddSuggestCommandPart(", and welcome.", "/help", "u")
+ :AddRunCommandPart(" SetDay", "/time set 0")
+ )
+end
+
+
+
+
diff --git a/MCServer/Plugins/DumpInfo/Init.lua b/MCServer/Plugins/DumpInfo/Init.lua
new file mode 100644
index 000000000..5d9c752b0
--- /dev/null
+++ b/MCServer/Plugins/DumpInfo/Init.lua
@@ -0,0 +1,49 @@
+function Initialize(a_Plugin)
+ a_Plugin:SetName("DumpInfo")
+ a_Plugin:SetVersion(1)
+
+ -- Check if the infodump file exists.
+ if (not cFile:Exists("Plugins/InfoDump.lua")) then
+ LOGWARN("[DumpInfo] InfoDump.lua was not found.")
+ return false
+ end
+
+ -- Add the webtab.
+ a_Plugin:AddWebTab("DumpPlugin", HandleDumpPluginRequest)
+ return true
+end
+
+
+
+
+
+function HandleDumpPluginRequest(a_Request)
+ local Content = ""
+
+ -- Check if it already was requested to dump a plugin.
+ if (a_Request.PostParams["DumpInfo"] ~= nil) then
+ local F = loadfile("Plugins/InfoDump.lua")
+ F("Plugins/" .. a_Request.PostParams["DumpInfo"])
+ end
+
+ Content = Content .. [[
+<table>
+<th colspan="2">DumpInfo</th>]]
+
+ -- Loop through each plugin that is found.
+ for PluginName, k in pairs(cPluginManager:Get():GetAllPlugins()) do
+
+ -- Check if there is a file called 'Info.lua' or 'info.lua'
+ if (cFile:Exists("Plugins/" .. PluginName .. "/Info.lua")) then
+ Content = Content .. "<tr>"
+ Content = Content .. "<td>" .. PluginName .. "</td>"
+ Content = Content .. "<td> <form method='POST'> <input type='hidden' value='" .. PluginName .. "' name='DumpInfo'> <input type='submit' value='DumpInfo'> </form>"
+ Content = Content .. "</td>"
+ end
+ end
+
+ Content = Content .. [[
+</table>]]
+
+ return Content
+end
diff --git a/MCServer/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua
index df47d566b..c61f9c9e6 100644
--- a/MCServer/Plugins/InfoDump.lua
+++ b/MCServer/Plugins/InfoDump.lua
@@ -2,10 +2,17 @@
-- InfoDump.lua
--- Goes through all subfolders, loads Info.lua and dumps its g_PluginInfo into various text formats
--- This is used for generating plugin documentation for the forum and for GitHub's INFO.md files
+--[[
+Loads plugins' Info.lua and dumps its g_PluginInfo into various text formats
+This is used for generating plugin documentation for the forum and for GitHub's INFO.md files
--- This script requires LuaRocks with LFS installed, instructions are printed when this is not present.
+This script can be used in two ways:
+Executing "lua InfoDump.lua" will go through all subfolders and dump each Info.lua file it can find
+ Note that this mode of operation requires LuaRocks with LFS installed; instructions are printed
+ when the prerequisites are not met.
+Executing "lua InfoDump.lua PluginName" will load the Info.lua file from PluginName's folder and dump
+only that one plugin's documentation. This mode of operation doesn't require LuaRocks
+--]]
@@ -17,33 +24,6 @@ if (_VERSION ~= "Lua 5.1") then
return;
end
--- Try to load lfs, do not abort if not found
-local lfs, err = pcall(
- function()
- return require("lfs")
- end
-);
-
--- Rather, print a nice message with instructions:
-if not(lfs) then
- print([[
-Cannot load LuaFileSystem
-Install it through luarocks by executing the following command:
- sudo luarocks install luafilesystem
-
-If you don't have luarocks installed, you need to install them using your OS's package manager, usually:
- sudo apt-get install luarocks
-On windows, a binary distribution can be downloaded from the LuaRocks homepage, http://luarocks.org/en/Download
-]]);
-
- print("Original error text: ", err);
- return;
-end
-
--- We now know that LFS is present, get it normally:
-lfs = require("lfs");
-
-
@@ -89,6 +69,47 @@ end
+--- Replaces generic formatting with forum-specific formatting
+-- Also removes the single line-ends
+local function GithubizeString(a_Str)
+ assert(type(a_Str) == "string");
+
+ -- Remove the indentation, unless in the code tag:
+ -- Only one code or /code tag per line is supported!
+ local IsInCode = false;
+ local function RemoveIndentIfNotInCode(s)
+ if (IsInCode) then
+ -- we're in code section, check if this line terminates it
+ IsInCode = (s:find("{%%/code}") ~= nil);
+ return s .. "\n";
+ else
+ -- we're not in code section, check if this line starts it
+ IsInCode = (s:find("{%%code}") ~= nil);
+ return s:gsub("^%s*", "") .. "\n";
+ end
+ end
+ a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode);
+
+ -- Replace multiple line ends with {%p} and single line ends with a space,
+ -- so that manual word-wrap in the Info.lua file doesn't wrap in the forum.
+ a_Str = a_Str:gsub("\n\n", "{%%p}");
+ a_Str = a_Str:gsub("\n", " ");
+
+ -- Replace the generic formatting:
+ a_Str = a_Str:gsub("{%%p}", "\n\n");
+ a_Str = a_Str:gsub("{%%b}", "**"):gsub("{%%/b}", "**");
+ a_Str = a_Str:gsub("{%%i}", "*"):gsub("{%%/i}", "*");
+ a_Str = a_Str:gsub("{%%list}", ""):gsub("{%%/list}", "");
+ a_Str = a_Str:gsub("{%%li}", " - "):gsub("{%%/li}", "");
+ -- TODO: Other formatting
+
+ return a_Str;
+end
+
+
+
+
+
--- Builds an array of categories, each containing all the commands belonging to the category,
-- and the category description, if available.
-- Returns the array table, each item has the following format:
@@ -161,6 +182,43 @@ end
+--- Returns a string specifying the command.
+-- If a_Command is a simple string, returns a_Command colorized to blue
+-- If a_Command is a table, expects members Name (full command name) and Params (command parameters),
+-- colorizes command name blue and params green
+local function GetCommandRefForum(a_Command)
+ if (type(a_Command) == "string") then
+ return "[color=blue]" .. a_Command .. "[/color]";
+ end
+ return "[color=blue]" .. a_Command.Name .. "[/color] [color=green]" .. (a_Command.Params or "") .. "[/color]";
+end
+
+
+
+
+
+--- Returns a string specifying the command.
+-- If a_CommandParams is nil, returns a_CommandName apostrophed
+-- If a_CommandParams is a string, apostrophes a_CommandName with a_CommandParams
+local function GetCommandRefGithub(a_CommandName, a_CommandParams)
+ assert(type(a_CommandName) == "string");
+ if (a_CommandParams == nil) then
+ return "`" .. a_CommandName .. "`";
+ end
+
+ assert(type(a_CommandParams) == "table");
+ if ((a_CommandParams.Params == nil) or (a_CommandParams.Params == "")) then
+ return "`" .. a_CommandName .. "`";
+ end
+
+ assert(type(a_CommandParams.Params) == "string");
+ return "`" .. a_CommandName .. " " .. a_CommandParams.Params .. "`";
+end
+
+
+
+
+
--- Writes the specified command detailed help array to the output file, in the forum dump format
local function WriteCommandParameterCombinationsForum(a_CmdString, a_ParameterCombinations, f)
assert(type(a_CmdString) == "string");
@@ -174,7 +232,7 @@ local function WriteCommandParameterCombinationsForum(a_CmdString, a_ParameterCo
f:write("The following parameter combinations are recognized:\n");
for idx, combination in ipairs(a_ParameterCombinations) do
- f:write("[color=blue]", a_CmdString, "[/color] [color=green]", combination.Params, "[/color]");
+ f:write("[color=blue]", a_CmdString, "[/color] [color=green]", combination.Params or "", "[/color]");
if (combination.Help ~= nil) then
f:write(" - ", ForumizeString(combination.Help));
end
@@ -189,6 +247,34 @@ end
+--- Writes the specified command detailed help array to the output file, in the forum dump format
+local function WriteCommandParameterCombinationsGithub(a_CmdString, a_ParameterCombinations, f)
+ assert(type(a_CmdString) == "string");
+ assert(type(a_ParameterCombinations) == "table");
+ assert(f ~= nil);
+
+ if (#a_ParameterCombinations == 0) then
+ -- No explicit parameter combinations to write
+ return;
+ end
+
+ f:write("The following parameter combinations are recognized:\n\n");
+ for idx, combination in ipairs(a_ParameterCombinations) do
+ f:write(GetCommandRefGithub(a_CmdString, combination));
+ if (combination.Help ~= nil) then
+ f:write(" - ", GithubizeString(combination.Help));
+ end
+ if (combination.Permission ~= nil) then
+ f:write(" (Requires permission '**", combination.Permission, "**')");
+ end
+ f:write("\n");
+ end
+end
+
+
+
+
+
--- Writes all commands in the specified category to the output file, in the forum dump format
local function WriteCommandsCategoryForum(a_Category, f)
-- Write category name:
@@ -211,7 +297,7 @@ local function WriteCommandsCategoryForum(a_Category, f)
f:write("Permission required: [color=red]", cmd.Info.Permission, "[/color]\n");
end
if (cmd.Info.DetailedDescription ~= nil) then
- f:write(cmd.Info.DetailedDescription);
+ f:write(ForumizeString(cmd.Info.DetailedDescription));
end
if (cmd.Info.ParameterCombinations ~= nil) then
WriteCommandParameterCombinationsForum(cmd.CommandString, cmd.Info.ParameterCombinations, f);
@@ -224,6 +310,34 @@ end
+--- Writes all commands in the specified category to the output file, in the Github dump format
+local function WriteCommandsCategoryGithub(a_Category, f)
+ -- Write category name:
+ local CategoryName = a_Category.Name;
+ if (CategoryName == "") then
+ CategoryName = "General";
+ end
+ f:write("\n### ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
+
+ -- Write description:
+ if (a_Category.Description ~= "") then
+ f:write(GithubizeString(a_Category.Description), "\n\n");
+ end
+
+ f:write("| Command | Permission | Description | \n")
+ f:write("| ------- | ---------- | ----------- | \n")
+
+ -- Write commands:
+ for idx2, cmd in ipairs(a_Category.Commands) do
+ f:write("|", cmd.CommandString, " | ", cmd.Info.Permission or "", " | ", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "| \n")
+ end
+ f:write("\n\n")
+end
+
+
+
+
+
local function DumpCommandsForum(a_PluginInfo, f)
-- Copy all Categories from a dictionary into an array:
local Categories = BuildCategories(a_PluginInfo);
@@ -251,9 +365,36 @@ end
+local function DumpCommandsGithub(a_PluginInfo, f)
+ -- Copy all Categories from a dictionary into an array:
+ local Categories = BuildCategories(a_PluginInfo);
+
+ -- Sort the categories by name:
+ table.sort(Categories,
+ function(cat1, cat2)
+ return (string.lower(cat1.Name) < string.lower(cat2.Name));
+ end
+ );
+
+ if (#Categories == 0) then
+ return;
+ end
+
+ f:write("\n# Commands\n");
+
+ -- Dump per-category commands:
+ for idx, cat in ipairs(Categories) do
+ WriteCommandsCategoryGithub(cat, f);
+ end
+end
+
+
+
+
+
local function DumpAdditionalInfoForum(a_PluginInfo, f)
local AInfo = a_PluginInfo.AdditionalInfo;
- if ((AInfo == nil) or (type(AInfo) ~= "table")) then
+ if (type(AInfo) ~= "table") then
-- There is no AdditionalInfo in a_PluginInfo
return;
end
@@ -270,6 +411,153 @@ end
+local function DumpAdditionalInfoGithub(a_PluginInfo, f)
+ local AInfo = a_PluginInfo.AdditionalInfo;
+ if (type(AInfo) ~= "table") then
+ -- There is no AdditionalInfo in a_PluginInfo
+ return;
+ end
+
+ for idx, info in ipairs(a_PluginInfo.AdditionalInfo) do
+ if ((info.Title ~= nil) and (info.Contents ~= nil)) then
+ f:write("\n# ", GithubizeString(info.Title), "\n");
+ f:write(GithubizeString(info.Contents), "\n");
+ end
+ end
+end
+
+
+
+
+
+--- Collects all permissions mentioned in the info, returns them as a sorted array
+-- Each array item is {Name = "PermissionName", Info = { PermissionInfo }}
+local function BuildPermissions(a_PluginInfo)
+ -- Collect all used permissions from Commands, reference the commands that use the permission:
+ local Permissions = a_PluginInfo.Permissions or {};
+ local function CollectPermissions(a_CmdPrefix, a_Commands)
+ for cmd, info in pairs(a_Commands) do
+ CommandString = a_CmdPrefix .. cmd;
+ if ((info.Permission ~= nil) and (info.Permission ~= "")) then
+ -- Add the permission to the list of permissions:
+ local Permission = Permissions[info.Permission] or {};
+ Permissions[info.Permission] = Permission;
+ -- Add the command to the list of commands using this permission:
+ Permission.CommandsAffected = Permission.CommandsAffected or {};
+ table.insert(Permission.CommandsAffected, CommandString);
+ end
+
+ -- Process the command param combinations for permissions:
+ local ParamCombinations = info.ParameterCombinations or {};
+ for idx, comb in ipairs(ParamCombinations) do
+ if ((comb.Permission ~= nil) and (comb.Permission ~= "")) then
+ -- Add the permission to the list of permissions:
+ local Permission = Permissions[comb.Permission] or {};
+ Permissions[info.Permission] = Permission;
+ -- Add the command to the list of commands using this permission:
+ Permission.CommandsAffected = Permission.CommandsAffected or {};
+ table.insert(Permission.CommandsAffected, {Name = CommandString, Params = comb.Params});
+ end
+ end
+
+ -- Process subcommands:
+ if (info.Subcommands ~= nil) then
+ CollectPermissions(CommandString .. " ", info.Subcommands);
+ end
+ end
+ end
+ CollectPermissions("", a_PluginInfo.Commands);
+
+ -- Copy the list of permissions to an array:
+ local PermArray = {};
+ for name, perm in pairs(Permissions) do
+ table.insert(PermArray, {Name = name, Info = perm});
+ end
+
+ -- Sort the permissions array:
+ table.sort(PermArray,
+ function(p1, p2)
+ return (p1.Name < p2.Name);
+ end
+ );
+ return PermArray;
+end
+
+
+
+
+
+local function DumpPermissionsForum(a_PluginInfo, f)
+ -- Get the processed sorted array of permissions:
+ local Permissions = BuildPermissions(a_PluginInfo);
+ if ((Permissions == nil) or (#Permissions <= 0)) then
+ return;
+ end
+
+ -- Dump the permissions:
+ f:write("\n[size=X-Large]Permissions[/size]\n[list]\n");
+ for idx, perm in ipairs(Permissions) do
+ f:write(" - [color=red]", perm.Name, "[/color] - ");
+ f:write(ForumizeString(perm.Info.Description or ""));
+ local CommandsAffected = perm.Info.CommandsAffected or {};
+ if (#CommandsAffected > 0) then
+ f:write("\n[list] Commands affected:\n- ");
+ local Affects = {};
+ for idx2, cmd in ipairs(CommandsAffected) do
+ table.insert(Affects, GetCommandRefForum(cmd));
+ end
+ f:write(table.concat(Affects, "\n - "));
+ f:write("\n[/list]");
+ end
+ if (perm.Info.RecommendedGroups ~= nil) then
+ f:write("\n[list] Recommended groups: ", perm.Info.RecommendedGroups, "[/list]");
+ end
+ f:write("\n");
+ end
+ f:write("[/list]");
+end
+
+
+
+
+
+local function DumpPermissionsGithub(a_PluginInfo, f)
+ -- Get the processed sorted array of permissions:
+ local Permissions = BuildPermissions(a_PluginInfo);
+ if ((Permissions == nil) or (#Permissions <= 0)) then
+ return;
+ end
+
+ -- Dump the permissions:
+ f:write("\n# Permissions\n");
+ f:write("| Permissions | Description | Commands | Recommended groups |\n")
+ f:write("| ----------- | ----------- | -------- | ------------------ |\n")
+ for idx, perm in ipairs(Permissions) do
+ f:write(perm.Name, " | ");
+ f:write(GithubizeString(perm.Info.Description or ""), " | ");
+ local CommandsAffected = perm.Info.CommandsAffected or {};
+ if (#CommandsAffected > 0) then
+ local Affects = {};
+ for idx2, cmd in ipairs(CommandsAffected) do
+ if (type(cmd) == "string") then
+ table.insert(Affects, GetCommandRefGithub(cmd));
+ else
+ table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd));
+ end
+ end
+ f:write(table.concat(Affects, ", "), " | ");
+ end
+ if (perm.Info.RecommendedGroups ~= nil) then
+ f:write(perm.Info.RecommendedGroups, " |");
+ end
+ f:write("\n");
+ end
+end
+
+
+
+
+
local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo)
-- Open the output file:
local f, msg = io.open(a_PluginInfo.Name .. "_forum.txt", "w");
@@ -282,7 +570,11 @@ local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo)
f:write(ForumizeString(a_PluginInfo.Description), "\n");
DumpAdditionalInfoForum(a_PluginInfo, f);
DumpCommandsForum(a_PluginInfo, f);
-
+ DumpPermissionsForum(a_PluginInfo, f);
+ if (a_PluginInfo.SourceLocation ~= nil) then
+ f:write("[b][color=blue]Source:[/color] [url=", a_PluginInfo.SourceLocation, "]Link[/url][/b]");
+ end
+
f:close();
end
@@ -290,8 +582,21 @@ end
-local function DumpPluginInfoGitHub()
- -- TODO
+local function DumpPluginInfoGithub(a_PluginFolder, a_PluginInfo)
+ -- Open the output file:
+ local f, msg = io.open(a_PluginInfo.Name .. ".md", "w"); -- TODO: Save to a_PluginFolder .. "/Readme.md" instead
+ if (f == nil) then
+ print("\tCannot dump github info for plugin " .. a_PluginFolder .. ": " .. msg);
+ return;
+ end
+
+ -- Write the description:
+ f:write(GithubizeString(a_PluginInfo.Description), "\n");
+ DumpAdditionalInfoGithub(a_PluginInfo, f);
+ DumpCommandsGithub(a_PluginInfo, f);
+ DumpPermissionsGithub(a_PluginInfo, f);
+
+ f:close();
end
@@ -301,12 +606,6 @@ end
--- Tries to load the g_PluginInfo from the plugin's Info.lua file
-- Returns the g_PluginInfo table on success, or nil and error message on failure
local function LoadPluginInfo(a_FolderName)
- -- Check if the Info file is present at all:
- local Attribs = lfs.attributes(a_FolderName .. "/Info.lua");
- if ((Attribs == nil) or (Attribs.mode ~= "file")) then
- return nil;
- end
-
-- Load and compile the Info file:
local cfg, err = loadfile(a_FolderName .. "/Info.lua");
if (cfg == nil) then
@@ -332,30 +631,76 @@ local function ProcessPluginFolder(a_FolderName)
local PluginInfo, Msg = LoadPluginInfo(a_FolderName);
if (PluginInfo == nil) then
if (Msg ~= nil) then
- print("\tCannot load Info.lua: " .. Msg);
+ print("\t" .. Msg);
end
return;
end
DumpPluginInfoForum(a_FolderName, PluginInfo);
+ DumpPluginInfoGithub(a_FolderName, PluginInfo);
end
-print("Processing plugin subfolders:");
-for fnam in lfs.dir(".") do
- if ((fnam ~= ".") and (fnam ~= "..")) then
- local Attributes = lfs.attributes(fnam);
- if (Attributes ~= nil) then
- if (Attributes.mode == "directory") then
- print(fnam);
- ProcessPluginFolder(fnam);
- end
+--- Tries to load LFS through LuaRocks, returns the LFS instance, or nil on error
+local function LoadLFS()
+ -- Try to load lfs, do not abort if not found ...
+ local lfs, err = pcall(
+ function()
+ return require("lfs")
end
+ );
+
+ -- ... rather, print a nice message with instructions:
+ if not(lfs) then
+ print([[
+ Cannot load LuaFileSystem
+ Install it through luarocks by executing the following command:
+ luarocks install luafilesystem (Windows)
+ sudo luarocks install luafilesystem (*nix)
+
+ If you don't have luarocks installed, you need to install them using your OS's package manager, usually:
+ sudo apt-get install luarocks (Ubuntu / Debian)
+ On windows, a binary distribution can be downloaded from the LuaRocks homepage, http://luarocks.org/en/Download
+ ]]);
+
+ print("Original error text: ", err);
+ return nil;
end
+
+ -- We now know that LFS is present, get it normally:
+ return require("lfs");
end
+
+local Arg1 = ...;
+if ((Arg1 ~= nil) and (Arg1 ~= "")) then
+ -- Called with a plugin folder name, export only that one
+ ProcessPluginFolder(Arg1)
+else
+ -- Called without any arguments, process all subfolders:
+ local lfs = LoadLFS();
+ if (lfs == nil) then
+ -- LFS not loaded, error has already been printed, just bail out
+ return;
+ end
+ print("Processing plugin subfolders:");
+ for fnam in lfs.dir(".") do
+ if ((fnam ~= ".") and (fnam ~= "..")) then
+ local Attributes = lfs.attributes(fnam);
+ if (Attributes ~= nil) then
+ if (Attributes.mode == "directory") then
+ print(fnam);
+ ProcessPluginFolder(fnam);
+ end
+ end
+ end
+ end
+end
+print("Done.");
+
+
diff --git a/MCServer/Plugins/InfoReg.lua b/MCServer/Plugins/InfoReg.lua
new file mode 100644
index 000000000..27e63aa5b
--- /dev/null
+++ b/MCServer/Plugins/InfoReg.lua
@@ -0,0 +1,198 @@
+
+-- InfoReg.lua
+
+-- Implements registration functions that process g_PluginInfo
+
+
+
+
+
+--- Lists all the subcommands that the player has permissions for
+local function ListSubcommands(a_Player, a_Subcommands, a_CmdString)
+ if (a_Player == nil) then
+ LOGINFO("The " .. a_CmdString .. " command requires another verb:")
+ else
+ a_Player:SendMessage("The " .. a_CmdString .. " command requires another verb:")
+ end
+
+ -- Enum all the subcommands:
+ local Verbs = {};
+ for cmd, info in pairs(a_Subcommands) do
+ if (a_Player:HasPermission(info.Permission or "")) then
+ table.insert(Verbs, " " .. a_CmdString .. " " .. cmd);
+ end
+ end
+ table.sort(Verbs);
+
+ -- Send the list:
+ if (a_Player == nil) then
+ for idx, verb in ipairs(Verbs) do
+ LOGINFO(verb);
+ end
+ else
+ for idx, verb in ipairs(Verbs) do
+ a_Player:SendMessage(verb);
+ end
+ end
+end
+
+
+
+
+
+--- This is a generic command callback used for handling multicommands' parent commands
+-- For example, if there are "/gal save" and "/gal load" commands, this callback handles the "/gal" command
+-- It is used for both console and in-game commands; the console version has a_Player set to nil
+local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_Level)
+ local Verb = a_Split[a_Level + 1];
+ if (Verb == nil) then
+ -- No verb was specified. If there is a handler for the upper level command, call it:
+ if (a_CmdInfo.Handler ~= nil) then
+ return a_CmdInfo.Handler(a_Split, a_Player);
+ end
+ -- Let the player know they need to give a subcommand:
+ ListSubcommands(a_Player, a_CmdInfo.Subcommands, a_CmdString);
+ return true;
+ end
+
+ -- A verb was specified, look it up in the subcommands table:
+ local Subcommand = a_CmdInfo.Subcommands[Verb];
+ if (Subcommand == nil) then
+ if (a_Level > 1) then
+ -- This is a true subcommand, display the message and make MCS think the command was handled
+ -- Otherwise we get weird behavior: for "/cmd verb" we get "unknown command /cmd" although "/cmd" is valid
+ if (a_Player == nil) then
+ LOGWARNING("The " .. a_CmdString .. " command doesn't support verb " .. Verb)
+ else
+ a_Player:SendMessage("The " .. a_CmdString .. " command doesn't support verb " .. Verb)
+ end
+ return true;
+ end
+ -- This is a top-level command, let MCS handle the unknown message
+ return false;
+ end
+
+ -- Check the permission:
+ if (a_Player ~= nil) then
+ if not(a_Player:HasPermission(Subcommand.Permission or "")) then
+ a_Player:SendMessage("You don't have permission to execute this command");
+ return true;
+ end
+ end
+
+ -- If the handler is not valid, check the next sublevel:
+ if (Subcommand.Handler == nil) then
+ if (Subcommand.Subcommands == nil) then
+ LOG("Cannot find handler for command " .. a_CmdString .. " " .. Verb);
+ return false;
+ end
+ MultiCommandHandler(a_Split, a_Player, a_CmdString .. " " .. Verb, Subcommand, a_Level + 1);
+ return true;
+ end
+
+ -- Execute:
+ return Subcommand.Handler(a_Split, a_Player);
+end
+
+
+
+
+
+--- Registers all commands specified in the g_PluginInfo.Commands
+function RegisterPluginInfoCommands()
+ -- A sub-function that registers all subcommands of a single command, using the command's Subcommands table
+ -- The a_Prefix param already contains the space after the previous command
+ -- a_Level is the depth of the subcommands being registered, with 1 being the top level command
+ local function RegisterSubcommands(a_Prefix, a_Subcommands, a_Level)
+ assert(a_Subcommands ~= nil);
+
+ -- A table that will hold aliases to subcommands temporarily, during subcommand iteration
+ local AliasTable = {}
+
+ -- Iterate through the subcommands, register them, and accumulate aliases:
+ for cmd, info in pairs(a_Subcommands) do
+ local CmdName = a_Prefix .. cmd;
+ local Handler = info.Handler;
+ -- Provide a special handler for multicommands:
+ if (info.Subcommands ~= nil) then
+ Handler = function(a_Split, a_Player)
+ return MultiCommandHandler(a_Split, a_Player, CmdName, info, a_Level);
+ end
+ end
+
+ if (Handler == nil) then
+ LOGWARNING(g_PluginInfo.Name .. ": Invalid handler for command " .. CmdName .. ", command will not be registered.");
+ else
+ local HelpString;
+ if (info.HelpString ~= nil) then
+ HelpString = " - " .. info.HelpString;
+ else
+ HelpString = "";
+ end
+ cPluginManager.BindCommand(CmdName, info.Permission or "", Handler, HelpString);
+ -- Register all aliases for the command:
+ if (info.Alias ~= nil) then
+ if (type(info.Alias) == "string") then
+ info.Alias = {info.Alias};
+ end
+ for idx, alias in ipairs(info.Alias) do
+ cPluginManager.BindCommand(a_Prefix .. alias, info.Permission or "", Handler, HelpString);
+ -- Also copy the alias's info table as a separate subcommand,
+ -- so that MultiCommandHandler() handles it properly. Need to off-load into a separate table
+ -- than the one we're currently iterating and join after the iterating.
+ AliasTable[alias] = info
+ end
+ end
+ end -- else (if Handler == nil)
+
+ -- Recursively register any subcommands:
+ if (info.Subcommands ~= nil) then
+ RegisterSubcommands(a_Prefix .. cmd .. " ", info.Subcommands, a_Level + 1);
+ end
+ end -- for cmd, info - a_Subcommands[]
+
+ -- Add the subcommand aliases that were off-loaded during registration:
+ for alias, info in pairs(AliasTable) do
+ a_Subcommands[alias] = info
+ end
+ AliasTable = {}
+ end
+
+ -- Loop through all commands in the plugin info, register each:
+ RegisterSubcommands("", g_PluginInfo.Commands, 1);
+end
+
+
+
+
+
+--- Registers all console commands specified in the g_PluginInfo.ConsoleCommands
+function RegisterPluginInfoConsoleCommands()
+ -- A sub-function that registers all subcommands of a single command, using the command's Subcommands table
+ -- The a_Prefix param already contains the space after the previous command
+ local function RegisterSubcommands(a_Prefix, a_Subcommands, a_Level)
+ assert(a_Subcommands ~= nil);
+
+ for cmd, info in pairs(a_Subcommands) do
+ local CmdName = a_Prefix .. cmd;
+ local Handler = info.Handler
+ if (Handler == nil) then
+ Handler = function(a_Split)
+ return MultiCommandHandler(a_Split, nil, CmdName, info, a_Level);
+ end
+ end
+ cPluginManager.BindConsoleCommand(CmdName, Handler, info.HelpString or "");
+ -- Recursively register any subcommands:
+ if (info.Subcommands ~= nil) then
+ RegisterSubcommands(a_Prefix .. cmd .. " ", info.Subcommands, a_Level + 1);
+ end
+ end
+ end
+
+ -- Loop through all commands in the plugin info, register each:
+ RegisterSubcommands("", g_PluginInfo.ConsoleCommands, 1);
+end
+
+
+
+
diff --git a/MCServer/Plugins/MagicCarpet/coremessaging.lua b/MCServer/Plugins/MagicCarpet/coremessaging.lua
deleted file mode 100644
index 9fb2c0db1..000000000
--- a/MCServer/Plugins/MagicCarpet/coremessaging.lua
+++ /dev/null
@@ -1,19 +0,0 @@
-Core = cPluginManager:Get():GetPlugin("Core")
-
-function SendMessage(a_Player, a_Message)
- if (Core ~= nil) then
- Core:Call("SendMessage", a_Player, a_Message)
- end
-end
-
-function SendMessageSuccess(a_Player, a_Message)
- if (Core ~= nil) then
- Core:Call("SendMessageSuccess", a_Player, a_Message)
- end
-end
-
-function SendMessageFailure(a_Player, a_Message)
- if (Core ~= nil) then
- Core:Call("SendMessageFailure", a_Player, a_Message)
- end
-end
diff --git a/MCServer/Plugins/MagicCarpet/plugin.lua b/MCServer/Plugins/MagicCarpet/plugin.lua
index b05816e48..417ea0e02 100644
--- a/MCServer/Plugins/MagicCarpet/plugin.lua
+++ b/MCServer/Plugins/MagicCarpet/plugin.lua
@@ -6,7 +6,7 @@ function Initialize( Plugin )
Plugin:SetVersion( 2 )
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
- cPluginManager.AddHook(cPluginManager.HOOK_DISCONNECT, OnDisconnect)
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_DESTROYED, OnDisconnect)
local PluginManager = cPluginManager:Get()
PluginManager:BindCommand("/mc", "magiccarpet", HandleCarpetCommand, " - Spawns a magical carpet");
@@ -37,12 +37,12 @@ function HandleCarpetCommand( Split, Player )
if( Carpet == nil ) then
Carpets[ Player ] = cCarpet:new()
- SendMessageSuccess(Player, "You're on a magic carpet!")
- SendMessage(Player, "Look straight down to descend. Jump to ascend.")
+ Player:SendMessageSuccess("You're on a magic carpet!")
+ Player:SendMessageInfo("Look straight down to descend. Jump to ascend.")
else
Carpet:remove()
Carpets[ Player ] = nil
- SendMessageSuccess(Player, "The carpet vanished!")
+ Player:SendMessageSuccess("The carpet vanished!")
end
return true