diff options
80 files changed, 5626 insertions, 876 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d359f9004..9ce4c9ff3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,6 +19,7 @@ Code Stuff - This helps prevent mistakes such as "if (a & 1 == 0)" * White space is free, so use it freely - "freely" as in "plentifully", not "arbitrarily" + * Please leave the first line of all files blank, to get around an IDE bug. Copyright diff --git a/GNUmakefile b/GNUmakefile index f139b3d39..00778a8f5 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -21,8 +21,11 @@ # Macros # +# allow user to override compiler +# if no compiler is specified make specifies cc +ifeq ($(CC),cc) CC = /usr/bin/g++ - +endif all: MCServer/MCServer @@ -82,6 +85,15 @@ endif endif +################################################### +# Fix Crypto++ warnings in clang + +ifeq ($(shell $(CXX) --version 2>&1 | grep -i -c "clang version"),0) +CC_OPTIONS += -Wno-tautological-compare +CXX_OPTIONS += -Wno-tautological-compare +disableasm = 1 +endif + ################################################### # Set the link libraries based on the OS diff --git a/MCServer/.gitignore b/MCServer/.gitignore index ac226a77d..ff0517cfa 100644 --- a/MCServer/.gitignore +++ b/MCServer/.gitignore @@ -4,7 +4,9 @@ MCServer logs players world* +API/ API.txt +API_wiki.txt *.dat schematics *.schematic @@ -15,3 +17,4 @@ memdump* ProtectionAreas.sqlite helgrind.log motd.txt +*.deuser diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua new file mode 100644 index 000000000..53ec87572 --- /dev/null +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -0,0 +1,1528 @@ + +-- APIDesc.lua + +-- Contains the API objects' descriptions + + + + +g_APIDesc = +{ + Classes = + { + --[[ + -- What the APIDump plugin understands / how to document stuff: + ExampleClassName = + { + Desc = "Description, exported as the first paragraph of the class page. Usually enclosed within double brackets." + + Functions = + { + FunctionName = { Params = "Parameter list", Return = "Return values list", Notes = "Notes" ), + OverloadedFunctionName = -- When a function supports multiple parameter variants + { + { Params = "Parameter list 1", Return = "Return values list 1", Notes = "Notes 1" }, + { Params = "Parameter list 2", Return = "Return values list 2", Notes = "Notes 2" }, + } + } , + + Constants = + { + ConstantName = { Notes = "Notes about the constant" }, + } , + + AdditionalInfo = -- Paragraphs to be exported after the function definitions table + { + { + Header = "Header 1", + Contents = "Contents of the additional section 1", + }, + { + Header = "Header 2", + Contents = "Contents of the additional section 2", + } + }, + + Inherits = "ParentClassName", -- Only present if the class inherits from another API class + }, + ]]-- + + cArrowEntity = + { + Desc = [[ + Represents the arrow when it is shot from the bow. A subclass of the {{cProjectileEntity}}. + ]], + + Functions = + { + CanPickup = { Params = "{{cPlayer|Player}}", Return = "bool", Notes = "Returns true if the specified player can pick the arrow when it's on the ground" }, + GetDamageCoeff = { Params = "", Return = "number", Notes = "Returns the damage coefficient stored within the arrow. The damage dealt by this arrow is multiplied by this coeff" }, + GetPickupState = { Params = "", Return = "PickupState", Notes = "Returns the pickup state (one of the psXXX constants, above)" }, + IsCritical = { Params = "", Return = "bool", Notes = "Returns true if the arrow should deal critical damage. Based on the bow charge when the arrow was shot." }, + SetDamageCoeff = { Params = "number", Return = "", Notes = "Sets the damage coefficient. The damage dealt by this arrow is multiplied by this coeff" }, + SetIsCritical = { Params = "bool", Return = "", Notes = "Sets the IsCritical flag on the arrow. Critical arrow deal additional damage" }, + SetPickupState = { Params = "PickupState", Return = "", Notes = "Sets the pickup state (one of the psXXX constants, above)" }, + }, + + Constants = + { + psInCreative = { Notes = "The arrow can be picked up only by players in creative gamemode" }, + psInSurvivalOrCreative = { Notes = "The arrow can be picked up by players in survival or creative gamemode" }, + psNoPickup = { Notes = "The arrow cannot be picked up at all" }, + }, + + Inherits = "cProjectileEntity", + }, + + cBlockArea = + { + Desc = [[ + This class is used when multiple adjacent blocks are to be manipulated. Because of chunking + and multithreading, manipulating single blocks using {{cWorld|cWorld:SetBlock}}() is a rather + time-consuming operation (locks for exclusive access need to be obtained, chunk lookup is done + for each block), so whenever you need to manipulate multiple adjacent blocks, it's better to wrap + the operation into a cBlockArea access. cBlockArea is capable of reading / writing across chunk + boundaries, has no chunk lookups for get and set operations and is not subject to multithreading + locking (because it is not shared among threads).</p> + <p> + cBlockArea remembers its origin (MinX, MinY, MinZ coords in the Read() call) and therefore supports + absolute as well as relative get / set operations. Despite that, the contents of a cBlockArea can + be written back into the world at any coords.</p> + <p> + cBlockArea can hold any combination of the following datatypes:<ul> + <li>block types</li> + <li>block metas</li> + <li>blocklight</li> + <li>skylight</li> + </ul> + Read() and Write() functions have parameters that tell the class which datatypes to read / write. + Note that a datatype that has not been read cannot be written (FIXME).</p> + <p> + Typical usage:<ul> + <li>Create cBlockArea object</li> + <li>Read an area from the world / load from file / create anew</li> + <li>Modify blocks inside cBlockArea</li> + <li>Write the area back to a world / save to file</li> + </ul></p> + ]], + Functions = + { + constructor = { Params = "", Return = "cBlockArea", Notes = "Creates a new empty cBlockArea object" }, + Clear = { Params = "", Return = "", Notes = "Clears the object, resets it to zero size" }, + CopyFrom = { Params = "BlockAreaSrc", Return = "", Notes = "Copies contents from BlockAreaSrc into self" }, + CopyTo = { Params = "BlockAreaDst", Return = "", Notes = "Copies contents from self into BlockAreaDst." }, + Create = { Params = "SizeX, SizeY, SizeZ, [DataTypes]", Return = "", Notes = "Initializes this BlockArea to an empty area of the specified size and origin of {0, 0, 0}. Any previous contents are lost." }, + Crop = { Params = "AddMinX, SubMaxX, AddMinY, SubMaxY, AddMinZ, SubMaxZ", Return = "", Notes = "Crops the specified number of blocks from each border. Modifies the size of this blockarea object." }, + 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() )." }, + 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" }, + 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" }, + GetRelBlockLight = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the blocklight at the specified relative coords" }, + 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" }, + 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" }, + 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" }, + 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." }, + 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." }, + 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" }, + 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" }, + Write = { Params = "World, MinX, MinY, MinZ, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" }, + }, + Constants = + { + baTypes = { Notes = "Operation should work on block types" }, + baMetas = { Notes = "Operations should work on block metas" }, + baLight = { Notes = "Operations should work on block (emissive) light" }, + baSkyLight = { Notes = "Operations should work on skylight" }, + msOverwrite = { Notes = "Src overwrites anything in Dst" }, + msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" }, + msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" }, + msLake = { Notes = "Special mode for merging lake images" }, + }, + + AdditionalInfo = + { + { + Header = "Merge strategies", + Contents = + [[ + <p>The strategy parameter specifies how individual blocks are combined together, using the table below. + </p> + <table class="inline"> + <tbody><tr> + <th colspan="2">area block</th><th colspan="3">result</th> + </tr> + <tr> + <th> this </th><th> Src </th><th> msOverwrite </th><th> msFillAir </th><th> msImprint </th> + </tr> + <tr> + <td> air </td><td> air </td><td> air </td><td> air </td><td> air </td> + </tr> + <tr> + <td> A </td><td> air </td><td> air </td><td> A </td><td> A </td> + </tr> + <tr> + <td> air </td><td> B </td><td> B </td><td> B </td><td> B </td> + </tr> + <tr> + <td> A </td><td> B </td><td> B </td><td> A </td><td> B </td> + </tr> + </tbody></table> + + <p> + So to sum up: + <ol> + <li class="level1">msOverwrite completely overwrites all blocks with the Src's blocks</li> + <li class="level1">msFillAir overwrites only those blocks that were air</li> + <li class="level1">msImprint overwrites with only those blocks that are non-air</li> + </ol> + </p> + + <p> + Special strategies: + </p> + + <p> + <strong>msLake</strong> (evaluate top-down, first match wins): + </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> air </td><td> air </td><td> Air always gets hollowed out, even under the oceans </td> + </tr><tr> + <td> water </td><td> * </td><td> water </td><td> Water is never overwritten </td> + </tr><tr> + <td> lava </td><td> * </td><td> lava </td><td> Lava is never overwritten </td> + </tr><tr> + <td> * </td><td> water </td><td> water </td><td> Water always overwrites anything </td> + </tr><tr> + <td> * </td><td> lava </td><td> lava </td><td> Lava always overwrites anything </td> + </tr><tr> + <td> dirt </td><td> stone </td><td> stone </td><td> Stone overwrites dirt </td> + </tr><tr> + <td> grass </td><td> stone </td><td> stone </td><td> ... and grass </td> + </tr><tr> + <td> mycelium </td><td> stone </td><td> stone </td><td> ... and mycelium </td> + </tr><tr> + <td> A </td><td> stone </td><td> A </td><td> ... but nothing else </td> + </tr><tr> + <td> A </td><td> * </td><td> A </td><td> Everything else is left as it is </td> + </tr> + </tbody></table> + ]], + }, -- Merge strategies + }, -- AdditionalInfo + }, -- cBlockArea + + cBlockEntity = + { + Desc = [[ + Block entities are simply blocks in the world that have persistent data, such as the text for a sign + or contents of a chest. All block entities are also saved in the chunk data of the chunk they reside in. + The cBlockEntity class acts as a common ancestor for all the individual block entities. + ]], + + Functions = + { + GetBlockType = { Params = "", Return = "BLOCKTYPE", Notes = "Returns the blocktype which is represented by this blockentity. This is the primary means of type-identification" }, + GetChunkX = { Params = "", Return = "number", Notes = "Returns the chunk X-coord of the block entity's chunk" }, + GetChunkZ = { Params = "", Return = "number", Notes = "Returns the chunk Z-coord of the block entity's chunk" }, + GetPosX = { Params = "", Return = "number", Notes = "Returns the block X-coord of the block entity's block" }, + GetPosY = { Params = "", Return = "number", Notes = "Returns the block Y-coord of the block entity's block" }, + GetPosZ = { Params = "", Return = "number", Notes = "Returns the block Z-coord of the block entity's block" }, + GetRelX = { Params = "", Return = "number", Notes = "Returns the relative X coord of the block entity's block within the chunk" }, + GetRelZ = { Params = "", Return = "number", Notes = "Returns the relative Z coord of the block entity's block within the chunk" }, + GetWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world to which the block entity belongs" }, + }, + Constants = + { + }, + }, + + cBlockEntityWithItems = + { + Desc = [[ + This class is a common ancestor for all {{cBlockEntity|block entities}} that provide item storage. + Internally, the object has a {{cItemGrid|cItemGrid}} object for storing the items; this ItemGrid is + accessible through the API. The storage is a grid of items, items in it can be addressed either by a slot + number, or by XY coords within the grid. If a UI window is opened for this block entity, the item storage + is monitored for changes and the changes are immediately sent to clients of the UI window. + ]], + + Inherits = "cBlockEntity", + + Functions = + { + GetContents = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the cItemGrid object representing the items stored within this block entity" }, + GetSlot = + { + { Params = "SlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the cItem for the specified slot number. Returns nil for invalid slot numbers" }, + { Params = "X, Y", Return = "{{cItem|cItem}}", Notes = "Returns the cItem for the specified slot coords. Returns nil for invalid slot coords" }, + }, + SetSlot = + { + { Params = "SlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot number. Ignored if invalid slot number" }, + { Params = "X, Y, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot coords. Ignored if invalid slot coords" }, + }, + }, + Constants = + { + }, + }, + + cBoundingBox = + { + Desc = "", + Functions = {}, + Constants = {}, + }, + + cChatColor = + { + Desc = [[ + A wrapper class for constants representing colors or effects. + ]], + + Functions = + { + MakeColor = { Params = "ColorCodeConstant", Return = "string", Notes = "Creates the complete color-code-sequence from the color or effect constant" }, + }, + Constants = + { + Color = { Notes = "The first character of the color-code-sequence, §" }, + Delimiter = { Notes = "The first character of the color-code-sequence, §" }, + Random = { Notes = "Random letters and symbols animate instead of the text" }, + Plain = { Notes = "Resets all formatting to normal" }, + }, + }, + + cChestEntity = + { + Desc = [[ + A chest entity is a {{cBlockEntityWithItems|cBlockEntityWithItems}} descendant that represents a chest + in the world. Note that doublechests consist of two separate cChestEntity objects, they do not collaborate + in any way. + ]], + + Inherits = "cBlockEntityWithItems", + + Functions = + { + }, + Constants = + { + }, + }, + + cChunkDesc = + { + Desc = [[ + The cChunkDesc class is a container for chunk data while the chunk is being generated. As such, it is + only used as a parameter for the {{OnChunkGenerating|OnChunkGenerating}} and + {{OnChunkGenerated|OnChunkGenerated}} hooks and cannot be constructed on its own. Plugins can use this + class in both those hooks to manipulate generated chunks. + ]], + + Functions = + { + FillBlocks = { Params = "BlockType, BlockMeta", Return = "", Notes = "Fills the entire chunk with the specified blocks" }, + GetBiome = { Params = "RelX, RelZ", Return = "EMCSBiome", Notes = "Returns the biome at the specified relative coords" }, + GetBlockMeta = { Params = "RelX, RelY, RelZ", Return = "NIBBLETYPE", Notes = "Returns the block meta at the specified relative coords" }, + GetBlockType = { Params = "RelX, RelY, RelZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified relative coords" }, + GetBlockTypeMeta = { Params = "RelX, RelY, RelZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified relative coords" }, + GetHeight = { Params = "RelX, RelZ", Return = "number", Notes = "Returns the height at the specified relative coords" }, + IsUsingDefaultBiomes = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default biome generator" }, + IsUsingDefaultComposition = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default composition generator" }, + IsUsingDefaultFinish = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default finishers" }, + IsUsingDefaultHeight = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default height generator" }, + IsUsingDefaultStructures = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default structures" }, + ReadBlockArea = { Params = "BlockArea, MinRelX, MaxRelX, MinRelY, MaxRelY, MinRelZ, MaxRelZ", Return = "", Notes = "Reads data from the chunk into the block area object" }, + SetBiome = { Params = "RelX, RelZ, EMCSBiome", Return = "", Notes = "Sets the biome at the specified relative coords" }, + SetBlockMeta = { Params = "RelX, RelY, RelZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified relative coords" }, + SetBlockType = { Params = "RelX, RelY, RelZ, BlockType", Return = "", Notes = "Sets the block type at the specified relative coords" }, + SetBlockTypeMeta = { Params = "RelX, RelY, RelZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block type and meta at the specified relative coords" }, + SetHeight = { Params = "RelX, RelZ, Height", Return = "", Notes = "Sets the height at the specified relative coords" }, + SetUseDefaultBiomes = { Params = "bool", Return = "", Notes = "Sets the chunk to use default biome generator or not" }, + SetUseDefaultComposition = { Params = "bool", Return = "", Notes = "Sets the chunk to use default composition generator or not" }, + 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" }, + WriteBlockArea = { Params = "BlockArea, MinRelX, MinRelY, MinRelZ", Return = "", Notes = "Writes data from the block area into the chunk" }, + }, + Constants = + { + }, + }, + + cClientHandle = + { + Desc = [[ + A cClientHandle represents technical aspect of a connected player - their game client connection. + ]], + + Functions = + { + 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" }, + 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)" }, + Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" }, + 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 block to the client. This can be used to create fake blocks." }, + }, + Constants = + { + MAX = { Notes = "10" }, + MIN = { Notes = "4" }, + }, + }, + + cCraftingGrid = + { + Desc = [[ + cCraftingGrid represents the player's crafting grid. It is used only in + {{OnCraftingNoRecipe|OnCraftingNoRecipe}}, {{OnPostCrafting|OnPostCrafting}} and + {{OnPreCrafting|OnPreCrafting}} hooks. Plugins may use it to inspect the items the player placed + on their crafting grid. + ]], + + Functions = + { + Clear = { Params = "", Return = "", Notes = "Clears the entire grid" }, + ConsumeGrid = { Params = "{{cCraftingGrid|CraftingGrid}}", Return = "", Notes = "Consumes items specified in CraftingGrid from the current contents" }, + Dump = { Params = "", Return = "", Notes = "DEBUG build: Dumps the contents of the grid to the log. RELEASE build: no action" }, + GetHeight = { Params = "", Return = "number", Notes = "Returns the height of the grid" }, + GetItem = { Params = "x, y", Return = "{{cItem|cItem}}", Notes = "Returns the item at the specified coords" }, + GetWidth = { Params = "", Return = "number", Notes = "Returns the width of the grid" }, + SetItem = + { + { Params = "x, y, {{cItem|cItem}}", Return = "", Notes = "Sets the item at the specified coords" }, + { Params = "x, y, ItemType, ItemCount, ItemDamage", Return = "", Notes = "Sets the item at the specified coords" }, + }, + }, + Constants = + { + }, + }, + + cCraftingRecipe = + { + Desc = [[ + This class is used to represent a crafting recipe, either a built-in one, or one created dynamically in a plugin. It is used only as a parameter for {{OnCraftingNoRecipe|OnCraftingNoRecipe}}, {{OnPostCrafting|OnPostCrafting}} and {{OnPreCrafting|OnPreCrafting}} hooks. Plugins may use it to inspect or modify a crafting recipe that a player views in their crafting window, either at a crafting table or the survival inventory screen. +</p> + <p>Internally, the class contains a {{cItem|cItem}} for the result. +]], + Functions = + { + Clear = { Params = "", Return = "", Notes = "Clears the entire recipe, both ingredients and results" }, + ConsumeIngredients = { Params = "CraftingGrid", Return = "", Notes = "Consumes ingredients specified in the given {{cCraftingGrid|cCraftingGrid}} class" }, + Dump = { Params = "", Return = "", Notes = "DEBUG build: dumps ingredients and result into server log. RELEASE build: no action" }, + GetIngredient = { Params = "x, y", Return = "{{cItem|cItem}}", Notes = "Returns the ingredient stored in the recipe at the specified coords" }, + GetIngredientsHeight = { Params = "", Return = "number", Notes = "Returns the height of the ingredients' grid" }, + GetIngredientsWidth = { Params = "", Return = "number", Notes = "Returns the width of the ingredients' grid" }, + GetResult = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the result of the recipe" }, + SetIngredient = + { + { Params = "x, y, {{cItem|cItem}}", Return = "", Notes = "Sets the ingredient at the specified coords" }, + { Params = "x, y, ItemType, ItemCount, ItemDamage", Return = "", Notes = "Sets the ingredient at the specified coords" }, + }, + SetResult = + { + { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the result item" }, + { Params = "ItemType, ItemCount, ItemDamage", Return = "", Notes = "Sets the result item" }, + }, + }, + Constants = + { + }, + }, + + cCuboid = + { + Desc = [[ + cCuboid offers some native support for integral-boundary cuboids. A cuboid simply consists of two + {{vector3i}}-s. It offers some extra functions for sorting and checking if a point is inside the + cuboid. + ]], + Functions = + { + Sort = { Notes = "void" }, + IsInside = { Notes = "bool" }, + IsInside = { Notes = "bool" }, + }, + Variables = + { + p1 = { Notes = "{{Vector3i}} of one corner. Usually the lesser of the two coords in each set" }, + p2 = { Notes = "{{Vector3i}} of the other corner. Usually the larger of the two coords in each set" }, + }, + }, + + cDispenserEntity = + { + Desc = [[This class represents a dispenser block entity in the world. Most of this block entity's functionality is implemented in the {{cDropSpenserEntity|cDropSpenserEntity}} class that represents the behavior common with a {{cDropperEntity|dropper}} entity. +</p> + <p>An object of this class can be created from scratch when generating chunks ({{OnChunkGenerated|OnChunkGenerated}} and {{OnChunkGenerating|OnChunkGenerating}} hooks). +]], + Functions = + { + constructor = { Params = "BlockX, BlockY, BlockZ", Return = "cDispenserEntity", Notes = "Creates a new cDispenserEntity at the specified coords" }, + }, + Constants = + { + }, + Inherits = "cDropSpenserEntity", + }, + + cDropperEntity = + { + Desc = [[This class represents a dropper block entity in the world. Most of this block entity's functionality is implemented in the {{cDropSpenserEntity|cDropSpenserEntity}} class that represents the behavior common with the {{cDispenserEntity|dispenser}} entity. +</p> + <p>An object of this class can be created from scratch when generating chunks ({{OnChunkGenerated|OnChunkGenerated}} and {{OnChunkGenerating|OnChunkGenerating}} hooks). +]], + Functions = + { + constructor = { Params = "BlockX, BlockY, BlockZ", Return = "cDropperEntity", Notes = "Creates a new cDropperEntity at the specified coords" }, + }, + Constants = + { + }, + Inherits = "cDropSpenserEntity", + }, + + cDropSpenserEntity = + { + Desc = [[This is a class that implements behavior common to both {{cDispenserEntity|dispensers}} and {{cDropperEntity|droppers}}. +]], + Functions = + { + Activate = { Params = "", Return = "", Notes = "Sets the block entity to dropspense an item in the next tick" }, + AddDropSpenserDir = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "BlockX, BlockY, BlockZ", Notes = "Adjusts the block coords to where the dropspenser items materialize" }, + SetRedstonePower = { Params = "IsPowered", Return = "", Notes = "Sets the redstone status of the dropspenser. If the redstone power goes from off to on, the dropspenser will be activated" }, + }, + Constants = + { + ContentsWidth = { Notes = "Width (X) of the cItemGrid representing the contents" }, + ContentsHeight = { Notes = "Height (Y) of the cItemGrid representing the contents" }, + }, + + Inherits = "cBlockEntity"; + }, + + cEnchantments = + { + Desc = [[This class is the storage for enchantments for a single {{cItem|cItem}} object, through its m_Enchantments member variable. Although it is possible to create a standalone object of this class, it is not yet used in any API directly. +</p> + <p>Enchantments can be initialized either programmatically by calling the individual functions (SetLevel()), or by using a string description of the enchantment combination. This string description is in the form "id=lvl;id=lvl;...;id=lvl;", where id is either a numerical ID of the enchantment, or its textual representation from the table below, and lvl is the desired enchantment level. The class can also create its string description from its current contents; however that string description will only have the numerical IDs. +]], + Functions = + { + constructor = { Params = "", Return = "cEnchantments", Notes = "Creates a new empty cEnchantments object" }, + constructor = { Params = "StringSpec", Return = "cEnchantments", Notes = "Creates a new cEnchantments object filled with enchantments based on the string description" }, + AddFromString = { Params = "StringSpec", Return = "", Notes = "Adds the enchantments in the string description into the object. If a specified enchantment already existed, it is overwritten." }, + Clear = { Params = "", Return = "", Notes = "Removes all enchantments" }, + GetLevel = { Params = "EnchantmentNumID", Return = "number", Notes = "Returns the level of the specified enchantment stored in this object; 0 if not stored" }, + IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if the object stores no enchantments" }, + SetLevel = { Params = "EnchantmentNumID, Level", Return = "", Notes = "Sets the level for the specified enchantment, adding it if not stored before or removing it if level < = 0" }, + StringToEnchantmentID = { Params = "EnchantmentTextID", Return = "number", Notes = "(static) Returns the enchantment numerical ID, -1 if not understood. Case insensitive" }, + ToString = { Params = "", Return = "string", Notes = "Returns the string description of all the enchantments stored in this object, in numerical-ID form" }, + }, + Constants = + { + }, + }, + + cEntity = + { + Desc = [[A cEntity object represents an object in the world, it has a position and orientation. cEntity is an abstract class, and can not be instantiated directly, instead, all entities are implemented as subclasses. The cEntity class works as the common interface for the operations that all (most) entities support. +</p> + <p>All cEntity objects have an Entity Type so it can be determined what kind of entity it is efficiently. Entities also have a class inheritance awareness, they know their class name, their parent class' name and can decide if there is a class within their inheritance chain. Since these functions operate on strings, they are slightly slower than checking the entity type directly, on the other hand, they are more specific (compare etMob vs "cSpider" class name). +</p> + <p>Note that you should not store a cEntity object between two hooks' calls, because MCServer may remove that entity in between the calls. If you need to refer to an entity later, use its UniqueID and {{cWorld|cWorld}}'s entity manipulation functions to access the entity. +]], + Functions = + { + Destroy = { Params = "", Return = "", Notes = "Schedules the entity to be destroyed" }, + GetChunkX = { Params = "", Return = "number", Notes = "Returns the X-coord of the chunk in which the entity is placed" }, + GetChunkY = { Params = "", Return = "number", Notes = "Returns the Y-coord of the chunk in which the entity is placed" }, + GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the chunk in which the entity is placed" }, + GetClass = { Params = "", Return = "string", Notes = "Returns the classname of the entity, such as \"spider\" or \"pickup\"" }, + GetClassStatic = { Params = "", Return = "string", Notes = "Returns the entity classname that this class implements. Each descendant overrides this function. Is static" }, + GetEntityType = { Params = "", Return = "cEntity.eEntityType", Notes = "Returns the type of the entity, one of the etXXX constants" }, + GetLookVector = { Params = "", Return = "Vector3f", Notes = "Returns the vector that defines the direction in which the entity is looking" }, + 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" }, + 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" }, + GetPosition = { Params = "", Return = "Vector3d", Notes = "Returns the entity's pivot position as a 3D vector" }, + GetRoll = { Params = "", Return = "number", Notes = "Returns the roll (sideways rotation) of the entity" }, + GetRot = { Params = "", Return = "Vector3f", Notes = "Returns the entire rotation vector (Rotation, Pitch, Roll)" }, + GetRotation = { Params = "", Return = "number", Notes = "Returns the rotation (direction) of the entity" }, + 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" }, + GetSpeedZ = { Params = "", Return = "number", Notes = "Returns the Z-part of the speed vector" }, + GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity" }, + GetWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world where the entity resides" }, + 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" }, + IsCrouched = { Params = "", Return = "bool", Notes = "Returns true if the entity is crouched. False for entities that don't support crouching" }, + IsDestroyed = { Params = "", Return = "bool", Notes = "Returns true if the entity has been destroyed and is awaiting removal from the internal structures" }, + IsMinecart = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a minecart" }, + IsMob = { Params = "", Return = "bool", Notes = "Returns true if the entity represents any mob" }, + IsOnFire = { Params = "", Return = "bool", Notes = "Returns true if the entity is on fire" }, + IsPickup = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a pickup" }, + IsPlayer = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a player" }, + IsTNT = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a TNT entity" }, + IsRclking = { Params = "", Return = "bool", Notes = "Currently unimplemented" }, + IsSprinting = { Params = "", Return = "bool", Notes = "Returns true if the entity is sprinting. ENtities that cannot sprint return always false" }, + SetPitch = { Params = "number", Return = "", Notes = "Sets the pitch (nose-down rotation) of the entity" }, + SetPosX = { Params = "number", Return = "", Notes = "Sets the X-coord of the entity's pivot" }, + SetPosY = { Params = "number", Return = "", Notes = "Sets the Y-coord of the entity's pivot" }, + SetPosZ = { Params = "number", Return = "", Notes = "Sets the Z-coord of the entity's pivot" }, + SetPosition = { Params = "X, Y, Z", Return = "", Notes = "Sets all three coords of the entity's pivot" }, + SetPosition = { Params = "{{Vector3d|Vector3d}}", Return = "", Notes = ":::" }, + SetRoll = { Params = "number", Return = "", Notes = "Sets the roll (sideways rotation) of the entity" }, + SetRot = { Params = "{{Vector3f|Vector3f}}", Return = "", Notes = "Sets the entire rotation vector (Rotation, Pitch, Roll)" }, + SetRotation = { Params = "number", Return = "", Notes = "Sets the rotation (direction) of the entity" }, + }, + Constants = + { + etEntity = { Notes = "N" }, + etPlayer = { Notes = "{{cPlayer|cPlayer" }, + etPickup = { Notes = "{{cPickup|cPickup" }, + etMob = { Notes = "{{cMonster|cMonster}} and descendan" }, + etFallingBlock = { Notes = "{{cFallingBlock|cFallingBlock" }, + etMinecart = { Notes = "{{cMinecart|cMinecart" }, + etTNT = { Notes = "{{cTNTEntity|cTNTEntity" }, + }, + }, + + cFireChargeEntity = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cProjectileEntity", + } , + + cFurnaceEntity = + { + Desc = [[This class represents a furnace block entity in the world. An object of this class can be created from scratch when generating chunks ({{OnChunkGenerated|OnChunkGenerated}} and {{OnChunkGenerating|OnChunkGenerating}} hooks) +]], + Functions = + { + constructor = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "cFurnaceEntity", Notes = "Creates a new cFurnaceEntity at the specified coords and the specified block type / meta" }, + GetCookTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current item finishes cooking, in ticks" }, + GetFuelBurnTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current fuel is depleted, in ticks" }, + GetFuelSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the fuel slot" }, + GetInputSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the input slot" }, + GetOutputSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the output slot" }, + GetTimeCooked = { Params = "", Return = "number", Notes = "Returns the time that the current item has been cooking, in ticks" }, + HasFuelTimeLeft = { Params = "", Return = "bool", Notes = "Returns true if there's time before the current fuel is depleted" }, + SetFuelSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the fuel slot" }, + SetInputSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the input slot" }, + SetOutputSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the output slot" }, + }, + Constants = + { + fsInput = { Notes = "Index of the input slot, when using the GetSlot() / SetSlot() functions" }, + fsFuel = { Notes = "Index of the fuel slot, when using the GetSlot() / SetSlot() functions" }, + fsOutput = { Notes = "Index of the output slot, when using the GetSlot() / SetSlot() functions" }, + ContentsWidth = { Notes = "Width (X) of the {{cItemGrid|cItemGrid}} representing the contents" }, + ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid|cItemGrid}} representing the contents" }, + }, + Inherits = "cBlockEntityWithItems" + }, + + cGhastFireballEntity = + { + Desc = "", + Functions = {}, + Constants = {}, + } , + + cGroup = + { + Desc = [[cGroup is a group {{cPlayer|cPlayer}}'s can be in. Groups define the permissions players have, and optionally the color of their name in the chat. +]], + Functions = + { + SetName = { Notes = "void" }, + GetName = { Notes = "String" }, + SetColor = { Notes = "void" }, + GetColor = { Notes = "String" }, + AddCommand = { Notes = "void" }, + HasCommand = { Notes = "bool" }, + AddPermission = { Notes = "void" }, + InheritFrom = { Notes = "void" }, + }, + Constants = + { + }, + }, + + cIniFile = + { + Desc = [[The cIniFile is a class that makes it simple to read from and write to INI files. MCServer uses mostly INI files for settings and options. +]], + Functions = + { + constructor = { Return = "{{cIniFile|cIniFile}}" }, + CaseSensitive = { Notes = "void" }, + CaseInsensitive = { Notes = "void" }, + Path = { Notes = "void" }, + Path = { Notes = "String" }, + SetPath = { Notes = "void" }, + ReadFile = { Notes = "bool" }, + WriteFile = { Notes = "bool" }, + Erase = { Notes = "void" }, + Clear = { Notes = "void" }, + Reset = { Notes = "void" }, + FindKey = { Notes = "long i" }, + FindValue = { Notes = "long i" }, + NumKeys = { Notes = "unsigned i" }, + GetNumKeys = { Notes = "unsigned i" }, + AddKeyName = { Notes = "unsigned int" }, + KeyName = { Notes = "Stri" }, + GetKeyName = { Notes = "Stri" }, + NumValues = { Notes = "unsigned int" }, + GetNumValues = { Notes = "unsigned int" }, + NumValues = { Notes = "unsigned int" }, + GetNumValues = { Notes = "unsigned int" }, + ValueName = { Notes = "Stri" }, + GetValueName = { Notes = "Stri" }, + ValueName = { Notes = "Stri" }, + GetValueName = { Notes = "Stri" }, + GetValue = { Notes = "Stri" }, + GetValue = { Notes = "Stri" }, + GetValueI = { Notes = "i" }, + GetValueB = { Notes = "bo" }, + GetValueF = { Notes = "doub" }, + GetValueSet = { Notes = "Stri" }, + GetValueSetI = { Notes = "i" }, + GetValueSetB = { Notes = "bo" }, + GetValueSetF = { Notes = "doub" }, + SetValue = { Notes = "bool" }, + SetValue = { Notes = "bool" }, + SetValueI = { Notes = "bool" }, + SetValueB = { Notes = "bool" }, + SetValueF = { Notes = "bool" }, + DeleteValueByID = { Notes = "bool" }, + DeleteValue = { Notes = "bool" }, + DeleteKey = { Notes = "bool" }, + NumHeaderComments = { Notes = "unsigned int" }, + HeaderComment = { Notes = "void" }, + HeaderComment = { Notes = "Stri" }, + DeleteHeaderComment = { Notes = "bool" }, + DeleteHeaderComments = { Notes = "void" }, + NumKeyComments = { Notes = "unsigned i" }, + NumKeyComments = { Notes = "unsigned i" }, + KeyComment = { Notes = "bool" }, + KeyComment = { Notes = "bool" }, + KeyComment = { Notes = "Stri" }, + KeyComment = { Notes = "Stri" }, + DeleteKeyComment = { Notes = "bool" }, + DeleteKeyComment = { Notes = "bool" }, + DeleteKeyComments = { Notes = "bool" }, + DeleteKeyComments = { Notes = "bool" }, + }, + Constants = + { + }, + }, + + cInventory = + { + Desc = [[This object is used to store the items that a {{cPlayer|cPlayer}} has. It also keeps track of what item the player has currently selected in their hotbar. +Internally, the class uses three {{cItemGrid|cItemGrid}} objects to store the contents: +<li>Armor</li> +<li>Inventory</li> +<li>Hotbar</li> +These ItemGrids are available in the API and can be manipulated by the plugins, too. +]], + Functions = + { + AddItem = { Params = "{{cItem|cItem}}, [AllowNewStacks]", Return = "number", Notes = "Adds an item to the storage; if AllowNewStacks is true (default), will also create new stacks in empty slots. Returns the number of items added" }, + AddItems = { Params = "{{cItems|cItems}}, [AllowNewStacks]", Return = "number", Notes = "Same as AddItem, but for several items at once" }, + ChangeSlotCount = { Params = "SlotNum, AddToCount", Return = "number", Notes = "Adds AddToCount to the count of items in the specified slot. If the slot was empty, ignores the call. Returns the new count in the slot, or -1 if invalid SlotNum" }, + Clear = { Params = "", Return = "", Notes = "Empties all slots" }, + CopyToItems = { Params = "{{cItems|cItems}}", Return = "", Notes = "Copies all non-empty slots into the cItems object provided; original cItems contents are preserved" }, + DamageEquippedItem = { Params = "[DamageAmount]", Return = "bool", Notes = "Adds the specified damage (1 by default) to the currently equipped it" }, + DamageItem = { Params = "SlotNum, [DamageAmount]", Return = "bool", Notes = "Adds the specified damage (1 by default) to the specified item, returns true if the item reached its max damage and should be destroyed" }, + GetArmorGrid = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the ItemGrid representing the armor grid (1 x 4 slots)" }, + GetArmorSlot = { Params = "ArmorSlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the specified armor slot contents. Note that the returned item is read-only" }, + GetEquippedBoots = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the \"boots\" slot of the armor grid. Note that the returned item is read-only" }, + GetEquippedChestplate = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the \"chestplate\" slot of the armor grid. Note that the returned item is read-only" }, + GetEquippedHelmet = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the \"helmet\" slot of the armor grid. Note that the returned item is read-only" }, + GetEquippedItem = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the currently selected item from the hotbar. Note that the returned item is read-only" }, + GetEquippedLeggings = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the \"leggings\" slot of the armor grid. Note that the returned item is read-only" }, + GetEquippedSlotNum = { Params = "", Return = "number", Notes = "Returns the hotbar slot number for the currently selected item" }, + GetHotbarGrid = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the ItemGrid representing the hotbar grid (9 x 1 slots)" }, + GetHotbarSlot = { Params = "HotBarSlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the specified hotbar slot contents. Note that the returned item is read-only" }, + GetInventoryGrid = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the ItemGrid representing the main inventory (9 x 3 slots)" }, + GetInventorySlot = { Params = "InventorySlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the specified main inventory slot contents. Note that the returned item is read-only" }, + GetOwner = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player whose inventory this object represents" }, + GetSlot = { Params = "SlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the contents of the specified slot. Note that the returned item is read-only" }, + HasItems = { Params = "{{cItem|cItem}}", Return = "bool", Notes = "Returns true if there are at least as many items of the specified type as in the parameter" }, + HowManyCanFit = { Params = "{{cItem|cItem}}", Return = "number", Notes = "Returns the number of the specified items that can fit in the storage, including empty slots" }, + HowManyItems = { Params = "{{cItem|cItem}}", Return = "number", Notes = "Returns the number of the specified items that are currently stored" }, + RemoveOneEquippedItem = { Params = "", Return = "", Notes = "Removes one item from the hotbar's currently selected slot" }, + SetArmorSlot = { Params = "ArmorSlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the specified armor slot contents" }, + SetEquippedSlotNum = { Params = "EquippedSlotNum", Return = "", Notes = "Sets the currently selected hotbar slot number" }, + SetHotbarSlot = { Params = "HotbarSlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the specified hotbar slot contents" }, + SetInventorySlot = { Params = "InventorySlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the specified main inventory slot contents" }, + SetSlot = { Params = "SlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the specified slot contents" }, + }, + Constants = + { + invArmorCount = { Notes = "Number of slots in the Armor part" }, + invArmorOffset = { Notes = "Starting slot number of the Armor part" }, + invInventoryCount = { Notes = "Number of slots in the main inventory part" }, + invInventoryOffset = { Notes = "Starting slot number of the main inventory part" }, + invHotbarCount = { Notes = "Number of slots in the Hotbar part" }, + invHotbarOffset = { Notes = "Starting slot number of the Hotbar part" }, + invNumSlots = { Notes = "Total number of slots in a cInventory" }, + }, + }, + + cItem = + { + Desc = [[ + cItem is what defines an item or stack of items in the game, it contains the item ID, damage, + quantity and enchantments. Each slot in a {{cInventory|cInventory}} class or a + {{cItemGrid|cItemGrid}} class is a cItem and each cPickup contains a cItem. The enchantments + are contained in a {{cEnchantments|cEnchantments}} class + ]], + + Functions = + { + constructor = + { + { Params = "", Return = "cItem", Notes = "Creates a new empty cItem obje" }, + { Params = "ItemType, Count, Damage, EnchantmentString", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default) and enchantments (non-enchanted by default)" }, + { Params = "cItem", Return = "cItem", Notes = "Creates an exact copy of the cItem object in the parameter" }, + } , + Clear = { Params = "", Return = "", Notes = "Resets the instance to an empty item" }, + CopyOne = { Params = "", Return = "cItem", Notes = "Creates a copy of this object, with its count set to 1" }, + DamageItem = { Params = "[Amount]", Return = "bool", Notes = "Adds the specified damage. Returns true when damage reaches max value and the item should be destroyed (but doesn't destroy the item)" }, + Empty = { Params = "", Return = "", Notes = "Resets the instance to an empty item" }, + GetMaxDamage = { Params = "", Return = "number", Notes = "Returns the maximum value for damage that this item can get before breaking; zero if damage is not accounted for for this item type" }, + IsDamageable = { Params = "", Return = "bool", Notes = "Returns true if this item does account for its damage" }, + IsEnchantable = { Params = "ItemType", Return = "bool", Notes = "(static) Returns true if the specified ItemType is an enchantable item, as defined by the 1.2.5 network protocol (deprecated)" }, + 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)" }, + 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" }, + IsStackableWith = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is stackable with the one stored in the object" }, + }, + Constants = + { + }, + }, + + 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: +<li>Chest contents</li> +<li>(TODO) Chest minecart contents</li> +<li>Dispenser contents</li> +<li>Dropper contents</li> +<li>(TODO) Furnace contents (?)</li> +<li>(TODO) Hopper contents</li> +<li>(TODO) Hopper minecart contents</li> +<li>Player Inventory areas</li> +<li>(TODO) Trapped chest contents</li> +</p> + <p>The items contained in this object are accessed either by a pair of XY coords, or a slot number (x + Width * y). There are functions available for converting between the two formats. +]], + Functions = + { + AddItem = { Params = "{{cItem|cItem}}, [AllowNewStacks]", Return = "number", Notes = "Adds an item to the storage; if AllowNewStacks is true (default), will also create new stacks in empty slots. Returns the number of items added" }, + AddItems = { Params = "{{cItems|cItems}}, [AllowNewStacks]", Return = "number", Notes = "Same as AddItem, but for several items at once" }, + ChangeSlotCount = { Params = "SlotNum, AddToCount", Return = "number", Notes = "Adds AddToCount to the count of items in the specified slot. If the slot was empty, ignores the call. Returns the new count in the slot, or -1 if invalid SlotNum" }, + ChangeSlotCount = { Params = "X, Y, AddToCount", Return = "number", Notes = "Adds AddToCount to the count of items in the specified slot. If the slot was empty, ignores the call. Returns the new count in the slot, or -1 if invalid slot coords" }, + Clear = { Params = "", Return = "", Notes = "Empties all slots" }, + CopyToItems = { Params = "{{cItems|cItems}}", Return = "", Notes = "Copies all non-empty slots into the cItems object provided; original cItems contents are preserved" }, + DamageItem = { Params = "SlotNum, [DamageAmount]", Return = "bool", Notes = "Adds the specified damage (1 by default) to the specified item, returns true if the item reached its max damage and should be destroyed" }, + DamageItem = { Params = "X, Y, [DamageAmount]", Return = "bool", Notes = "Adds the specified damage (1 by default) to the specified item, returns true if the item reached its max damage and should be destroyed" }, + EmptySlot = { Params = "SlotNum", Return = "", Notes = "Destroys the item in the specified slot" }, + EmptySlot = { Params = "X, Y", Return = "", Notes = "Destroys the item in the specified slot" }, + GetFirstEmptySlot = { Params = "", Return = "number", Notes = "Returns the SlotNumber of the first empty slot, -1 if all slots are full" }, + GetHeight = { Params = "", Return = "number", Notes = "Returns the Y dimension of the grid" }, + GetLastEmptySlot = { Params = "", Return = "number", Notes = "Returns the SlotNumber of the last empty slot, -1 if all slots are full" }, + GetNextEmptySlot = { Params = "StartFrom", Return = "number", Notes = "Returns the SlotNumber of the first empty slot following StartFrom, -1 if all the following slots are full" }, + GetNumSlots = { Params = "", Return = "number", Notes = "Returns the total number of slots in the grid (Width * Height)" }, + GetSlot = { Params = "SlotNumber", Return = "{{cItem|cItem}}", Notes = "Returns the item in the specified slot. Note that the item is read-only" }, + GetSlot = { Params = "X, Y", Return = "{{cItem|cItem}}", Notes = "Returns the item in the specified slot. Note that the item is read-only" }, + GetSlotCoords = { Params = "SlotNum", Return = "number, number", Notes = "Returns the X and Y coords for the specified SlotNumber. Returns \"-1, -1\" on invalid SlotNumber" }, + GetSlotNum = { Params = "X, Y", Return = "number", Notes = "Returns the SlotNumber for the specified slot coords. Returns -1 on invalid coords" }, + GetWidth = { Params = "", Return = "number", Notes = "Returns the X dimension of the grid" }, + HasItems = { Params = "{{cItem|cItem}}", Return = "bool", Notes = "Returns true if there are at least as many items of the specified type as in the parameter" }, + HowManyCanFit = { Params = "{{cItem|cItem}}", Return = "number", Notes = "Returns the number of the specified items that can fit in the storage, including empty slots" }, + HowManyItems = { Params = "{{cItem|cItem}}", Return = "number", Notes = "Returns the number of the specified items that are currently stored" }, + IsSlotEmpty = { Params = "SlotNum", Return = "bool", Notes = "Returns true if the specified slot is empty, or an invalid slot is specified" }, + IsSlotEmpty = { Params = "X, Y", Return = "bool", Notes = "Returns true if the specified slot is empty, or an invalid slot is specified" }, + RemoveOneItem = { Params = "SlotNum", Return = "{{cItem|cItem}}", Notes = "Removes one item from the stack in the specified slot and returns it as a single cItem. Empty slots are skipped and an empty item is returned" }, + RemoveOneItem = { Params = "X, Y", Return = "{{cItem|cItem}}", Notes = "Removes one item from the stack in the specified slot and returns it as a single cItem. Empty slots are skipped and an empty item is returned" }, + SetSlot = { Params = "SlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the specified slot to the specified item" }, + SetSlot = { Params = "X, Y, {{cItem|cItem}}", Return = "", Notes = "Sets the specified slot to the specified item" }, + }, + Constants = + { + }, + }, + + cItems = + { + Desc = [[ + This class represents a numbered collection (array) of {{cItem}} objects. The array indices start at + zero, each consecutive item gets a consecutive index. This class is used for spawning multiple + pickups or for mass manipulating an inventory. + ]], + Functions = + { + constructor = { Params = "", Return = "cItems", Notes = "Creates a new cItems object" }, + Add = { Params = "Index, {{cItem|cItem}}", Return = "", Notes = "Adds a new item to the end of the collection" }, + Add = { Params = "Index, ItemType, ItemCount, ItemDamage", Return = "", Notes = "Adds a new item to the end of the collection" }, + Clear = { Params = "", Return = "", Notes = "Removes all items from the collection" }, + Delete = { Params = "Index", Return = "", Notes = "Deletes item at the specified index" }, + Get = { Params = "Index", Return = "{{cItem|cItem}}", Notes = "Returns the item at the specified index" }, + Set = { Params = "Index, {{cItem|cItem}}", Return = "", Notes = "Sets the item at the specified index to the specified item" }, + Set = { Params = "Index, ItemType, ItemCount, ItemDamage", Return = "", Notes = "Sets the item at the specified index to the specified item" }, + Size = { Params = "", Return = "number", Notes = "Returns the number of items in the collection" }, + }, + Constants = + { + }, + }, + + cLineBlockTracer = + { + Desc = "", + Functions = {}, + Constants = {}, + }, + + 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. +</p> + <p>This class inherits from the {{cWindow|cWindow}} class, so all cWindow's functions and constants can be used, in addition to the cLuaWindow-specific functions listed below. +</p> + <p>The contents of this window are represented by a {{cWindow|cWindow}}:GetSlot() etc. or {{cPlayer|cPlayer}}:GetInventory() to access the player inventory. +</p> + <p>When creating a new cLuaWindow object, you need to specify both the window type and the contents' width and height. Note that MCServer accepts any combination of these, but opening a window for a player may crash their client if the contents' dimensions don't match the client's expectations. +</p> + <p>To open the window for a player, call {{cPlayer|cPlayer}}:OpenWindow(). Multiple players can open window of the same cLuaWindow object. All players see the same items in the window's contents (like chest, unlike crafting table). +]], + Functions = + { + constructor = { Params = "WindowType, ContentsWidth, ContentsHeight, Title", Return = "", Notes = "Creates a new object of this class" }, + GetContents = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the cItemGrid object representing the internal storage in this window" }, + SetOnClosing = { Params = "OnClosingCallback", Return = "", Notes = "Sets the function that the window will call when it is about to be closed by a player" }, + SetOnSlotChanged = { Params = "OnSlotChangedCallback", Return = "", Notes = "Sets the function that the window will call when a slot is changed by a player" }, + }, + Constants = + { + }, + AdditionalInfo = + { + { + Header = "Callbacks", + Contents = [[ + The object calls the following functions at the appropriate time: + ]], + }, + { + Header = "OnClosing Callback", + Contents = [[ + This callback, settable via the SetOnClosing() function, will be called when the player tries to close the window, or the window is closed for any other reason (such as a player disconnecting).</p> +<pre> +function OnWindowClosing(a_Window, a_Player, a_CanRefuse) +</pre> + <p> + The a_Window parameter is the cLuaWindow object representing the window, a_Player is the player for whom the window is about to close. a_CanRefuse specifies whether the callback can refuse the closing. If the callback returns true and a_CanRefuse is true, the window is not closed (internally, the server sends a new OpenWindow packet to the client). + ]], + }, + { + Header = "OnSlotChanged Callback", + Contents = [[ + This callback, settable via the SetOnSlotChanged() function, will be called whenever the contents of any slot in the window's contents (i. e. NOT in the player inventory!) changes.</p> +<pre> +function OnWindowSlotChanged(a_Window, a_SlotNum) +</pre> + <p>The a_Window parameter is the cLuaWindow object representing the window, a_SlotNum is the slot number. There is no reference to a {{cPlayer}}, because the slot change needn't originate from the player action. To get or set the slot, you'll need to retrieve a cPlayer object, for example by calling {{cWorld|cWorld}}:DoWithPlayer(). + </p> + <p>Any returned values are ignored. + ]], + }, + { + Header = "Example", + Contents = [[ + This example is taken from the Debuggers plugin, used to test the API functionality. It opens a window and refuse to close it 3 times. It also logs slot changes to the server console. +<pre> +-- Callback that refuses to close the window twice, then allows: +local Attempt = 1; +local OnClosing = function(Window, Player, CanRefuse) + Player:SendMessage("Window closing attempt #" .. Attempt .. "; CanRefuse = " .. tostring(CanRefuse)); + Attempt = Attempt + 1; + return CanRefuse and (Attempt <= 3); -- refuse twice, then allow, unless CanRefuse is set to true +end + +-- Log the slot changes: +local OnSlotChanged = function(Window, SlotNum) + LOG("Window \"" .. Window:GetWindowTitle() .. "\" slot " .. SlotNum .. " changed."); +end + +-- Set window contents: +-- a_Player is a cPlayer object received from the outside of this code fragment +local Window = cLuaWindow(cWindow.Hopper, 3, 3, "TestWnd"); +Window:SetSlot(a_Player, 0, cItem(E_ITEM_DIAMOND, 64)); +Window:SetOnClosing(OnClosing); +Window:SetOnSlotChanged(OnSlotChanged); + +-- Open the window: +a_Player:OpenWindow(Window); +</pre> + ]], + }, + }, -- AdditionalInfo + }, -- cLuaWindow + + cMonster = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cPawn", + }, + + cPawn = + { + Desc = [[cPawn is a controllable pawn object, controlled by either AI or a player. cPawn inherits all functions and members of {{centity|centity}} +]], + Functions = + { + TeleportToEntity = { Notes = "void" }, + TeleportTo = { Notes = "void" }, + Heal = { Notes = "void" }, + TakeDamage = { Notes = "void" }, + KilledBy = { Notes = "void" }, + GetHealth = { Notes = "int" }, + }, + Constants = + { + }, + Inherits = "cEntity", + }, + + cPickup = + { + Desc = [[cPickup is a pickup object representation. It is also commonly known as "drops". With this class you could create your own "drop" or modify automatically created. +]], + Functions = + { + cPickup = { Notes = "[[cPickup}}" }, + GetItem = { Notes = "{{cItem|cItem}}" }, + CollectedBy = { Notes = "bool" }, + }, + Constants = + { + }, + Inherits = "cEntity", + }, + + cPlayer = + { + Desc = [[cPlayer describes a human player in the server. cPlayer inherits all functions and members of {{cPawn|cPawn}} +]], + Functions = + { + GetEyeHeight = { Notes = "double" }, + GetEyePosition = { Notes = "{{Vector3d|Vector3d}}" }, + GetFlying = { Notes = "bool" }, + GetStance = { Notes = "double" }, + GetInventory = { Notes = "{{cInventory|cInventory}}" }, + TeleportTo = { Notes = "void" }, + GetGameMode = { Notes = "{{eGameMode|eGameMode}}" }, + GetIP = { Notes = "String" }, + GetLastBlockActionTime = { Notes = "float" }, + GetLastBlockActionCnt = { Notes = "int" }, + SetLastBlockActionCnt = { Notes = "void" }, + SetLastBlockActionTime = { Notes = "void" }, + SetGameMode = { Notes = "void" }, + MoveTo = { Notes = "void" }, + GetClientHandle = { Notes = "{{cClientHandle|cClientHandle}}" }, + SendMessage = { Notes = "void" }, + GetName = { Notes = "String" }, + SetName = { Notes = "void" }, + AddToGroup = { Notes = "void" }, + CanUseCommand = { Notes = "bool" }, + HasPermission = { Notes = "bool" }, + IsInGroup = { Notes = "bool" }, + GetColor = { Notes = "String" }, + TossItem = { Notes = "void" }, + Heal = { Notes = "void" }, + TakeDamage = { Notes = "void" }, + KilledBy = { Notes = "void" }, + Respawn = { Notes = "void" }, + SetVisible = { Notes = "void" }, + IsVisible = { Notes = "bool" }, + MoveToWorld = { Notes = "bool" }, + LoadPermissionsFromDisk = { Notes = "void" }, + GetGroups = { Notes = "list<{{cGroup|cGroup}}>" }, + GetResolvedPermissions = { Notes = "String" }, + }, + Constants = + { + }, + Inherits = "cPawn", + }, + + cPlugin = + { + Desc = [[cPlugin describes a Lua plugin. This page is dedicated to new-style plugins and contain their functions. +]], + Functions = + { + GetName = { Notes = "String" }, + SetName = { Notes = "void" }, + GetVersion = { Notes = "int" }, + SetVersion = { Notes = "void" }, + GetFileName = { Notes = "String" }, + CreateWebPlugin = { Notes = "{{cWebPlugin|cWebPlugin}}" }, + }, + Constants = + { + }, + }, + + cPluginLua = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cPlugin", + }, + + cPluginManager = + { + Desc = [[This class is used for generic plugin-related functionality. The plugin manager has a list of all plugins, can enable or disable plugins, manages hook and in-game console commands. +</p> + <p>There is one instance of cPluginManager in MCServer, to get it, call either {{GetPluginManager|GetPluginManager}}() or cPluginManager:Get() function. +]], + Functions = + { + AddHook = { Params = "{{cPlugin|Plugin}}, HookType", Return = "", Notes = "Adds processing of the specified hook" }, + BindCommand = { Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "Binds an in-game command with the specified callback function, permission and help string" }, + BindConsoleCommand = { Params = "Command, Callback, HelpString", Return = "", Notes = "Binds a console command with the specified callback function and help string" }, + DisablePlugin = { Params = "PluginName", Return = "", Notes = "Disables a plugin specified by its name" }, + ExecuteCommand = { Params = "Player, Command", Return = "bool", Notes = "Executes the command as if given by the specified Player. Checks permissions. Returns true if executed" }, + ExecuteConsoleCommand = { Params = "Command", Return = "bool", Notes = "Executes the command as if given on the server console. 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)" }, + ForceExecuteCommand = { Params = "Player, Command", Return = "bool", Notes = "Same as ExecuteCommand, but doesn't check permissions" }, + ForEachCommand = { Params = "Callback", Return = "", Notes = "Calls the Callback function for each command that has been bound using BindCommand()" }, + ForEachConsoleCommand = { Params = "Callback", Return = "", Notes = "Calls the Callback function for each command that has been bound using BindConsoleCommand()" }, + Get = { Params = "", Return = "cPluginManager", Notes = "Returns the single instance of the plugin manager" }, + GetAllPlugins = { Params = "", Return = "PluginTable", Notes = "Returns a table of all plugins, [name => cPlugin] pairs" }, + GetCommandPermission = { Params = "Command", Return = "Permission", Notes = "Returns the permission needed for executing the specified command" }, + GetNumPlugins = { Params = "", Return = "number", Notes = "Returns the number of plugins, including the disabled ones" }, + GetPlugin = { Params = "PluginName", Return = "{{cPlugin|cPlugin}}", Notes = "Returns a plugin handle of the specified plugin" }, + IsCommandBound = { Params = "Command", Return = "boolean", Notes = "Returns true if in-game Command is already bound (by any plugin)" }, + IsConsoleCommandBound = { Params = "Command", Return = "boolean", Notes = "Returns true if console Command is already bound (by any plugin)" }, + LoadPlugin = { Params = "PluginFolder", Return = "", Notes = "Loads a plugin from the specified folder" }, + ReloadPlugins = { Params = "", Return = "", Notes = "Reloads all active plugins" }, + }, + Constants = + { + }, + }, + + cProjectileEntity = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cEntity", + }, + + cRoot = + { + Desc = [[There is always only one cRoot object in MCServer. cRoot manages all the important objects such as {{cServer|cServer}} +]], + Functions = + { + }, + Constants = + { + }, + }, + + cServer = + { + Desc = [[cServer is typically only used by plugins to broadcast a chat message to all players in the server. Natively however, cServer accepts connections from clients and adds those clients to the game. +]], + Functions = + { + }, + Constants = + { + }, + }, + + cSignEntity = + { + Desc = [[ +A sign entity represents a sign in the world. +Sign entities are saved and loaded from disk when the chunk they reside in is saved or loaded +]], + Functions = + { + }, + Constants = + { + }, + + Inherits = "cBlockEntity"; + }, + + cStringMap = + { + Desc = [[cStringMap is an object that maps strings with strings, it's also known as a dictionary +]], + Functions = + { + }, + Constants = + { + }, + }, + + cThrownEggEntity = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cProjectileEntity", + }, + + cThrownEnderPearlEntity = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cProjectileEntity", + }, + + cThrownSnowballEntity = + { + Desc = "", + Functions = {}, + Constants = {}, + Inherits = "cProjectileEntity", + }, + + 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 +]], + Functions = + { + }, + Constants = + { + }, + }, + + cWebAdmin = + { + Desc = "", + Functions = {}, + Constants = {}, + }, + + cWebPlugin = + { + Desc = "", + Functions = {}, + Constants = {}, + }, + + cWindow = + { + Desc = [[This class is the common ancestor for all window classes used by MCServer. It is inherited by the {{cLuaWindow|cLuaWindow}} class that plugins use for opening custom windows. It is planned to be used for window-related hooks in the future. It implements the basic functionality of any window. +</p> + <p>Note that one cWindow object can be used for multiple players at the same time, and therefore the slot contents are player-specific (e. g. crafting grid, or player inventory). Thus the GetSlot() and SetSlot() functions need to have the {{cPlayer|cPlayer}} parameter that specifies the player for which the contents are to be queried. +]], + Functions = + { + GetWindowID = { Params = "", Return = "number", Notes = "Returns the ID of the window, as used by the network protocol" }, + GetWindowTitle = { Params = "", Return = "string", Notes = "Returns the window title that will be displayed to the player" }, + GetWindowType = { Params = "", Return = "number", Notes = "Returns the type of the window, one of the constants in the table above" }, + IsSlotInPlayerHotbar = { Params = "number", Return = "bool", Notes = "Returns true if the specified slot number is in the player hotbar" }, + IsSlotInPlayerInventory = { Params = "number", Return = "bool", Notes = "Returns true if the specified slot number is in the player's main inventory or in the hotbar. Note that this returns false for armor slots!" }, + IsSlotInPlayerMainInventory = { Params = "number", Return = "bool", Notes = "Returns true if the specified slot number is in the player's main inventory" }, + SetSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the contents of the specified slot for the specified player. Ignored if the slot number is invalid" }, + SetWindowTitle = { Params = "string", Return = "", Notes = "Sets the window title that will be displayed to the player" }, + }, + Constants = + { + Inventory = { Notes = "" }, + Chest = { Notes = "0" }, + Workbench = { Notes = "1" }, + Furnace = { Notes = "2" }, + DropSpenser = { Notes = "3" }, + Enchantment = { Notes = "4" }, + Brewery = { Notes = "5" }, + NPCTrade = { Notes = "6" }, + Beacon = { Notes = "7" }, + Anvil = { Notes = "8" }, + Hopper = { Notes = "9" }, + }, + }, + + cWorld = + { + Desc = [[ + cWorld is the game world. It is the hub of all the information managed by individual classes, + providing convenient access to them. MCServer supports multiple worlds in any combination of + world types. You can have two overworlds, three nethers etc. To enumerate all world the server + provides, use the {{cRoot}}:ForEachWorld() function.</p> + <p> + The world data is held in individual chunks. Each chunk consists of 16 (x) * 16 (z) * 256 (y) + blocks, each block is specified by its block type (8-bit) and block metadata (4-bit). + Additionally, each block has two light values calculated - skylight (how much daylight it receives) + and blocklight (how much light from light-emissive blocks it receives), both 4-bit.</p> + <p> + Each world runs several separate threads used for various housekeeping purposes, the most important + of those is the Tick thread. This thread updates the game logic 20 times per second, and it is + the thread where all the gameplay actions are evaluated. Liquid physics, entity interactions, + player ovement etc., all are applied in this thread.</p> + <p> + Additional threads include the generation thread (generates new chunks as needed, storage thread + (saves and loads chunk from the disk), lighting thread (updates block light values) and the + chunksender thread (compresses chunks to send to the clients).</p> + <p> + The world provides access to all its {{cPlayer|players}}, {{cEntity|entities}} and {{cBlockEntity|block + entities}}. Because of multithreading issues, individual objects cannot be retrieved for indefinite + handling, but rather must be modified in callbacks, within which they are guaranteed to stay valid.</p> + <p> + Physics for individual blocks are handled by the simulators. These will fire in each tick for all + blocks that have been scheduled for simulator update ("simulator wakeup"). The simulators include + liquid physics, falling blocks, fire spreading and extinguishing and redstone.</p> + <p> + Game time is also handled by the world. It provides the time-of-day and the total world age. + ]], + + Functions = + { + BroadcastChat = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the Message to all players in this world, except the optional ExceptClient" }, + 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, {{cProjectile|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." }, + 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." }, + 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>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." }, + 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>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>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>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>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." }, + 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>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." }, + 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>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 = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, without waking up the simulators or replacing the block entities for the previous block type. Do not use if the block being replaced has a block entity tied to it!" }, + FindAndDoWithPlayer = { Params = "PlayerNameHint, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of a name similar to the specified name (weighted-match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre>function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found. Note that the name matching is very loose, so it is a good idea to check the player name in the callback function." }, + ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre>function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." }, + ForEachEntity = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre>function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." }, + ForEachEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the specified chunk. Returns true if all the entities have been processed (including when there are zero entities), or false if the chunk is not loaded or the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre>function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." }, + ForEachFurnaceInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each furnace in the chunk. Returns true if all furnaces in the chunk have been processed (including when there are zero furnaces), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre>function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next furnace, or true to abort the enumeration." }, + ForEachPlayer = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each player in the loaded world. Returns true if all the players have been processed (including when there are zero players), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre>function Callback({{cPlayer|Player}}, [CallbackData])</pre> The callback should return false or no value to continue with the next player, or true to abort the enumeration." }, + GenerateChunk = { Params = "ChunkX, ChunkZ", Return = "", Notes = "Queues the specified chunk in the chunk generator. Ignored if the chunk is already generated (use RegenerateChunk() to force chunk re-generation)." }, + GetBiomeAt = { Params = "BlockX, BlockZ", Return = "eBiome", Notes = "Returns the biome at the specified coords. Reads the biome from the chunk, if it is loaded, otherwise it uses the chunk generator to provide the biome value." }, + GetBlock = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type of the block at the specified coords, or 0 if the appropriate chunk is not loaded." }, + GetBlockBlockLight = { Params = "BlockX, BlockY, BlockZ", Return = "number", Notes = "Returns the amount of block light at the specified coords, or 0 if the appropriate chunk is not loaded." }, + GetBlockInfo = { Params = "BlockX, BlockY, BlockZ", Return = "BlockValid, BlockType, BlockMeta, BlockSkyLight, BlockBlockLight", Notes = "Returns the complete block info for the block at the specified coords. The first value specifies if the block is in a valid loaded chunk, the other values are valid only if BlockValid is true." }, + GetBlockMeta = { Params = "BlockX, BlockY, BlockZ", Return = "number", Notes = "Returns the block metadata of the block at the specified coords, or 0 if the appropriate chunk is not loaded." }, + GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "number", Notes = "Returns the block skylight of the block at the specified coords, or 0 if the appropriate chunk is not loaded." }, + GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BlockValid, BlockType, BlockMeta", Notes = "Returns the block type and metadata for the block at the specified coords. The first value specifies if the block is in a valid loaded chunk, the other values are valid only if BlockValid is true." }, + GetClassStatic = { Params = "", Return = "", Notes = "" }, + GetDimension = { Params = "", Return = "", Notes = "" }, + GetGameMode = { Params = "", Return = "", Notes = "" }, + GetGeneratorQueueLength = { Params = "", Return = "", Notes = "" }, + GetHeight = { Params = "", Return = "", Notes = "" }, + GetIniFileName = { Params = "", Return = "", Notes = "" }, + GetLightingQueueLength = { Params = "", Return = "", Notes = "" }, + GetMaxCactusHeight = { Params = "", Return = "", Notes = "" }, + GetMaxSugarcaneHeight = { Params = "", Return = "", Notes = "" }, + GetName = { Params = "", Return = "", Notes = "" }, + GetNumChunks = { Params = "", Return = "", Notes = "" }, + GetSignLines = { Params = "", Return = "", Notes = "" }, + GetSpawnX = { Params = "", Return = "", Notes = "" }, + GetSpawnY = { Params = "", Return = "", Notes = "" }, + GetSpawnZ = { Params = "", Return = "", Notes = "" }, + GetStorageLoadQueueLength = { Params = "", Return = "", Notes = "" }, + GetStorageSaveQueueLength = { Params = "", Return = "", Notes = "" }, + GetTicksUntilWeatherChange = { Params = "", Return = "", Notes = "" }, + GetTime = { Params = "", Return = "", Notes = "" }, + GetTimeOfDay = { Params = "", Return = "", Notes = "" }, + GetWeather = { Params = "", Return = "", Notes = "" }, + GetWorldAge = { Params = "", Return = "", Notes = "" }, + GrowCactus = { Params = "", Return = "", Notes = "" }, + GrowMelonPumpkin = { Params = "", Return = "", Notes = "" }, + GrowRipePlant = { Params = "", Return = "", Notes = "" }, + GrowSugarcane = { Params = "", Return = "", Notes = "" }, + GrowTree = { Params = "", Return = "", Notes = "" }, + GrowTreeByBiome = { Params = "", Return = "", Notes = "" }, + GrowTreeFromSapling = { Params = "", Return = "", Notes = "" }, + IsBlockDirectlyWatered = { Params = "", Return = "", Notes = "" }, + IsDeepSnowEnabled = { Params = "", Return = "", Notes = "" }, + IsGameModeAdventure = { Params = "", Return = "", Notes = "" }, + IsGameModeCreative = { Params = "", Return = "", Notes = "" }, + IsGameModeSurvival = { Params = "", Return = "", Notes = "" }, + IsPVPEnabled = { Params = "", Return = "", Notes = "" }, + QueueBlockForTick = { Params = "", Return = "", Notes = "" }, + QueueSaveAllChunks = { Params = "", Return = "", Notes = "" }, + QueueSetBlock = { Params = "", Return = "", Notes = "" }, + RegenerateChunk = { Params = "", Return = "", Notes = "" }, + SaveAllChunks = { Params = "", Return = "", Notes = "" }, + SendBlockTo = { Params = "", Return = "", Notes = "" }, + SetBlock = { Params = "", Return = "", Notes = "" }, + SetBlockMeta = { Params = "", Return = "", Notes = "" }, + SetNextBlockTick = { Params = "", Return = "", Notes = "" }, + SetSignLines = { Params = "", Return = "", Notes = "" }, + SetTicksUntilWeatherChange = { Params = "", Return = "", Notes = "" }, + SetTimeOfDay = { Params = "", Return = "", Notes = "" }, + SetWeather = { Params = "", Return = "", Notes = "" }, + SetWorldTime = { Params = "", Return = "", Notes = "" }, + SpawnItemPickups = { Params = "", Return = "", Notes = "" }, + SpawnMob = { Params = "", Return = "", Notes = "" }, + SpawnPrimedTNT = { Params = "", Return = "", Notes = "" }, + TryGetHeight = { Params = "", Return = "", Notes = "" }, + UnloadUnusedChunks = { Params = "", Return = "", Notes = "" }, + UpdateSign = { Params = "", Return = "", Notes = "" }, + WakeUpSimulators = { Params = "", Return = "", Notes = "" }, + WakeUpSimulatorsInArea = { Params = "", Return = "", Notes = "" }, + }, + Constants = + { + }, + }, + + TakeDamageInfo = + { + Desc = [[The TakeDamageInfo is a struct that contains the amount of damage, and the entity that caused the damage. It is used in the {{OnTakeDamage|OnTakeDamage}}() hook and in the {{cEntity|cEntity}}'s TakeDamage() function. +]], + Functions = + { + }, + Constants = + { + }, + }, + + Vector3d = + { + Desc = [[A Vector3d object uses double precision floating point values to describe a point in space. Vector3d is part of the {{vector3|vector3}} family. +]], + Functions = + { + operator_plus = {Params = "{{Vector3d}}", Return = "{{Vector3d}}", Notes = "Returns the sum of this vector with the specified vector" }, + }, + Constants = + { + }, + }, + + Vector3f = + { + Desc = [[A Vector3f object uses floating point values to describe a point in space. Vector3f is part of the {{vector3|vector3}} family. +]], + Functions = + { + }, + Constants = + { + }, + }, + + Vector3i = + { + Desc = [[A Vector3i object uses integer values to describe a point in space. Vector3i is part of the {{vector3|vector3}} family. +]], + Functions = + { + }, + Constants = + { + }, + }, + }, + + + IgnoreFunctions = + { + "Globals.assert", + "Globals.collectgarbage", + "Globals.xpcall", + "%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: + "Initialize", + "DumpAPITxt", + "CreateAPITables", + "DumpAPIHtml", + "ReadDescriptions", + "WriteHtmlClass", + }, +} ; + + + + + diff --git a/MCServer/Plugins/APIDump/APIDump.deproj b/MCServer/Plugins/APIDump/APIDump.deproj new file mode 100644 index 000000000..9ee9170f2 --- /dev/null +++ b/MCServer/Plugins/APIDump/APIDump.deproj @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<project> + <file> + <filename>APIDesc.lua</filename> + </file> + <file> + <filename>main.lua</filename> + </file> +</project> diff --git a/MCServer/Plugins/APIDump/main.css b/MCServer/Plugins/APIDump/main.css new file mode 100644 index 000000000..f9cdfc3ce --- /dev/null +++ b/MCServer/Plugins/APIDump/main.css @@ -0,0 +1,23 @@ +table +{ + background-color: #fff; + border-spacing: 0px; + border-collapse: collapse; + border-color: gray; +} + +tr +{ + display: table-row; + vertical-align: inherit; + border-color: inherit; +} + +td, th +{ + display: table-cell; + vertical-align: inherit; + padding: 3px; + border: 1px solid #ccc; +} + diff --git a/MCServer/Plugins/APIDump/main.lua b/MCServer/Plugins/APIDump/main.lua index 853ff6301..73acd3e69 100644 --- a/MCServer/Plugins/APIDump/main.lua +++ b/MCServer/Plugins/APIDump/main.lua @@ -1,5 +1,14 @@ --- Global variables -PLUGIN = {}; -- Reference to own plugin object + +-- main.lua + +-- Implements the plugin entrypoint (in this case the entire plugin) + + + + + +-- Global variables: +g_Plugin = nil; @@ -7,17 +16,19 @@ PLUGIN = {}; -- Reference to own plugin object function Initialize(Plugin) - PLUGIN = Plugin + g_Plugin = Plugin; - Plugin:SetName("APIDump") - Plugin:SetVersion(1) + Plugin:SetName("APIDump"); + Plugin:SetVersion(1); - PluginManager = cRoot:Get():GetPluginManager() LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) -- dump all available API functions and objects: - DumpAPI(); - + -- DumpAPITxt(); + + -- Dump all available API object in HTML format into a subfolder: + DumpAPIHtml(); + return true end @@ -26,16 +37,16 @@ end -function DumpAPI() +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"); + -- LOG(prefix .. i .. " == _G, CYCLE, ignoring"); elseif (v == _G.package) then - LOG(prefix .. i .. " == _G.package, ignoring"); + -- LOG(prefix .. i .. " == _G.package, ignoring"); else dump(prefix .. i .. ".", v, Output) end @@ -59,3 +70,536 @@ function DumpAPI() f:close(); LOG("API.txt written."); end + + + + + +function CreateAPITables() + --[[ + We want an API table of the following shape: + local API = { + { + Name = "cCuboid", + Functions = { + {Name = "Sort"}, + {Name = "IsInside"} + }, + Constants = { + } + Descendants = {}, -- Will be filled by ReadDescriptions(), array of class APIs (references to other member in the tree) + }}, + { + Name = "cBlockArea", + Functions = { + {Name = "Clear"}, + {Name = "CopyFrom"}, + ... + } + Constants = { + {Name = "baTypes", Value = 0}, + {Name = "baMetas", Value = 1}, + ... + } + ... + }} + }; + local Globals = { + Functions = { + ... + }, + Constants = { + ... + } + }; + --]] + + local Globals = {Functions = {}, Constants = {}, Descendants = {}}; + local API = {}; + + local function Add(a_APIContainer, a_ObjName, a_ObjValue) + if (type(a_ObjValue) == "function") then + table.insert(a_APIContainer.Functions, {Name = a_ObjName}); + elseif ( + (type(a_ObjValue) == "number") or + (type(a_ObjValue) == "string") + ) then + table.insert(a_APIContainer.Constants, {Name = a_ObjName, Value = a_ObjValue}); + end + end + + local function ParseClass(a_ClassName, a_ClassObj) + local res = {Name = a_ClassName, Functions = {}, Constants = {}, Descendants = {}}; + for i, v in pairs(a_ClassObj) do + Add(res, i, v); + end + return res; + end + + for i, v in pairs(_G) do + if ( + (v ~= _G) and -- don't want the global namespace + (v ~= _G.packages) and -- don't want any packages + (v ~= _G[".get"]) and + (v ~= g_APIDesc) + ) then + if (type(v) == "table") then + table.insert(API, ParseClass(i, v)); + else + Add(Globals, i, v); + end + end + end + + return API, Globals; +end + + + + + +function DumpAPIHtml() + LOG("Dumping all available functions and constants to API subfolder..."); + + 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 + ); + + -- Add Globals into the API: + Globals.Name = "Globals"; + table.insert(API, Globals); + + -- Read in the descriptions: + ReadDescriptions(API); + + -- Create a "class index" file, write each class as a link to that file, + -- then dump class contents into class-specific file + local f = io.open("API/index.html", "w"); + if (f == nil) then + -- Create the output folder + os.execute("mkdir API"); + local err; + f, err = io.open("API/index.html", "w"); + if (f == nil) then + LOGINFO("Cannot output HTML API: " .. err); + return; + end + end + + f:write([[<html><head><title>MCServer API - class index</title> + <link rel="stylesheet" type="text/css" href="main.css" /> + </head><body><h1>MCServer API - class index</h1> + <p>The following classes are available in the MCServer Lua scripting language: + <ul> + ]]); + for i, cls in ipairs(API) do + f:write("<li><a href=\"" .. cls.Name .. ".html\">" .. cls.Name .. "</a></li>\n"); + WriteHtmlClass(cls, API); + end + f:write("</ul></p></body></html>"); + f:close(); + + -- Copy the CSS file to the output folder (overwrite any existing): + cssf = io.open("API/main.css", "w"); + if (cssf ~= nil) then + cssfi = io.open(g_Plugin:GetLocalDirectory() .. "/main.css", "r"); + if (cssfi ~= nil) then + local CSS = cssfi:read("*all"); + cssf:write(CSS); + cssfi:close(); + end + cssf:close(); + end + + -- List the undocumented objects: + 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 + local HasFunctions = ((cls.UndocumentedFunctions ~= nil) and (#cls.UndocumentedFunctions > 0)); + local HasConstants = ((cls.UndocumentedConstants ~= nil) and (#cls.UndocumentedConstants > 0)); + if (HasFunctions or HasConstants) then + f:write("\t\t" .. cls.Name .. " =\n\t\t{\n"); + if ((cls.Desc == nil) or (cls.Desc == "")) then + f:write("\t\t\tDesc = \"\"\n"); + end + end + + 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 + f:write("\t\t\t\t" .. fn .. " = { Params = \"\", Return = \"\", Notes = \"\" },\n"); + end -- for j, fn - cls.Undocumented[] + f:write("\t\t\t},\n\n"); + end + + 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 + f:write("\t\t\t\t" .. cn .. " = { Notes = \"\" },\n"); + end -- for j, fn - cls.Undocumented[] + f:write("\t\t\t},\n\n"); + end + + if (HasFunctions or HasConstants) then + f:write("\t\t},\n\n"); + end + end -- for i, cls - API[] + f:close(); + end + + -- List the unexported documented API objects: + f = io.open("API/unexported-documented.txt", "w"); + if (f ~= nil) then + for clsname, cls in pairs(g_APIDesc.Classes) do + if not(cls.IsExported) then + -- The whole class is not exported + f:write("class\t" .. clsname .. "\n"); + else + if (cls.Functions ~= nil) then + for fnname, fnapi in pairs(cls.Functions) do + if not(fnapi.IsExported) then + f:write("func\t" .. clsname .. "." .. fnname .. "\n"); + end + end -- for j, fn - cls.Functions[] + end + if (cls.Constants ~= nil) then + for cnname, cnapi in pairs(cls.Constants) do + if not(cnapi.IsExported) then + f:write("const\t" .. clsname .. "." .. cnname .. "\n"); + end + end -- for j, fn - cls.Functions[] + end + end + end -- for i, cls - g_APIDesc.Classes[] + f:close(); + end + + LOG("API subfolder written"); +end + + + + + +function ReadDescriptions(a_API) + -- Returns true if the function (specified by its fully qualified name) is to be ignored + local function IsFunctionIgnored(a_FnName) + if (g_APIDesc.IgnoreFunctions == nil) then + return false; + end + for i, name in ipairs(g_APIDesc.IgnoreFunctions) do + if (a_FnName:match(name)) then + return true; + end + end + return false; + end + + -- Returns true if the constant (specified by its fully qualified name) is to be ignored + local function IsConstantIgnored(a_CnName) + if (g_APIDesc.IgnoreConstants == nil) then + return false; + end; + for i, name in ipairs(g_APIDesc.IgnoreConstants) do + if (a_CnName:match(name)) then + return true; + end + end + return false; + end + + for i, cls in ipairs(a_API) do + -- Rename special functions: + for j, fn in ipairs(cls.Functions) do + if (fn.Name == ".call") then + fn.DocID = "constructor"; + fn.Name = "() <i>(constructor)</i>"; + elseif (fn.Name == ".add") then + fn.DocID = "operator_plus"; + fn.Name = "<i>operator +</i>"; + elseif (fn.Name == ".div") then + fn.DocID = "operator_div"; + fn.Name = "<i>operator /</i>"; + elseif (fn.Name == ".mul") then + fn.DocID = "operator_mul"; + fn.Name = "<i>operator *</i>"; + elseif (fn.Name == ".sub") then + fn.DocID = "operator_sub"; + fn.Name = "<i>operator -</i>"; + end + end + + local APIDesc = g_APIDesc.Classes[cls.Name]; + if (APIDesc ~= nil) then + APIDesc.IsExported = true; + cls.Desc = APIDesc.Desc; + cls.AdditionalInfo = APIDesc.AdditionalInfo; + + -- Process inheritance: + if (APIDesc.Inherits ~= nil) then + for j, icls in ipairs(a_API) do + if (icls.Name == APIDesc.Inherits) then + table.insert(icls.Descendants, cls); + cls.Inherits = icls; + end + end + end + + cls.UndocumentedFunctions = {}; -- This will contain names of all the functions that are not documented + cls.UndocumentedConstants = {}; -- This will contain names of all the constants that are not documented + + local DoxyFunctions = {}; -- This will contain all the API functions together with their documentation + + local function AddFunction(a_Name, a_Params, a_Return, a_Notes) + table.insert(DoxyFunctions, {Name = a_Name, Params = a_Params, Return = a_Return, Notes = a_Notes}); + end + + if (APIDesc.Functions ~= nil) then + -- Assign function descriptions: + for j, func in ipairs(cls.Functions) do + local FnName = func.DocID or func.Name; + local FnDesc = APIDesc.Functions[FnName]; + if (FnDesc == nil) then + -- No description for this API function + AddFunction(func.Name); + if not(IsFunctionIgnored(cls.Name .. "." .. FnName)) then + table.insert(cls.UndocumentedFunctions, FnName); + end + else + -- Description is available + if (FnDesc[1] == nil) then + -- Single function definition + AddFunction(func.Name, FnDesc.Params, FnDesc.Return, FnDesc.Notes); + else + -- Multiple function overloads + for k, desc in ipairs(FnDesc) do + AddFunction(func.Name, desc.Params, desc.Return, desc.Notes); + end -- for k, desc - FnDesc[] + end + FnDesc.IsExported = true; + end + end -- for j, func + + -- Replace functions with their described and overload-expanded versions: + cls.Functions = DoxyFunctions; + end -- if (APIDesc.Functions ~= nil) + + if (APIDesc.Constants ~= nil) then + -- Assign constant descriptions: + for j, cons in ipairs(cls.Constants) do + local CnDesc = APIDesc.Constants[cons.Name]; + if (CnDesc == nil) then + -- Not documented + if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then + table.insert(cls.UndocumentedConstants, cons.Name); + end + else + cons.Notes = CnDesc.Notes; + CnDesc.IsExported = true; + end + end -- for j, cons + end -- if (APIDesc.Constants ~= nil) + else + -- Class is not documented at all, add all its members to Undocumented lists: + cls.UndocumentedFunctions = {}; + cls.UndocumentedConstants = {}; + for j, 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 + if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then + table.insert(cls.UndocumentedConstants, cons.Name); + end + end -- for j, cons - cls.Constants[] + end -- else if (APIDesc ~= nil) + + -- Remove ignored functions: + local NewFunctions = {}; + for j, fn in ipairs(cls.Functions) do + if (not(IsFunctionIgnored(cls.Name .. "." .. fn.Name))) then + table.insert(NewFunctions, fn); + end + end -- for j, fn + cls.Functions = NewFunctions; + + -- Sort the functions (they may have been renamed): + table.sort(cls.Functions, + function(f1, f2) + if (f1.Name == f2.Name) then + -- Same name, either comparing the same function to itself, or two overloads, in which case compare the params + if ((f1.Params == nil) or (f2.Params == nil)) then + return 0; + end + return (f1.Params < f2.Params); + end + return (f1.Name < f2.Name); + end + ); + + -- Sort the constants: + table.sort(cls.Constants, + function(c1, c2) + return (c1.Name < c2.Name); + end + ); + end -- for i, cls + + -- Sort the descendants lists: + for i, cls in ipairs(a_API) do + table.sort(cls.Descendants, + function(c1, c2) + return (c1.Name < c2.Name); + end + ); + end -- for i, cls +end + + + + + +function WriteHtmlClass(a_ClassAPI, a_AllAPI) + local cf, err = io.open("API/" .. a_ClassAPI.Name .. ".html", "w"); + if (cf == nil) then + return; + end + + -- Make a link out of anything with the special linkifying syntax {{link|title}} + local function LinkifyString(a_String) + local txt = a_String:gsub("{{([^|}]*)|([^}]*)}}", "<a href=\"%1.html\">%2</a>") -- {{link|title}} + txt = txt:gsub("{{([^|}]*)}}", "<a href=\"%1.html\">%1</a>") -- {{LinkAndTitle}} + return txt; + end + + -- Writes a table containing all functions in the specified list, with an optional "inherited from" header when a_InheritedName is valid + local function WriteFunctions(a_Functions, a_InheritedName) + if (#a_Functions == 0) then + return; + end + + if (a_InheritedName ~= nil) then + cf:write("<h2>Functions inherited from " .. a_InheritedName .. "</h2>"); + end + cf:write("<table><tr><th>Name</th><th>Parameters</th><th>Return value</th><th>Notes</th></tr>\n"); + for i, func in ipairs(a_Functions) do + cf:write("<tr><td>" .. func.Name .. "</td>"); + cf:write("<td>" .. LinkifyString(func.Params or "").. "</td>"); + cf:write("<td>" .. LinkifyString(func.Return or "").. "</td>"); + cf:write("<td>" .. LinkifyString(func.Notes or "") .. "</td></tr>\n"); + end + cf:write("</table>\n"); + end + + local function WriteDescendants(a_Descendants) + if (#a_Descendants == 0) then + return; + end + cf:write("<ul>"); + for i, desc in ipairs(a_Descendants) do + cf:write("<li><a href=\"".. desc.Name .. ".html\">" .. desc.Name .. "</a>"); + WriteDescendants(desc.Descendants); + cf:write("</li>\n"); + end + cf:write("</ul>\n"); + end + + -- Build an array of inherited classes chain: + local InheritanceChain = {}; + local CurrInheritance = a_ClassAPI.Inherits; + while (CurrInheritance ~= nil) do + table.insert(InheritanceChain, CurrInheritance); + CurrInheritance = CurrInheritance.Inherits; + end + + cf:write([[<html><head><title>MCServer API - ]] .. a_ClassAPI.Name .. [[</title> + <link rel="stylesheet" type="text/css" href="main.css" /> + </head><body> + <h1>Contents</h1> + <ul> + ]]); + + local HasInheritance = ((#a_ClassAPI.Descendants > 0) or (a_ClassAPI.Inherits ~= nil)); + + -- Write the table of contents: + if (HasInheritance) then + cf:write("<li><a href=\"#inherits\">Inheritance</a></li>\n"); + end + cf:write("<li><a href=\"#constants\">Constants</a></li>\n"); + cf:write("<li><a href=\"#functions\">Functions</a></li>\n"); + if (a_ClassAPI.AdditionalInfo ~= nil) then + for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do + cf:write("<li><a href=\"#additionalinfo_" .. i .. "\">" .. additional.Header .. "</a></li>\n"); + end + end + cf:write("</ul>"); + + -- Write the class description: + cf:write("<a name=\"desc\"><h1>" .. a_ClassAPI.Name .. " class</h1></a>\n"); + if (a_ClassAPI.Desc ~= nil) then + cf:write("<p>"); + cf:write(LinkifyString(a_ClassAPI.Desc)); + cf:write("</p>\n"); + end; + + -- Write the inheritance, if available: + if (HasInheritance) then + cf:write("<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 + cf:write("<li><a href=\"" .. cls.Name .. ".html\">" .. cls.Name .. "</a></li>\n"); + end + cf:write("</ul></p>\n"); + end + if (#a_ClassAPI.Descendants > 0) then + cf:write("<p>This class has the following descendants:\n"); + WriteDescendants(a_ClassAPI.Descendants); + cf:write("</p>\n"); + end + end + + -- Write the constants: + cf:write("<a name=\"constants\"><h1>Constants</h1></a>\n"); + cf:write("<table><tr><th>Name</th><th>Value</th><th>Notes</th></tr>\n"); + for i, cons in ipairs(a_ClassAPI.Constants) do + cf:write("<tr><td>" .. cons.Name .. "</td>"); + cf:write("<td>" .. cons.Value .. "</td>"); + cf:write("<td>" .. LinkifyString(cons.Notes or "") .. "</td></tr>\n"); + end + cf:write("</table>\n"); + + -- Write the functions, including the inherited ones: + cf:write("<a name=\"functions\"><h1>Functions</h1></a>\n"); + WriteFunctions(a_ClassAPI.Functions, nil); + for i, cls in ipairs(InheritanceChain) do + WriteFunctions(cls.Functions, cls.Name); + end + + -- Write the additional infos: + if (a_ClassAPI.AdditionalInfo ~= nil) then + for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do + cf:write("<a name=\"additionalinfo_" .. i .. "\"><h1>" .. additional.Header .. "</h1></a>\n"); + cf:write(additional.Contents); + end + end + + cf:write("</body></html>"); + cf:close(); +end + + + + + diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index be16e3465..b895da05e 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -1,6 +1,5 @@ --- Global variables -PLUGIN = {}; -- Reference to own plugin object +-- Global variables g_DropSpensersToActivate = {}; -- A list of dispensers and droppers (as {World, X, Y Z} quadruplets) that are to be activated every tick g_HungerReportTick = 10; g_ShowFoodStats = false; -- When true, each player's food stats are sent to them every 10 ticks @@ -11,8 +10,6 @@ g_ShowFoodStats = false; -- When true, each player's food stats are sent to the function Initialize(Plugin) - PLUGIN = Plugin - Plugin:SetName("Debuggers") Plugin:SetVersion(1) @@ -46,6 +43,7 @@ function Initialize(Plugin) PluginManager:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window"); PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off"); PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player"); + PluginManager:BindCommand("/fb", "debuggers", HandleFireballCmd, "- Creates a ghast fireball as if shot by the player"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -480,6 +478,7 @@ end function OnWorldTick(a_World, a_Dt) + -- Report food stats, if switched on: local Tick = a_World:GetWorldAge(); if (not(g_ShowFoodStats) or (math.mod(Tick, 10) ~= 0)) then return false; @@ -825,3 +824,18 @@ end + +function HandleFireballCmd(a_Split, a_Player) + local World = a_Player:GetWorld(); + local Pos = a_Player:GetEyePosition(); + local Speed = a_Player:GetLookVector(); + Speed:Normalize(); + Pos = Pos + Speed * 2; + + World:CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity.pkGhastFireball, a_Player, Speed * 10); + return true; +end + + + + diff --git a/MCServer/groups.example.ini b/MCServer/groups.example.ini index f1a8df7d7..2e4b5ebee 100644 --- a/MCServer/groups.example.ini +++ b/MCServer/groups.example.ini @@ -13,5 +13,5 @@ Color=2 Inherits=Default [Default] -Permissions=core.build,core.help,core.playerlist,core.pluginlist,core.spawn,transapi.setlang +Permissions=core.build,core.help,core.playerlist,core.pluginlist,core.spawn,transapi.setlang,core.tell,core.me Color=7 diff --git a/MakeLuaAPI.cmd b/MakeLuaAPI.cmd new file mode 100644 index 000000000..80bb206d4 --- /dev/null +++ b/MakeLuaAPI.cmd @@ -0,0 +1,65 @@ +@echo off +:: MakeLuaAPI.cmd +:: This script is run after the nightbuild to produce the Lua API documentation and upload it to a website. +:: It expects at least three environment variables set: ftpsite, ftpuser and ftppass, specifying the FTP site and login to use for the upload + + + + + +:: Check that we got all the environment vars needed for the upload: + +if "a%ftppass%" == "a" ( + echo You need to set FTP password in the ftppass environment variable to upload the files + goto end +) +if "a%ftpuser%" == "a" ( + echo You need to set FTP username in the ftpuser environment variable to upload the files + goto end +) +if "a%ftpsite%" == "a" ( + echo You need to set FTP server in the ftpsite environment variable to upload the files + goto end +) + + + + + +:: Create the API documentation by running the server and stopping it right after it starts: + +cd MCServer +echo stop | MCServer +cd .. + + + + + +:: Upload the API to the web: + +ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /LuaAPI MCServer/API/*.* +if errorlevel 1 goto haderror +echo Upload finished. + +goto end + + + + + +:haderror +echo an error was encountered, check command output above +pause +goto finished + + + + + +:end +if "a%1" == "a" pause + + + +:finished
\ No newline at end of file diff --git a/Nightbuild2008.cmd b/Nightbuild2008.cmd index 0d93380e9..6de8d9f67 100644 --- a/Nightbuild2008.cmd +++ b/Nightbuild2008.cmd @@ -102,7 +102,7 @@ if errorlevel 1 goto haderror :: Copy all the example ini files into the Install folder for zipping: -copy MCServer\*.example.ini Install\*.example.ini +copy MCServer\*.example.ini Install\ :: Use 7-zip to compress the resulting files into a single file: set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID% diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore index 5d98f06ec..96210cfc9 100644 --- a/Tools/AnvilStats/.gitignore +++ b/Tools/AnvilStats/.gitignore @@ -6,4 +6,4 @@ Release/ Profiling *.png world/ -*.html
\ No newline at end of file +*.html diff --git a/Tools/ProtoProxy/.gitignore b/Tools/ProtoProxy/.gitignore index 3097f7aab..2a38341e5 100644 --- a/Tools/ProtoProxy/.gitignore +++ b/Tools/ProtoProxy/.gitignore @@ -1,4 +1,5 @@ Debug Release +Logs/ *.log *.nbt diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index 70dd6acd8..e985c2ff6 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -8,6 +8,9 @@ #include "Server.h" #include <iostream> +#ifdef _WIN32 + #include <direct.h> // For _mkdir() +#endif @@ -232,6 +235,18 @@ enum +AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32) +{ + return Printf("<%d, %d, %d> ~ {%.02f, %.02f, %.02f}", + a_X, a_Y, a_Z, + (double)a_X / a_Divisor, (double)a_Y / a_Divisor, (double)a_Z / a_Divisor + ); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cConnection: @@ -249,7 +264,14 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) : m_ServerBuffer(1024 KiB), m_HasClientPinged(false) { - Printf(m_LogNameBase, "Log_%d", (int)time(NULL)); + // Create the Logs subfolder, if not already created: + #if defined(_WIN32) + _mkdir("Logs"); + #else + mkdir("Logs", 0777); + #endif + + Printf(m_LogNameBase, "Logs/Log_%d", (int)time(NULL)); AString fnam(m_LogNameBase); fnam.append(".log"); m_LogFile = fopen(fnam.c_str(), "w"); @@ -1481,7 +1503,7 @@ bool cConnection::HandleServerEntityRelativeMove(void) HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dz); Log("Received a PACKET_ENTITY_RELATIVE_MOVE from the server:"); Log(" EntityID = %d", EntityID); - Log(" RelMove = <%d, %d, %d>", dx, dy, dz); + Log(" RelMove = %s", PrintableAbsIntTriplet(dx, dy, dz).c_str()); COPY_TO_CLIENT(); return true; } @@ -1500,7 +1522,7 @@ bool cConnection::HandleServerEntityRelativeMoveLook(void) HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); Log("Received a PACKET_ENTITY_RELATIVE_MOVE_LOOK from the server:"); Log(" EntityID = %d", EntityID); - Log(" RelMove = <%d, %d, %d>", dx, dy, dz); + Log(" RelMove = %s", PrintableAbsIntTriplet(dx, dy, dz).c_str()); Log(" Yaw = %d", Yaw); Log(" Pitch = %d", Pitch); COPY_TO_CLIENT(); @@ -1529,14 +1551,14 @@ bool cConnection::HandleServerEntityStatus(void) bool cConnection::HandleServerEntityTeleport(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockY); - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsY); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsZ); HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw); HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch); Log("Received a PACKET_ENTITY_TELEPORT from the server:"); Log(" EntityID = %d", EntityID); - Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ); + Log(" Pos = (%d, %d, %d) ~ {%.02f, %.02f, %.02f}", AbsX, AbsY, AbsZ, (double)AbsX / 32, (double)AbsY / 32, (double)AbsZ / 32); Log(" Yaw = %d", Yaw); Log(" Pitch = %d", Pitch); COPY_TO_CLIENT(); @@ -1555,7 +1577,7 @@ bool cConnection::HandleServerEntityVelocity(void) HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityZ); Log("Received a PACKET_ENTITY_VELOCITY from the server:"); Log(" EntityID = %d", EntityID); - Log(" Velocity = <%d, %d, %d>", VelocityX, VelocityY, VelocityZ); + Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str()); COPY_TO_CLIENT(); return true; } @@ -1624,7 +1646,8 @@ bool cConnection::HandleServerKick(void) // Split by NULL chars (StringSplit() won't work here): size_t Last = 0; - for (size_t i = 0; i < Reason.size(); i++) + size_t Len = Reason.size(); + for (size_t i = 0; i < Len; i++) { if (Reason[i] == 0) { @@ -1632,14 +1655,40 @@ bool cConnection::HandleServerKick(void) Last = i + 1; } } + if (Last < Len) + { + Split.push_back(Reason.substr(Last)); + } - if (Split.size() == 5) + if (Split.size() == 6) { - Log(" Protocol version: \"%s\"", Split[0].c_str()); - Log(" Server version: \"%s\"", Split[1].c_str()); - Log(" MOTD: \"%s\"", Split[2].c_str()); - Log(" Cur players: \"%s\"", Split[3].c_str()); - Log(" Max players: \"%s\"", Split[4].c_str()); + Log(" Preamble: \"%s\"", Split[0].c_str()); + Log(" Protocol version: \"%s\"", Split[1].c_str()); + Log(" Server version: \"%s\"", Split[2].c_str()); + Log(" MOTD: \"%s\"", Split[3].c_str()); + Log(" Cur players: \"%s\"", Split[4].c_str()); + Log(" Max players: \"%s\"", Split[5].c_str()); + + // Modify the MOTD to show that it's being ProtoProxied: + Reason.assign(Split[0]); + Reason.push_back(0); + Reason.append(Split[1]); + Reason.push_back(0); + Reason.append(Split[2]); + Reason.push_back(0); + Reason.append(Printf("ProtoProxy: %s", Split[3].c_str())); + Reason.push_back(0); + Reason.append(Split[4]); + Reason.push_back(0); + Reason.append(Split[5]); + AString ReasonBE16; + UTF8ToRawBEUTF16(Reason.data(), Reason.size(), ReasonBE16); + AString PacketStart("\xff"); + PacketStart.push_back((ReasonBE16.size() / 2) / 256); + PacketStart.push_back((ReasonBE16.size() / 2) % 256); + CLIENTSEND(PacketStart.data(), PacketStart.size()); + CLIENTSEND(ReasonBE16.data(), ReasonBE16.size()); + return true; } else { @@ -1996,9 +2045,9 @@ bool cConnection::HandleServerSpawnMob(void) Log("Received a PACKET_SPAWN_MOB from the server:"); Log(" EntityID = %d", EntityID); Log(" MobType = %d", MobType); - Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Angles = [%d, %d, %d]", Yaw, Pitch, HeadYaw); - Log(" Velocity = <%d, %d, %d>", VelocityX, VelocityY, VelocityZ); + Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str()); Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str()); LogMetadata(Metadata, 4); COPY_TO_CLIENT(); @@ -2029,7 +2078,7 @@ bool cConnection::HandleServerSpawnNamedEntity(void) Log("Received a PACKET_SPAWN_NAMED_ENTITY from the server:"); Log(" EntityID = %d (0x%x)", EntityID, EntityID); Log(" Name = %s", EntityName.c_str()); - Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); Log(" CurrentItem = %d", CurrentItem); Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str()); @@ -2102,12 +2151,12 @@ bool cConnection::HandleServerSpawnObjectVehicle(void) Log("Received a PACKET_SPAWN_OBJECT_VEHICLE from the server:"); Log(" EntityID = %d (0x%x)", EntityID, EntityID); Log(" ObjType = %d (0x%x)", ObjType, ObjType); - Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); Log(" DataIndicator = %d (0x%x)", DataIndicator, DataIndicator); if (DataIndicator != 0) { - Log(" Velocity = <%d, %d, %d>", VelocityX, VelocityY, VelocityZ); + Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str()); DataLog(ExtraData.data(), ExtraData.size(), " ExtraData size = %d:", ExtraData.size()); } COPY_TO_CLIENT(); @@ -2129,7 +2178,7 @@ bool cConnection::HandleServerSpawnPainting(void) Log("Received a PACKET_SPAWN_PAINTING from the server:"); Log(" EntityID = %d", EntityID); Log(" ImageName = \"%s\"", ImageName.c_str()); - Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Direction = %d", Direction); COPY_TO_CLIENT(); return true; @@ -2156,7 +2205,7 @@ bool cConnection::HandleServerSpawnPickup(void) Log("Received a PACKET_SPAWN_PICKUP from the server:"); Log(" EntityID = %d", EntityID); Log(" Item = %s", ItemDesc.c_str()); - Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32); + Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Angles = [%d, %d, %d]", Rotation, Pitch, Roll); COPY_TO_CLIENT(); return true; diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 7ffa3c887..af07300e3 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -387,6 +387,14 @@ > </File> <File + RelativePath="..\source\BoundingBox.cpp" + > + </File> + <File + RelativePath="..\source\BoundingBox.h" + > + </File> + <File RelativePath="..\source\ByteBuffer.cpp" > </File> @@ -479,10 +487,6 @@ > </File> <File - RelativePath="..\source\Doors.h" - > - </File> - <File RelativePath="..\source\Enchantments.cpp" > </File> @@ -1112,6 +1116,14 @@ Name="Entities" > <File + RelativePath="..\source\Entities\Boat.cpp" + > + </File> + <File + RelativePath="..\source\Entities\Boat.h" + > + </File> + <File RelativePath="..\source\Entities\Entity.cpp" > </File> @@ -2148,6 +2160,10 @@ > </File> <File + RelativePath="..\source\Blocks\BlockPumpkin.h" + > + </File> + <File RelativePath="..\source\Blocks\BlockRail.h" > </File> @@ -2240,6 +2256,10 @@ > </File> <File + RelativePath="..\source\Items\ItemBoat.h" + > + </File> + <File RelativePath="..\source\Items\ItemBow.h" > </File> @@ -2860,6 +2880,14 @@ > </File> </Filter> + <Filter + Name="APIDump" + > + <File + RelativePath="..\MCServer\Plugins\APIDump\main.lua" + > + </File> + </Filter> </Filter> </Files> <Globals> diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg index 8d87be307..b423c43a5 100644 --- a/source/AllToLua.pkg +++ b/source/AllToLua.pkg @@ -53,6 +53,7 @@ $cfile "Vector3d.h" $cfile "Vector3i.h" $cfile "Matrix4f.h" $cfile "Cuboid.h" +$cfile "BoundingBox.h" $cfile "Tracer.h" $cfile "Group.h" $cfile "BlockArea.h" diff --git a/source/Bindings.cpp b/source/Bindings.cpp index fbc25ed1c..c0e4f9911 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:04. +** Generated automatically by tolua++-1.0.92 on 09/15/13 20:27:51. */ #ifndef __cplusplus @@ -53,6 +53,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); #include "Vector3i.h" #include "Matrix4f.h" #include "Cuboid.h" +#include "BoundingBox.h" #include "Tracer.h" #include "Group.h" #include "BlockArea.h" @@ -163,6 +164,13 @@ static int tolua_collect_cTracer (lua_State* tolua_S) return 0; } +static int tolua_collect_cBoundingBox (lua_State* tolua_S) +{ + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + Mtolua_delete(self); + return 0; +} + static int tolua_collect_Vector3f (lua_State* tolua_S) { Vector3f* self = (Vector3f*) tolua_tousertype(tolua_S,1,0); @@ -204,66 +212,69 @@ static int tolua_collect_Vector3d (lua_State* tolua_S) static void tolua_reg_types (lua_State* tolua_S) { tolua_usertype(tolua_S,"cThrownEnderPearlEntity"); - tolua_usertype(tolua_S,"TakeDamageInfo"); - tolua_usertype(tolua_S,"cPluginManager"); - tolua_usertype(tolua_S,"cMonster"); - tolua_usertype(tolua_S,"cCraftingGrid"); - tolua_usertype(tolua_S,"cCraftingRecipe"); - tolua_usertype(tolua_S,"cPlugin"); - tolua_usertype(tolua_S,"cWindow"); - tolua_usertype(tolua_S,"cStringMap"); - tolua_usertype(tolua_S,"cItemGrid"); - tolua_usertype(tolua_S,"cBlockArea"); + tolua_usertype(tolua_S,"cFurnaceEntity"); + tolua_usertype(tolua_S,"cEntity"); + tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"cEnchantments"); - tolua_usertype(tolua_S,"cLuaWindow"); - tolua_usertype(tolua_S,"cServer"); + tolua_usertype(tolua_S,"cMonster"); + tolua_usertype(tolua_S,"cPluginLua"); tolua_usertype(tolua_S,"cRoot"); - tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"std::vector<cIniFile::key>"); - tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cPickup"); - tolua_usertype(tolua_S,"std::vector<std::string>"); - tolua_usertype(tolua_S,"cTracer"); - tolua_usertype(tolua_S,"cClientHandle"); + tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"cFireChargeEntity"); + tolua_usertype(tolua_S,"cWorld"); tolua_usertype(tolua_S,"cChunkDesc"); tolua_usertype(tolua_S,"cFurnaceRecipe"); - tolua_usertype(tolua_S,"Vector3i"); - tolua_usertype(tolua_S,"cChatColor"); - tolua_usertype(tolua_S,"cThrownSnowballEntity"); - tolua_usertype(tolua_S,"cWebAdmin"); - tolua_usertype(tolua_S,"cCraftingRecipes"); - tolua_usertype(tolua_S,"cItems"); - tolua_usertype(tolua_S,"cWebPlugin"); - tolua_usertype(tolua_S,"cItem"); + tolua_usertype(tolua_S,"cPluginManager"); tolua_usertype(tolua_S,"Vector3f"); - tolua_usertype(tolua_S,"cArrowEntity"); - tolua_usertype(tolua_S,"cDropSpenserEntity"); - tolua_usertype(tolua_S,"sWebAdminPage"); - tolua_usertype(tolua_S,"HTTPFormData"); + tolua_usertype(tolua_S,"cCraftingRecipes"); tolua_usertype(tolua_S,"cChestEntity"); tolua_usertype(tolua_S,"cDispenserEntity"); - tolua_usertype(tolua_S,"HTTPRequest"); - tolua_usertype(tolua_S,"cBlockEntity"); - tolua_usertype(tolua_S,"cItemGrid::cListener"); - tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"cFurnaceEntity"); - tolua_usertype(tolua_S,"cDropperEntity"); - tolua_usertype(tolua_S,"cPluginLua"); - tolua_usertype(tolua_S,"cBlockEntityWithItems"); + tolua_usertype(tolua_S,"cGhastFireballEntity"); tolua_usertype(tolua_S,"cLineBlockTracer"); + tolua_usertype(tolua_S,"cListeners"); + tolua_usertype(tolua_S,"cThrownSnowballEntity"); + tolua_usertype(tolua_S,"Vector3d"); + tolua_usertype(tolua_S,"TakeDamageInfo"); + tolua_usertype(tolua_S,"cCraftingRecipe"); + tolua_usertype(tolua_S,"cPlugin"); + tolua_usertype(tolua_S,"cItemGrid"); + tolua_usertype(tolua_S,"cBlockArea"); + tolua_usertype(tolua_S,"cLuaWindow"); + tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cBoundingBox"); + tolua_usertype(tolua_S,"cBlockEntityWithItems"); + tolua_usertype(tolua_S,"HTTPFormData"); + tolua_usertype(tolua_S,"cTracer"); + tolua_usertype(tolua_S,"cArrowEntity"); + tolua_usertype(tolua_S,"cDropSpenserEntity"); + tolua_usertype(tolua_S,"cWindow"); + tolua_usertype(tolua_S,"Vector3i"); + tolua_usertype(tolua_S,"cCraftingGrid"); + tolua_usertype(tolua_S,"cGroup"); + tolua_usertype(tolua_S,"cStringMap"); + tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cCriticalSection"); + tolua_usertype(tolua_S,"HTTPTemplateRequest"); + tolua_usertype(tolua_S,"cServer"); + tolua_usertype(tolua_S,"std::vector<std::string>"); + tolua_usertype(tolua_S,"cClientHandle"); + tolua_usertype(tolua_S,"cChatColor"); + tolua_usertype(tolua_S,"sWebAdminPage"); + tolua_usertype(tolua_S,"cWebPlugin"); tolua_usertype(tolua_S,"cIniFile"); - tolua_usertype(tolua_S,"cEntity"); - tolua_usertype(tolua_S,"cListeners"); + tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"cThrownEggEntity"); + tolua_usertype(tolua_S,"cPlayer"); tolua_usertype(tolua_S,"cGroupManager"); tolua_usertype(tolua_S,"cBlockEntityWindowOwner"); - tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"HTTPRequest"); tolua_usertype(tolua_S,"cProjectileEntity"); - tolua_usertype(tolua_S,"cWorld"); - tolua_usertype(tolua_S,"cPlayer"); - tolua_usertype(tolua_S,"Vector3d"); + tolua_usertype(tolua_S,"cItemGrid::cListener"); + tolua_usertype(tolua_S,"cDropperEntity"); + tolua_usertype(tolua_S,"cThrownEggEntity"); } /* method: new of class cIniFile */ @@ -4717,6 +4728,38 @@ static int tolua_AllToLua_cEntity_IsMinecart00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: IsBoat of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_IsBoat00 +static int tolua_AllToLua_cEntity_IsBoat00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsBoat'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsBoat(); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsBoat'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: IsTNT of class cEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_IsTNT00 static int tolua_AllToLua_cEntity_IsTNT00(lua_State* tolua_S) @@ -6445,6 +6488,41 @@ static int tolua_AllToLua_cEntity_AddSpeedZ00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: SteerVehicle of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SteerVehicle00 +static int tolua_AllToLua_cEntity_SteerVehicle00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); + float a_Forward = ((float) tolua_tonumber(tolua_S,2,0)); + float a_Sideways = ((float) tolua_tonumber(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SteerVehicle'", NULL); +#endif + { + self->SteerVehicle(a_Forward,a_Sideways); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SteerVehicle'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetUniqueID of class cEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetUniqueID00 static int tolua_AllToLua_cEntity_GetUniqueID00(lua_State* tolua_S) @@ -6645,6 +6723,133 @@ tolua_lerror: } #endif //#ifndef TOLUA_DISABLE +/* method: GetGravity of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetGravity00 +static int tolua_AllToLua_cEntity_GetGravity00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetGravity'", NULL); +#endif + { + float tolua_ret = (float) self->GetGravity(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetGravity'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: SetGravity of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetGravity00 +static int tolua_AllToLua_cEntity_SetGravity00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); + float a_Gravity = ((float) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetGravity'", NULL); +#endif + { + self->SetGravity(a_Gravity); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SetGravity'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: SetRotationFromSpeed of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetRotationFromSpeed00 +static int tolua_AllToLua_cEntity_SetRotationFromSpeed00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetRotationFromSpeed'", NULL); +#endif + { + self->SetRotationFromSpeed(); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SetRotationFromSpeed'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: SetPitchFromSpeed of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetPitchFromSpeed00 +static int tolua_AllToLua_cEntity_SetPitchFromSpeed00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetPitchFromSpeed'", NULL); +#endif + { + self->SetPitchFromSpeed(); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SetPitchFromSpeed'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetRawDamageAgainst of class cEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetRawDamageAgainst00 static int tolua_AllToLua_cEntity_GetRawDamageAgainst00(lua_State* tolua_S) @@ -9957,6 +10162,71 @@ static int tolua_AllToLua_cArrowEntity_CanPickup00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: IsCritical of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_IsCritical00 +static int tolua_AllToLua_cArrowEntity_IsCritical00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsCritical'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsCritical(); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsCritical'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: SetIsCritical of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_SetIsCritical00 +static int tolua_AllToLua_cArrowEntity_SetIsCritical00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cArrowEntity",0,&tolua_err) || + !tolua_isboolean(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cArrowEntity* self = (cArrowEntity*) tolua_tousertype(tolua_S,1,0); + bool a_IsCritical = ((bool) tolua_toboolean(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetIsCritical'", NULL); +#endif + { + self->SetIsCritical(a_IsCritical); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SetIsCritical'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: Get of class cPluginManager */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_Get00 static int tolua_AllToLua_cPluginManager_Get00(lua_State* tolua_S) @@ -11789,100 +12059,6 @@ static int tolua_AllToLua_cWorld_GetBlockBlockLight00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: GetBlockTypeMeta of class cWorld */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetBlockTypeMeta00 -static int tolua_AllToLua_cWorld_GetBlockTypeMeta00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnumber(tolua_S,4,0,&tolua_err) || - !tolua_isnumber(tolua_S,5,0,&tolua_err) || - !tolua_isnumber(tolua_S,6,0,&tolua_err) || - !tolua_isnoobj(tolua_S,7,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); - int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0)); - int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0)); - int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0)); - unsigned char a_BlockType = (( unsigned char) tolua_tonumber(tolua_S,5,0)); - unsigned char a_BlockMeta = (( unsigned char) tolua_tonumber(tolua_S,6,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetBlockTypeMeta'", NULL); -#endif - { - bool tolua_ret = (bool) self->GetBlockTypeMeta(a_BlockX,a_BlockY,a_BlockZ,a_BlockType,a_BlockMeta); - tolua_pushboolean(tolua_S,(bool)tolua_ret); - tolua_pushnumber(tolua_S,(lua_Number)a_BlockType); - tolua_pushnumber(tolua_S,(lua_Number)a_BlockMeta); - } - } - return 3; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetBlockTypeMeta'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: GetBlockInfo of class cWorld */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetBlockInfo00 -static int tolua_AllToLua_cWorld_GetBlockInfo00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnumber(tolua_S,4,0,&tolua_err) || - !tolua_isnumber(tolua_S,5,0,&tolua_err) || - !tolua_isnumber(tolua_S,6,0,&tolua_err) || - !tolua_isnumber(tolua_S,7,0,&tolua_err) || - !tolua_isnumber(tolua_S,8,0,&tolua_err) || - !tolua_isnoobj(tolua_S,9,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); - int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0)); - int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0)); - int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0)); - unsigned char a_BlockType = (( unsigned char) tolua_tonumber(tolua_S,5,0)); - unsigned char a_Meta = (( unsigned char) tolua_tonumber(tolua_S,6,0)); - unsigned char a_SkyLight = (( unsigned char) tolua_tonumber(tolua_S,7,0)); - unsigned char a_BlockLight = (( unsigned char) tolua_tonumber(tolua_S,8,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetBlockInfo'", NULL); -#endif - { - bool tolua_ret = (bool) self->GetBlockInfo(a_BlockX,a_BlockY,a_BlockZ,a_BlockType,a_Meta,a_SkyLight,a_BlockLight); - tolua_pushboolean(tolua_S,(bool)tolua_ret); - tolua_pushnumber(tolua_S,(lua_Number)a_BlockType); - tolua_pushnumber(tolua_S,(lua_Number)a_Meta); - tolua_pushnumber(tolua_S,(lua_Number)a_SkyLight); - tolua_pushnumber(tolua_S,(lua_Number)a_BlockLight); - } - } - return 5; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetBlockInfo'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: FastSetBlock of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_FastSetBlock01 static int tolua_AllToLua_cWorld_FastSetBlock01(lua_State* tolua_S) @@ -12378,9 +12554,9 @@ static int tolua_AllToLua_cWorld_WakeUpSimulatorsInArea00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: DoExplosiontAt of class cWorld */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_DoExplosiontAt00 -static int tolua_AllToLua_cWorld_DoExplosiontAt00(lua_State* tolua_S) +/* method: DoExplosionAt of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_DoExplosionAt00 +static int tolua_AllToLua_cWorld_DoExplosionAt00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -12408,16 +12584,16 @@ static int tolua_AllToLua_cWorld_DoExplosiontAt00(lua_State* tolua_S) eExplosionSource a_Source = ((eExplosionSource) (int) tolua_tonumber(tolua_S,7,0)); void* a_SourceData = ((void*) tolua_touserdata(tolua_S,8,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DoExplosiontAt'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DoExplosionAt'", NULL); #endif { - self->DoExplosiontAt(a_ExplosionSize,a_BlockX,a_BlockY,a_BlockZ,a_CanCauseFire,a_Source,a_SourceData); + self->DoExplosionAt(a_ExplosionSize,a_BlockX,a_BlockY,a_BlockZ,a_CanCauseFire,a_Source,a_SourceData); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'DoExplosiontAt'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'DoExplosionAt'.",&tolua_err); return 0; #endif } @@ -20811,6 +20987,114 @@ static int tolua_AllToLua_Vector3d_Cross00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: LineCoeffToXYPlane of class Vector3d */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3d_LineCoeffToXYPlane00 +static int tolua_AllToLua_Vector3d_LineCoeffToXYPlane00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const Vector3d",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const Vector3d* self = (const Vector3d*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_OtherEnd = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + double a_Z = ((double) tolua_tonumber(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'LineCoeffToXYPlane'", NULL); +#endif + { + double tolua_ret = (double) self->LineCoeffToXYPlane(*a_OtherEnd,a_Z); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'LineCoeffToXYPlane'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: LineCoeffToXZPlane of class Vector3d */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3d_LineCoeffToXZPlane00 +static int tolua_AllToLua_Vector3d_LineCoeffToXZPlane00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const Vector3d",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const Vector3d* self = (const Vector3d*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_OtherEnd = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + double a_Y = ((double) tolua_tonumber(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'LineCoeffToXZPlane'", NULL); +#endif + { + double tolua_ret = (double) self->LineCoeffToXZPlane(*a_OtherEnd,a_Y); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'LineCoeffToXZPlane'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: LineCoeffToYZPlane of class Vector3d */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3d_LineCoeffToYZPlane00 +static int tolua_AllToLua_Vector3d_LineCoeffToYZPlane00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const Vector3d",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const Vector3d* self = (const Vector3d*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_OtherEnd = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + double a_X = ((double) tolua_tonumber(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'LineCoeffToYZPlane'", NULL); +#endif + { + double tolua_ret = (double) self->LineCoeffToYZPlane(*a_OtherEnd,a_X); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'LineCoeffToYZPlane'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: Equals of class Vector3d */ #ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3d_Equals00 static int tolua_AllToLua_Vector3d_Equals00(lua_State* tolua_S) @@ -21228,6 +21512,24 @@ static int tolua_set_Vector3d_z(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* get function: EPS of class Vector3d */ +#ifndef TOLUA_DISABLE_tolua_get_Vector3d_EPS +static int tolua_get_Vector3d_EPS(lua_State* tolua_S) +{ + tolua_pushnumber(tolua_S,(lua_Number)Vector3d::EPS); + return 1; +} +#endif //#ifndef TOLUA_DISABLE + +/* get function: NO_INTERSECTION of class Vector3d */ +#ifndef TOLUA_DISABLE_tolua_get_Vector3d_NO_INTERSECTION +static int tolua_get_Vector3d_NO_INTERSECTION(lua_State* tolua_S) +{ + tolua_pushnumber(tolua_S,(lua_Number)Vector3d::NO_INTERSECTION); + return 1; +} +#endif //#ifndef TOLUA_DISABLE + /* method: new of class Vector3i */ #ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3i_new00 static int tolua_AllToLua_Vector3i_new00(lua_State* tolua_S) @@ -22405,6 +22707,700 @@ static int tolua_AllToLua_cCuboid_IsSorted00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: new of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new00 +static int tolua_AllToLua_cBoundingBox_new00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnumber(tolua_S,7,0,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + double a_MinX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_MaxX = ((double) tolua_tonumber(tolua_S,3,0)); + double a_MinY = ((double) tolua_tonumber(tolua_S,4,0)); + double a_MaxY = ((double) tolua_tonumber(tolua_S,5,0)); + double a_MinZ = ((double) tolua_tonumber(tolua_S,6,0)); + double a_MaxZ = ((double) tolua_tonumber(tolua_S,7,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(a_MinX,a_MaxX,a_MinY,a_MaxY,a_MinZ,a_MaxZ)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new_local of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new00_local +static int tolua_AllToLua_cBoundingBox_new00_local(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnumber(tolua_S,7,0,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + double a_MinX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_MaxX = ((double) tolua_tonumber(tolua_S,3,0)); + double a_MinY = ((double) tolua_tonumber(tolua_S,4,0)); + double a_MaxY = ((double) tolua_tonumber(tolua_S,5,0)); + double a_MinZ = ((double) tolua_tonumber(tolua_S,6,0)); + double a_MaxZ = ((double) tolua_tonumber(tolua_S,7,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(a_MinX,a_MaxX,a_MinY,a_MaxY,a_MinZ,a_MaxZ)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new01 +static int tolua_AllToLua_cBoundingBox_new01(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Min = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Max = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(*a_Min,*a_Max)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_new00(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new_local of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new01_local +static int tolua_AllToLua_cBoundingBox_new01_local(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Min = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Max = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(*a_Min,*a_Max)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_new00_local(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new02 +static int tolua_AllToLua_cBoundingBox_new02(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Pos = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + double a_Radius = ((double) tolua_tonumber(tolua_S,3,0)); + double a_Height = ((double) tolua_tonumber(tolua_S,4,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(*a_Pos,a_Radius,a_Height)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_new01(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new_local of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new02_local +static int tolua_AllToLua_cBoundingBox_new02_local(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Pos = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + double a_Radius = ((double) tolua_tonumber(tolua_S,3,0)); + double a_Height = ((double) tolua_tonumber(tolua_S,4,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(*a_Pos,a_Radius,a_Height)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_new01_local(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new03 +static int tolua_AllToLua_cBoundingBox_new03(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cBoundingBox",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else + { + const cBoundingBox* a_Orig = ((const cBoundingBox*) tolua_tousertype(tolua_S,2,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(*a_Orig)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_new02(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new_local of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_new03_local +static int tolua_AllToLua_cBoundingBox_new03_local(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cBoundingBox",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else + { + const cBoundingBox* a_Orig = ((const cBoundingBox*) tolua_tousertype(tolua_S,2,0)); + { + cBoundingBox* tolua_ret = (cBoundingBox*) Mtolua_new((cBoundingBox)(*a_Orig)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBoundingBox"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_new02_local(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: Move of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_Move00 +static int tolua_AllToLua_cBoundingBox_Move00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + double a_OffX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_OffY = ((double) tolua_tonumber(tolua_S,3,0)); + double a_OffZ = ((double) tolua_tonumber(tolua_S,4,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Move'", NULL); +#endif + { + self->Move(a_OffX,a_OffY,a_OffZ); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'Move'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: Move of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_Move01 +static int tolua_AllToLua_cBoundingBox_Move01(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_Off = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Move'", NULL); +#endif + { + self->Move(*a_Off); + } + } + return 0; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_Move00(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: Expand of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_Expand00 +static int tolua_AllToLua_cBoundingBox_Expand00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + double a_ExpandX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_ExpandY = ((double) tolua_tonumber(tolua_S,3,0)); + double a_ExpandZ = ((double) tolua_tonumber(tolua_S,4,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Expand'", NULL); +#endif + { + self->Expand(a_ExpandX,a_ExpandY,a_ExpandZ); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'Expand'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: DoesIntersect of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_DoesIntersect00 +static int tolua_AllToLua_cBoundingBox_DoesIntersect00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cBoundingBox",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + const cBoundingBox* a_Other = ((const cBoundingBox*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DoesIntersect'", NULL); +#endif + { + bool tolua_ret = (bool) self->DoesIntersect(*a_Other); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'DoesIntersect'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: Union of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_Union00 +static int tolua_AllToLua_cBoundingBox_Union00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cBoundingBox",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + const cBoundingBox* a_Other = ((const cBoundingBox*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Union'", NULL); +#endif + { + cBoundingBox tolua_ret = (cBoundingBox) self->Union(*a_Other); + { +#ifdef __cplusplus + void* tolua_obj = Mtolua_new((cBoundingBox)(tolua_ret)); + tolua_pushusertype(tolua_S,tolua_obj,"cBoundingBox"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#else + void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(cBoundingBox)); + tolua_pushusertype(tolua_S,tolua_obj,"cBoundingBox"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#endif + } + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'Union'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInside of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_IsInside00 +static int tolua_AllToLua_cBoundingBox_IsInside00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_Point = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsInside'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsInside(*a_Point); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsInside'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInside of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_IsInside01 +static int tolua_AllToLua_cBoundingBox_IsInside01(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + double a_X = ((double) tolua_tonumber(tolua_S,2,0)); + double a_Y = ((double) tolua_tonumber(tolua_S,3,0)); + double a_Z = ((double) tolua_tonumber(tolua_S,4,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsInside'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsInside(a_X,a_Y,a_Z); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_IsInside00(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInside of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_IsInside02 +static int tolua_AllToLua_cBoundingBox_IsInside02(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"cBoundingBox",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + cBoundingBox* a_Other = ((cBoundingBox*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsInside'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsInside(*a_Other); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_IsInside01(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInside of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_IsInside03 +static int tolua_AllToLua_cBoundingBox_IsInside03(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_Min = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Max = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsInside'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsInside(*a_Min,*a_Max); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_IsInside02(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInside of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_IsInside04 +static int tolua_AllToLua_cBoundingBox_IsInside04(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,4,&tolua_err) || !tolua_isusertype(tolua_S,4,"const Vector3d",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Min = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Max = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); + const Vector3d* a_Point = ((const Vector3d*) tolua_tousertype(tolua_S,4,0)); + { + bool tolua_ret = (bool) cBoundingBox::IsInside(*a_Min,*a_Max,*a_Point); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_IsInside03(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInside of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_IsInside05 +static int tolua_AllToLua_cBoundingBox_IsInside05(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnoobj(tolua_S,7,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Min = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Max = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); + double a_X = ((double) tolua_tonumber(tolua_S,4,0)); + double a_Y = ((double) tolua_tonumber(tolua_S,5,0)); + double a_Z = ((double) tolua_tonumber(tolua_S,6,0)); + { + bool tolua_ret = (bool) cBoundingBox::IsInside(*a_Min,*a_Max,a_X,a_Y,a_Z); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_IsInside04(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + +/* method: CalcLineIntersection of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_CalcLineIntersection00 +static int tolua_AllToLua_cBoundingBox_CalcLineIntersection00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnoobj(tolua_S,6,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBoundingBox* self = (cBoundingBox*) tolua_tousertype(tolua_S,1,0); + const Vector3d* a_Line1 = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Line2 = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); + double a_LineCoeff = ((double) tolua_tonumber(tolua_S,4,0)); + char a_Face = ((char) tolua_tonumber(tolua_S,5,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CalcLineIntersection'", NULL); +#endif + { + bool tolua_ret = (bool) self->CalcLineIntersection(*a_Line1,*a_Line2,a_LineCoeff,a_Face); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushnumber(tolua_S,(lua_Number)a_LineCoeff); + tolua_pushnumber(tolua_S,(lua_Number)a_Face); + } + } + return 3; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'CalcLineIntersection'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: CalcLineIntersection of class cBoundingBox */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBoundingBox_CalcLineIntersection01 +static int tolua_AllToLua_cBoundingBox_CalcLineIntersection01(lua_State* tolua_S) +{ + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cBoundingBox",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,3,&tolua_err) || !tolua_isusertype(tolua_S,3,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,4,&tolua_err) || !tolua_isusertype(tolua_S,4,"const Vector3d",0,&tolua_err)) || + (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const Vector3d",0,&tolua_err)) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnumber(tolua_S,7,0,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) + ) + goto tolua_lerror; + else + { + const Vector3d* a_Min = ((const Vector3d*) tolua_tousertype(tolua_S,2,0)); + const Vector3d* a_Max = ((const Vector3d*) tolua_tousertype(tolua_S,3,0)); + const Vector3d* a_Line1 = ((const Vector3d*) tolua_tousertype(tolua_S,4,0)); + const Vector3d* a_Line2 = ((const Vector3d*) tolua_tousertype(tolua_S,5,0)); + double a_LineCoeff = ((double) tolua_tonumber(tolua_S,6,0)); + char a_Face = ((char) tolua_tonumber(tolua_S,7,0)); + { + bool tolua_ret = (bool) cBoundingBox::CalcLineIntersection(*a_Min,*a_Max,*a_Line1,*a_Line2,a_LineCoeff,a_Face); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushnumber(tolua_S,(lua_Number)a_LineCoeff); + tolua_pushnumber(tolua_S,(lua_Number)a_Face); + } + } + return 3; +tolua_lerror: + return tolua_AllToLua_cBoundingBox_CalcLineIntersection00(tolua_S); +} +#endif //#ifndef TOLUA_DISABLE + /* method: new of class cTracer */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cTracer_new00 static int tolua_AllToLua_cTracer_new00(lua_State* tolua_S) @@ -28367,6 +29363,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"dimOverworld",dimOverworld); tolua_constant(tolua_S,"dimEnd",dimEnd); tolua_constant(tolua_S,"dtAttack",dtAttack); + tolua_constant(tolua_S,"dtRangedAttack",dtRangedAttack); tolua_constant(tolua_S,"dtLightning",dtLightning); tolua_constant(tolua_S,"dtFalling",dtFalling); tolua_constant(tolua_S,"dtDrowning",dtDrowning); @@ -28379,11 +29376,15 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"dtFireContact",dtFireContact); tolua_constant(tolua_S,"dtInVoid",dtInVoid); tolua_constant(tolua_S,"dtPotionOfHarming",dtPotionOfHarming); + tolua_constant(tolua_S,"dtEnderPearl",dtEnderPearl); tolua_constant(tolua_S,"dtAdmin",dtAdmin); tolua_constant(tolua_S,"dtPawnAttack",dtPawnAttack); tolua_constant(tolua_S,"dtEntityAttack",dtEntityAttack); tolua_constant(tolua_S,"dtMob",dtMob); tolua_constant(tolua_S,"dtMobAttack",dtMobAttack); + tolua_constant(tolua_S,"dtArrowAttack",dtArrowAttack); + tolua_constant(tolua_S,"dtArrow",dtArrow); + tolua_constant(tolua_S,"dtProjectile",dtProjectile); tolua_constant(tolua_S,"dtFall",dtFall); tolua_constant(tolua_S,"dtDrown",dtDrown); tolua_constant(tolua_S,"dtSuffocation",dtSuffocation); @@ -28431,6 +29432,12 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_array(tolua_S,"g_BlockRequiresSpecialTool",tolua_get_AllToLua_g_BlockRequiresSpecialTool,tolua_set_AllToLua_g_BlockRequiresSpecialTool); tolua_array(tolua_S,"g_BlockIsSolid",tolua_get_AllToLua_g_BlockIsSolid,tolua_set_AllToLua_g_BlockIsSolid); tolua_constant(tolua_S,"BLOCK_FACE_NONE",BLOCK_FACE_NONE); + tolua_constant(tolua_S,"BLOCK_FACE_XM",BLOCK_FACE_XM); + tolua_constant(tolua_S,"BLOCK_FACE_XP",BLOCK_FACE_XP); + tolua_constant(tolua_S,"BLOCK_FACE_YM",BLOCK_FACE_YM); + tolua_constant(tolua_S,"BLOCK_FACE_YP",BLOCK_FACE_YP); + tolua_constant(tolua_S,"BLOCK_FACE_ZM",BLOCK_FACE_ZM); + tolua_constant(tolua_S,"BLOCK_FACE_ZP",BLOCK_FACE_ZP); tolua_constant(tolua_S,"BLOCK_FACE_BOTTOM",BLOCK_FACE_BOTTOM); tolua_constant(tolua_S,"BLOCK_FACE_TOP",BLOCK_FACE_TOP); tolua_constant(tolua_S,"BLOCK_FACE_NORTH",BLOCK_FACE_NORTH); @@ -28583,6 +29590,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"etMonster",cEntity::etMonster); tolua_constant(tolua_S,"etFallingBlock",cEntity::etFallingBlock); tolua_constant(tolua_S,"etMinecart",cEntity::etMinecart); + tolua_constant(tolua_S,"etBoat",cEntity::etBoat); tolua_constant(tolua_S,"etTNT",cEntity::etTNT); tolua_constant(tolua_S,"etProjectile",cEntity::etProjectile); tolua_constant(tolua_S,"etMob",cEntity::etMob); @@ -28595,6 +29603,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsPickup",tolua_AllToLua_cEntity_IsPickup00); tolua_function(tolua_S,"IsMob",tolua_AllToLua_cEntity_IsMob00); tolua_function(tolua_S,"IsMinecart",tolua_AllToLua_cEntity_IsMinecart00); + tolua_function(tolua_S,"IsBoat",tolua_AllToLua_cEntity_IsBoat00); tolua_function(tolua_S,"IsTNT",tolua_AllToLua_cEntity_IsTNT00); tolua_function(tolua_S,"IsA",tolua_AllToLua_cEntity_IsA00); tolua_function(tolua_S,"GetClass",tolua_AllToLua_cEntity_GetClass00); @@ -28648,12 +29657,17 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"AddSpeedX",tolua_AllToLua_cEntity_AddSpeedX00); tolua_function(tolua_S,"AddSpeedY",tolua_AllToLua_cEntity_AddSpeedY00); tolua_function(tolua_S,"AddSpeedZ",tolua_AllToLua_cEntity_AddSpeedZ00); + tolua_function(tolua_S,"SteerVehicle",tolua_AllToLua_cEntity_SteerVehicle00); tolua_function(tolua_S,"GetUniqueID",tolua_AllToLua_cEntity_GetUniqueID00); tolua_function(tolua_S,"IsDestroyed",tolua_AllToLua_cEntity_IsDestroyed00); tolua_function(tolua_S,"Destroy",tolua_AllToLua_cEntity_Destroy00); tolua_function(tolua_S,"TakeDamage",tolua_AllToLua_cEntity_TakeDamage00); tolua_function(tolua_S,"TakeDamage",tolua_AllToLua_cEntity_TakeDamage01); tolua_function(tolua_S,"TakeDamage",tolua_AllToLua_cEntity_TakeDamage02); + tolua_function(tolua_S,"GetGravity",tolua_AllToLua_cEntity_GetGravity00); + tolua_function(tolua_S,"SetGravity",tolua_AllToLua_cEntity_SetGravity00); + tolua_function(tolua_S,"SetRotationFromSpeed",tolua_AllToLua_cEntity_SetRotationFromSpeed00); + tolua_function(tolua_S,"SetPitchFromSpeed",tolua_AllToLua_cEntity_SetPitchFromSpeed00); tolua_function(tolua_S,"GetRawDamageAgainst",tolua_AllToLua_cEntity_GetRawDamageAgainst00); tolua_function(tolua_S,"GetArmorCoverAgainst",tolua_AllToLua_cEntity_GetArmorCoverAgainst00); tolua_function(tolua_S,"GetKnockbackAmountAgainst",tolua_AllToLua_cEntity_GetKnockbackAmountAgainst00); @@ -28790,6 +29804,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetDamageCoeff",tolua_AllToLua_cArrowEntity_GetDamageCoeff00); tolua_function(tolua_S,"SetDamageCoeff",tolua_AllToLua_cArrowEntity_SetDamageCoeff00); tolua_function(tolua_S,"CanPickup",tolua_AllToLua_cArrowEntity_CanPickup00); + tolua_function(tolua_S,"IsCritical",tolua_AllToLua_cArrowEntity_IsCritical00); + tolua_function(tolua_S,"SetIsCritical",tolua_AllToLua_cArrowEntity_SetIsCritical00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cThrownEggEntity","cThrownEggEntity","cProjectileEntity",NULL); tolua_beginmodule(tolua_S,"cThrownEggEntity"); @@ -28800,6 +29816,12 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_cclass(tolua_S,"cThrownSnowballEntity","cThrownSnowballEntity","cProjectileEntity",NULL); tolua_beginmodule(tolua_S,"cThrownSnowballEntity"); tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cGhastFireballEntity","cGhastFireballEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cGhastFireballEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cFireChargeEntity","cFireChargeEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cFireChargeEntity"); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cPluginManager","cPluginManager","",NULL); tolua_beginmodule(tolua_S,"cPluginManager"); tolua_constant(tolua_S,"HOOK_BLOCK_TO_PICKUPS",cPluginManager::HOOK_BLOCK_TO_PICKUPS); @@ -28919,8 +29941,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetBlockMeta",tolua_AllToLua_cWorld_SetBlockMeta00); tolua_function(tolua_S,"GetBlockSkyLight",tolua_AllToLua_cWorld_GetBlockSkyLight00); tolua_function(tolua_S,"GetBlockBlockLight",tolua_AllToLua_cWorld_GetBlockBlockLight00); - tolua_function(tolua_S,"GetBlockTypeMeta",tolua_AllToLua_cWorld_GetBlockTypeMeta00); - tolua_function(tolua_S,"GetBlockInfo",tolua_AllToLua_cWorld_GetBlockInfo00); tolua_function(tolua_S,"FastSetBlock",tolua_AllToLua_cWorld_FastSetBlock01); tolua_function(tolua_S,"GetBlock",tolua_AllToLua_cWorld_GetBlock01); tolua_function(tolua_S,"GetBlockMeta",tolua_AllToLua_cWorld_GetBlockMeta01); @@ -28935,7 +29955,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetSpawnZ",tolua_AllToLua_cWorld_GetSpawnZ00); tolua_function(tolua_S,"WakeUpSimulators",tolua_AllToLua_cWorld_WakeUpSimulators00); tolua_function(tolua_S,"WakeUpSimulatorsInArea",tolua_AllToLua_cWorld_WakeUpSimulatorsInArea00); - tolua_function(tolua_S,"DoExplosiontAt",tolua_AllToLua_cWorld_DoExplosiontAt00); + tolua_function(tolua_S,"DoExplosionAt",tolua_AllToLua_cWorld_DoExplosionAt00); tolua_function(tolua_S,"GetSignLines",tolua_AllToLua_cWorld_GetSignLines00); tolua_function(tolua_S,"GrowTree",tolua_AllToLua_cWorld_GrowTree00); tolua_function(tolua_S,"GrowTreeFromSapling",tolua_AllToLua_cWorld_GrowTreeFromSapling00); @@ -29357,6 +30377,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SqrLength",tolua_AllToLua_Vector3d_SqrLength00); tolua_function(tolua_S,"Dot",tolua_AllToLua_Vector3d_Dot00); tolua_function(tolua_S,"Cross",tolua_AllToLua_Vector3d_Cross00); + tolua_function(tolua_S,"LineCoeffToXYPlane",tolua_AllToLua_Vector3d_LineCoeffToXYPlane00); + tolua_function(tolua_S,"LineCoeffToXZPlane",tolua_AllToLua_Vector3d_LineCoeffToXZPlane00); + tolua_function(tolua_S,"LineCoeffToYZPlane",tolua_AllToLua_Vector3d_LineCoeffToYZPlane00); tolua_function(tolua_S,"Equals",tolua_AllToLua_Vector3d_Equals00); tolua_function(tolua_S,".add",tolua_AllToLua_Vector3d__add00); tolua_function(tolua_S,".add",tolua_AllToLua_Vector3d__add01); @@ -29368,6 +30391,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_variable(tolua_S,"x",tolua_get_Vector3d_x,tolua_set_Vector3d_x); tolua_variable(tolua_S,"y",tolua_get_Vector3d_y,tolua_set_Vector3d_y); tolua_variable(tolua_S,"z",tolua_get_Vector3d_z,tolua_set_Vector3d_z); + tolua_variable(tolua_S,"EPS",tolua_get_Vector3d_EPS,NULL); + tolua_variable(tolua_S,"NO_INTERSECTION",tolua_get_Vector3d_NO_INTERSECTION,NULL); tolua_endmodule(tolua_S); #ifdef __cplusplus tolua_cclass(tolua_S,"Vector3i","Vector3i","",tolua_collect_Vector3i); @@ -29430,6 +30455,38 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsSorted",tolua_AllToLua_cCuboid_IsSorted00); tolua_endmodule(tolua_S); #ifdef __cplusplus + tolua_cclass(tolua_S,"cBoundingBox","cBoundingBox","",tolua_collect_cBoundingBox); + #else + tolua_cclass(tolua_S,"cBoundingBox","cBoundingBox","",NULL); + #endif + tolua_beginmodule(tolua_S,"cBoundingBox"); + tolua_function(tolua_S,"new",tolua_AllToLua_cBoundingBox_new00); + tolua_function(tolua_S,"new_local",tolua_AllToLua_cBoundingBox_new00_local); + tolua_function(tolua_S,".call",tolua_AllToLua_cBoundingBox_new00_local); + tolua_function(tolua_S,"new",tolua_AllToLua_cBoundingBox_new01); + tolua_function(tolua_S,"new_local",tolua_AllToLua_cBoundingBox_new01_local); + tolua_function(tolua_S,".call",tolua_AllToLua_cBoundingBox_new01_local); + tolua_function(tolua_S,"new",tolua_AllToLua_cBoundingBox_new02); + tolua_function(tolua_S,"new_local",tolua_AllToLua_cBoundingBox_new02_local); + tolua_function(tolua_S,".call",tolua_AllToLua_cBoundingBox_new02_local); + tolua_function(tolua_S,"new",tolua_AllToLua_cBoundingBox_new03); + tolua_function(tolua_S,"new_local",tolua_AllToLua_cBoundingBox_new03_local); + tolua_function(tolua_S,".call",tolua_AllToLua_cBoundingBox_new03_local); + tolua_function(tolua_S,"Move",tolua_AllToLua_cBoundingBox_Move00); + tolua_function(tolua_S,"Move",tolua_AllToLua_cBoundingBox_Move01); + tolua_function(tolua_S,"Expand",tolua_AllToLua_cBoundingBox_Expand00); + tolua_function(tolua_S,"DoesIntersect",tolua_AllToLua_cBoundingBox_DoesIntersect00); + tolua_function(tolua_S,"Union",tolua_AllToLua_cBoundingBox_Union00); + tolua_function(tolua_S,"IsInside",tolua_AllToLua_cBoundingBox_IsInside00); + tolua_function(tolua_S,"IsInside",tolua_AllToLua_cBoundingBox_IsInside01); + tolua_function(tolua_S,"IsInside",tolua_AllToLua_cBoundingBox_IsInside02); + tolua_function(tolua_S,"IsInside",tolua_AllToLua_cBoundingBox_IsInside03); + tolua_function(tolua_S,"IsInside",tolua_AllToLua_cBoundingBox_IsInside04); + tolua_function(tolua_S,"IsInside",tolua_AllToLua_cBoundingBox_IsInside05); + tolua_function(tolua_S,"CalcLineIntersection",tolua_AllToLua_cBoundingBox_CalcLineIntersection00); + tolua_function(tolua_S,"CalcLineIntersection",tolua_AllToLua_cBoundingBox_CalcLineIntersection01); + tolua_endmodule(tolua_S); + #ifdef __cplusplus tolua_cclass(tolua_S,"cTracer","cTracer","",tolua_collect_cTracer); #else tolua_cclass(tolua_S,"cTracer","cTracer","",NULL); diff --git a/source/Bindings.h b/source/Bindings.h index c706c2281..8dc9f5d4d 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:05.
+** Generated automatically by tolua++-1.0.92 on 09/15/13 20:27:51.
*/
/* Exported function */
diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 40664647a..c3bd3c750 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -21,6 +21,7 @@ bool g_BlockPistonBreakable[256]; bool g_BlockIsSnowable[256]; bool g_BlockRequiresSpecialTool[256]; bool g_BlockIsSolid[256]; +bool g_BlockIsTorchPlaceable[256]; @@ -419,6 +420,7 @@ AString DamageTypeToString(eDamageType a_DamageType) switch (a_DamageType) { case dtAttack: return "dtAttack"; + case dtRangedAttack: return "dtRangedAttack"; case dtLightning: return "dtLightning"; case dtFalling: return "dtFalling"; case dtDrowning: return "dtDrowning"; @@ -463,6 +465,7 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString) { // Cannonical names: { dtAttack, "dtAttack"}, + { dtRangedAttack, "dtRangedAttack"}, { dtLightning, "dtLightning"}, { dtFalling, "dtFalling"}, { dtDrowning, "dtDrowning"}, @@ -478,23 +481,26 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString) { dtAdmin, "dtAdmin"}, // Common synonyms: - { dtPawnAttack, "dtAttack"}, - { dtEntityAttack, "dtAttack"}, - { dtMob, "dtAttack"}, - { dtMobAttack, "dtAttack"}, - { dtFall, "dtFalling"}, - { dtDrown, "dtDrowning"}, - { dtSuffocation, "dtSuffocating"}, - { dtStarvation, "dtStarving"}, - { dtHunger, "dtStarving"}, - { dtCactus, "dtCactusContact"}, - { dtCactuses, "dtCactusContact"}, - { dtCacti, "dtCactusContact"}, - { dtLava, "dtLavaContact"}, - { dtPoison, "dtPoisoning"}, - { dtBurning, "dtOnFire"}, - { dtInFire, "dtFireContact"}, - { dtPlugin, "dtAdmin"}, + { dtAttack, "dtPawnAttack"}, + { dtAttack, "dtEntityAttack"}, + { dtAttack, "dtMob"}, + { dtAttack, "dtMobAttack"}, + { dtRangedAttack, "dtArrowAttack"}, + { dtRangedAttack, "dtArrow"}, + { dtRangedAttack, "dtProjectile"}, + { dtFalling, "dtFall"}, + { dtDrowning, "dtDrown"}, + { dtSuffocating, "dtSuffocation"}, + { dtStarving, "dtStarvation"}, + { dtStarving, "dtHunger"}, + { dtCactusContact, "dtCactus"}, + { dtCactusContact, "dtCactuses"}, + { dtCactusContact, "dtCacti"}, + { dtLavaContact, "dtLava"}, + { dtPoisoning, "dtPoison"}, + { dtOnFire, "dtBurning"}, + { dtFireContact, "dtInFire"}, + { dtAdmin, "dtPlugin"}, } ; for (int i = 0; i < ARRAYCOUNT(DamageTypeMap); i++) { @@ -523,6 +529,7 @@ public: memset(g_BlockTransparent, 0x00, sizeof(g_BlockTransparent)); memset(g_BlockOneHitDig, 0x00, sizeof(g_BlockOneHitDig)); memset(g_BlockPistonBreakable, 0x00, sizeof(g_BlockPistonBreakable)); + memset(g_BlockIsTorchPlaceable, 0x00, sizeof(g_BlockIsTorchPlaceable)); // Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415 for (int i = 0; i < ARRAYCOUNT(g_BlockIsSnowable); i++) @@ -696,6 +703,7 @@ public: g_BlockIsSnowable[E_BLOCK_GLASS] = false; g_BlockIsSnowable[E_BLOCK_ICE] = false; g_BlockIsSnowable[E_BLOCK_LAVA] = false; + g_BlockIsSnowable[E_BLOCK_LILY_PAD] = false; g_BlockIsSnowable[E_BLOCK_LOCKED_CHEST] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_OFF] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_ON] = false; @@ -717,8 +725,9 @@ public: g_BlockIsSnowable[E_BLOCK_WALLSIGN] = false; g_BlockIsSnowable[E_BLOCK_WATER] = false; g_BlockIsSnowable[E_BLOCK_YELLOW_FLOWER] = false; + - // Blocks that don´t drop without a special tool + // Blocks that don't drop without a special tool g_BlockRequiresSpecialTool[E_BLOCK_BRICK] = true; g_BlockRequiresSpecialTool[E_BLOCK_CAULDRON] = true; g_BlockRequiresSpecialTool[E_BLOCK_COAL_ORE] = true; @@ -754,31 +763,20 @@ public: g_BlockRequiresSpecialTool[E_BLOCK_VINES] = true; // Nonsolid Blocks: + g_BlockIsSolid[E_BLOCK_ACTIVATOR_RAIL] = false; g_BlockIsSolid[E_BLOCK_AIR] = false; - g_BlockIsSolid[E_BLOCK_BED] = false; - g_BlockIsSolid[E_BLOCK_BIRCH_WOOD_STAIRS] = false; - g_BlockIsSolid[E_BLOCK_BRICK_STAIRS] = false; g_BlockIsSolid[E_BLOCK_BROWN_MUSHROOM] = false; - g_BlockIsSolid[E_BLOCK_CACTUS] = false; - g_BlockIsSolid[E_BLOCK_CAKE] = false; - g_BlockIsSolid[E_BLOCK_CHEST] = false; - g_BlockIsSolid[E_BLOCK_COBBLESTONE_STAIRS] = false; + g_BlockIsSolid[E_BLOCK_CARROTS] = false; + g_BlockIsSolid[E_BLOCK_COBWEB] = false; g_BlockIsSolid[E_BLOCK_CROPS] = false; - g_BlockIsSolid[E_BLOCK_ENCHANTMENT_TABLE] = false; + g_BlockIsSolid[E_BLOCK_DETECTOR_RAIL] = false; g_BlockIsSolid[E_BLOCK_END_PORTAL] = false; - g_BlockIsSolid[E_BLOCK_END_PORTAL_FRAME] = false; - g_BlockIsSolid[E_BLOCK_FARMLAND] = false; - g_BlockIsSolid[E_BLOCK_FENCE] = false; g_BlockIsSolid[E_BLOCK_FIRE] = false; - g_BlockIsSolid[E_BLOCK_GLASS] = false; - g_BlockIsSolid[E_BLOCK_IRON_DOOR] = false; - g_BlockIsSolid[E_BLOCK_JUNGLE_WOOD_STAIRS] = false; - g_BlockIsSolid[E_BLOCK_LADDER] = false; + g_BlockIsSolid[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_LAVA] = false; - g_BlockIsSolid[E_BLOCK_LEAVES] = false; g_BlockIsSolid[E_BLOCK_LEVER] = false; - g_BlockIsSolid[E_BLOCK_LOCKED_CHEST] = false; - g_BlockIsSolid[E_BLOCK_NETHER_BRICK_STAIRS] = false; + g_BlockIsSolid[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = false; + g_BlockIsSolid[E_BLOCK_MELON_STEM] = false; g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false; g_BlockIsSolid[E_BLOCK_PISTON] = false; g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false; @@ -791,29 +789,84 @@ public: g_BlockIsSolid[E_BLOCK_RED_MUSHROOM] = false; g_BlockIsSolid[E_BLOCK_RED_ROSE] = false; g_BlockIsSolid[E_BLOCK_REEDS] = false; - g_BlockIsSolid[E_BLOCK_SANDSTONE_STAIRS] = false; g_BlockIsSolid[E_BLOCK_SAPLING] = false; g_BlockIsSolid[E_BLOCK_SIGN_POST] = false; g_BlockIsSolid[E_BLOCK_SNOW] = false; - g_BlockIsSolid[E_BLOCK_SPRUCE_WOOD_STAIRS] = false; g_BlockIsSolid[E_BLOCK_STATIONARY_LAVA] = false; g_BlockIsSolid[E_BLOCK_STATIONARY_WATER] = false; - g_BlockIsSolid[E_BLOCK_STONE_BRICK_STAIRS] = false; g_BlockIsSolid[E_BLOCK_STONE_BUTTON] = false; g_BlockIsSolid[E_BLOCK_STONE_PRESSURE_PLATE] = false; - g_BlockIsSolid[E_BLOCK_STONE_SLAB] = false; g_BlockIsSolid[E_BLOCK_TALL_GRASS] = false; - g_BlockIsSolid[E_BLOCK_TNT] = false; g_BlockIsSolid[E_BLOCK_TORCH] = false; - g_BlockIsSolid[E_BLOCK_TRAPDOOR] = false; + g_BlockIsSolid[E_BLOCK_TRIPWIRE] = false; g_BlockIsSolid[E_BLOCK_VINES] = false; g_BlockIsSolid[E_BLOCK_WALLSIGN] = false; g_BlockIsSolid[E_BLOCK_WATER] = false; g_BlockIsSolid[E_BLOCK_WOODEN_BUTTON] = false; - g_BlockIsSolid[E_BLOCK_WOODEN_DOOR] = false; g_BlockIsSolid[E_BLOCK_WOODEN_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false; g_BlockIsSolid[E_BLOCK_YELLOW_FLOWER] = false; + + // Torch placeable + g_BlockIsTorchPlaceable[E_BLOCK_BEDROCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_COAL] = true; + g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_REDSTONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_BOOKCASE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_BRICK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_CLAY] = true; + g_BlockIsTorchPlaceable[E_BLOCK_COAL_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_COBBLESTONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_COMMAND_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_CRAFTING_TABLE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DIAMOND_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DIAMOND_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DIRT] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DISPENSER] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DOUBLE_STONE_SLAB] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DOUBLE_WOODEN_SLAB] = true; + g_BlockIsTorchPlaceable[E_BLOCK_DROPPER] = true; + g_BlockIsTorchPlaceable[E_BLOCK_EMERALD_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_EMERALD_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_END_STONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_FURNACE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_GLOWSTONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_GOLD_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_GOLD_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_GRASS] = true; + g_BlockIsTorchPlaceable[E_BLOCK_GRAVEL] = true; + g_BlockIsTorchPlaceable[E_BLOCK_HARDENED_CLAY] = true; + g_BlockIsTorchPlaceable[E_BLOCK_HAY_BALE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_HUGE_BROWN_MUSHROOM] = true; + g_BlockIsTorchPlaceable[E_BLOCK_HUGE_RED_MUSHROOM] = true; + g_BlockIsTorchPlaceable[E_BLOCK_IRON_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_IRON_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_JACK_O_LANTERN] = true; + g_BlockIsTorchPlaceable[E_BLOCK_JUKEBOX] = true; + g_BlockIsTorchPlaceable[E_BLOCK_LAPIS_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_LAPIS_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_LOG] = true; + g_BlockIsTorchPlaceable[E_BLOCK_MELON] = true; + g_BlockIsTorchPlaceable[E_BLOCK_MOSSY_COBBLESTONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_MYCELIUM] = true; + g_BlockIsTorchPlaceable[E_BLOCK_NETHERRACK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_NETHER_BRICK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_NETHER_QUARTZ_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_NOTE_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_OBSIDIAN] = true; + g_BlockIsTorchPlaceable[E_BLOCK_PLANKS] = true; + g_BlockIsTorchPlaceable[E_BLOCK_PUMPKIN] = true; + g_BlockIsTorchPlaceable[E_BLOCK_QUARTZ_BLOCK] = true; + g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_LAMP_OFF] = true; + g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_LAMP_ON] = true; + g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_ORE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_ORE_GLOWING] = true; + g_BlockIsTorchPlaceable[E_BLOCK_SANDSTONE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_SAND] = true; + g_BlockIsTorchPlaceable[E_BLOCK_SILVERFISH_EGG] = true; + g_BlockIsTorchPlaceable[E_BLOCK_SPONGE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_STAINED_CLAY] = true; + g_BlockIsTorchPlaceable[E_BLOCK_WOOL] = true; + g_BlockIsTorchPlaceable[E_BLOCK_STONE] = true; } } BlockPropertiesInitializer; diff --git a/source/BlockID.h b/source/BlockID.h index 40da3c651..7971b4f84 100644 --- a/source/BlockID.h +++ b/source/BlockID.h @@ -165,7 +165,7 @@ enum ENUM_BLOCK_ID E_BLOCK_NETHER_QUARTZ_ORE = 153, E_BLOCK_HOPPER = 154, E_BLOCK_QUARTZ_BLOCK = 155, - E_BLOCK_QUARTZ_STAIR = 156, + E_BLOCK_QUARTZ_STAIRS = 156, E_BLOCK_ACTIVATOR_RAIL = 157, E_BLOCK_DROPPER = 158, @@ -659,6 +659,7 @@ enum eDamageType { // Canonical names for the types (as documented in the plugin wiki): dtAttack, // Being attacked by a mob + dtRangedAttack, // Being attacked by a projectile, possibly from a mob dtLightning, // Hit by a lightning strike dtFalling, // Falling down; dealt when hitting the ground dtDrowning, // Drowning in water / lava @@ -671,6 +672,7 @@ enum eDamageType dtFireContact, // Standing inside a fire block dtInVoid, // Falling into the Void (Y < 0) dtPotionOfHarming, + dtEnderPearl, // Thrown an ender pearl, teleported by it dtAdmin, // Damage applied by an admin command // Some common synonyms: @@ -678,6 +680,9 @@ enum eDamageType dtEntityAttack = dtAttack, dtMob = dtAttack, dtMobAttack = dtAttack, + dtArrowAttack = dtRangedAttack, + dtArrow = dtRangedAttack, + dtProjectile = dtRangedAttack, dtFall = dtFalling, dtDrown = dtDrowning, dtSuffocation = dtSuffocating, @@ -770,7 +775,7 @@ extern bool g_BlockPistonBreakable[256]; extern bool g_BlockIsSnowable[256]; extern bool g_BlockRequiresSpecialTool[256]; extern bool g_BlockIsSolid[256]; - +extern bool g_BlockIsTorchPlaceable[256]; diff --git a/source/Blocks/BlockBed.cpp b/source/Blocks/BlockBed.cpp index f5e9db88d..66eb9130c 100644 --- a/source/Blocks/BlockBed.cpp +++ b/source/Blocks/BlockBed.cpp @@ -56,7 +56,7 @@ void cBlockBedHandler::OnUse(cWorld *a_World, cPlayer *a_Player, int a_BlockX, i if (a_World->GetDimension() != dimOverworld) { Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ); - a_World->DoExplosiontAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords); + a_World->DoExplosionAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords); } else { diff --git a/source/Blocks/BlockBed.h b/source/Blocks/BlockBed.h index 0bf1cfc0f..8a289b22c 100644 --- a/source/Blocks/BlockBed.h +++ b/source/Blocks/BlockBed.h @@ -37,12 +37,6 @@ public: } - virtual bool DoesAllowBlockOnTop() override - { - return false; - } - - // Bed specific helper functions static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/source/Blocks/BlockCactus.h b/source/Blocks/BlockCactus.h index 1d123bc0a..4147ad473 100644 --- a/source/Blocks/BlockCactus.h +++ b/source/Blocks/BlockCactus.h @@ -63,12 +63,6 @@ public: return true; } - - - virtual bool CanBePlacedOnSide(void) override - { - return false; - } void OnUpdate(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override diff --git a/source/Blocks/BlockCrops.h b/source/Blocks/BlockCrops.h index 4bc76fd50..9e19b14ec 100644 --- a/source/Blocks/BlockCrops.h +++ b/source/Blocks/BlockCrops.h @@ -20,12 +20,6 @@ public: } - virtual bool DoesAllowBlockOnTop() override - { - return false; - } - - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override { MTRand rand; diff --git a/source/Blocks/BlockDeadBush.h b/source/Blocks/BlockDeadBush.h index 379e8e5df..14617d006 100644 --- a/source/Blocks/BlockDeadBush.h +++ b/source/Blocks/BlockDeadBush.h @@ -28,18 +28,6 @@ public: { return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SAND); } - - - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } - - - virtual bool CanBePlacedOnSide() override - { - return false; - } } ; diff --git a/source/Blocks/BlockDoor.cpp b/source/Blocks/BlockDoor.cpp index 02cbd28e2..e71ccd368 100644 --- a/source/Blocks/BlockDoor.cpp +++ b/source/Blocks/BlockDoor.cpp @@ -3,7 +3,6 @@ #include "BlockDoor.h" #include "../Item.h" #include "../World.h" -#include "../Doors.h" #include "../Entities/Player.h" @@ -26,7 +25,7 @@ void cBlockDoorHandler::OnDestroyed(cWorld * a_World, int a_BlockX, int a_BlockY if (OldMeta & 8) { // Was upper part of door - if (cDoors::IsDoor(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) + if (IsDoor(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) { a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); } @@ -34,7 +33,7 @@ void cBlockDoorHandler::OnDestroyed(cWorld * a_World, int a_BlockX, int a_BlockY else { // Was lower part - if (cDoors::IsDoor(a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) + if (IsDoor(a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) { a_World->FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); } @@ -49,7 +48,7 @@ void cBlockDoorHandler::OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX { if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR) { - cDoors::ChangeDoor(a_World, a_BlockX, a_BlockY, a_BlockZ); + ChangeDoor(a_World, a_BlockX, a_BlockY, a_BlockZ); } } diff --git a/source/Blocks/BlockDoor.h b/source/Blocks/BlockDoor.h index 4978fee38..03a79d47d 100644 --- a/source/Blocks/BlockDoor.h +++ b/source/Blocks/BlockDoor.h @@ -3,7 +3,6 @@ #include "BlockHandler.h" #include "../World.h" -#include "../Doors.h" #include "../Entities/Player.h" @@ -43,7 +42,7 @@ public: } a_BlockType = m_BlockType; - a_BlockMeta = cDoors::RotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation()); return true; } @@ -68,12 +67,6 @@ public: } - virtual bool CanBePlacedOnSide(void) override - { - return false; - } - - virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); @@ -98,6 +91,83 @@ public: } return false; } + + + /// Converts the player's yaw to placed door's blockmeta + inline static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) + { + ASSERT((a_Yaw >= -180) && (a_Yaw < 180)); + + a_Yaw += 90 + 45; + if (a_Yaw > 360) + { + a_Yaw -= 360; + } + if ((a_Yaw >= 0) && (a_Yaw < 90)) + { + return 0x0; + } + else if ((a_Yaw >= 180) && (a_Yaw < 270)) + { + return 0x2; + } + else if ((a_Yaw >= 90) && (a_Yaw < 180)) + { + return 0x1; + } + else + { + return 0x3; + } + } + + + /// Returns true if the specified blocktype is any kind of door + inline static bool IsDoor(BLOCKTYPE a_Block) + { + return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR); + } + + + /// Returns the metadata for the opposite door state (open vs closed) + static NIBBLETYPE ChangeStateMetaData(NIBBLETYPE a_MetaData) + { + return a_MetaData ^ 4; + } + + + /// Changes the door at the specified coords from open to close or vice versa + static void ChangeDoor(cWorld * a_World, int a_X, int a_Y, int a_Z) + { + NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_X, a_Y, a_Z); + + a_World->SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData)); + + if (OldMetaData & 8) + { + // Current block is top of the door + BLOCKTYPE BottomBlock = a_World->GetBlock(a_X, a_Y - 1, a_Z); + NIBBLETYPE BottomMeta = a_World->GetBlockMeta(a_X, a_Y - 1, a_Z); + + if (IsDoor(BottomBlock) && !(BottomMeta & 8)) + { + a_World->SetBlockMeta(a_X, a_Y - 1, a_Z, ChangeStateMetaData(BottomMeta)); + } + } + else + { + // Current block is bottom of the door + BLOCKTYPE TopBlock = a_World->GetBlock(a_X, a_Y + 1, a_Z); + NIBBLETYPE TopMeta = a_World->GetBlockMeta(a_X, a_Y + 1, a_Z); + + if (IsDoor(TopBlock) && (TopMeta & 8)) + { + a_World->SetBlockMeta(a_X, a_Y + 1, a_Z, ChangeStateMetaData(TopMeta)); + } + } + } + + } ; diff --git a/source/Blocks/BlockFenceGate.h b/source/Blocks/BlockFenceGate.h index d6f8aa85f..6423a7cb0 100644 --- a/source/Blocks/BlockFenceGate.h +++ b/source/Blocks/BlockFenceGate.h @@ -2,7 +2,6 @@ #pragma once #include "BlockHandler.h" -#include "../Doors.h" @@ -26,7 +25,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = cDoors::RotationToMetaData(a_Player->GetRotation() + 270); + a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation()); return true; } @@ -34,7 +33,7 @@ public: virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE NewMetaData = cDoors::RotationToMetaData(a_Player->GetRotation() + 270); + NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetRotation()); OldMetaData ^= 4; // Toggle the gate if ((OldMetaData & 1) == (NewMetaData & 1)) { @@ -53,6 +52,35 @@ public: { return true; } + + + /// Converts the player's yaw to placed gate's blockmeta + inline static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) + { + ASSERT((a_Yaw >= -180) && (a_Yaw < 180)); + + a_Yaw += 360 + 45; + if (a_Yaw > 360) + { + a_Yaw -= 360; + } + if ((a_Yaw >= 0) && (a_Yaw < 90)) + { + return 0x0; + } + else if ((a_Yaw >= 180) && (a_Yaw < 270)) + { + return 0x2; + } + else if ((a_Yaw >= 90) && (a_Yaw < 180)) + { + return 0x1; + } + else + { + return 0x3; + } + } } ; diff --git a/source/Blocks/BlockFlower.h b/source/Blocks/BlockFlower.h index 952901ba5..421e2d5d8 100644 --- a/source/Blocks/BlockFlower.h +++ b/source/Blocks/BlockFlower.h @@ -30,18 +30,6 @@ public: } - virtual bool DoesAllowBlockOnTop(void) override - { - return true; - } - - - virtual bool CanBePlacedOnSide(void) override - { - return false; - } - - virtual const char * GetStepSound(void) override { return "step.grass"; diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp index 2627ac6b4..3e97d1e9d 100644 --- a/source/Blocks/BlockHandler.cpp +++ b/source/Blocks/BlockHandler.cpp @@ -41,6 +41,7 @@ #include "BlockNote.h" #include "BlockOre.h" #include "BlockPiston.h" +#include "BlockPumpkin.h" #include "BlockRail.h" #include "BlockRedstone.h" #include "BlockRedstoneRepeater.h" @@ -153,8 +154,10 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_PISTON: return new cBlockPistonHandler (a_BlockType); case E_BLOCK_PISTON_EXTENSION: return new cBlockPistonHeadHandler (); case E_BLOCK_PLANKS: return new cBlockWoodHandler (a_BlockType); + case E_BLOCK_PUMPKIN: return new cBlockPumpkinHandler (a_BlockType); + case E_BLOCK_JACK_O_LANTERN: return new cBlockPumpkinHandler (a_BlockType); case E_BLOCK_PUMPKIN_STEM: return new cBlockStemsHandler (a_BlockType); - case E_BLOCK_QUARTZ_STAIR: return new cBlockStairsHandler (a_BlockType); + case E_BLOCK_QUARTZ_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_POTATOES: return new cBlockCropsHandler (a_BlockType); case E_BLOCK_POWERED_RAIL: return new cBlockRailHandler (a_BlockType); @@ -412,24 +415,6 @@ bool cBlockHandler::DoesIgnoreBuildCollision(void) -bool cBlockHandler::DoesAllowBlockOnTop(void) -{ - return true; -} - - - - - -bool cBlockHandler::CanBePlacedOnSide(void) -{ - return true; -} - - - - - bool cBlockHandler::DoesDropOnUnsuitable(void) { return true; diff --git a/source/Blocks/BlockHandler.h b/source/Blocks/BlockHandler.h index 228ce174b..0487505ee 100644 --- a/source/Blocks/BlockHandler.h +++ b/source/Blocks/BlockHandler.h @@ -83,10 +83,7 @@ public: NOTE: This call doesn't actually place the block */ // virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); - - /// Called when the player tries to place a block on top of this block (Only if he aims directly on this block); return false to disallow - virtual bool DoesAllowBlockOnTop(void); - + /// Called to check whether this block supports a rclk action. If it returns true, OnUse() is called virtual bool IsUseable(void); @@ -99,9 +96,6 @@ public: For example blocks placed "on" snow will be placed at the same position. So: Snow ignores Build collision */ virtual bool DoesIgnoreBuildCollision(void); - - /// Indicates this block can be placed on the side of other blocks. Default: true - virtual bool CanBePlacedOnSide(void); /// Does this block drop if it gets destroyed by an unsuitable situation? Default: true virtual bool DoesDropOnUnsuitable(void); diff --git a/source/Blocks/BlockLever.h b/source/Blocks/BlockLever.h index 362cf563e..ddf48297c 100644 --- a/source/Blocks/BlockLever.h +++ b/source/Blocks/BlockLever.h @@ -42,12 +42,6 @@ public: a_BlockMeta = cRedstoneSimulator::LeverDirectionToMetaData(a_BlockFace); return true; } - - - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } virtual const char * GetStepSound(void) override diff --git a/source/Blocks/BlockMushroom.h b/source/Blocks/BlockMushroom.h index b3b23e2ba..2846a6317 100644 --- a/source/Blocks/BlockMushroom.h +++ b/source/Blocks/BlockMushroom.h @@ -46,18 +46,6 @@ public: } return true; } - - - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } - - - virtual bool CanBePlacedOnSide(void) override - { - return false; - } virtual const char * GetStepSound(void) override diff --git a/source/Blocks/BlockMycelium.h b/source/Blocks/BlockMycelium.h index 0ed7162ac..7f897c72a 100644 --- a/source/Blocks/BlockMycelium.h +++ b/source/Blocks/BlockMycelium.h @@ -20,6 +20,11 @@ public: { a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0)); } + + virtual const char * GetStepSound(void) override + { + return "step.gravel"; + } } ; diff --git a/source/Blocks/BlockPumpkin.h b/source/Blocks/BlockPumpkin.h new file mode 100644 index 000000000..76abc6818 --- /dev/null +++ b/source/Blocks/BlockPumpkin.h @@ -0,0 +1,60 @@ +#pragma once + +#include "BlockHandler.h" + + + + +class cBlockPumpkinHandler : + public cBlockHandler +{ +public: + cBlockPumpkinHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + virtual bool GetPlacementBlockTypeMeta( + cWorld * a_World, cPlayer * a_Player, + int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, + int a_CursorX, int a_CursorY, int a_CursorZ, + BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta + ) override + { + a_BlockType = m_BlockType; + a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation()); + return true; + } + + inline static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) + { + ASSERT((a_Yaw >= -180) && (a_Yaw < 180)); + + a_Yaw += 180 + 45; + if (a_Yaw > 360) + { + a_Yaw -= 360; + } + if ((a_Yaw >= 0) && (a_Yaw < 90)) + { + return 0x0; + } + else if ((a_Yaw >= 180) && (a_Yaw < 270)) + { + return 0x2; + } + else if ((a_Yaw >= 90) && (a_Yaw < 180)) + { + return 0x1; + } + else + { + return 0x3; + } + } + +} ; + + + + diff --git a/source/Blocks/BlockRedstone.h b/source/Blocks/BlockRedstone.h index ae0466937..f28f3f2d6 100644 --- a/source/Blocks/BlockRedstone.h +++ b/source/Blocks/BlockRedstone.h @@ -16,11 +16,6 @@ public: virtual void OnDestroyed(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } - virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { @@ -33,12 +28,6 @@ public: // Reset meta to 0 a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, 1)); } - - - virtual bool CanBePlacedOnSide(void) override - { - return false; - } } ; diff --git a/source/Blocks/BlockRedstoneRepeater.h b/source/Blocks/BlockRedstoneRepeater.h index f3e250963..24250ab86 100644 --- a/source/Blocks/BlockRedstoneRepeater.h +++ b/source/Blocks/BlockRedstoneRepeater.h @@ -32,23 +32,11 @@ public: } - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } - - virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); } - - virtual bool CanBePlacedOnSide(void) override - { - return false; - } - virtual const char * GetStepSound(void) override { return "step.wood"; diff --git a/source/Blocks/BlockSapling.h b/source/Blocks/BlockSapling.h index 17ef4984f..fff2fa88b 100644 --- a/source/Blocks/BlockSapling.h +++ b/source/Blocks/BlockSapling.h @@ -29,12 +29,6 @@ public: { return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); } - - - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } void OnUpdate(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override @@ -50,12 +44,6 @@ public: a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x08); } } - - - virtual bool CanBePlacedOnSide() override - { - return false; - } virtual const char * GetStepSound(void) override diff --git a/source/Blocks/BlockSign.h b/source/Blocks/BlockSign.h index e6426180f..7fbe61893 100644 --- a/source/Blocks/BlockSign.h +++ b/source/Blocks/BlockSign.h @@ -23,12 +23,6 @@ public: { a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0)); } - - - virtual bool DoesAllowBlockOnTop(void) override - { - return false; - } virtual const char * GetStepSound(void) override diff --git a/source/Blocks/BlockSugarcane.h b/source/Blocks/BlockSugarcane.h index 9d66d6be6..28a60df80 100644 --- a/source/Blocks/BlockSugarcane.h +++ b/source/Blocks/BlockSugarcane.h @@ -77,12 +77,6 @@ public: { a_World->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, 1); } - - - virtual bool CanBePlacedOnSide() override - { - return false; - } virtual const char * GetStepSound(void) override diff --git a/source/Blocks/BlockTorch.h b/source/Blocks/BlockTorch.h index 3a50cab77..b9e0dbf27 100644 --- a/source/Blocks/BlockTorch.h +++ b/source/Blocks/BlockTorch.h @@ -24,16 +24,31 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - // Find proper placement. Use the player-supplied one as the default, but fix if not okay: - if (!TorchCanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace)) + // Find proper placement of torch + + if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM)) { - a_BlockFace = FindSuitableFace(a_World, a_BlockX, a_BlockY, a_BlockZ); - - if (a_BlockFace == BLOCK_FACE_BOTTOM) + a_BlockFace = FindSuitableFace(a_World, a_BlockX, a_BlockY, a_BlockZ); // Top or bottom faces clicked, find a suitable face + if (a_BlockFace == BLOCK_FACE_NONE) { + // Client wouldn't have sent anything anyway, but whatever return false; } } + else + { + // Not top or bottom faces, try to preserve whatever face was clicked + if (!TorchCanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace)) + { + // Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face + a_BlockFace = FindSuitableFace(a_World, a_BlockX, a_BlockY, a_BlockZ); + if (a_BlockFace == BLOCK_FACE_NONE) + { + return false; + } + } + } + a_BlockType = m_BlockType; a_BlockMeta = DirectionToMetaData(a_BlockFace); return true; @@ -100,51 +115,58 @@ public: } - virtual bool DoesAllowBlockOnTop(void) override - { - return true; - } - - - static bool CanBePlacedOn(BLOCKTYPE a_BlockType, char a_Direction) + static bool CanBePlacedOn(BLOCKTYPE a_BlockType, char a_BlockFace) { - if ( g_BlockIsSolid[a_BlockType] ) { - return (a_Direction == 0x1); // allow only direction "standing on floor" + if ( !g_BlockIsTorchPlaceable[a_BlockType] ) + { + return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright } - else { - return g_BlockIsSolid[a_BlockType]; + else + { + return true; } } static bool TorchCanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) { - // TODO: If placing a torch from below, check all 4 XZ neighbors, place it on that neighbor instead - // How to propagate that change up? - // Simon: The easiest way is to calculate the position two times, shouldn�t cost much cpu power :) - - if (a_BlockFace == BLOCK_FACE_BOTTOM) - { - return false; - } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); - return CanBePlacedOn(a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ), a_BlockFace); } - /// Finds a suitable Face for the Torch. Returns BLOCK_FACE_BOTTOM on failure + /// Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure static char FindSuitableFace(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) { - for (int i = 1; i <= 5; i++) + // TODO: If placing a torch from below, check all 4 XZ neighbors, place it on that neighbor instead + // How to propagate that change up? + // Simon: The easiest way is to calculate the position two times, shouldn't cost much cpu power :) + + for (int i = 0; i <= 5; i++) { - if (TorchCanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, i)) + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, i, true); + BLOCKTYPE BlockInQuestion = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + + if ( + ((BlockInQuestion == E_BLOCK_GLASS) || + (BlockInQuestion == E_BLOCK_FENCE) || + (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) || + (BlockInQuestion == E_BLOCK_COBBLESTONE_WALL)) && + (i = 1) + ) + { + return i; + } + else if ( g_BlockIsTorchPlaceable[BlockInQuestion] ) { return i; } + else + { + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, i, false); + } } - return BLOCK_FACE_BOTTOM; + return BLOCK_FACE_NONE; } @@ -163,11 +185,28 @@ public: virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - // TODO: Use AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison char Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - return TorchCanBePlacedAt(a_Chunk.GetWorld(), BlockX, a_RelY, BlockZ, Face); + + AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); + BLOCKTYPE BlockInQuestion; + a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockInQuestion); + + if ((BlockInQuestion == E_BLOCK_GLASS) || (BlockInQuestion == E_BLOCK_FENCE) || (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE)) + { + // Torches can be placed on tops of glass and fences, despite them being 'untorcheable' + // No need to check for upright orientation, it was done when the torch was placed + return true; + } + else if ( !g_BlockIsTorchPlaceable[BlockInQuestion] ) + { + return false; + } + else + { + return true; + } } diff --git a/source/BoundingBox.cpp b/source/BoundingBox.cpp new file mode 100644 index 000000000..d8a1bc679 --- /dev/null +++ b/source/BoundingBox.cpp @@ -0,0 +1,331 @@ + +// BoundingBox.cpp + +// Implements the cBoundingBox class representing an axis-aligned bounding box with floatingpoint coords + +#include "Globals.h" +#include "BoundingBox.h" +#include "Defines.h" + + + + + +#if 0 + +/// A simple self-test that is executed on program start, used to verify bbox functionality +class SelfTest +{ +public: + SelfTest(void) + { + Vector3d Min(1, 1, 1); + Vector3d Max(2, 2, 2); + Vector3d LineDefs[] = + { + Vector3d(1.5, 4, 1.5), Vector3d(1.5, 3, 1.5), // Should intersect at 2, face 1 (YP) + Vector3d(1.5, 0, 1.5), Vector3d(1.5, 4, 1.5), // Should intersect at 0.25, face 0 (YM) + Vector3d(0, 0, 0), Vector3d(2, 2, 2), // Should intersect at 0.5, face 0, 3 or 5 (anyM) + Vector3d(0.999, 0, 1.5), Vector3d(0.999, 4, 1.5), // Should not intersect + Vector3d(1.999, 0, 1.5), Vector3d(1.999, 4, 1.5), // Should intersect at 0.25, face 0 (YM) + Vector3d(2.001, 0, 1.5), Vector3d(2.001, 4, 1.5), // Should not intersect + } ; + for (int i = 0; i < ARRAYCOUNT(LineDefs) / 2; i++) + { + double LineCoeff; + char Face; + Vector3d Line1 = LineDefs[2 * i]; + Vector3d Line2 = LineDefs[2 * i + 1]; + bool res = cBoundingBox::CalcLineIntersection(Min, Max, Line1, Line2, LineCoeff, Face); + printf("LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", + Line1.x, Line1.y, Line1.z, + Line2.x, Line2.y, Line2.z, + res ? 1 : 0, LineCoeff, Face + ); + } // for i - LineDefs[] + printf("BoundingBox selftest complete."); + } +} Test; + +#endif + + + + + +cBoundingBox::cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ) : + m_Min(a_MinX, a_MinY, a_MinZ), + m_Max(a_MaxX, a_MaxY, a_MaxZ) +{ +} + + + + + +cBoundingBox::cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max) : + m_Min(a_Min), + m_Max(a_Max) +{ +} + + + + + +cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height) : + m_Min(a_Pos.x - a_Radius, a_Pos.y, a_Pos.z - a_Radius), + m_Max(a_Pos.x + a_Radius, a_Pos.y + a_Height, a_Pos.z + a_Radius) +{ +} + + + + + +cBoundingBox::cBoundingBox(const cBoundingBox & a_Orig) : + m_Min(a_Orig.m_Min), + m_Max(a_Orig.m_Max) +{ +} + + + + + +void cBoundingBox::Move(double a_OffX, double a_OffY, double a_OffZ) +{ + m_Min.x += a_OffX; + m_Min.y += a_OffY; + m_Min.z += a_OffZ; + m_Max.x += a_OffX; + m_Max.y += a_OffY; + m_Max.z += a_OffZ; +} + + + + + +void cBoundingBox::Move(const Vector3d & a_Off) +{ + m_Min.x += a_Off.x; + m_Min.y += a_Off.y; + m_Min.z += a_Off.z; + m_Max.x += a_Off.x; + m_Max.y += a_Off.y; + m_Max.z += a_Off.z; +} + + + + + +void cBoundingBox::Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ) +{ + m_Min.x -= a_ExpandX; + m_Min.y -= a_ExpandY; + m_Min.z -= a_ExpandZ; + m_Max.x += a_ExpandX; + m_Max.y += a_ExpandY; + m_Max.z += a_ExpandZ; +} + + + + + +bool cBoundingBox::DoesIntersect(const cBoundingBox & a_Other) +{ + return ( + ((a_Other.m_Min.x <= m_Max.x) && (a_Other.m_Max.x >= m_Min.x)) && // X coords intersect + ((a_Other.m_Min.y <= m_Max.y) && (a_Other.m_Max.y >= m_Min.y)) && // Y coords intersect + ((a_Other.m_Min.z <= m_Max.z) && (a_Other.m_Max.z >= m_Min.z)) // Z coords intersect + ); +} + + + + + +cBoundingBox cBoundingBox::Union(const cBoundingBox & a_Other) +{ + return cBoundingBox( + std::min(m_Min.x, a_Other.m_Min.x), + std::min(m_Min.y, a_Other.m_Min.y), + std::min(m_Min.z, a_Other.m_Min.z), + std::max(m_Max.x, a_Other.m_Max.x), + std::max(m_Max.y, a_Other.m_Max.y), + std::max(m_Max.z, a_Other.m_Max.z) + ); +} + + + + + +bool cBoundingBox::IsInside(const Vector3d & a_Point) +{ + return IsInside(m_Min, m_Max, a_Point); +} + + + + + +bool cBoundingBox::IsInside(double a_X, double a_Y,double a_Z) +{ + return IsInside(m_Min, m_Max, a_X, a_Y, a_Z); +} + + + + + +bool cBoundingBox::IsInside(cBoundingBox & a_Other) +{ + // If both a_Other's coords are inside this, then the entire a_Other is inside + return (IsInside(a_Other.m_Min) && IsInside(a_Other.m_Max)); +} + + + + + +bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max) +{ + // If both coords are inside this, then the entire a_Other is inside + return (IsInside(a_Min) && IsInside(a_Max)); +} + + + + + +bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point) +{ + return ( + ((a_Point.x >= a_Min.x) && (a_Point.x <= a_Max.x)) && + ((a_Point.y >= a_Min.y) && (a_Point.y <= a_Max.y)) && + ((a_Point.z >= a_Min.z) && (a_Point.z <= a_Max.z)) + ); +} + + + + + +bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z) +{ + return ( + ((a_X >= a_Min.x) && (a_X <= a_Max.x)) && + ((a_Y >= a_Min.y) && (a_Y <= a_Max.y)) && + ((a_Z >= a_Min.z) && (a_Z <= a_Max.z)) + ); +} + + + + + +bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face) +{ + return CalcLineIntersection(m_Min, m_Max, a_Line1, a_Line2, a_LineCoeff, a_Face); +} + + + + + +bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face) +{ + if (IsInside(a_Min, a_Max, a_Line1)) + { + // The starting point is inside the bounding box. + a_LineCoeff = 0; + a_Face = BLOCK_FACE_YM; // Make it look as the top face was hit, although none really are. + return true; + } + + char Face = 0; + double Coeff = Vector3d::NO_INTERSECTION; + + // Check each individual bbox face for intersection with the line, remember the one with the lowest coeff + double c = a_Line1.LineCoeffToXYPlane(a_Line2, a_Min.z); + if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + { + Face = (a_Line1.z > a_Line2.z) ? BLOCK_FACE_ZP : BLOCK_FACE_ZM; + Coeff = c; + } + c = a_Line1.LineCoeffToXYPlane(a_Line2, a_Max.z); + if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + { + Face = (a_Line1.z > a_Line2.z) ? BLOCK_FACE_ZP : BLOCK_FACE_ZM; + Coeff = c; + } + c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Min.y); + if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + { + Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM; + Coeff = c; + } + c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Max.y); + if ((c >= 0) && (c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + { + Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM; + Coeff = c; + } + c = a_Line1.LineCoeffToYZPlane(a_Line2, a_Min.x); + if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + { + Face = (a_Line1.x > a_Line2.x) ? BLOCK_FACE_XP : BLOCK_FACE_XM; + Coeff = c; + } + c = a_Line1.LineCoeffToYZPlane(a_Line2, a_Max.x); + if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + { + Face = (a_Line1.x > a_Line2.x) ? BLOCK_FACE_XP : BLOCK_FACE_XM; + Coeff = c; + } + + if (Coeff >= Vector3d::NO_INTERSECTION) + { + // There has been no intersection + return false; + } + + a_LineCoeff = Coeff; + a_Face = Face; + return true; +} + + + + + +bool cBoundingBox::Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection) +{ + a_Intersection.m_Min.x = std::max(m_Min.x, a_Other.m_Min.x); + a_Intersection.m_Max.x = std::min(m_Max.x, a_Other.m_Max.x); + if (a_Intersection.m_Min.x >= a_Intersection.m_Max.x) + { + return false; + } + a_Intersection.m_Min.y = std::max(m_Min.y, a_Other.m_Min.y); + a_Intersection.m_Max.y = std::min(m_Max.y, a_Other.m_Max.y); + if (a_Intersection.m_Min.y >= a_Intersection.m_Max.y) + { + return false; + } + a_Intersection.m_Min.z = std::max(m_Min.z, a_Other.m_Min.z); + a_Intersection.m_Max.z = std::min(m_Max.z, a_Other.m_Max.z); + if (a_Intersection.m_Min.z >= a_Intersection.m_Max.z) + { + return false; + } + return true; +} + + + + diff --git a/source/BoundingBox.h b/source/BoundingBox.h new file mode 100644 index 000000000..ff9963989 --- /dev/null +++ b/source/BoundingBox.h @@ -0,0 +1,90 @@ + +// BoundingBox.h + +// Declares the cBoundingBox class representing an axis-aligned bounding box with floatingpoint coords + + + + +#pragma once + +#include "Vector3d.h" + + + + + +// tolua_begin + +/** Represents two sets of coords, minimum and maximum for each direction. +All the coords within those limits (inclusive the edges) are considered "inside" the box. +For intersection purposes, though, if the intersection is "sharp" in any coord (i. e. zero volume), +the boxes are considered non-intersecting. +*/ +class cBoundingBox +{ +public: + cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ); + cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max); + cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height); + cBoundingBox(const cBoundingBox & a_Orig); + + /// Moves the entire boundingbox by the specified offset + void Move(double a_OffX, double a_OffY, double a_OffZ); + + /// Moves the entire boundingbox by the specified offset + void Move(const Vector3d & a_Off); + + /// Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each direction) + void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ); + + /// Returns true if the two bounding boxes intersect + bool DoesIntersect(const cBoundingBox & a_Other); + + /// Returns the union of the two bounding boxes + cBoundingBox Union(const cBoundingBox & a_Other); + + /// Returns true if the point is inside the bounding box + bool IsInside(const Vector3d & a_Point); + + /// Returns true if the point is inside the bounding box + bool IsInside(double a_X, double a_Y,double a_Z); + + /// Returns true if a_Other is inside this bounding box + bool IsInside(cBoundingBox & a_Other); + + /// Returns true if a boundingbox specified by a_Min and a_Max is inside this bounding box + bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max); + + /// Returns true if the specified point is inside the bounding box specified by its min/max corners + static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point); + + /// Returns true if the specified point is inside the bounding box specified by its min/max corners + static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z); + + /** Returns true if this bounding box is intersected by the line specified by its two points + Also calculates the distance along the line in which the intersection occurs (0 .. 1) + Only forward collisions (a_LineCoeff >= 0) are returned. + */ + bool CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face); + + /** Returns true if the specified bounding box is intersected by the line specified by its two points + Also calculates the distance along the line in which the intersection occurs (0 .. 1) and the face hit (BLOCK_FACE_ constants) + Only forward collisions (a_LineCoeff >= 0) are returned. + */ + static bool CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face); + + // tolua_end + + /// Calculates the intersection of the two bounding boxes; returns true if nonempty + bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection); + +protected: + Vector3d m_Min; + Vector3d m_Max; + +} ; // tolua_export + + + + diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index a15f3aed1..3c098fdfe 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -1562,7 +1562,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback -void cChunkMap::DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlocksAffected) +void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlocksAffected) { // Don't explode if outside of Y range (prevents the following test running into unallocated memory): if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height - 1)) diff --git a/source/ChunkMap.h b/source/ChunkMap.h index b0af0d779..fcb164f7b 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -184,7 +184,7 @@ public: bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible /// Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates - void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected); + void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected); /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 357c07105..1806ce8e6 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -11,7 +11,6 @@ #include "BlockEntities/SignEntity.h" #include "UI/Window.h" #include "Item.h" -#include "Doors.h" #include "Piston.h" #include "Mobs/Monster.h" #include "ChatColor.h" @@ -98,6 +97,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) , m_HasStartedDigging(false) , m_CurrentExplosionTick(0) , m_RunningSumExplosions(0) + , m_HasSentPlayerChunk(false) { m_Protocol = new cProtocolRecognizer(this); @@ -489,8 +489,14 @@ void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_Hel void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround) { + if ((m_Player == NULL) || (m_State != csPlaying)) + { + // The client hasn't been spawned yet and sends nonsense, we know better + return; + } + /* - // TODO: Invalid stance check + // TODO: Invalid stance check if ((a_PosY >= a_Stance) || (a_Stance > a_PosY + 1.65)) { LOGD("Invalid stance"); @@ -499,7 +505,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, } */ - // LOGD("recv player pos: {%0.2f %0.2f %0.2f}, ground: %d", a_PosX, a_PosY, a_PosZ, a_IsOnGround ? 1 : 0); + // If the player has moved too far, "repair" them: Vector3d Pos(a_PosX, a_PosY, a_PosZ); if ((m_Player->GetPosition() - Pos).SqrLength() > 100 * 100) { @@ -513,7 +519,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, { // we only add this exhaustion if the player is not swimming - otherwise we end up with both jump + swim exhaustion - if(! m_Player->IsSwimming() ) + if (!m_Player->IsSwimming()) { m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2); } @@ -908,15 +914,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c } else { - // Check for Blocks not allowing placement on top - if ((a_BlockFace == BLOCK_FACE_TOP) && !Handler->DoesAllowBlockOnTop()) - { - // Resend the old block - // Sometimes the client still places the block O.o - World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - return; - } - if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision()) { // Tried to place a block *into* another? @@ -938,13 +935,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c cBlockHandler * NewBlock = BlockHandler(BlockType); - if ((a_BlockFace != BLOCK_FACE_TOP) && !NewBlock->CanBePlacedOnSide()) - { - // Cannot be placed on the side of an other block - World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - return; - } - if (cRoot::Get()->GetPluginManager()->CallHookPlayerPlacingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta)) { // A plugin doesn't agree with placing the block, revert the block on the client: @@ -997,11 +987,15 @@ void cClientHandle::HandleChat(const AString & a_Message) void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsOnGround) { + if ((m_Player == NULL) || (m_State != csPlaying)) + { + return; + } + m_Player->SetRotation (a_Rotation); m_Player->SetHeadYaw (a_Rotation); m_Player->SetPitch (a_Pitch); m_Player->SetTouchGround(a_IsOnGround); - m_Player->WrapRotation(); } @@ -1010,6 +1004,12 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround) { + if ((m_Player == NULL) || (m_State != csPlaying)) + { + // The client hasn't been spawned yet and sends nonsense, we know better + return; + } + /* // TODO: Invalid stance check if ((a_PosY >= a_Stance) || (a_Stance > a_PosY + 1.65)) @@ -1019,46 +1019,13 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_ return; } */ - switch (m_State) - { - case csPlaying: - { - m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); - m_Player->SetStance (a_Stance); - m_Player->SetTouchGround(a_IsOnGround); - m_Player->SetHeadYaw (a_Rotation); - m_Player->SetRotation (a_Rotation); - m_Player->SetPitch (a_Pitch); - m_Player->WrapRotation(); - break; - } - - case csDownloadingWorld: - { - Vector3d ReceivedPosition = Vector3d(a_PosX, a_PosY, a_PosZ); - // LOGD("Received MoveLook confirmation: {%0.2f %0.2f %0.2f}", a_PosX, a_PosY, a_PosZ); - - // Test the distance between points with a small/large enough value instead of comparing directly. Floating point inaccuracies might screw stuff up - double Dist = (ReceivedPosition - m_ConfirmPosition).SqrLength(); - if (Dist < 1.0) - { - if (ReceivedPosition.Equals(m_ConfirmPosition)) - { - LOGINFO("Exact position confirmed by client!"); - } - m_State = csPlaying; - } - else - { - LOGWARNING("Player \"%s\" sent a weird position confirmation %.2f blocks away, retrying", m_Username.c_str(), sqrt(Dist)); - LOGD(" Expected pos: {%0.2f, %0.2f, %0.2f}", m_ConfirmPosition.x, m_ConfirmPosition.y, m_ConfirmPosition.z); - LOGD(" Received pos: {%0.2f, %0.2f, %0.2f}", a_PosX, a_PosY, a_PosZ); - m_ConfirmPosition = m_Player->GetPosition(); - SendPlayerMoveLook(); - } - break; - } - } + + m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); + m_Player->SetStance (a_Stance); + m_Player->SetTouchGround(a_IsOnGround); + m_Player->SetHeadYaw (a_Rotation); + m_Player->SetRotation (a_Rotation); + m_Player->SetPitch (a_Pitch); } @@ -1090,6 +1057,15 @@ void cClientHandle::HandleSlotSelected(short a_SlotNum) +void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways) +{ + m_Player->SteerVehicle(a_Forward, a_Sideways); +} + + + + + void cClientHandle::HandleWindowClose(char a_WindowID) { m_Player->CloseWindowIfID(a_WindowID); @@ -1199,7 +1175,7 @@ void cClientHandle::HandleUseEntity(int a_TargetEntityID, bool a_IsLeftClick) void cClientHandle::HandleRespawn(void) { - if( m_Player == NULL ) + if (m_Player == NULL) { Destroy(); return; @@ -1413,6 +1389,7 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) m_State = csAuthenticated; m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; + m_HasSentPlayerChunk = false; } @@ -1486,17 +1463,23 @@ void cClientHandle::Tick(float a_Dt) Destroy(); } - if ((m_State == csDownloadingWorld) && m_ShouldCheckDownloaded) - { - CheckIfWorldDownloaded(); - m_ShouldCheckDownloaded = false; - } - if (m_Player == NULL) { return; } + // If the chunk the player's in was just sent, spawn the player: + if (m_HasSentPlayerChunk && (m_State != csPlaying)) + { + if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player)) + { + // Broadcast that this player has joined the game! Yay~ + m_Player->GetWorld()->BroadcastChat(m_Username + " joined the game!", this); + } + m_Protocol->SendPlayerMoveLook(); + m_State = csPlaying; + } + // Send a ping packet: cTimer t1; if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) @@ -1592,14 +1575,6 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ { ASSERT(m_Player != NULL); - if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld)) - { - if ((a_ChunkX == m_Player->GetChunkX()) && (a_ChunkZ == m_Player->GetChunkZ())) - { - m_Protocol->SendPlayerMoveLook(); - } - } - // Check chunks being sent, erase them from m_ChunksToSend: bool Found = false; { @@ -1609,11 +1584,6 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) { m_ChunksToSend.erase(itr); - - // Make the tick thread check if all the needed chunks have been downloaded - // -- needed to offload this from here due to a deadlock possibility - m_ShouldCheckDownloaded = true; - Found = true; break; } @@ -1628,6 +1598,15 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ } m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); + + // If it is the chunk the player's in, make them spawn (in the tick thread): + if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld)) + { + if ((a_ChunkX == m_Player->GetChunkX()) && (a_ChunkZ == m_Player->GetChunkZ())) + { + m_HasSentPlayerChunk = true; + } + } } @@ -2069,50 +2048,6 @@ void cClientHandle::SendWindowProperty(const cWindow & a_Window, int a_Property, -void cClientHandle::CheckIfWorldDownloaded(void) -{ - if (m_State != csDownloadingWorld) - { - return; - } - - bool ShouldSendConfirm = false; - { - cCSLock Lock(m_CSChunkLists); - ShouldSendConfirm = m_ChunksToSend.empty(); - } - - if (ShouldSendConfirm) - { - SendConfirmPosition(); - } -} - - - - - -void cClientHandle::SendConfirmPosition(void) -{ - LOG("Spawning player \"%s\" at {%.2f, %.2f, %.2f}", - m_Username.c_str(), m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ() - ); - - m_State = csConfirmingPos; - - if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player)) - { - // Broadcast that this player has joined the game! Yay~ - m_Player->GetWorld()->BroadcastChat(m_Username + " joined the game!", this); - } - - SendPlayerMoveLook(); -} - - - - - const AString & cClientHandle::GetUsername(void) const { return m_Username; diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 761cf25fe..07efc5d9c 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -56,7 +56,7 @@ public: static const int DEFAULT_VIEW_DISTANCE = 9; #endif static const int MAX_VIEW_DISTANCE = 10; - static const int MIN_VIEW_DISTANCE = 4; + static const int MIN_VIEW_DISTANCE = 3; /// How many ticks should be checked for a running average of explosions, for limiting purposes static const int NUM_CHECK_EXPLOSIONS_TICKS = 20; @@ -125,7 +125,7 @@ public: void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); void SendSpawnMob (const cMonster & a_Mob); void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch); - void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType); + void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType = 0); void SendTabCompletionResults(const AStringVector & a_Results); void SendTeleportEntity (const cEntity & a_Entity); void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); @@ -177,6 +177,7 @@ public: void HandleRespawn (void); void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem); void HandleSlotSelected (short a_SlotNum); + void HandleSteerVehicle (float Forward, float Sideways); void HandleTabCompletion (const AString & a_Text); void HandleUpdateSign ( int a_BlockX, int a_BlockY, int a_BlockZ, @@ -298,17 +299,14 @@ private: static int s_ClientCount; int m_UniqueID; + /// Set to true when the chunk where the player is is sent to the client. Used for spawning the player + bool m_HasSentPlayerChunk; + /// Returns true if the rate block interactions is within a reasonable limit (bot protection) bool CheckBlockInteractionsRate(void); - /// Checks whether all loaded chunks have been sent to the client; if so, sends the position to confirm - void CheckIfWorldDownloaded(void); - - /// Sends the PlayerMoveLook packet that the client needs to reply to for the game to start - void SendConfirmPosition(void); - /// Adds a single chunk to be streamed to the client; used by StreamChunks() void StreamChunk(int a_ChunkX, int a_ChunkZ); diff --git a/source/Defines.h b/source/Defines.h index 6bc1a18f6..6dd81137e 100644 --- a/source/Defines.h +++ b/source/Defines.h @@ -43,16 +43,24 @@ extern bool g_BlockIsSolid[256]; -/// Block face constants, used in PlayerDigging and PlayerBlockPlacement packets -enum +/// Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc +enum eBlockFace { - BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air - BLOCK_FACE_BOTTOM = 0, // Interacting with the bottom face of the block (YM) - BLOCK_FACE_TOP = 1, // Interacting with the top face of the block (YP) - BLOCK_FACE_NORTH = 2, // Interacting with the northern face of the block (ZP) - BLOCK_FACE_SOUTH = 3, // Interacting with the southern face of the block (ZM) - BLOCK_FACE_WEST = 4, // Interacting with the western face of the block (XP) - BLOCK_FACE_EAST = 5, // Interacting with the eastern face of the block (XM) + BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air + BLOCK_FACE_XM = 5, // Interacting with the X- face of the block + BLOCK_FACE_XP = 4, // Interacting with the X+ face of the block + BLOCK_FACE_YM = 0, // Interacting with the Y- face of the block + BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block + BLOCK_FACE_ZM = 3, // Interacting with the Z- face of the block + BLOCK_FACE_ZP = 2, // Interacting with the Z+ face of the block + + // Synonyms using the (deprecated) world directions: + BLOCK_FACE_BOTTOM = BLOCK_FACE_YM, // Interacting with the bottom face of the block + BLOCK_FACE_TOP = BLOCK_FACE_YP, // Interacting with the top face of the block + BLOCK_FACE_NORTH = BLOCK_FACE_ZP, // Interacting with the northern face of the block + BLOCK_FACE_SOUTH = BLOCK_FACE_ZM, // Interacting with the southern face of the block + BLOCK_FACE_WEST = BLOCK_FACE_XP, // Interacting with the western face of the block + BLOCK_FACE_EAST = BLOCK_FACE_XM, // Interacting with the eastern face of the block } ; @@ -345,8 +353,7 @@ inline void AddFaceDirection(int & a_BlockX, unsigned char & a_BlockY, int & a_B -#include <math.h> -#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f +#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a_Y, double & a_Z) { diff --git a/source/Doors.h b/source/Doors.h deleted file mode 100644 index 69784a3d7..000000000 --- a/source/Doors.h +++ /dev/null @@ -1,87 +0,0 @@ - -#pragma once - - - - - -// tolua_begin -class cDoors -{ -public: - static char RotationToMetaData(double a_Rotation) - { - a_Rotation += 90 + 45; // So its not aligned with axis - if (a_Rotation > 360) - { - a_Rotation -= 360; - } - if (a_Rotation >= 0.f && a_Rotation < 90) - { - return 0x0; - } - else if ((a_Rotation >= 180) && (a_Rotation < 270)) - { - return 0x2; - } - else if ((a_Rotation >= 90) && (a_Rotation < 180)) - { - return 0x1; - } - else - { - return 0x3; - } - } - - - static NIBBLETYPE ChangeStateMetaData(NIBBLETYPE a_MetaData) - { - - a_MetaData ^= 4; //XOR bit 2 aka 3. bit (Door open state) - - return a_MetaData; - } - - - static void ChangeDoor(cWorld * a_World, int a_X, int a_Y, int a_Z) - { - NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_X, a_Y, a_Z); - - a_World->SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData)); - - if (OldMetaData & 8) - { - // Current block is top of the door - BLOCKTYPE BottomBlock = a_World->GetBlock(a_X, a_Y - 1, a_Z); - NIBBLETYPE BottomMeta = a_World->GetBlockMeta(a_X, a_Y - 1, a_Z); - - if (IsDoor(BottomBlock) && !(BottomMeta & 8)) - { - a_World->SetBlockMeta(a_X, a_Y - 1, a_Z, ChangeStateMetaData(BottomMeta)); - } - } - else - { - // Current block is bottom of the door - BLOCKTYPE TopBlock = a_World->GetBlock(a_X, a_Y + 1, a_Z); - NIBBLETYPE TopMeta = a_World->GetBlockMeta(a_X, a_Y + 1, a_Z); - - if (IsDoor(TopBlock) && (TopMeta & 8)) - { - a_World->SetBlockMeta(a_X, a_Y + 1, a_Z, ChangeStateMetaData(TopMeta)); - } - } - } - - - inline static bool IsDoor(BLOCKTYPE a_Block) - { - return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR); - } -} ; -// tolua_end - - - - diff --git a/source/Entities/Boat.cpp b/source/Entities/Boat.cpp new file mode 100644 index 000000000..56e766dd4 --- /dev/null +++ b/source/Entities/Boat.cpp @@ -0,0 +1,87 @@ + +// Boat.cpp + +// Implements the cBoat class representing a boat in the world + +#include "Globals.h" +#include "Boat.h" +#include "../World.h" +#include "../ClientHandle.h" +#include "Player.h" + + + + + +cBoat::cBoat(double a_X, double a_Y, double a_Z) : + super(etBoat, a_X, a_Y, a_Z, 0.98, 0.7) +{ + SetMass(20.f); + SetMaxHealth(6); + SetHealth(6); +} + + + + +void cBoat::SpawnOn(cClientHandle & a_ClientHandle) +{ + a_ClientHandle.SendSpawnVehicle(*this, 1); +} + + + + + +void cBoat::DoTakeDamage(TakeDamageInfo & TDI) +{ + super::DoTakeDamage(TDI); + + if (GetHealth() == 0) + { + Destroy(true); + } +} + + + + + +void cBoat::OnRightClicked(cPlayer & a_Player) +{ + if (m_Attachee != NULL) + { + if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) + { + // This player is already sitting in, they want out. + a_Player.Detach(); + return; + } + + if (m_Attachee->IsPlayer()) + { + // Another player is already sitting in here, cannot attach + return; + } + + // Detach whatever is sitting in this boat now: + m_Attachee->Detach(); + } + + // Attach the player to this boat + a_Player.AttachTo(this); +} + + + + + +void cBoat::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + super::HandlePhysics(a_Dt, a_Chunk); + BroadcastMovementUpdate(); +} + + + + diff --git a/source/Entities/Boat.h b/source/Entities/Boat.h new file mode 100644 index 000000000..734ebda83 --- /dev/null +++ b/source/Entities/Boat.h @@ -0,0 +1,38 @@ + +// Boat.h + +// Declares the cBoat class representing a boat in the world + + + + + +#pragma once + +#include "Entity.h" +#include "../Item.h" + + + + + +class cBoat : + public cEntity +{ + typedef cEntity super; + +public: + CLASS_PROTODEF(cBoat); + + // cEntity overrides: + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; + virtual void OnRightClicked(cPlayer & a_Player) override; + virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + + cBoat(double a_X, double a_Y, double a_Z); +} ; + + + + diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp index e79b441f3..d9272b39d 100644 --- a/source/Entities/Entity.cpp +++ b/source/Entities/Entity.cpp @@ -55,6 +55,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_TicksSinceLastBurnDamage(0) , m_TicksSinceLastLavaDamage(0) , m_TicksSinceLastFireDamage(0) + , m_TicksSinceLastVoidDamage(0) , m_TicksLeftBurning(0) , m_WaterSpeed(0, 0, 0) , m_Width(a_Width) @@ -253,6 +254,39 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R +void cEntity::SetRotationFromSpeed(void) +{ + const double EPS = 0.0000001; + if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS)) + { + // atan2() may overflow or is undefined, pick any number + SetRotation(0); + return; + } + SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI); +} + + + + + +void cEntity::SetPitchFromSpeed(void) +{ + const double EPS = 0.0000001; + double xz = sqrt(m_Speed.x * m_Speed.x + m_Speed.z * m_Speed.z); // Speed XZ-plane component + if ((abs(xz) < EPS) && (abs(m_Speed.y) < EPS)) + { + // atan2() may overflow or is undefined, pick any number + SetPitch(0); + return; + } + SetPitch(atan2(m_Speed.y, xz) * 180 / PI); +} + + + + + void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI)) @@ -472,6 +506,11 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { TickBurning(a_Chunk); } + if ((a_Chunk.IsValid()) && (GetPosY() < -46)) + { + TickInVoid(a_Chunk); + } + else { m_TicksSinceLastVoidDamage = 0; } } @@ -491,8 +530,15 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) { // Outside of the world - // TODO: Current speed should still be added to the entity position - // Otherwise TNT explosions in the void will still effect the bottommost layers of the world + + cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); + // See if we can commit our changes. If not, we will discard them. + if (NextChunk != NULL) + { + SetSpeed(NextSpeed); + NextPos += (NextSpeed * a_Dt); + SetPosition(NextPos); + } return; } @@ -534,7 +580,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) bool IsNoAirSurrounding = true; for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock); + if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) + { + // The pickup is too close to an unloaded chunk, bail out of any physics handling + return; + } if (!g_BlockIsSolid[GotBlock]) { NextPos.x += gCrossCoords[i].x; @@ -545,12 +595,15 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } // for i - gCrossCoords[] if (IsNoAirSurrounding) - { NextPos.y += 0.5; } + { + NextPos.y += 0.5; + } m_bOnGround = true; - LOGD("Entity #%d (%s) is inside a block at {%d,%d,%d}", - m_UniqueID, GetClass(), BlockX, BlockY, BlockZ); + LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", + m_UniqueID, GetClass(), BlockX, BlockY, BlockZ + ); } if (!m_bOnGround) @@ -844,6 +897,23 @@ void cEntity::TickBurning(cChunk & a_Chunk) +void cEntity::TickInVoid(cChunk & a_Chunk) +{ + if (m_TicksSinceLastVoidDamage == 20) + { + TakeDamage(dtInVoid, NULL, 2, 0); + m_TicksSinceLastVoidDamage = 0; + } + else + { + m_TicksSinceLastVoidDamage++; + } +} + + + + + /// Called when the entity starts burning void cEntity::OnStartedBurning(void) { @@ -1275,6 +1345,25 @@ void cEntity::AddSpeedZ(double a_AddSpeedZ) +void cEntity::SteerVehicle(float a_Forward, float a_Sideways) +{ + if (m_AttachedTo == NULL) + { + return; + } + if ((a_Forward != 0) || (a_Sideways != 0)) + { + Vector3d LookVector = GetLookVector(); + double AddSpeedX = LookVector.x * a_Forward + LookVector.z * a_Sideways; + double AddSpeedZ = LookVector.z * a_Forward - LookVector.x * a_Sideways; + m_AttachedTo->AddSpeed(AddSpeedX, 0, AddSpeedZ); + } +} + + + + + ////////////////////////////////////////////////////////////////////////// // Get look vector (this is NOT a rotation!) Vector3d cEntity::GetLookVector(void) const diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h index 2d058abae..a2c99d2a0 100644 --- a/source/Entities/Entity.h +++ b/source/Entities/Entity.h @@ -92,6 +92,7 @@ public: etMonster, etFallingBlock, etMinecart, + etBoat, etTNT, etProjectile, @@ -119,6 +120,7 @@ public: bool IsPickup (void) const { return (m_EntityType == etPickup); } bool IsMob (void) const { return (m_EntityType == etMob); } bool IsMinecart(void) const { return (m_EntityType == etMinecart); } + bool IsBoat (void) const { return (m_EntityType == etBoat); } bool IsTNT (void) const { return (m_EntityType == etTNT); } /// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true) @@ -185,6 +187,8 @@ public: void AddSpeedX (double a_AddSpeedX); void AddSpeedY (double a_AddSpeedY); void AddSpeedZ (double a_AddSpeedZ); + + void SteerVehicle(float a_Forward, float a_Sideways); inline int GetUniqueID(void) const { return m_UniqueID; } inline bool IsDestroyed(void) const { return !m_IsInitialized; } @@ -201,6 +205,16 @@ public: /// Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage() void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount); + float GetGravity(void) const { return m_Gravity; } + + void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; } + + /// Sets the rotation to match the speed vector (entity goes "face-forward") + void SetRotationFromSpeed(void); + + /// Sets the pitch to match the speed vector (entity gies "face-forward") + void SetPitchFromSpeed(void); + // tolua_end /// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied @@ -253,6 +267,9 @@ public: /// Updates the state related to this entity being on fire virtual void TickBurning(cChunk & a_Chunk); + + /// Handles when the entity is in the void + virtual void TickInVoid(cChunk & a_Chunk); /// Called when the entity starts burning virtual void OnStartedBurning(void); @@ -375,6 +392,9 @@ protected: /// Time, in ticks, until the entity extinguishes its fire int m_TicksLeftBurning; + + /// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void. + int m_TicksSinceLastVoidDamage; virtual void Destroyed(void) {} // Called after the entity has been destroyed diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 8356d588e..04d285b01 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -220,7 +220,6 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) if (m_IsChargingBow) { m_BowCharge += 1; - LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge); } if (m_bDirtyPosition) @@ -611,10 +610,13 @@ void cPlayer::SetSprint(bool a_IsSprinting) void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) { - if (m_GameMode == eGameMode_Creative) + if (a_TDI.DamageType != dtInVoid) { - // No damage / health in creative mode - return; + if (IsGameModeCreative()) + { + // No damage / health in creative mode + return; + } } super::DoTakeDamage(a_TDI); diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 91b2c97a8..4c8e680d0 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -8,6 +8,16 @@ #include "../ClientHandle.h" #include "Player.h" #include "../LineBlockTracer.h" +#include "../BoundingBox.h" +#include "../ChunkMap.h" +#include "../Chunk.h" + + + + + +/// Converts an angle in radians into a byte representation used by the network protocol +#define ANGLE_TO_PROTO(X) (Byte)(X * 255 / 360) @@ -21,20 +31,49 @@ class cProjectileTracerCallback : { public: cProjectileTracerCallback(cProjectileEntity * a_Projectile) : - m_Projectile(a_Projectile) + m_Projectile(a_Projectile), + m_SlowdownCoeff(0.99) // Default slowdown when not in water { } + double GetSlowdownCoeff(void) const { return m_SlowdownCoeff; } + protected: cProjectileEntity * m_Projectile; + double m_SlowdownCoeff; + // cCallbacks overrides: virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { + /* + // DEBUG: + LOGD("Hit block %d:%d at {%d, %d, %d} face %d, %s (%s)", + a_BlockType, a_BlockMeta, + a_BlockX, a_BlockY, a_BlockZ, a_EntryFace, + g_BlockIsSolid[a_BlockType] ? "solid" : "non-solid", + ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str() + ); + */ + if (g_BlockIsSolid[a_BlockType]) { // The projectile hit a solid block - m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace); - return true; + // Calculate the exact hit coords: + cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); + Vector3d Line1 = m_Projectile->GetPosition(); + Vector3d Line2 = Line1 + m_Projectile->GetSpeed(); + double LineCoeff = 0; + char Face; + if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face)) + { + Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff; + m_Projectile->OnHitSolidBlock(Intersection, Face); + return true; + } + else + { + LOGD("WEIRD! block tracer reports a hit, but BBox tracer doesn't. Ignoring the hit."); + } } // Convey some special effects from special blocks: @@ -44,12 +83,14 @@ protected: case E_BLOCK_STATIONARY_LAVA: { m_Projectile->StartBurning(30); + m_SlowdownCoeff = std::min(m_SlowdownCoeff, 0.9); // Slow down to 0.9* the speed each tick when moving through lava break; } case E_BLOCK_WATER: case E_BLOCK_STATIONARY_WATER: { m_Projectile->StopBurning(); + m_SlowdownCoeff = std::min(m_SlowdownCoeff, 0.8); // Slow down to 0.8* the speed each tick when moving through water break; } } // switch (a_BlockType) @@ -64,6 +105,86 @@ protected: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProjectileEntityCollisionCallback: + +class cProjectileEntityCollisionCallback : + public cEntityCallback +{ +public: + cProjectileEntityCollisionCallback(cProjectileEntity * a_Projectile, const Vector3d & a_Pos, const Vector3d & a_NextPos) : + m_Projectile(a_Projectile), + m_Pos(a_Pos), + m_NextPos(a_NextPos), + m_MinCoeff(1), + m_HitEntity(NULL) + { + } + + + virtual bool Item(cEntity * a_Entity) override + { + if ( + (a_Entity == m_Projectile) || // Do not check collisions with self + (a_Entity == m_Projectile->GetCreator()) // Do not check whoever shot the projectile + ) + { + // TODO: Don't check creator only for the first 5 ticks + // so that arrows stuck in ground and dug up can hurt the player + return false; + } + + cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + // Instead of colliding the bounding box with another bounding box in motion, we collide an enlarged bounding box with a hairline. + // The results should be good enough for our purposes + double LineCoeff; + char Face; + EntBox.Expand(m_Projectile->GetWidth() / 2, m_Projectile->GetHeight() / 2, m_Projectile->GetWidth() / 2); + if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face)) + { + // No intersection whatsoever + return false; + } + + // TODO: Some entities don't interact with the projectiles (pickups, falling blocks) + // TODO: Allow plugins to interfere about which entities can be hit + + if (LineCoeff < m_MinCoeff) + { + // The entity is closer than anything we've stored so far, replace it as the potential victim + m_MinCoeff = LineCoeff; + m_HitEntity = a_Entity; + } + + // Don't break the enumeration, we want all the entities + return false; + } + + /// Returns the nearest entity that was hit, after the enumeration has been completed + cEntity * GetHitEntity(void) const { return m_HitEntity; } + + /// Returns the line coeff where the hit was encountered, after the enumeration has been completed + double GetMinCoeff(void) const { return m_MinCoeff; } + + /// Returns true if the callback has encountered a true hit + bool HasHit(void) const { return (m_MinCoeff < 1); } + +protected: + cProjectileEntity * m_Projectile; + const Vector3d & m_Pos; + const Vector3d & m_NextPos; + double m_MinCoeff; // The coefficient of the nearest hit on the Pos line + + // Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback + // is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing + cEntity * m_HitEntity; // The nearest hit entity +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cProjectileEntity: cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) : @@ -85,6 +206,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve m_IsInGround(false) { SetSpeed(a_Speed); + SetRotationFromSpeed(); + SetPitchFromSpeed(); } @@ -101,10 +224,12 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, switch (a_Kind) { - case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); - case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); // TODO: the rest } @@ -116,26 +241,17 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, -void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - // TODO: Set proper position based on what face was hit - switch (a_BlockFace) - { - case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break; - case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break; - case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; - } + // Set the position based on what face was hit: + SetPosition(a_HitPos); SetSpeed(0, 0, 0); // DEBUG: LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d", m_UniqueID, - GetPosX(), GetPosY(), GetPosZ(), - a_BlockFace + a_HitPos.x, a_HitPos.y, a_HitPos.z, + a_HitFace ); m_IsInGround = true; @@ -192,20 +308,51 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) // Trace the tick's worth of movement as a line: Vector3d NextPos = Pos + PerTickSpeed; cProjectileTracerCallback TracerCallback(this); - if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) + if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) { - // Nothing in the way, update the position - SetPosition(NextPos); + // Something has been hit, abort all other processing + return; + } + // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff + + // Test for entity collisions: + cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); + a_Chunk.ForEachEntity(EntityCollisionCallback); + if (EntityCollisionCallback.HasHit()) + { + // An entity was hit: + Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff(); + + // DEBUG: + LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)", + m_UniqueID, + EntityCollisionCallback.GetHitEntity()->GetUniqueID(), + EntityCollisionCallback.GetHitEntity()->GetClass(), + HitPos.x, HitPos.y, HitPos.z, + EntityCollisionCallback.GetMinCoeff() + ); + + OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); } + // TODO: Test the entities in the neighboring chunks, too + + // Update the position: + SetPosition(NextPos); - // Add gravity effect to the vertical speed component: - SetSpeedY(GetSpeedY() + m_Gravity / 20); + // Add slowdown and gravity effect to the speed: + Vector3d NewSpeed(GetSpeed()); + NewSpeed.y += m_Gravity / 20; + NewSpeed *= TracerCallback.GetSlowdownCoeff(); + SetSpeed(NewSpeed); + SetRotationFromSpeed(); + SetPitchFromSpeed(); // DEBUG: - LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}", + LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}", m_UniqueID, GetPosX(), GetPosY(), GetPosZ(), - GetSpeedX(), GetSpeedY(), GetSpeedZ() + GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetRotation(), GetPitch() ); } @@ -216,7 +363,8 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cProjectileEntity::SpawnOn(cClientHandle & a_Client) { // Default spawning - use the projectile kind to spawn an object: - a_Client.SendSpawnObject(*this, m_ProjectileKind, 0, 0, 0); + a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch())); + a_Client.SendEntityMetadata(*this); } @@ -229,12 +377,16 @@ void cProjectileEntity::SpawnOn(cClientHandle & a_Client) cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), m_PickupState(psNoPickup), - m_DamageCoeff(2) + m_DamageCoeff(2), + m_IsCritical(false) { SetSpeed(a_Speed); SetMass(0.1); - LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}", - m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ() + SetRotationFromSpeed(); + SetPitchFromSpeed(); + LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", + m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetRotation(), GetPitch() ); } @@ -245,7 +397,8 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), m_PickupState(psInSurvivalOrCreative), - m_DamageCoeff(2) + m_DamageCoeff(2), + m_IsCritical((a_Force >= 1)) { } @@ -269,14 +422,43 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const -void cArrowEntity::SpawnOn(cClientHandle & a_Client) +void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + super::OnHitSolidBlock(a_HitPos, a_HitFace); + + // Broadcast the position and speed packets before teleporting: + BroadcastMovementUpdate(); + + // Teleport the entity to the exact hit coords: + m_World->BroadcastTeleportEntity(*this); +} + + + + + +void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { - a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0); + if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer()) + { + // Not an entity that interacts with an arrow + return; + } + + int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); + if (m_IsCritical) + { + Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); + } + a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); + + Destroy(); } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cThrownEggEntity: @@ -290,7 +472,7 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, -void cThrownEggEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { // TODO: Random-spawn a chicken or four @@ -314,9 +496,15 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X -void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - // TODO: Teleport the creator here, make them take 5 damage + // Teleport the creator here, make them take 5 damage: + if (m_Creator != NULL) + { + // TODO: The coords might need some tweaking based on the block face + m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); + m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); + } Destroy(); } @@ -338,7 +526,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do -void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs @@ -349,3 +537,94 @@ void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_Bl +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cGhastFireballEntity : + +cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this); +} + + + + + +void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFireChargeEntity : + +cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1); + } +} + + + + + +void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); + + // TODO: Some entities are immune to hits + a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning +} + + + + diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 95dc00abc..547aa174e 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -47,8 +47,11 @@ public: static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL); - /// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace); + /// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace); + + /// Called by the physics blocktracer when the entity hits another entity + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) {} // tolua_begin @@ -64,6 +67,11 @@ public: /// Returns true if the projectile has hit the ground and is stuck there bool IsInGround(void) const { return m_IsInGround; } + // tolua_end + + /// Sets the internal InGround flag. To be used by MCA loader only! + void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; } + protected: eKind m_ProjectileKind; @@ -73,8 +81,6 @@ protected: /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; - // tolua_end - // cEntity overrides: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; @@ -128,6 +134,12 @@ public: /// Returns true if the specified player can pick the arrow up bool CanPickup(const cPlayer & a_Player) const; + /// Returns true if the arrow is set as critical + bool IsCritical(void) const { return m_IsCritical; } + + /// Sets the IsCritical flag + void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } + // tolua_end protected: @@ -137,9 +149,13 @@ protected: /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow double m_DamageCoeff; + + /// If true, the arrow deals more damage + bool m_IsCritical; // cProjectileEntity overrides: - virtual void SpawnOn(cClientHandle & a_Client) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; // tolua_begin } ; @@ -166,7 +182,7 @@ protected: // tolua_end // cProjectileEntity overrides: - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; // tolua_begin @@ -194,7 +210,7 @@ protected: // tolua_end // cProjectileEntity overrides: - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; // tolua_begin @@ -218,12 +234,41 @@ public: cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + + // tolua_begin + +} ; + + + + + +class cGhastFireballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: // tolua_end + CLASS_PROTODEF(cGhastFireballEntity); + + cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + // cProjectileEntity overrides: - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + // TODO: Deflecting the fireballs by arrow- or sword- hits + // tolua_begin } ; @@ -232,6 +277,34 @@ protected: +class cFireChargeEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireChargeEntity); + + cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // tolua_begin + +} ; + + + + // tolua_end diff --git a/source/Entities/TNTEntity.cpp b/source/Entities/TNTEntity.cpp index ad3d9ae0c..339107b2e 100644 --- a/source/Entities/TNTEntity.cpp +++ b/source/Entities/TNTEntity.cpp @@ -52,7 +52,7 @@ void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk) { Destroy(true); LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ()); - m_World->DoExplosiontAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this); + m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this); return; } } diff --git a/source/Items/ItemBoat.h b/source/Items/ItemBoat.h new file mode 100644 index 000000000..6e3395f1d --- /dev/null +++ b/source/Items/ItemBoat.h @@ -0,0 +1,54 @@ + +// ItemBoat.h + +// Declares the various boat ItemHandlers + + + + + +#pragma once + +#include "../Entities/Boat.h" + + + + + +class cItemBoatHandler : + public cItemHandler +{ + typedef cItemHandler super; + +public: + cItemBoatHandler(int a_ItemType) : + super(a_ItemType) + { + } + + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override + { + if (a_Dir < 0) + { + return false; + } + + double x = (double)a_BlockX + 0.5; + double y = (double)a_BlockY + 0.5; + double z = (double)a_BlockZ + 0.5; + + cBoat * Boat = NULL; + + Boat = new cBoat (x, y, z); + Boat->Initialize(a_World); + + return true; + } + +} ; + + + + diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp index 2ae193d52..08a7b661d 100644 --- a/source/Items/ItemHandler.cpp +++ b/source/Items/ItemHandler.cpp @@ -8,6 +8,7 @@ // Handlers: #include "ItemBed.h" +#include "ItemBoat.h" #include "ItemBow.h" #include "ItemBrewingStand.h" #include "ItemBucket.h" @@ -53,7 +54,11 @@ cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) { if (a_ItemType < 0) { - ASSERT(!"Bad item type"); + // Either nothing (-1), or bad value, both cases should return the air handler + if (a_ItemType < -1) + { + ASSERT(!"Bad item type"); + } a_ItemType = 0; } @@ -85,6 +90,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType); case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); case E_ITEM_BED: return new cItemBedHandler(a_ItemType); + case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType); case E_ITEM_BOW: return new cItemBowHandler; case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 87efecd35..082521eee 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -92,6 +92,21 @@ static int tolua_StringSplit(lua_State * tolua_S) +static int tolua_StringSplitAndTrim(lua_State * tolua_S) +{ + cLuaState LuaState(tolua_S); + std::string str = (std::string)tolua_tocppstring(LuaState, 1, 0); + std::string delim = (std::string)tolua_tocppstring(LuaState, 2, 0); + + AStringVector Split = StringSplitAndTrim(str, delim); + LuaState.Push(Split); + return 1; +} + + + + + static int tolua_LOG(lua_State* tolua_S) { const char* str = tolua_tocppstring(tolua_S,1,0); @@ -621,6 +636,114 @@ static int tolua_ForEach(lua_State * tolua_S) +static int tolua_cWorld_GetBlockInfo(lua_State * tolua_S) +{ + // Exported manually, because tolua would generate useless additional parameters (a_BlockType .. a_BlockSkyLight) + // Function signature: GetBlockInfo(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta, BlockSkyLight, BlockBlockLight] + #ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || + !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || + !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || + !tolua_isnumber (tolua_S, 4, 0, &tolua_err) || + !tolua_isnoobj (tolua_S, 5, &tolua_err) + ) + goto tolua_lerror; + else + #endif + { + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0); + int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); + int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); + int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); + #ifndef TOLUA_RELEASE + if (self == NULL) + { + tolua_error(tolua_S, "invalid 'self' in function 'SetSignLines' / 'UpdateSign'", NULL); + } + #endif + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta, BlockSkyLight, BlockBlockLight; + bool res = self->GetBlockInfo(BlockX, BlockY, BlockZ, BlockType, BlockMeta, BlockSkyLight, BlockBlockLight); + tolua_pushboolean(tolua_S, res ? 1 : 0); + if (res) + { + tolua_pushnumber(tolua_S, BlockType); + tolua_pushnumber(tolua_S, BlockMeta); + tolua_pushnumber(tolua_S, BlockSkyLight); + tolua_pushnumber(tolua_S, BlockBlockLight); + return 5; + } + } + } + return 1; + + #ifndef TOLUA_RELEASE +tolua_lerror: + tolua_error(tolua_S, "#ferror in function 'GetBlockInfo'.", &tolua_err); + return 0; + #endif +} + + + + + +static int tolua_cWorld_GetBlockTypeMeta(lua_State * tolua_S) +{ + // Exported manually, because tolua would generate useless additional parameters (a_BlockType, a_BlockMeta) + // Function signature: GetBlockTypeMeta(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta] + #ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || + !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || + !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || + !tolua_isnumber (tolua_S, 4, 0, &tolua_err) || + !tolua_isnoobj (tolua_S, 5, &tolua_err) + ) + goto tolua_lerror; + else + #endif + { + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0); + int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); + int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); + int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); + #ifndef TOLUA_RELEASE + if (self == NULL) + { + tolua_error(tolua_S, "invalid 'self' in function 'SetSignLines' / 'UpdateSign'", NULL); + } + #endif + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + bool res = self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta); + tolua_pushboolean(tolua_S, res ? 1 : 0); + if (res) + { + tolua_pushnumber(tolua_S, BlockType); + tolua_pushnumber(tolua_S, BlockMeta); + return 3; + } + } + } + return 1; + + #ifndef TOLUA_RELEASE +tolua_lerror: + tolua_error(tolua_S, "#ferror in function 'GetBlockTypeMeta'.", &tolua_err); + return 0; + #endif +} + + + + + static int tolua_cWorld_SetSignLines(lua_State * tolua_S) { // Exported manually, because tolua would generate useless additional return values (a_Line1 .. a_Line4) @@ -1808,12 +1931,13 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) void ManualBindings::Bind(lua_State * tolua_S) { tolua_beginmodule(tolua_S, NULL); - tolua_function(tolua_S, "StringSplit", tolua_StringSplit); - tolua_function(tolua_S, "LOG", tolua_LOG); - tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO); - tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); - tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); - tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_function(tolua_S, "StringSplit", tolua_StringSplit); + tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim); + tolua_function(tolua_S, "LOG", tolua_LOG); + tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO); + tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); + tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); + tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); tolua_beginmodule(tolua_S, "cLineBlockTracer"); tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace); @@ -1839,6 +1963,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); + tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); + tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index 9ae91f1e0..76b9414f7 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -15,6 +15,7 @@ #include "../Vector3i.h" #include "../Vector3d.h" #include "../Tracer.h" +#include "../Chunk.h" // #include "../../iniFile/iniFile.h" @@ -25,6 +26,8 @@ cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : super(etMob, a_Width, a_Height) , m_Target(NULL) + , m_AttackRate(3) + , idle_interval(0) , m_bMovingToDestination(false) , m_DestinationTime( 0 ) , m_DestroyTimer( 0 ) @@ -37,10 +40,9 @@ cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const A , m_SeePlayerInterval (0) , m_EMPersonality(AGGRESSIVE) , m_AttackDamage(1.0f) - , m_AttackRange(5.0f) + , m_AttackRange(2.0f) , m_AttackInterval(0) - , m_AttackRate(3) - , idle_interval(0) + , m_BurnsInDaylight(false) { if (!a_ConfigName.empty()) { @@ -100,6 +102,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) return; } + // Burning in daylight + HandleDaylightBurning(a_Chunk); + HandlePhysics(a_Dt,a_Chunk); BroadcastMovementUpdate(); @@ -473,3 +478,35 @@ void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned + +void cMonster::HandleDaylightBurning(cChunk & a_Chunk) +{ + if (!m_BurnsInDaylight) + { + return; + } + + int RelY = (int)floor(GetPosY()); + if ((RelY < 0) || (RelY >= cChunkDef::Height)) + { + // Outside the world + return; + } + + int RelX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; + if ( + (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight + (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand + (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime + !IsOnFire() // Not already burning + ) + { + // Burn for 100 ticks, then decide again + StartBurning(100); + } +} + + + + diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index 755678d39..5f33d4450 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -107,6 +107,9 @@ public: void SetAttackDamage(float ad); void SetSightDistance(float sd); + /// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick + void SetBurnsInDaylight(bool a_BurnsInDaylight) { a_BurnsInDaylight = a_BurnsInDaylight; } + enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState; enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality; @@ -134,8 +137,12 @@ protected: float m_AttackDamage; float m_AttackRange; float m_AttackInterval; + + bool m_BurnsInDaylight; void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0); + + void HandleDaylightBurning(cChunk & a_Chunk); } ; // tolua_export diff --git a/source/Mobs/Skeleton.cpp b/source/Mobs/Skeleton.cpp index ad4037db9..10dad4065 100644 --- a/source/Mobs/Skeleton.cpp +++ b/source/Mobs/Skeleton.cpp @@ -11,24 +11,7 @@ cSkeleton::cSkeleton(void) : super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8) { -} - - - - - -void cSkeleton::Tick(float a_Dt, cChunk & a_Chunk) -{ - cMonster::Tick(a_Dt, a_Chunk); - - if ((GetWorld()->GetBlockSkyLight(GetPosX(), GetPosY(), GetPosZ()) == 15) && (GetWorld()->GetBlock(GetPosX(), GetPosY(), GetPosZ()) != E_BLOCK_SOULSAND)) - { - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire()) - { - // Burn for 100 ticks, then decide again - StartBurning(100); - } - } + SetBurnsInDaylight(true); } diff --git a/source/Mobs/Skeleton.h b/source/Mobs/Skeleton.h index bc541bac2..d0a2da490 100644 --- a/source/Mobs/Skeleton.h +++ b/source/Mobs/Skeleton.h @@ -17,7 +17,6 @@ public: CLASS_PROTODEF(cSkeleton); - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; } ; diff --git a/source/Mobs/Zombie.cpp b/source/Mobs/Zombie.cpp index f3adf1283..9b238baef 100644 --- a/source/Mobs/Zombie.cpp +++ b/source/Mobs/Zombie.cpp @@ -8,28 +8,10 @@ -// They're eating your brains! - cZombie::cZombie(void) : super("Zombie", 54, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8) { -} - - - - - -void cZombie::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - if ((GetWorld()->GetBlockSkyLight(GetPosX(), GetPosY(), GetPosZ()) == 15) && (GetWorld()->GetBlock(GetPosX(), GetPosY(), GetPosZ()) != E_BLOCK_SOULSAND)) - { - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire()) - { - // Burn for 100 ticks, then decide again - StartBurning(100); - } - } + SetBurnsInDaylight(true); } diff --git a/source/Mobs/Zombie.h b/source/Mobs/Zombie.h index 61f8e3bb8..4835a53c4 100644 --- a/source/Mobs/Zombie.h +++ b/source/Mobs/Zombie.h @@ -12,11 +12,10 @@ class cZombie : typedef cAggressiveMonster super; public: - cZombie(); + cZombie(void); CLASS_PROTODEF(cZombie); - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; } ; diff --git a/source/OSSupport/Event.cpp b/source/OSSupport/Event.cpp index 32f780946..cbacbba17 100644 --- a/source/OSSupport/Event.cpp +++ b/source/OSSupport/Event.cpp @@ -116,50 +116,3 @@ void cEvent::Set(void) - -cEvent::eWaitResult cEvent::Wait(int a_TimeoutMilliSec) -{ - #ifdef _WIN32 - DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMilliSec); - switch (res) - { - case WAIT_OBJECT_0: - { - // The semaphore was signalled - return wrSignalled; - } - case WAIT_TIMEOUT: - { - // The timeout was hit - return wrTimeout; - } - default: - { - LOGWARNING("cEvent: timed-waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError()); - return wrError; - } - } - #else - timespec timeout; - timeout.tv_sec = time(NULL) + a_TimeoutMilliSec / 1000; - timeout.tv_nsec = (a_TimeoutMilliSec % 1000) * 1000000; - int res = sem_timedwait(m_Event, &timeout); - if (res == 0) - { - // The semaphore was signalled - return wrSignalled; - } - int err = errno; - if (err == ETIMEDOUT) - { - // The timeout was hit - return wrTimeout; - } - LOGWARNING("cEvent: timed-waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, err); - return wrError; - #endif -} - - - - diff --git a/source/OSSupport/Event.h b/source/OSSupport/Event.h index 803d73b7e..71f418c0c 100644 --- a/source/OSSupport/Event.h +++ b/source/OSSupport/Event.h @@ -19,22 +19,12 @@ class cEvent { public: - enum eWaitResult - { - wrSignalled, - wrTimeout, - wrError, - } ; - cEvent(void); ~cEvent(); void Wait(void); void Set (void); - /// Waits for the semaphore with a timeout - eWaitResult Wait(int a_TimeoutMilliSec); - private: #ifdef _WIN32 diff --git a/source/Piston.cpp b/source/Piston.cpp index f4244d177..b5fda1600 100644 --- a/source/Piston.cpp +++ b/source/Piston.cpp @@ -270,7 +270,13 @@ bool cPiston::CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) return false; } } - return CanPush(a_BlockType, a_BlockMeta) || CanBreakPush(a_BlockType, a_BlockMeta); + + if (CanBreakPush(a_BlockType, a_BlockMeta)) + { + return false; // CanBreakPush returns true, but we need false to prevent pulling + } + + return CanPush(a_BlockType, a_BlockMeta); } diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index 4577e0c16..54bd28c9f 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -584,7 +584,7 @@ void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) WriteByte ((unsigned char)PACKET_PLAYER_LIST_ITEM); WriteString(PlayerName); WriteBool (a_IsOnline); - WriteShort (a_Player.GetClientHandle()->GetPing()); + WriteShort (a_IsOnline ? a_Player.GetClientHandle()->GetPing() : 0); Flush(); } diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp index 26a1a9fad..a06eb0b8b 100644 --- a/source/Protocol/Protocol132.cpp +++ b/source/Protocol/Protocol132.cpp @@ -452,8 +452,17 @@ void cProtocol132::SendTabCompletionResults(const AStringVector & a_Results) void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) { - // Not used in 1.3.2 - // Does it unload chunks on its own? + // Unloading the chunk is done by sending a "map chunk" packet + // with IncludeInitialize set to true and primary bitmap set to 0: + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_CHUNK_DATA); + WriteInt (a_ChunkX); + WriteInt (a_ChunkZ); + WriteBool(true); // IncludeInitialize + WriteShort(0); // Primary bitmap + WriteShort(0); // Add bitmap + WriteInt(0); + Flush(); } diff --git a/source/Protocol/Protocol16x.cpp b/source/Protocol/Protocol16x.cpp index 3a640da21..be5b45f19 100644 --- a/source/Protocol/Protocol16x.cpp +++ b/source/Protocol/Protocol16x.cpp @@ -213,6 +213,10 @@ int cProtocol161::ParseSteerVehicle(void) { m_Client->HandleUnmount(); } + else + { + m_Client->HandleSteerVehicle(Forward, Sideways); + } return PARSE_OK; } diff --git a/source/Vector3d.cpp b/source/Vector3d.cpp index 987c380dc..96ebebab5 100644 --- a/source/Vector3d.cpp +++ b/source/Vector3d.cpp @@ -8,16 +8,70 @@ -Vector3d::Vector3d(const Vector3f & v ) - : x( v.x ) - , y( v.y ) - , z( v.z ) +const double Vector3d::EPS = 0.000001; ///< The max difference between two coords for which the coords are assumed equal +const double Vector3d::NO_INTERSECTION = 1e70; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane + + + + + +Vector3d::Vector3d(const Vector3f & v) : + x(v.x), + y(v.y), + z(v.z) +{ +} + + + + + +Vector3d::Vector3d(const Vector3f * v) : + x(v->x), + y(v->y), + z(v->z) { } -Vector3d::Vector3d(const Vector3f * v ) - : x( v->x ) - , y( v->y ) - , z( v->z ) + + + + +double Vector3d::LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const { -}
\ No newline at end of file + if (abs(z - a_OtherEnd.z) < EPS) + { + return NO_INTERSECTION; + } + return (a_Z - z) / (a_OtherEnd.z - z); +} + + + + + +double Vector3d::LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const +{ + if (abs(y - a_OtherEnd.y) < EPS) + { + return NO_INTERSECTION; + } + return (a_Y - y) / (a_OtherEnd.y - y); +} + + + + + +double Vector3d::LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const +{ + if (abs(x - a_OtherEnd.x) < EPS) + { + return NO_INTERSECTION; + } + return (a_X - x) / (a_OtherEnd.x - x); +} + + + + diff --git a/source/Vector3d.h b/source/Vector3d.h index ecc72e421..a06a17c09 100644 --- a/source/Vector3d.h +++ b/source/Vector3d.h @@ -3,26 +3,54 @@ #include <math.h> class Vector3f; -class Vector3d // tolua_export -{ // tolua_export -public: // tolua_export + + + +// tolua_begin + +class Vector3d +{ +public: // convert from float - Vector3d(const Vector3f & v ); // tolua_export - Vector3d(const Vector3f * v ); // tolua_export + Vector3d(const Vector3f & v); + Vector3d(const Vector3f * v); + + Vector3d() : x(0), y(0), z(0) {} + Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {} + + inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; } + inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; } + inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); } + inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } + inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); } + inline double SqrLength() const { return x * x + y * y + z * z; } + inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } + inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } + + /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Z coord + The result satisfies the following equation: + (*this + Result * (a_OtherEnd - *this)).z = a_Z + If the line is too close to being parallel, this function returns NO_INTERSECTION + */ + double LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const; - Vector3d() : x(0), y(0), z(0) {} // tolua_export - Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export + /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Y coord + The result satisfies the following equation: + (*this + Result * (a_OtherEnd - *this)).y = a_Y + If the line is too close to being parallel, this function returns NO_INTERSECTION + */ + double LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const; - inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export - inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; } // tolua_export - inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); } // tolua_export - inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } // tolua_export - inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); } // tolua_export - inline double SqrLength() const { return x * x + y * y + z * z; } // tolua_export - inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } // tolua_export - inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } // tolua_export + /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified X coord + The result satisfies the following equation: + (*this + Result * (a_OtherEnd - *this)).x = a_X + If the line is too close to being parallel, this function returns NO_INTERSECTION + */ + double LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const; - inline bool Equals( const Vector3d & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export + inline bool Equals(const Vector3d & v) const { return ((x == v.x) && (y == v.y) && (z == v.z)); } + + // tolua_end void operator += ( const Vector3d& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; } void operator += ( Vector3d* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; } @@ -30,14 +58,24 @@ public: // tolua_export void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; } void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; } - Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export - Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export - Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export - Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export - Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export - Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export - Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export + // tolua_begin + + Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } + Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } + Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } + Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } + Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } + Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } + Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } + + double x, y, z; + + static const double EPS; ///< The max difference between two coords for which the coords are assumed equal + static const double NO_INTERSECTION; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane +} ; + +// tolua_end + + - double x, y, z; // tolua_export -};// tolua_export diff --git a/source/World.cpp b/source/World.cpp index 1d403994d..882cf90d2 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -525,7 +525,7 @@ void cWorld::Start(void) m_LastSave = 0; m_LastUnload = 0; - // preallocate some memory for ticking blocks so we don�t need to allocate that often + // preallocate some memory for ticking blocks so we don't need to allocate that often m_BlockTickQueue.reserve(1000); m_BlockTickQueueCopy.reserve(1000); @@ -969,7 +969,7 @@ bool cWorld::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback -void cWorld::DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) +void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) { if (cPluginManager::Get()->CallHookExploding(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData) || (a_ExplosionSize <= 0)) { @@ -979,7 +979,7 @@ void cWorld::DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_Bl // TODO: Add damage to entities, add support for pickups, and implement block hardiness Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ); cVector3iArray BlocksAffected; - m_ChunkMap->DoExplosiontAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected); + m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected); BroadcastSoundEffect("random.explode", (int)floor(a_BlockX * 8), (int)floor(a_BlockY * 8), (int)floor(a_BlockZ * 8), 1.0f, 0.6f); { cCSLock Lock(m_CSPlayers); diff --git a/source/World.h b/source/World.h index 1f82f4efc..16ef6b3ce 100644 --- a/source/World.h +++ b/source/World.h @@ -334,10 +334,15 @@ public: void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
- bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
- bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
+
+ // tolua_end
+
+ bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); // TODO: Exported in ManualBindings.cpp
+ bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); // TODO: Exported in ManualBindings.cpp
// TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+ // tolua_begin
+
// Vector3i variants:
void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); }
@@ -414,13 +419,13 @@ public: | esCreeper | cCreeper * |
| esBed | cVector3i * |
| esEnderCrystal | Vector3i * |
- | esGhastFireball | TBD |
+ | esGhastFireball | cGhastFireball * |
| esWitherSkullBlack | TBD |
| esWitherSkullBlue | TBD |
| esWitherBirth | TBD |
| esPlugin | void * |
*/
- void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
+ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
diff --git a/source/WorldStorage/NBTChunkSerializer.cpp b/source/WorldStorage/NBTChunkSerializer.cpp index baae0dc01..11dc50ee3 100644 --- a/source/WorldStorage/NBTChunkSerializer.cpp +++ b/source/WorldStorage/NBTChunkSerializer.cpp @@ -19,6 +19,7 @@ #include "../OSSupport/MakeDir.h" #include "FastNBT.h" #include "../Entities/FallingBlock.h" +#include "../Entities/Boat.h" #include "../Entities/Minecart.h" #include "../Mobs/Monster.h" #include "../Entities/Pickup.h" @@ -252,6 +253,17 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C +void cNBTChunkSerializer::AddBoatEntity(cBoat * a_Boat) +{ + m_Writer.BeginCompound(""); + AddBasicEntity(a_Boat, "Boat"); + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock) { m_Writer.BeginCompound(""); @@ -340,7 +352,7 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) m_Writer.AddShort("xTile", (Int16)floor(Pos.x)); m_Writer.AddShort("yTile", (Int16)floor(Pos.y)); m_Writer.AddShort("zTile", (Int16)floor(Pos.z)); - m_Writer.AddShort("inTile", 0); // TODO: Query the block type (is it needed?) + m_Writer.AddShort("inTile", 0); // TODO: Query the block type m_Writer.AddShort("shake", 0); // TODO: Any shake? m_Writer.AddByte ("inGround", a_Projectile->IsInGround() ? 1 : 0); @@ -360,6 +372,7 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) } case cProjectileEntity::pkFireCharge: case cProjectileEntity::pkWitherSkull: + case cProjectileEntity::pkEnderPearl: { m_Writer.BeginList("Motion", TAG_Double); m_Writer.AddDouble("", a_Projectile->GetSpeedX()); @@ -461,6 +474,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity) switch (a_Entity->GetEntityType()) { + case cEntity::etBoat: AddBoatEntity ((cBoat *) a_Entity); break; case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *) a_Entity); break; case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break; case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break; diff --git a/source/WorldStorage/NBTChunkSerializer.h b/source/WorldStorage/NBTChunkSerializer.h index 481c578f3..9d4ac208c 100644 --- a/source/WorldStorage/NBTChunkSerializer.h +++ b/source/WorldStorage/NBTChunkSerializer.h @@ -19,6 +19,7 @@ class cFastNBTWriter; class cEntity; class cBlockEntity; +class cBoat; class cChestEntity; class cDispenserEntity; class cDropperEntity; @@ -94,6 +95,7 @@ protected: // Entities: void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName); + void AddBoatEntity (cBoat * a_Boat); void AddFallingBlockEntity(cFallingBlock * a_FallingBlock); void AddMinecartEntity (cMinecart * a_Minecart); void AddMonsterEntity (cMonster * a_Monster); diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp index 3ab64148e..4db1ed106 100644 --- a/source/WorldStorage/WSSAnvil.cpp +++ b/source/WorldStorage/WSSAnvil.cpp @@ -23,6 +23,7 @@ #include "../OSSupport/MakeDir.h" #include "FastNBT.h" #include "../Mobs/Monster.h" +#include "../Entities/Boat.h" #include "../Entities/FallingBlock.h" #include "../Entities/Minecart.h" #include "../Entities/Pickup.h" @@ -911,7 +912,11 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) { - if (strncmp(a_IDTag, "FallingBlock", a_IDTagLength) == 0) + if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0) + { + LoadBoatFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "FallingBlock", a_IDTagLength) == 0) { LoadFallingBlockFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } @@ -952,14 +957,34 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a { LoadMinecartHFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } - if (strncmp(a_IDTag, "Item", a_IDTagLength) == 0) + else if (strncmp(a_IDTag, "Item", a_IDTagLength) == 0) { LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } - if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0) + else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0) { LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } + else if (strncmp(a_IDTag, "Snowball", a_IDTagLength) == 0) + { + LoadSnowballFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Egg", a_IDTagLength) == 0) + { + LoadEggFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Fireball", a_IDTagLength) == 0) + { + LoadFireballFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "SmallFireball", a_IDTagLength) == 0) + { + LoadFireChargeFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "ThrownEnderpearl", a_IDTagLength) == 0) + { + LoadThrownEnderpearlFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } // TODO: other entities } @@ -967,6 +992,20 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a +void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cBoat> Boat(new cBoat(0, 0, 0)); + if (!LoadEntityBaseFromNBT(*Boat.get(), a_NBT, a_TagIdx)) + { + return; + } + a_Entities.push_back(Boat.release()); +} + + + + + void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { // TODO @@ -1100,7 +1139,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); - if (!LoadEntityBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx)) + if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx)) { return; } @@ -1136,6 +1175,86 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ +void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + if (!LoadProjectileBaseFromNBT(*Snowball.get(), a_NBT, a_TagIdx)) + { + return; + } + + // Store the new snowball in the entities list: + a_Entities.push_back(Snowball.release()); +} + + + + + +void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + if (!LoadProjectileBaseFromNBT(*Egg.get(), a_NBT, a_TagIdx)) + { + return; + } + + // Store the new egg in the entities list: + a_Entities.push_back(Egg.release()); +} + + + + + +void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + if (!LoadProjectileBaseFromNBT(*Fireball.get(), a_NBT, a_TagIdx)) + { + return; + } + + // Store the new fireball in the entities list: + a_Entities.push_back(Fireball.release()); +} + + + + + +void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + if (!LoadProjectileBaseFromNBT(*FireCharge.get(), a_NBT, a_TagIdx)) + { + return; + } + + // Store the new FireCharge in the entities list: + a_Entities.push_back(FireCharge.release()); +} + + + + + +void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + if (!LoadProjectileBaseFromNBT(*Enderpearl.get(), a_NBT, a_TagIdx)) + { + return; + } + + // Store the new enderpearl in the entities list: + a_Entities.push_back(Enderpearl.release()); +} + + + + + bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) { double Pos[3]; @@ -1167,6 +1286,30 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N +bool cWSSAnvil::LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) +{ + if (!LoadEntityBaseFromNBT(a_Entity, a_NBT, a_TagIdx)) + { + return false; + } + + bool IsInGround = false; + int InGroundIdx = a_NBT.FindChildByName(a_TagIdx, "inGround"); + if (InGroundIdx > 0) + { + IsInGround = (a_NBT.GetByte(InGroundIdx) != 0); + } + a_Entity.SetIsInGround(IsInGround); + + // TODO: Load inTile, TileCoords + + return true; +} + + + + + bool cWSSAnvil::LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx) { if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List) || (a_NBT.GetChildrenType(a_TagIdx) != TAG_Double)) diff --git a/source/WorldStorage/WSSAnvil.h b/source/WorldStorage/WSSAnvil.h index b2556ab50..7685d2236 100644 --- a/source/WorldStorage/WSSAnvil.h +++ b/source/WorldStorage/WSSAnvil.h @@ -18,6 +18,8 @@ // fwd: ItemGrid.h class cItemGrid; +class cProjectileEntity; + @@ -138,18 +140,27 @@ protected: void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); - void LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSnowballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadEggFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFireballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFireChargeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); /// Loads entity common data from the NBT compound; returns true if successful bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx); + /// Loads projectile common data from the NBT compound; returns true if successful + bool LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIx); + /// Loads an array of doubles of the specified length from the specified NBT list tag a_TagIdx; returns true if successful bool LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx); |