1
0

Merge branch 'master' into Slabs

Conflicts:
	src/Blocks/BlockDirt.h
This commit is contained in:
Howaner 2014-04-03 22:03:18 +02:00
commit 32d054e8fd
335 changed files with 18516 additions and 7170 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
build/
nbproject/
ipch/
Win32/
MCServer/MCServer

View File

@ -3,7 +3,13 @@ compiler:
- gcc
- clang
# Build MCServer
script: cmake . -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | ./MCServer)
script: cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | $MCSERVER_PATH)
env:
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer_debug
# Notification Settings
notifications:

View File

@ -5,7 +5,7 @@ LOCAL_MODULE := mcserver
LOCAL_SRC_FILES := $(shell find ../CryptoPP ../lua ../jsoncpp ../zlib ../src ../tolua++ ../iniFile ../expat ../md5 ../sqlite ../luaexpat '(' -name '*.cpp' -o -name '*.c' ')')
LOCAL_SRC_FILES := $(shell find ../lib/polarssl ../lib/lua ../lib/jsoncpp ../lib/zlib ../src ../lib/tolua++ ../lib/iniFile ../lib/expat ../lib/md5 ../lib/sqlite ../lib/luaexpat '(' -name '*.cpp' -o -name '*.c' ')')
LOCAL_SRC_FILES := $(filter-out %SquirrelFunctions.cpp %SquirrelBindings.cpp %cPlugin_Squirrel.cpp %cSquirrelCommandBinder.cpp %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(patsubst %.cpp,../%.cpp,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES))
@ -24,17 +24,17 @@ LOCAL_C_INCLUDES := ../src \
../src/packets \
../src/items \
../src/blocks \
../tolua++/src/lib \
../lua/src \
../zlib-1.2.7 \
../iniFile \
../tolua++/include \
../jsoncpp/include \
../jsoncpp/src/lib_json \
../expat/ \
../md5/ \
../sqlite/ \
../luaexpat/ \
../lib/tolua++/src/lib \
../lib/lua/src \
../lib/zlib-1.2.7 \
../lib/iniFile \
../lib/tolua++/include \
../lib/jsoncpp/include \
../lib/jsoncpp/src/lib_json \
../lib/expat/ \
../lib/md5/ \
../lib/sqlite/ \
../lib/luaexpat/ \
.. \

View File

@ -3,6 +3,17 @@ cmake_minimum_required (VERSION 2.6)
# Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html )
enable_language(CXX C)
# These env variables are used for configuring Travis CI builds.
# See https://github.com/mc-server/MCServer/pull/767
if(DEFINED ENV{TRAVIS_MCSERVER_BUILD_TYPE})
message("Setting build type to $ENV{TRAVIS_MCSERVER_BUILD_TYPE}")
set(CMAKE_BUILD_TYPE $ENV{TRAVIS_MCSERVER_BUILD_TYPE})
endif()
if(DEFINED ENV{TRAVIS_MCSERVER_FORCE32})
set(FORCE32 $ENV{TRAVIS_MCSERVER_FORCE32})
endif()
# This has to be done before any flags have been set up.
if(${BUILD_TOOLS})
add_subdirectory(Tools/MCADefrag/)

View File

@ -1,7 +1,7 @@
Code Stuff
----------
* We use C++03
* We use C++03 with some C++11 extensions (ask if you think that something would be useful)
* Use the provided wrappers for OS stuff:
- Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection`, `cSemaphore` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep`
* No magic numbers, use named constants:
@ -22,8 +22,10 @@ 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"
* All `case` statements inside a `switch` need an extra indent.
* Each and every control statement deserves its braces. This helps maintainability later on when the file is edited, lines added or removed - the control logic doesn't break so easily.
- The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form.
- These two rules really mean that indent is governed by braces
* Add an empty last line in all source files (GCC and GIT can complain otherwise)
* Use doxy-comments for functions in the header file, format as `/** Description */`
* Use spaces after the comment markers: `// Comment` instead of `//Comment`

View File

@ -665,9 +665,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = source \
iniFile \
WebServer
INPUT = src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

197
LICENSE
View File

@ -1,4 +1,199 @@
Copyright MCServer Contributors
MCServer: A performant C++ Minecraft Server
www: http://mc-server.org/
Copyright 2014 MCServer Team
------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

7
MCServer/.gitignore vendored
View File

@ -6,6 +6,7 @@
MCServer
MCServer_debug
CommLogs/
GalExports/
logs
players
world*
@ -19,10 +20,8 @@ schematics
*.pdb
memdump*
*.grab
Galleries.cfg
Galleries.example.cfg
Galleries.sqlite
ProtectionAreas.sqlite
*.cfg
*.sqlite
helgrind.log
valgrind.log
motd.txt

View File

@ -1,2 +1,3 @@
*.txt
*.md
*/

View File

@ -1,29 +0,0 @@
-- @EnableMobDebug.lua
-- Enables the MobDebug debugger, used by ZeroBrane Studio, for a plugin
-- Needs to be named with a @ at the start so that it's loaded as the first file of the plugin
--[[
Usage:
Copy this file to your plugin's folder when you want to debug that plugin
You should neither check this file into the plugin's version control system,
nor distribute it in the final release.
--]]
-- Try to load the debugger, be silent about failures:
local IsSuccess, MobDebug = pcall(require, "mobdebug")
if (IsSuccess) then
MobDebug.start()
-- The debugger will automatically put a breakpoint on this line, use this opportunity to set more breakpoints in your code
LOG(cPluginManager:GetCurrentPlugin():GetName() .. ": MobDebug enabled")
end

View File

@ -114,7 +114,7 @@ g_APIDesc =
GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified absolute coords" },
GetBlockType = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified absolute coords" },
GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified absolute coords" },
GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the objectis currently holding" },
GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the object is currently holding" },
GetOrigin = { Params = "", Return = "OriginX, OriginY, OriginZ", Notes = "Returns the origin coords of where the area was read from." },
GetOriginX = { Params = "", Return = "number", Notes = "Returns the origin x-coord" },
GetOriginY = { Params = "", Return = "number", Notes = "Returns the origin y-coord" },
@ -129,11 +129,13 @@ g_APIDesc =
GetSizeY = { Params = "", Return = "number", Notes = "Returns the size of the held data in the y-axis" },
GetSizeZ = { Params = "", Return = "number", Notes = "Returns the size of the held data in the z-axis" },
GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the area - the total number of blocks stored within." },
GetWEOffset = { Params = "", Return = "{{Vector3i}}", Notes = "Returns the WE offset, a data value sometimes stored in the schematic files. MCServer doesn't use this value, but provides access to it using this method. The default is {0, 0, 0}."},
HasBlockLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include blocklight" },
HasBlockMetas = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block metas" },
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
HasBlockTypes = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block types" },
LoadFromSchematicFile = { Params = "FileName", Return = "", Notes = "Clears current content and loads new content from the specified schematic file. Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
LoadFromSchematicString = { Params = "SchematicData", Return = "", Notes = "Clears current content and loads new content from the specified string (assumed to contain .schematic data). Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
Merge =
{
{ Params = "BlockAreaSrc, {{Vector3i|RelMinCoords}}, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
@ -161,6 +163,7 @@ g_APIDesc =
RotateCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Modifies blocks' metas (if present) to match." },
RotateCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Doesn't modify blocks' metas." },
SaveToSchematicFile = { Params = "FileName", Return = "", Notes = "Saves the current contents to a schematic file. Returns true if successful." },
SaveToSchematicString = { Params = "", Return = "string", Notes = "Saves the current contents to a string (in a .schematic file format). Returns the data if successful, nil if failed." },
SetBlockLight = { Params = "BlockX, BlockY, BlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified absolute coords" },
SetBlockMeta = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified absolute coords" },
SetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified absolute coords" },
@ -176,6 +179,11 @@ g_APIDesc =
SetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified relative coords" },
SetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType", Return = "", Notes = "Sets the block type at the specified relative coords" },
SetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block type and meta at the specified relative coords" },
SetWEOffset =
{
{ Params = "{{Vector3i|Offset}}", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
{ Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
},
Write =
{
{ Params = "World, {{Vector3i|MinPoint}}, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" },
@ -192,6 +200,8 @@ g_APIDesc =
msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" },
msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" },
msLake = { Notes = "Special mode for merging lake images" },
msSpongePrint = { Notes = "Similar to msImprint, sponge block doesn't overwrite anything, all other blocks overwrite everything"},
msMask = { Notes = "The blocks that are exactly the same are kept in Dst, all differing blocks are replaced by air"},
},
ConstantGroups =
{
@ -239,6 +249,9 @@ g_APIDesc =
<tr>
<td> A </td><td> B </td><td> B </td><td> A </td><td> B </td>
</tr>
<tr>
<td> A </td><td> A </td><td> A </td><td> A </td><td> A </td>
</td>
</tbody></table>
<p>
@ -250,12 +263,24 @@ g_APIDesc =
</ol>
</p>
<h3>Special strategies</h3>
<p>For each strategy, evaluate the table rows from top downwards, the first match wins.</p>
<p>
Special strategies:
<strong>msDifference</strong> - changes all the blocks which are the same to air. Otherwise the source block gets placed.
</p>
<table><tbody<tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
</tr><tr>
<td> * </td><td> B </td><td> B </td><td> The blocks are different so we use block B </td>
</tr><tr>
<td> B </td><td> B </td><td> Air </td><td> The blocks are the same so we get air. </td>
</tr>
</tbody></table>
<p>
<strong>msLake</strong> (evaluate top-down, first match wins):
<strong>msLake</strong> - used for merging areas with lava and water lakes, in the appropriate generator.
</p>
<table><tbody><tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
@ -285,11 +310,75 @@ g_APIDesc =
<td> A </td><td> * </td><td> A </td><td> Everything else is left as it is </td>
</tr>
</tbody></table>
]],
<p>
<strong>msSpongePrint</strong> - used for most prefab-generators to merge the prefabs. Similar to
msImprint, but uses the sponge block as the NOP block instead, so that the prefabs may carve out air
pockets, too.
</p>
<table><tbody><tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
</tr><tr>
<th> this </th><th> Src </th><th> result </th><th> </th>
</tr><tr>
<td> A </td><td> sponge </td><td> A </td><td> Sponge is the NOP block </td>
</tr><tr>
<td> * </td><td> B </td><td> B </td><td> Everything else overwrites anything </td>
</tr>
</tbody></table>
<p>
<strong>msMask</strong> - the blocks that are the same in the other area are kept, all the
differing blocks are replaced with air. Meta is used in the comparison, too, two blocks of the
same type but different meta are considered different and thus replaced with air.
</p>
<table><tbody><tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
</tr><tr>
<th> this </th><th> Src </th><th> result </th><th> </th>
</tr><tr>
<td> A </td><td> A </td><td> A </td><td> Same blocks are kept </td>
</tr><tr>
<td> A </td><td> non-A </td><td> air </td><td> Differing blocks are replaced with air </td>
</tr>
</tbody></table>
]],
}, -- Merge strategies
}, -- AdditionalInfo
}, -- cBlockArea
cBlockInfo =
{
Desc = [[
This class is used to query and register block properties.
]],
Functions =
{
FullyOccupiesVoxel = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block fully occupies its voxel." },
Get = { Params = "Type", Return = "{{cBlockInfo}}", Notes = "(STATIC) Returns the {{cBlockInfo}} structure for the specified type." },
GetLightValue = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block emits on its own." },
GetSpreadLightFalloff = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block consumes." },
IsOneHitDig = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block will be destroyed after a single hit." },
IsPistonBreakable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether a piston can break the specified block." },
IsSnowable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block can hold snow atop." },
IsSolid = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block is solid." },
IsTransparent = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block is transparent." },
RequiresSpecialTool = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block requires a special tool to drop." },
},
Variables =
{
m_FullyOccupiesVoxel = { Type = "bool", Notes = "Does this block fully occupy its voxel - is it a 'full' block?" },
m_IsSnowable = { Type = "bool", Notes = "Can this block hold snow atop?" },
m_IsSolid = { Type = "bool", Notes = "Is this block solid (player cannot walk through)?" },
m_LightValue = { Type = "number", Notes = "How much light do the blocks emit on their own?" },
m_OneHitDig = { Type = "bool", Notes = "Is a block destroyed after a single hit?" },
m_PistonBreakable = { Type = "bool", Notes = "Can a piston break this block?" },
m_RequiresSpecialTool = { Type = "bool", Notes = "Does this block require a tool to drop?" },
m_SpreadLightFalloff = { Type = "number", Notes = "How much light do the blocks consume?" },
m_Transparent = { Type = "bool", Notes = "Is a block completely transparent? (light doesn't get decreased(?))" },
},
}, -- cBlockInfo
cChatColor =
{
Desc = [[
@ -383,6 +472,7 @@ g_APIDesc =
SetUseDefaultFinish = { Params = "bool", Return = "", Notes = "Sets the chunk to use default finishers or not" },
SetUseDefaultHeight = { Params = "bool", Return = "", Notes = "Sets the chunk to use default height generator or not" },
SetUseDefaultStructures = { Params = "bool", Return = "", Notes = "Sets the chunk to use default structures or not" },
UpdateHeightmap = { Params = "", Return = "", Notes = "Updates the heightmap to match current contents. The plugins should do that if they modify the contents and don't modify the heightmap accordingly; MCServer expects (and checks in Debug mode) that the heightmap matches the contents when the cChunkDesc is returned from a plugin." },
WriteBlockArea = { Params = "{{cBlockArea|BlockArea}}, MinRelX, MinRelY, MinRelZ", Return = "", Notes = "Writes data from the block area into the chunk" },
},
AdditionalInfo =
@ -432,6 +522,7 @@ end
Functions =
{
GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
@ -440,6 +531,7 @@ end
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" },
SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." },
SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." },
SetUsername = { Params = "Name", Return = "", Notes = "Sets the username" },
SetViewDistance = { Params = "ViewDistance", Return = "", Notes = "Sets the viewdistance (number of chunks loaded for the player in each direction)" },
SendBlockChange = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sends a BlockChange packet to the client. This can be used to create fake blocks only for that player." },
@ -451,6 +543,58 @@ end
},
}, -- cClientHandle
cCompositeChat =
{
Desc = [[
Encapsulates a chat message that can contain various formatting, URLs, commands executed on click
and commands suggested on click. The chat message can be sent by the regular chat-sending functions,
{{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p>
<p>
Note that most of the functions in this class are so-called modifiers - they modify the object and
then return the object itself, so that they can be chained one after another.
]],
Functions =
{
constructor =
{
{ Params = "", Return = "", Notes = "Creates an empty chat message" },
{ Params = "Text", Return = "", Notes = "Creates a chat message containing the specified text, parsed by the ParseText() function. This allows easy migration from old chat messages." },
},
AddRunCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, runs the specified command. Chaining." },
AddSuggestCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, puts the specified command into the player's chat input area. Chaining." },
AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." },
AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." },
Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" },
GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" },
ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." },
SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." },
UnderlineUrls = { Params = "", Return = "self", Notes = "Makes all URL parts contained in the message underlined. Doesn't affect parts added in the future. Chaining." },
},
AdditionalInfo =
{
{
Header = "Chaining example",
Contents = [[
Sending a chat message that is composed of multiple different parts has been made easy thanks to
chaining. Consider the following example that shows how a message containing all kinds of parts
is sent (adapted from the Debuggers plugin):
<pre class="prettyprint lang-lua">
function OnPlayerJoined(a_Player)
-- Send an example composite chat message to the player:
a_Player:SendMessage(cCompositeChat()
:AddTextPart("Hello, ")
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2") -- Colored underlined link
:AddSuggestCommandPart(", and welcome.", "/help", "u") -- Underlined suggest-command
:AddRunCommandPart(" SetDay", "/time set 0") -- Regular text that will execute command when clicked
:SetMessageType(mtJoin) -- It is a join-message
)
end</pre>
]],
},
}, -- AdditionalInfo
}, -- cCompositeChat
cCraftingGrid =
{
Desc = [[
@ -633,14 +777,14 @@ end
GetMass = { Params = "", Return = "number", Notes = "Returns the mass of the entity. Currently unused." },
GetMaxHealth = { Params = "", Return = "number", Notes = "Returns the maximum number of hitpoints this entity is allowed to have." },
GetParentClass = { Params = "", Return = "string", Notes = "Returns the name of the direct parent class for this entity" },
GetPitch = { Params = "", Return = "number", Notes = "Returns the pitch (nose-down rotation) of the entity" },
GetPitch = { Params = "", Return = "number", Notes = "Returns the pitch (nose-down rotation) of the entity. Measured in degrees, normal values range from -90 to +90. +90 means looking down, 0 means looking straight ahead, -90 means looking up." },
GetPosition = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the entity's pivot position as a 3D vector" },
GetPosX = { Params = "", Return = "number", Notes = "Returns the X-coord of the entity's pivot" },
GetPosY = { Params = "", Return = "number", Notes = "Returns the Y-coord of the entity's pivot" },
GetPosZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the entity's pivot" },
GetRawDamageAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the raw damage that this entity's equipment would cause when attacking the ReceiverEntity. This includes this entity's weapon {{cEnchantments|enchantments}}, but excludes the receiver's armor or potion effects. See {{TakeDamageInfo}} for more information on attack damage." },
GetRoll = { Params = "", Return = "number", Notes = "Returns the roll (sideways rotation) of the entity. Currently unused." },
GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the entire rotation vector (Yaw, Pitch, Roll)" },
GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "(OBSOLETE) Returns the entire rotation vector (Yaw, Pitch, Roll)" },
GetSpeed = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the complete speed vector of the entity" },
GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" },
GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" },
@ -648,7 +792,7 @@ end
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity within the running server. Note that this ID is not persisted to the data files." },
GetWidth = { Params = "", Return = "number", Notes = "Returns the width (X and Z size) of the entity." },
GetWorld = { Params = "", Return = "{{cWorld}}", Notes = "Returns the world where the entity resides" },
GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity." },
GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. Measured in degrees, values range from -180 to +180. 0 means ZP, 90 means XM, -180 means ZM, -90 means XP." },
Heal = { Params = "Hitpoints", Return = "", Notes = "Heals the specified number of hitpoints. Hitpoints is expected to be a positive number." },
IsA = { Params = "ClassName", Return = "bool", Notes = "Returns true if the entity class is a descendant of the specified class name, or the specified class itself" },
IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." },
@ -791,7 +935,6 @@ cFile:Delete("/usr/bin/virus.exe");
SetColor = { Return = "" },
GetColor = { Return = "string" },
AddCommand = { Return = "" },
HasCommand = { Return = "bool" },
AddPermission = { Return = "" },
InheritFrom = { Return = "" },
},
@ -1058,7 +1201,6 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
IsStackableWith = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is stackable with the one stored in the object. Two items with different enchantments cannot be stacked" },
IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." },
IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." },
IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." },
@ -1115,6 +1257,42 @@ local Item5 = cItem(E_ITEM_DIAMOND_CHESTPLATE, 1, 0, "thorns=1;unbreaking=3");
},
}, -- cItem
cObjective =
{
Desc = [[
This class represents a single scoreboard objective.
]],
Functions =
{
AddScore = { Params = "string, number", Return = "Score", Notes = "Adds a value to the score of the specified player and returns the new value." },
GetDisplayName = { Params = "", Return = "string", Notes = "Returns the display name of the objective. This name will be shown to the connected players." },
GetName = { Params = "", Return = "string", Notes = "Returns the internal name of the objective." },
GetScore = { Params = "string", Return = "Score", Notes = "Returns the score of the specified player." },
GetType = { Params = "", Return = "eType", Notes = "Returns the type of the objective. (i.e what is being tracked)" },
Reset = { Params = "", Return = "", Notes = "Resets the scores of the tracked players." },
ResetScore = { Params = "string", Return = "", Notes = "Reset the score of the specified player." },
SetDisplayName = { Params = "string", Return = "", Notes = "Sets the display name of the objective." },
SetScore = { Params = "string, Score", Return = "", Notes = "Sets the score of the specified player." },
SubScore = { Params = "string, number", Return = "Score", Notes = "Subtracts a value from the score of the specified player and returns the new value." },
},
Constants =
{
otAchievement = { Notes = "" },
otDeathCount = { Notes = "" },
otDummy = { Notes = "" },
otHealth = { Notes = "" },
otPlayerKillCount = { Notes = "" },
otStat = { Notes = "" },
otStatBlockMine = { Notes = "" },
otStatEntityKill = { Notes = "" },
otStatEntityKilledBy = { Notes = "" },
otStatItemBreak = { Notes = "" },
otStatItemCraft = { Notes = "" },
otStatItemUse = { Notes = "" },
otTotalKillCount = { Notes = "" },
},
}, -- cObjective
cPainting =
{
Desc = "This class represents a painting in the world. These paintings are special and different from Vanilla in that they can be critical-hit.",
@ -1528,7 +1706,6 @@ a_Player:OpenWindow(Window);
AddToGroup = { Params = "GroupName", Return = "", Notes = "Temporarily adds the player to the specified group. The assignment is lost when the player disconnects." },
CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "(STATIC) Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." },
CanFly = { Return = "bool", Notes = "Returns if the player is able to fly." },
CanUseCommand = { Params = "Command", Return = "bool", Notes = "Returns true if the player is allowed to use the specified command." },
CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." },
CloseWindowIfID = { Params = "WindowID, [CanRefuse]", Return = "", Notes = "Closes the currently open UI window if its ID matches the given ID. If CanRefuse is true (default), the window may refuse the closing." },
DeltaExperience = { Params = "DeltaXP", Return = "", Notes = "Adds or removes XP from the current XP amount. Won't allow XP to go negative. Returns the new experience, -1 on error (XP overflow)." },
@ -1538,25 +1715,26 @@ a_Player:OpenWindow(Window);
GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." },
GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." },
GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" },
GetEffectiveGameMode = { Params = "", Return = "{{eGameMode|GameMode}}", Notes = "Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions." },
GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." },
GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." },
GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" },
GetEyePosition = { Return = "{{Vector3d|EyePositionVector}}", Notes = "Returns the position of the player's eyes, as a {{Vector3d}}" },
GetFloaterID = { Params = "", Return = "number", Notes = "Returns the Entity ID of the fishing hook floater that belongs to the player. Returns -1 if no floater is associated with the player. FIXME: Undefined behavior when the player has used multiple fishing rods simultanously." },
GetFlyingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the maximum flying speed, relative to the default game flying speed. Defaults to 1, but plugins may modify it for faster or slower flying." },
GetFoodExhaustionLevel = { Params = "", Return = "number", Notes = "Returns the food exhaustion level" },
GetFoodLevel = { Params = "", Return = "number", Notes = "Returns the food level (number of half-drumsticks on-screen)" },
GetFoodPoisonedTicksRemaining = { Params = "", Return = "", Notes = "Returns the number of ticks left for the food posoning effect" },
GetFoodSaturationLevel = { Params = "", Return = "number", Notes = "Returns the food saturation (overcharge of the food level, is depleted before food level)" },
GetFoodTickTimer = { Params = "", Return = "", Notes = "Returns the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." },
GetGameMode = { Return = "{{eGameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."},
GetGameMode = { Return = "{{Globals#GameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."},
GetGroups = { Return = "array-table of {{cGroup}}", Notes = "Returns all the groups that this player is member of, as a table. The groups are stored in the array part of the table, beginning with index 1."},
GetIP = { Return = "string", Notes = "Returns the IP address of the player, if available. Returns an empty string if there's no IP to report."},
GetInventory = { Return = "{{cInventory|Inventory}}", Notes = "Returns the player's inventory"},
GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed (as reported by the 1.6.1+ protocols)" },
GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status." },
GetName = { Return = "string", Notes = "Returns the player's name" },
GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed (as reported by the 1.6.1+ protocols)" },
GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed, relative to the game default speed. Defaults to 1, but plugins may modify it for faster or slower walking." },
GetResolvedPermissions = { Return = "array-table of string", Notes = "Returns all the player's permissions, as a table. The permissions are stored in the array part of the table, beginning with index 1." },
GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed (as reported by the 1.6.1+ protocols)" },
GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed, relative to the game default speed. Defaults to 1.3, but plugins may modify it for faster or slower sprinting." },
GetStance = { Return = "number", Notes = "Returns the player's stance (Y-pos of player's eyes)" },
GetThrowSpeed = { Params = "SpeedCoeff", Return = "{{Vector3d}}", Notes = "Returns the speed vector for an object thrown with the specified speed coeff. Basically returns the normalized look vector multiplied by the coeff, with a slight random variation." },
GetThrowStartPos = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the position where the projectiles should start when thrown by this player." },
@ -1593,19 +1771,19 @@ a_Player:OpenWindow(Window);
SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." },
SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." },
SetFlying = { Params = "IsFlying", Notes = "Sets if the player is flying or not." },
SetFlyingMaxSpeed = { Params = "FlyingMaxSpeed", Return = "", Notes = "Sets the flying maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client." },
SetFoodExhaustionLevel = { Params = "ExhaustionLevel", Return = "", Notes = "Sets the food exhaustion to the specified level." },
SetFoodLevel = { Params = "FoodLevel", Return = "", Notes = "Sets the food level (number of half-drumsticks on-screen)" },
SetFoodPoisonedTicksRemaining = { Params = "FoodPoisonedTicksRemaining", Return = "", Notes = "Sets the number of ticks remaining for food poisoning. Doesn't send foodpoisoning effect to the client, use FoodPoison() for that." },
SetFoodSaturationLevel = { Params = "FoodSaturationLevel", Return = "", Notes = "Sets the food saturation (overcharge of the food level)." },
SetFoodTickTimer = { Params = "FoodTickTimer", Return = "", Notes = "Sets the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." },
SetGameMode = { Params = "{{eGameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." },
SetGameMode = { Params = "{{Globals#GameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." },
SetIsFishing = { Params = "IsFishing, [FloaterEntityID]", Return = "", Notes = "Sets the 'IsFishing' flag for the player. The floater entity ID is expected for the true variant, it can be omitted when IsFishing is false. FIXME: Undefined behavior when multiple fishing rods are used simultanously" },
SetName = { Params = "Name", Return = "", Notes = "Sets the player name. This rename will NOT be visible to any players already in the server who are close enough to see this player." },
SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed (as reported by the 1.6.1+ protocols)" },
SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client, if appropriate." },
SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." },
SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed (as reported by the 1.6.1+ protocols)" },
SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed, relative to the game default speed. The default value is 1.3. Sends the updated speed to the client, if appropriate." },
SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" },
TossItem = { Params = "DraggedItem, [Amount], [CreateType], [CreateDamage]", Return = "", Notes = "FIXME: This function will be rewritten, avoid it. It tosses an item, either from the inventory, dragged in hand (while in UI window) or a newly created one." },
XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." },
},
Constants =
@ -1667,13 +1845,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
BindCommand =
{
{ Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
{ Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
{ Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
{ Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
},
BindConsoleCommand =
{
{ Params = "Command, Callback, HelpString", Return = "", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
{ Params = "Command, Callback, HelpString", Return = "", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
{ Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
{ Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
},
CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." },
DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." },
@ -1697,6 +1875,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
Constants =
{
HOOK_BLOCK_SPREAD = { Notes = "Called when a block spreads based on world conditions" },
HOOK_BLOCK_TO_PICKUPS = { Notes = "Called when a block has been dug and is being converted to pickups. The server has provided the default pickups and the plugins may modify them." },
HOOK_CHAT = { Notes = "Called when a client sends a chat message that is not a command. The plugin may modify the chat message" },
HOOK_CHUNK_AVAILABLE = { Notes = "Called when a chunk is loaded or generated and becomes available in the {{cWorld|world}}." },
@ -1773,6 +1952,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
BroadcastChatInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." },
BroadcastChatSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." },
BroadcastChatWarning = { Params = "Message", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." },
CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil." },
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for the given player." },
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
@ -1821,6 +2001,36 @@ end
},
}, -- cRoot
cScoreboard =
{
Desc = [[
This class manages the objectives and teams of a single world.
]],
Functions =
{
AddPlayerScore = { Params = "Name, Type, Value", Return = "", Notes = "Adds a value to all player scores of the specified objective type." },
ForEachObjective = { Params = "CallBackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each objective in the scoreboard. Returns true if all objectives have been processed (including when there are zero objectives), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cObjective|Objective}}, [CallbackData])</pre> The callback should return false or no value to continue with the next objective, or true to abort the enumeration." },
ForEachTeam = { Params = "CallBackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each team in the scoreboard. Returns true if all teams have been processed (including when there are zero teams), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cObjective|Objective}}, [CallbackData])</pre> The callback should return false or no value to continue with the next team, or true to abort the enumeration." },
GetNumObjectives = { Params = "", Return = "number", Notes = "Returns the nuber of registered objectives." },
GetNumTeams = { Params = "", Return = "number", Notes = "Returns the number of registered teams." },
GetObjective = { Params = "string", Return = "{{cObjective}}", Notes = "Returns the objective with the specified name." },
GetObjectiveIn = { Params = "DisplaySlot", Return = "{{cObjective}}", Notes = "Returns the objective in the specified display slot. Can be nil." },
GetTeam = { Params = "string", Return = "{{cTeam}}", Notes = "Returns the team with the specified name." },
RegisterObjective = { Params = "Name, DisplayName, Type", Return = "{{cObjective}}", Notes = "Registers a new scoreboard objective. Returns the {{cObjective}} instance, nil on error." },
RegisterTeam = { Params = "Name, DisplayName, Prefix, Suffix", Return = "{{cTeam}}", Notes = "Registers a new team. Returns the {{cTeam}} instance, nil on error." },
RemoveObjective = { Params = "string", Return = "bool", Notes = "Removes the objective with the specified name. Returns true if operation was successful." },
RemoveTeam = { Params = "string", Return = "bool", Notes = "Removes the team with the specified name. Returns true if operation was successful." },
SetDisplay = { Params = "Name, DisplaySlot", Return = "", Notes = "Updates the currently displayed objective." },
},
Constants =
{
dsCount = { Notes = "" },
dsList = { Notes = "" },
dsName = { Notes = "" },
dsSidebar = { Notes = "" },
},
}, -- cScoreboard
cServer =
{
Desc = [[
@ -1841,13 +2051,40 @@ end
},
}, -- cServer
cTeam =
{
Desc = [[
This class manages a single player team.
]],
Functions =
{
AddPlayer = { Params = "string", Returns = "bool", Notes = "Adds a player to this team. Returns true if the operation was successful." },
AllowsFriendlyFire = { Params = "", Return = "bool", Notes = "Returns whether team friendly fire is allowed." },
CanSeeFriendlyInvisible = { Params = "", Return = "bool", Notes = "Returns whether players can see invisible teammates." },
HasPlayer = { Params = "string", Returns = "bool", Notes = "Returns whether the specified player is a member of this team." },
GetDisplayName = { Params = "", Return = "string", Notes = "Returns the display name of the team." },
GetName = { Params = "", Return = "string", Notes = "Returns the internal name of the team." },
GetNumPlayers = { Params = "", Return = "number", Notes = "Returns the number of registered players." },
GetPrefix = { Params = "", Return = "string", Notes = "Returns the prefix prepended to the names of the members of this team." },
RemovePlayer = { Params = "string", Returns = "bool", Notes = "Removes the player with the specified name from this team. Returns true if the operation was successful." },
Reset = { Params = "", Returns = "", Notes = "Removes all players from this team." },
GetSuffix = { Params = "", Return = "string", Notes = "Returns the suffix appended to the names of the members of this team." },
SetCanSeeFriendlyInvisible = { Params = "bool", Return = "", Notes = "Set whether players can see invisible teammates." },
SetDisplayName = { Params = "string", Return = "", Notes = "Sets the display name of this team. (i.e. what will be shown to the players)" },
SetFriendlyFire = { Params = "bool", Return = "", Notes = "Sets whether team friendly fire is allowed." },
SetPrefix = { Params = "string", Return = "", Notes = "Sets the prefix prepended to the names of the members of this team." },
SetSuffix = { Params = "string", Return = "", Notes = "Sets the suffix appended to the names of the members of this team." },
},
}, -- cTeam
cTNTEntity =
{
Desc = "This class manages a TNT entity.",
Functions =
{
GetCounterTime = { Return = "number", Notes = "Returns the time until the entity explodes." },
GetMaxFuseTime = { Return = "number", Notes = "Returns how long the fuse was." },
Explode = { Return = "", Notes = "Explode the tnt." },
GetFuseTicks = { Return = "number", Notes = "Returns the fuse ticks until the tnt will explode." },
SetFuseTicks = { Return = "number", Notes = "Set the fuse ticks until the tnt will explode." },
},
Inherits = "cEntity",
},
@ -1973,7 +2210,9 @@ end
DoWithDropSpenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper or a dispenser at the specified coords, calls the CallbackFunction with the {{cDropSpenserEntity}} parameter representing the dropper or dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropSpenserEntity|DropSpenserEntity}}, [CallbackData])</pre> Note that this can be used to access both dispensers and droppers in a similar way. The function returns false if there is neither dispenser nor dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithDropperAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper at the specified coords, calls the CallbackFunction with the {{cDropperEntity}} parameter representing the dropper. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropperEntity|DropperEntity}}, [CallbackData])</pre> The function returns false if there is no dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithEntityByID = { Params = "EntityID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If an entity with the specified ID exists, calls the callback with the {{cEntity}} parameter representing the entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The function returns false if the entity was not found, and it returns the same bool value that the callback has returned if the entity was found." },
DoWithFlowerPotAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a flower pot at the specified coords, calls the CallbackFunction with the {{cFlowerPotEntity}} parameter representing the flower pot. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFlowerPotEntity|FlowerPotEntity}}, [CallbackData])</pre> The function returns false if there is no flower pot, or if there is, it returns the bool value that the callback has returned." },
DoWithFurnaceAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a furnace at the specified coords, calls the CallbackFunction with the {{cFurnaceEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The function returns false if there is no furnace, or if there is, it returns the bool value that the callback has returned." },
DoWithMobHeadAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a mob head at the specified coords, calls the CallbackFunction with the {{cMobHeadEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cMobHeadEntity|MobHeadEntity}}, [CallbackData])</pre> The function returns false if there is no mob head, or if there is, it returns the bool value that the callback has returned." },
DoWithNoteBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a note block at the specified coords, calls the CallbackFunction with the {{cNoteEntity}} parameter representing the note block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cNoteEntity|NoteEntity}}, [CallbackData])</pre> The function returns false if there is no note block, or if there is, it returns the bool value that the callback has returned." },
DoWithPlayer = { Params = "PlayerName, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of the specified name (exact match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
FastSetBlock =
@ -2080,7 +2319,7 @@ end
SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " },
SpawnFallingBlock = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "EntityID", Notes = "Spawns an {{cFallingBlock|Falling Block}} entity at the specified coords with the given block type/meta" },
SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" },
SpawnPrimedTNT = { Params = "X, Y, Z, FuseTimeSecs, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse time. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
SpawnPrimedTNT = { Params = "X, Y, Z, FuseTicks, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse ticks. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." },
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as SetSignLiens()" },
UseBlockEntity = { Params = "{{cPlayer|Player}}, BlockX, BlockY, BlockZ", Return = "", Notes = "Makes the specified Player use the block entity at the specified coords (open chest UI, etc.) If the cords are in an unloaded chunk or there's no block entity, ignores the call." },
@ -2442,7 +2681,8 @@ end
]],
Functions =
{
AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFace|face}}"},
AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFaces|face}}"},
BlockFaceToString = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "string", Notes = "Returns the string representation of the {{Globals#BlockFaces|eBlockFace}} constant. Uses the axis-direction-based names, such as BLOCK_FACE_XP." },
BlockStringToType = {Params = "BlockTypeString", Return = "BLOCKTYPE", Notes = "Returns the block type parsed from the given string"},
ClickActionToString = {Params = "{{Globals#ClickAction|ClickAction}}", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"},
DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "},
@ -2456,14 +2696,37 @@ end
ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format 'ItemTypeText:ItemDamage * Count'"},
ItemToString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item type"},
ItemTypeToString = {Params = "ItemType", Return = "string", Notes = "Returns the string representation of ItemType "},
LOG = {Params = "string", Notes = "Logs a text into the server console using 'normal' severity (gray text) "},
LOGERROR = {Params = "string", Notes = "Logs a text into the server console using 'error' severity (black text on red background)"},
LOGINFO = {Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"},
LOGWARN = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"},
LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"},
LOG =
{
{Params = "string", Notes = "Logs a text into the server console using 'normal' severity (gray text)"},
{Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console. The severity is converted from the CompositeChat's MessageType."},
},
LOGERROR =
{
{Params = "string", Notes = "Logs a text into the server console using 'error' severity (black text on red background)"},
{Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'error' severity (black text on red background)"},
},
LOGINFO =
{
{Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"},
{Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'info' severity (yellow text)"},
},
LOGWARN =
{
{Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"},
{Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"},
},
LOGWARNING =
{
{Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"},
{Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'warning' severity (red text)"},
},
MirrorBlockFaceY = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after mirroring it around the Y axis (or rotating 180 degrees around it)." },
NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"},
NormalizeAngleDegrees = { Params = "AngleDegrees", Return = "AngleDegrees", Notes = "Returns the angle, wrapped into the [-180, +180) range." },
ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"},
RotateBlockFaceCCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees counter-clockwise." },
RotateBlockFaceCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees clockwise." },
StringSplit = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered."},
StringSplitAndTrim = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered. Each of the separate strings is trimmed (whitespace removed from the beginning and end of the string)"},
StringToBiome = {Params = "string", Return = "{{Globals#BiomeTypes|BiomeType}}", Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value"},
@ -2510,7 +2773,13 @@ end
Include = "^BLOCK_FACE_.*",
TextBefore = [[
These constants are used to describe individual faces of the block. They are used when the
client is interacting with a block, or when the {{cLineBlockTracer}} hits a block, etc.
client is interacting with a block in the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}},
{{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}}, {{OnPlayerLeftClick|HOOK_PLAYER_LEFT_CLICK}},
{{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}}, {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}},
{{OnPlayerRightClick|HOOK_PLAYER_RIGHT_CLICK}}, {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}},
{{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}}, {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}},
and {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} hooks, or when the {{cLineBlockTracer}} hits a
block, etc.
]],
},
ClickAction =
@ -2568,6 +2837,14 @@ end
data provided with the explosions, such as the exploding {{cCreeper|creeper}} entity or the
{{Vector3i|coords}} of the exploding bed.
]],
},
SpreadSource =
{
Include = "^ss.*",
TextBefore = [[
These constants are used to differentiate the various sources of spreads, such as grass growing.
They are used in the {{OnBlockSpread|HOOK_BLOCK_SPREAD}} hook.
]],
}
},
}, -- Globals
@ -2576,16 +2853,16 @@ end
IgnoreClasses =
{
"coroutine",
"debug",
"io",
"math",
"package",
"os",
"string",
"table",
"g_Stats",
"g_TrackedPages",
"^coroutine$",
"^debug$",
"^io$",
"^math$",
"^package$",
"^os$",
"^string$",
"^table$",
"^g_Stats$",
"^g_TrackedPages$",
},
IgnoreFunctions =
@ -2595,11 +2872,11 @@ end
"Globals.xpcall",
"Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace
"sqlite3.__newindex",
"%a+\.__%a+", -- AnyClass.__Anything
"%a+\.\.collector", -- AnyClass..collector
"%a+\.new", -- AnyClass.new
"%a+.new_local", -- AnyClass.new_local
"%a+.delete", -- AnyClass.delete
"%a+%.__%a+", -- AnyClass.__Anything
"%a+%.%.collector", -- AnyClass..collector
"%a+%.new", -- AnyClass.new
"%a+%.new_local", -- AnyClass.new_local
"%a+%.delete", -- AnyClass.delete
-- Functions global in the APIDump plugin:
"CreateAPITables",
@ -2637,6 +2914,7 @@ end
-- No sorting is provided for these, they will be output in the same order as defined here
{ FileName = "Writing-a-MCServer-plugin.html", Title = "Writing a MCServer plugin" },
{ FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" },
{ FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" },
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
}
} ;

View File

@ -196,9 +196,11 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
Inherits = "cBlockEntity",
Functions =
{
EjectRecord = { Params = "", Return = "", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0)" },
EjectRecord = { Params = "", Return = "bool", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0). Returns true if pickup ejected." },
GetRecord = { Params = "", Return = "number", Notes = "Returns the record currently present. Zero for no record, E_ITEM_*_DISC for records." },
PlayRecord = { Params = "", Return = "", Notes = "Plays the currently present record. No action if there's no current record." },
IsPlayingRecord = { Params = "", Return = "bool", Notes = "Returns true if the jukebox is playing a record." },
IsRecordItem = { Params = "ItemType", Return = "bool", Notes = "Returns true if the specified item is a record that can be played." },
PlayRecord = { Params = "RecordItemType", Return = "bool", Notes = "Plays the specified Record. Return false if the parameter isn't a playable Record (E_ITEM_XXX_DISC). If there is a record already playing, ejects it first." },
SetRecord = { Params = "number", Return = "", Notes = "Sets the currently present record. Use zero for no record, or E_ITEM_*_DISC for records." },
},
}, -- cJukeboxEntity
@ -236,6 +238,20 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
Inherits = "cBlockEntity";
}, -- cSignEntity
cFlowerPotEntity =
{
Desc = [[
This class represents a flower pot entity in the world.
]],
Functions =
{
IsItemInPot = { Params = "", Return = "bool", Notes = "Is a flower in the pot?" },
GetItem = { Params = "", Return = "{{cItem|Item}}", Notes = "Returns the item in the flower pot." },
SetItem = { Params = "{{cItem|Item}}", Return = "", Notes = "Set the item in the flower pot" },
},
Inherits = "cBlockEntity";
}, -- cFlowerPotEntity
}

View File

@ -53,7 +53,7 @@ return
{
Desc = [[
cCuboid offers some native support for integral-boundary cuboids. A cuboid internally consists of
two {{Vector3i}}s. By default the cuboid doesn't make any assumptions about the defining points,
two {{Vector3i}}-s. By default the cuboid doesn't make any assumptions about the defining points,
but for most of the operations in the cCuboid class, the p1 member variable is expected to be the
minima and the p2 variable the maxima. The Sort() function guarantees this condition.</p>
<p>
@ -63,12 +63,17 @@ return
{
constructor =
{
{ Params = "OtheCuboid", Return = "cCuboid", Notes = "Creates a new Cuboid object as a copy of OtherCuboid" },
{ Params = "", Return = "cCuboid", Notes = "Creates a new Cuboid object with all-zero coords" },
{ Params = "OtherCuboid", Return = "cCuboid", Notes = "Creates a new Cuboid object as a copy of OtherCuboid" },
{ Params = "{{Vector3i|Point1}}, {{Vector3i|Point2}}", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
{ Params = "X, Y, Z", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified point as both its corners (the cuboid has a size of 1 in each direction)." },
{ Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
},
Assign = { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "", Notes = "Assigns all the coords stored in the cuboid. Sort-state is ignored." },
Assign =
{
{ Params = "SrcCuboid", Return = "", Notes = "Copies all the coords from the src cuboid to this cuboid. Sort-state is ignored." },
{ Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "", Notes = "Assigns all the coords to the specified values. Sort-state is ignored." },
},
ClampX = { Params = "MinX, MaxX", Return = "", Notes = "Clamps both X coords into the range provided. Sortedness-agnostic." },
ClampY = { Params = "MinY, MaxY", Return = "", Notes = "Clamps both Y coords into the range provided. Sortedness-agnostic." },
ClampZ = { Params = "MinZ, MaxZ", Return = "", Notes = "Clamps both Z coords into the range provided. Sortedness-agnostic." },
@ -76,6 +81,7 @@ return
DifY = { Params = "", Return = "number", Notes = "Returns the difference between the two Y coords (Y-size minus 1). Assumes sorted." },
DifZ = { Params = "", Return = "number", Notes = "Returns the difference between the two Z coords (Z-size minus 1). Assumes sorted." },
DoesIntersect = { Params = "OtherCuboid", Return = "bool", Notes = "Returns true if this cuboid has at least one voxel in common with OtherCuboid. Note that edges are considered inclusive. Assumes both sorted." },
Engulf = { Params = "{{Vector3i|Point}}", Return = "", Notes = "If needed, expands the cuboid to include the specified point. Doesn't shrink. Assumes sorted. " },
Expand = { Params = "SubMinX, AddMaxX, SubMinY, AddMaxY, SubMinZ, AddMaxZ", Return = "", Notes = "Expands the cuboid by the specified amount in each direction. Works on unsorted cuboids as well. NOTE: this function doesn't check for underflows." },
GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the cuboid, in blocks. Note that the volume considers both coords inclusive. Works on unsorted cuboids, too." },
IsCompletelyInside = { Params = "OuterCuboid", Return = "bool", Notes = "Returns true if this cuboid is completely inside (in all directions) in OuterCuboid. Assumes both sorted." },
@ -308,6 +314,7 @@ end
},
Equals = { Params = "Vector3i", Return = "bool", Notes = "Returns true if this vector is exactly the same as the specified vector." },
Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector." },
Move = { Params = "X, Y, Z", Return = "", Notes = "Moves the vector by the specified amount in each axis direction." },
Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once" },
SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
},

View File

@ -0,0 +1,40 @@
return
{
HOOK_BLOCK_SPREAD =
{
CalledWhen = "Called when a block spreads based on world conditions",
DefaultFnName = "OnBlockSpread", -- also used as pagename
Desc = [[
This hook is called when a block spreads.</p>
<p>
The spread carries with it the type of its source - whether it's a block spreads.
It also carries the identification of the actual source. The exact type of the identification
depends on the source kind:
<table>
<tr><th>Source</th><th>Notes</th></tr>
<tr><td>ssFireSpread</td><td>Fire spreading</td></tr>
<tr><td>ssGrassSpread</td><td>Grass spreading</td></tr>
<tr><td>ssMushroomSpread</td><td>Mushroom spreading</td></tr>
<tr><td>ssMycelSpread</td><td>Mycel spreading</td></tr>
<tr><td>ssVineSpread</td><td>Vine spreading</td></tr>
</table></p>
]],
Params =
{
{ Name = "World", Type = "{{cWorld}}", Notes = "The world in which the block resides" },
{ Name = "BlockX", Type = "number", Notes = "X-coord of the block" },
{ Name = "BlockY", Type = "number", Notes = "Y-coord of the block" },
{ Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" },
{ Name = "Source", Type = "eSpreadSource", Notes = "Source of the spread. See the table above." },
},
Returns = [[
If the function returns false or no value, the next plugin's callback is called, and finally
MCServer will process the spread. If the function
returns true, no other callback is called for this event and the spread will not occur.
]],
}, -- HOOK_BLOCK_SPREAD
}

View File

@ -0,0 +1,24 @@
return
{
HOOK_PROJECTILE_HIT_BLOCK =
{
CalledWhen = "A projectile hits a solid block.",
DefaultFnName = "OnProjectileHitBlock", -- also used as pagename
Desc = [[
This hook is called when a {{cProjectileEntity|projectile}} hits a solid block..
]],
Params =
{
{ Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
},
Returns = [[
If the function returns false or no value, the next plugin's callback is called. If the function
returns true, no other callback is called for this event and the projectile flies through block..
]],
}, -- HOOK_PROJECTILE_HIT_BLOCK
}

View File

@ -0,0 +1,25 @@
return
{
HOOK_PROJECTILE_HIT_ENTITY =
{
CalledWhen = "A projectile hits another entity.",
DefaultFnName = "OnProjectileHitEntity", -- also used as pagename
Desc = [[
This hook is called when a {{cProjectileEntity|projectile}} hits another entity.
]],
Params =
{
{ Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
{ Name = "Entity", Type = "{{cEntity}}", Notes = "The entity wich was hit." },
},
Returns = [[
If the function returns false or no value, the next plugin's callback is called. If the function
returns true, no other callback is called for this event and the projectile flies through the entity.
]],
}, -- HOOK_PROJECTILE_HIT_ENTITY
}

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>MCServer - Setting up ZeroBrane Studio</title>
<link rel="stylesheet" type="text/css" href="main.css" />
<link rel="stylesheet" type="text/css" href="prettify.css" />
<script src="prettify.js"></script>
<script src="lang-lua.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id="content">
<h1>Setting up the ZeroBrane Studio IDE</h1>
<p>
This article will explain how to set up ZeroBrane Studio, an IDE for writing Lua code, so that you can develop MCServer plugins with the comfort of an IDE.</p>
<h2><img src="Static/zbs_logo.png" /> About ZeroBrane Studio</h2>
<p>To quickly introduce ZeroBrane Studio, it is an IDE for writing Lua code. It has the basic features expected of an IDE - it allows you to manage groups of files as a project, you can edit multiple files in a tabbed editor, the code is syntax-highlighted. Code completion, symbol browsing, and more. It also features a Lua debugger that allows you to debug your Lua code within any application that uses Lua and can load Lua packages. It is written using the multiplatform WxWidgets toolkit, and runs on multiple platforms, including Windows, Linux and MacOS.</p>
<p>Here's a screenshot of a default ZBS window with the debugger stepping through the code (scaled down):<br />
<img src="Static/zbs_workspace.png" /></p>
<p>As you can see, you can set breakpoints in the code, inspect variables' values, view the Lua call-stacks.</p>
<p>ZBS is open-source, the sources are on GitHub: <a href="https://github.com/pkulchenko/ZeroBraneStudio">https://github.com/pkulchenko/ZeroBraneStudio</a>. The project's homepage is at <a href="http://studio.zerobrane.com/">http://studio.zerobrane.com/</a>.
<h2><img src="Static/zbs_logo.png" /> First-time setup</h2>
<p>Since ZBS is a universal Lua IDE, you need to first set it up so that it is ready for MCS plugin development. For that, you need to download one file, <a href="https://raw.githubusercontent.com/pkulchenko/ZeroBranePackage/master/mcserver.lua">mcserver.lua</a> from the <a href="https://github.com/pkulchenko/ZeroBranePackage">ZBS's plugin repository</a>. Place that file in the "packages" folder inside your ZBS's folder. Note that there are other useful plugins in the repository and you may want to have a look there later on to further customize your ZBS. To install them, simply save them into the same folder.</p>
<p>Next you should install the code-completion support specific for MCServer. You should repeat this step from time to time, because the API evolves in time so new functions and classes are added to it quite often. You should have an APIDump plugin in your MCServer installation. Enable the APIDump plugin in the server settings, it's very cheap to keep it enabled and it doesn't cost any performance during normal gameplay. To generate the code-completion support file, enter the <code style="background: #ddd; border: 1px solid #aaa">api</code> command into the server console. This will create a new file, "mcserver_api.lua", next to the MCS executable. Move that file into the "api/lua" subfolder inside your ZBS's folder.</p>
<p>After you download the mcserver.lua file and install the completion support, you need to restart ZBS in order for the plugin to load. If there are no errors, you should see two new items in the Project -> Lua Interpreter submenu: "MCServer - debug mode" and "MCServer - release mode". The only difference between the two is which filename they use to launch MCServer - mcserver_debug(.exe) for the debug option and "mcserver(.exe)" for the release option. If you built your own MCServer executable and you built it in debug mode, you should select the debug mode option. In all other cases, including if you downloaded the already-compiled MCServer executable from the internet, you should select the release mode option.</p>
<p>For a first time user, it might be a bit overwhelming that there are no GUI settings in the ZBS, yet the IDE is very configurable. There are two files that you edit in order to change settings, either system-wide (all users of the computer share those settings) or user-wide (the settings are only for a specific user of the computer). Those files are regular Lua sources and you can quickly locate them and edit them from within the IDE itself, select Edit -> Preferences -> Settings: XYZ from the menu, with XYZ being either System or User.</p>
<p>There is a documentation on most of the settings on ZBS's webpage, have a look at <a href="http://studio.zerobrane.com/documentation.html">http://studio.zerobrane.com/documentation.html</a>, especially the Preferences section. Personally I recommend setting editor.usetabs to true and possibly adjusting the editor.tabwidth, turn off the editor.smartindent feature and for debugging the option debugger.alloweditting should be set to true unless you feel like punishing yourself.</p>
<h2><img src="Static/zbs_logo.png" /> Project management</h2>
<p>ZBS works with projects, it considers all files and subfolder in a specific folder to be a project. There's no need for a special project file nor for adding individual files to the workspace, all files are added automatically. To open a MCS plugin as the project, click the triple-dot button in the Project pane, or select Project -> Project directory -> Choose... from the menu. Browse and select the MCS plugin's folder. ZBS will load all the files in the plugin's folder and you can start editting code.</p>
<p>Note that although ZBS allows you to work with subfolders in your plugins (and you should, especially with larger plugins), the current mcserver ZBS plugin will not be able to start debugging unless you have a file open in the editor that is at the root level of the MCS plugin's folder.</p>
<h2><img src="Static/zbs_logo.png" /> Debugging</h2>
<p>You are now ready to debug your code. Before doing that, though, don't forget to save your project files. If you haven't done so already, enable your plugin in the settings.ini file. If you want the program to break at a certain line, it is best to set the breakpoint before starting the program. Set the cursor on the line and hit F9 (or use menu Project -> Toggle Breakpoint) to toggle a breakpoint on that line. Finally, hit F5, or select menu Project -> Start Debugging to launch MCServer under the debugger. The MCServer window comes up and loads your plugin. If the window doesn't come up, inspect the Output pane in ZBS, there are usually two reasons for failure:<ul>
<li>Your code in the currently open file has a hard syntax error. These are reported as "Compilation error" in the Output pane, double-click the line to go to the error</li>
<li>ZBS cannot find the MCServer executable. Make sure you are editting a file two levels down the folder hierarchy from the MCS executable and that the MCS executable is named properly (mcserver[.exe] or mcserver_debug[.exe]). Also make sure you have selected the right Interpreter (menu Project -> Lua Interpreter).</li>
</ul></p>
<p>Once running, if the execution hits a breakpoint, the ZBS window will come up and a green arrow is displayed next to the breakpoint line. You can step through the code using F10 (Step Into) and Shift+F10 (Step Over). You can also use the Watch window to inspect variable values, or simply hover your mouse over a variable to display its value in the tooltip. Use the Remote console pane to execute commands directly *inside* the MCServer's plugin context.</p>
<p>You can also use the Project -> Break menu item to break into the debugger as soon as possible. You can also set breakpoints while the MCS plugin is running. Note that due to the way in which the debugger is implemented, MCS may execute some more Lua code before the break / breakpoint comes into effect. If MCS is not executing any Lua code in your plugin, it will not break until the plugin code kicks in again. This may result in missed breakpoints and delays before the Break command becomes effective. Therefore it's best to set breakpoints before running the program, or while the program is waiting in another breakpoint.</p>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit 3b416b07a339b3abcbc127070d56eea05b05373d
Subproject commit 5c8557d4fdfa580c100510cde07a1a778ea2e244

View File

@ -27,9 +27,12 @@ function Initialize(Plugin)
PM:AddHook(cPluginManager.HOOK_CHAT, OnChat);
PM:AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
PM:AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
PM:AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded);
PM:AddHook(cPluginManager.HOOK_PLUGIN_MESSAGE, OnPluginMessage);
PM:AddHook(cPluginManager.HOOK_PLAYER_JOINED, OnPlayerJoined)
-- _X: Disabled so that the normal operation doesn't interfere with anything
-- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
@ -55,7 +58,8 @@ function Initialize(Plugin)
PM:BindCommand("/sched", "debuggers", HandleSched, "- Schedules a simple countdown using cWorld:ScheduleTask()");
PM:BindCommand("/cs", "debuggers", HandleChunkStay, "- Tests the ChunkStay Lua integration for the specified chunk coords");
PM:BindCommand("/compo", "debuggers", HandleCompo, "- Tests the cCompositeChat bindings")
PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one");
PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one")
PM:BindCommand("/wesel", "debuggers", HandleWESel, "- Expands the current WE selection by 1 block in X/Z")
Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
@ -65,10 +69,22 @@ function Initialize(Plugin)
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
-- TestBlockAreas();
-- TestSQLiteBindings();
-- TestExpatBindings();
-- TestPluginCalls();
-- TestBlockAreas()
-- TestSQLiteBindings()
-- TestExpatBindings()
-- TestPluginCalls()
TestBlockAreasString()
TestStringBase64()
--[[
-- Test cCompositeChat usage in console-logging:
LOGINFO(cCompositeChat("This is a simple message with some @2 color formatting @4 and http://links.to .")
:AddSuggestCommandPart("(Suggested command)", "cmd")
:AddRunCommandPart("(Run command)", "cmd")
:SetMessageType(mtInfo)
)
--]]
return true
end;
@ -201,6 +217,60 @@ end
function TestBlockAreasString()
-- Write one area to string, then to file:
local BA1 = cBlockArea()
BA1:Create(5, 5, 5, cBlockArea.baTypes + cBlockArea.baMetas)
BA1:Fill(cBlockArea.baTypes, E_BLOCK_DIAMOND_BLOCK)
BA1:FillRelCuboid(1, 3, 1, 3, 1, 3, cBlockArea.baTypes, E_BLOCK_GOLD_BLOCK)
local Data = BA1:SaveToSchematicString()
if ((type(Data) ~= "string") or (Data == "")) then
LOG("Cannot save schematic to string")
return
end
cFile:CreateFolder("schematics")
local f = io.open("schematics/StringTest.schematic", "wb")
f:write(Data)
f:close()
-- Load a second area from that file:
local BA2 = cBlockArea()
if not(BA2:LoadFromSchematicFile("schematics/StringTest.schematic")) then
LOG("Cannot read schematic from string test file")
return
end
BA2:Clear()
-- Load another area from a string in that file:
f = io.open("schematics/StringTest.schematic", "rb")
Data = f:read("*all")
if not(BA2:LoadFromSchematicString(Data)) then
LOG("Cannot load schematic from string")
end
end
function TestStringBase64()
-- Create a binary string:
local s = ""
for i = 0, 255 do
s = s .. string.char(i)
end
-- Roundtrip through Base64:
local Base64 = Base64Encode(s)
local UnBase64 = Base64Decode(Base64)
assert(UnBase64 == s)
end
function TestSQLiteBindings()
LOG("Testing SQLite bindings...");
@ -1258,3 +1328,54 @@ end
function HandleWESel(a_Split, a_Player)
-- Check if the selection is a cuboid:
local IsCuboid = cPluginManager:CallPlugin("WorldEdit", "IsPlayerSelectionCuboid")
if (IsCuboid == nil) then
a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit is not loaded"))
return true
elseif (IsCuboid == false) then
a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, the selection is not a cuboid"))
return true
end
-- Get the selection:
local SelCuboid = cCuboid()
local IsSuccess = cPluginManager:CallPlugin("WorldEdit", "GetPlayerCuboidSelection", a_Player, SelCuboid)
if not(IsSuccess) then
a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit reported failure while getting current selection"))
return true
end
-- Adjust the selection:
local NumBlocks = tonumber(a_Split[2] or "1") or 1
SelCuboid:Expand(NumBlocks, NumBlocks, 0, 0, NumBlocks, NumBlocks)
-- Set the selection:
local IsSuccess = cPluginManager:CallPlugin("WorldEdit", "SetPlayerCuboidSelection", a_Player, SelCuboid)
if not(IsSuccess) then
a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit reported failure while setting new selection"))
return true
end
a_Player:SendMessage(cCompositeChat():SetMessageType(mtInformation):AddTextPart("Successfully adjusted the selection by " .. NumBlocks .. " block(s)"))
return true
end
function OnPlayerJoined(a_Player)
-- Test composite chat chaining:
a_Player:SendMessage(cCompositeChat()
:AddTextPart("Hello, ")
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
:AddSuggestCommandPart(", and welcome.", "/help", "u")
:AddRunCommandPart(" SetDay", "/time set 0")
)
end

View File

@ -0,0 +1,49 @@
function Initialize(a_Plugin)
a_Plugin:SetName("DumpInfo")
a_Plugin:SetVersion(1)
-- Check if the infodump file exists.
if (not cFile:Exists("Plugins/InfoDump.lua")) then
LOGWARN("[DumpInfo] InfoDump.lua was not found.")
return false
end
-- Add the webtab.
a_Plugin:AddWebTab("DumpPlugin", HandleDumpPluginRequest)
return true
end
function HandleDumpPluginRequest(a_Request)
local Content = ""
-- Check if it already was requested to dump a plugin.
if (a_Request.PostParams["DumpInfo"] ~= nil) then
local F = loadfile("Plugins/InfoDump.lua")
F("Plugins/" .. a_Request.PostParams["DumpInfo"])
end
Content = Content .. [[
<table>
<th colspan="2">DumpInfo</th>]]
-- Loop through each plugin that is found.
for PluginName, k in pairs(cPluginManager:Get():GetAllPlugins()) do
-- Check if there is a file called 'Info.lua' or 'info.lua'
if (cFile:Exists("Plugins/" .. PluginName .. "/Info.lua")) then
Content = Content .. "<tr>"
Content = Content .. "<td>" .. PluginName .. "</td>"
Content = Content .. "<td> <form method='POST'> <input type='hidden' value='" .. PluginName .. "' name='DumpInfo'> <input type='submit' value='DumpInfo'> </form>"
Content = Content .. "</td>"
end
end
Content = Content .. [[
</table>]]
return Content
end

View File

@ -317,26 +317,19 @@ local function WriteCommandsCategoryGithub(a_Category, f)
if (CategoryName == "") then
CategoryName = "General";
end
f:write("\n## ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
f:write("\n### ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
-- Write description:
if (a_Category.Description ~= "") then
f:write(GithubizeString(a_Category.Description), "\n");
f:write(GithubizeString(a_Category.Description), "\n\n");
end
f:write("| Command | Permission | Description | \n")
f:write("| ------- | ---------- | ----------- | \n")
-- Write commands:
f:write("\n");
for idx2, cmd in ipairs(a_Category.Commands) do
f:write("\n### ", cmd.CommandString, "\n", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n\n");
if (cmd.Info.Permission ~= nil) then
f:write("Permission required: **", cmd.Info.Permission, "**\n\n");
end
if (cmd.Info.DetailedDescription ~= nil) then
f:write(GithubizeString(cmd.Info.DetailedDescription));
end
if (cmd.Info.ParameterCombinations ~= nil) then
WriteCommandParameterCombinationsGithub(cmd.CommandString, cmd.Info.ParameterCombinations, f);
end
f:write("|", cmd.CommandString, " | ", cmd.Info.Permission or "", " | ", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "| \n")
end
f:write("\n\n")
end
@ -537,12 +530,13 @@ local function DumpPermissionsGithub(a_PluginInfo, f)
-- Dump the permissions:
f:write("\n# Permissions\n");
f:write("| Permissions | Description | Commands | Recommended groups |\n")
f:write("| ----------- | ----------- | -------- | ------------------ |\n")
for idx, perm in ipairs(Permissions) do
f:write("### ", perm.Name, "\n");
f:write(GithubizeString(perm.Info.Description or ""));
f:write(perm.Name, " | ");
f:write(GithubizeString(perm.Info.Description or ""), " | ");
local CommandsAffected = perm.Info.CommandsAffected or {};
if (#CommandsAffected > 0) then
f:write("\n\nCommands affected:\n - ");
local Affects = {};
for idx2, cmd in ipairs(CommandsAffected) do
if (type(cmd) == "string") then
@ -551,11 +545,10 @@ local function DumpPermissionsGithub(a_PluginInfo, f)
table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd));
end
end
f:write(table.concat(Affects, "\n - "));
f:write("\n");
f:write(table.concat(Affects, ", "), " | ");
end
if (perm.Info.RecommendedGroups ~= nil) then
f:write("\n\nRecommended groups: ", perm.Info.RecommendedGroups, "\n");
f:write(perm.Info.RecommendedGroups, " |");
end
f:write("\n");
end
@ -578,7 +571,10 @@ local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo)
DumpAdditionalInfoForum(a_PluginInfo, f);
DumpCommandsForum(a_PluginInfo, f);
DumpPermissionsForum(a_PluginInfo, f);
if (a_PluginInfo.SourceLocation ~= nil) then
f:write("[b][color=blue]Source:[/color] [url=", a_PluginInfo.SourceLocation, "]Link[/url][/b]");
end
f:close();
end

View File

@ -9,16 +9,30 @@
--- Lists all the subcommands that the player has permissions for
local function ListSubcommands(a_Player, a_Subcommands, a_CmdString)
a_Player:SendMessage("The " .. a_CmdString .. " command requires another verb:");
if (a_Player == nil) then
LOGINFO("The " .. a_CmdString .. " command requires another verb:")
else
a_Player:SendMessage("The " .. a_CmdString .. " command requires another verb:")
end
-- Enum all the subcommands:
local Verbs = {};
for cmd, info in pairs(a_Subcommands) do
if (a_Player:HasPermission(info.Permission or "")) then
table.insert(Verbs, a_CmdString .. " " .. cmd);
table.insert(Verbs, " " .. a_CmdString .. " " .. cmd);
end
end
table.sort(Verbs);
for idx, verb in ipairs(Verbs) do
a_Player:SendMessage(verb);
-- Send the list:
if (a_Player == nil) then
for idx, verb in ipairs(Verbs) do
LOGINFO(verb);
end
else
for idx, verb in ipairs(Verbs) do
a_Player:SendMessage(verb);
end
end
end
@ -28,6 +42,7 @@ end
--- This is a generic command callback used for handling multicommands' parent commands
-- For example, if there are "/gal save" and "/gal load" commands, this callback handles the "/gal" command
-- It is used for both console and in-game commands; the console version has a_Player set to nil
local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_Level)
local Verb = a_Split[a_Level + 1];
if (Verb == nil) then
@ -46,7 +61,11 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
if (a_Level > 1) then
-- This is a true subcommand, display the message and make MCS think the command was handled
-- Otherwise we get weird behavior: for "/cmd verb" we get "unknown command /cmd" although "/cmd" is valid
a_Player:SendMessage("The " .. a_CmdString .. " command doesn't support verb " .. Verb);
if (a_Player == nil) then
LOGWARNING("The " .. a_CmdString .. " command doesn't support verb " .. Verb)
else
a_Player:SendMessage("The " .. a_CmdString .. " command doesn't support verb " .. Verb)
end
return true;
end
-- This is a top-level command, let MCS handle the unknown message
@ -54,18 +73,20 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
end
-- Check the permission:
if not(a_Player:HasPermission(Subcommand.Permission or "")) then
a_Player:SendMessage("You don't have permission to execute this command");
return true;
if (a_Player ~= nil) then
if not(a_Player:HasPermission(Subcommand.Permission or "")) then
a_Player:SendMessage("You don't have permission to execute this command");
return true;
end
end
-- Check if the handler is valid:
-- If the handler is not valid, check the next sublevel:
if (Subcommand.Handler == nil) then
if (Subcommand.Subcommands == nil) then
LOG("Cannot find handler for command " .. a_CmdString .. " " .. Verb);
return false;
end
ListSubcommands(a_Player, Subcommand.Subcommands, a_CmdString .. " " .. Verb);
MultiCommandHandler(a_Split, a_Player, a_CmdString .. " " .. Verb, Subcommand, a_Level + 1);
return true;
end
@ -149,21 +170,27 @@ end
function RegisterPluginInfoConsoleCommands()
-- A sub-function that registers all subcommands of a single command, using the command's Subcommands table
-- The a_Prefix param already contains the space after the previous command
local function RegisterSubcommands(a_Prefix, a_Subcommands)
local function RegisterSubcommands(a_Prefix, a_Subcommands, a_Level)
assert(a_Subcommands ~= nil);
for cmd, info in pairs(a_Subcommands) do
local CmdName = a_Prefix .. cmd;
cPluginManager.BindConsoleCommand(cmd, info.Handler, info.HelpString or "");
local Handler = info.Handler
if (Handler == nil) then
Handler = function(a_Split)
return MultiCommandHandler(a_Split, nil, CmdName, info, a_Level);
end
end
cPluginManager.BindConsoleCommand(CmdName, Handler, info.HelpString or "");
-- Recursively register any subcommands:
if (info.Subcommands ~= nil) then
RegisterSubcommands(a_Prefix .. cmd .. " ", info.Subcommands);
RegisterSubcommands(a_Prefix .. cmd .. " ", info.Subcommands, a_Level + 1);
end
end
end
-- Loop through all commands in the plugin info, register each:
RegisterSubcommands("", g_PluginInfo.ConsoleCommands);
RegisterSubcommands("", g_PluginInfo.ConsoleCommands, 1);
end

View File

@ -39,6 +39,7 @@
#
# Need to list each of the four log types, otherwise all logs would get converted into apple planks (^0)
ApplePlanks, 4 = AppleLog, *
ConiferPlanks, 4 = ConiferLog, *
BirchPlanks, 4 = BirchLog, *
@ -434,6 +435,55 @@ GoldNugget, 9 = GoldIngot, *
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
#******************************************************#
# Fireworks & Co.
# (Best not to add non-vanilla items to this as it will cause internal firework data handling code to log warnings)
# Ballistic firework rockets - plain and with firework star, all with 1 - 3 gunpowder
FireworkRocket = Paper, * | Gunpowder, *
FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, *
FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, *
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, *
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
# Radioactive firework stars
# Plain powder and dye
FireworkStar = Gunpowder, * | Dye ^-1, *
# Powder and effect, with effect combining
FireworkStar = Gunpowder, * | Dye ^-1, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, * | Diamond, *
# Powder and shape (no shape combining possible)
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, *
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, *
# Power and shape (no shape combining possible), combined with effect
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, *
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, *
# Power and shape (no shape combining possible), combined with effect (with effect combining)
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, * | Diamond, *
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, * | Diamond, *
# Star fade colour-change
FireworkStar = FireworkStar, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *

View File

@ -1,5 +1,3 @@
macro (add_flags_lnk FLAGS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
@ -62,6 +60,7 @@ macro(set_flags)
# We use a signed char (fixes #640 on RasPi)
add_flags_cxx("-fsigned-char")
endif()
@ -183,7 +182,24 @@ macro(set_exe_flags)
string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
add_flags_cxx("-Wall -Wextra")
add_flags_cxx("-Wall -Wextra -Wno-unused-parameter -Wno-error=switch")
# we support non-IEEE 754 fpus so can make no guarentees about error
add_flags_cxx("-ffast-math")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# clang does not provide the __extern_always_inline macro and a part of libm depends on this when using fast-math
add_flags_cxx("-D__extern_always_inline=inline")
add_flags_cxx("-Werror -Weverything -Wno-c++98-compat-pedantic -Wno-string-conversion")
add_flags_cxx("-Wno-extra-semi -Wno-error=switch-enum -Wno-documentation")
add_flags_cxx("-Wno-error=sign-conversion -Wno-error=conversion -Wno-padded")
add_flags_cxx("-Wno-error=deprecated -Wno-error=weak-vtables -Wno-error=float-equal")
add_flags_cxx("-Wno-error=missing-prototypes -Wno-error=non-virtual-dtor")
add_flags_cxx("-Wno-error=covered-switch-default -Wno-error=shadow")
add_flags_cxx("-Wno-error=exit-time-destructors -Wno-error=missing-variable-declarations")
add_flags_cxx("-Wno-error=global-constructors -Wno-implicit-fallthrough")
add_flags_cxx("-Wno-weak-vtables -Wno-switch-enum -Wno-exit-time-destructors")
endif()
endif()
endmacro()

View File

@ -37,7 +37,8 @@
// Some portability macros :)
#define stricmp strcasecmp
#define FORMATSTRING(formatIndex,va_argsIndex)
#else
#error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
@ -58,6 +59,8 @@
#define ALIGN_8
#define ALIGN_16
*/
#define FORMATSTRING(formatIndex,va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
#endif

View File

@ -131,8 +131,6 @@
} \
}
#define MAX_ENC_LEN 1024
@ -389,8 +387,6 @@ bool cConnection::RelayFromServer(void)
return CLIENTSEND(Buffer, res);
}
}
return true;
}
@ -427,8 +423,6 @@ bool cConnection::RelayFromClient(void)
return SERVERSEND(Buffer, res);
}
}
return true;
}
@ -473,14 +467,14 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, int a_Size, const char * a_Peer)
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
{
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
const Byte * Data = (const Byte *)a_Data;
while (a_Size > 0)
{
Byte Buffer[64 KiB];
int NumBytes = (a_Size > sizeof(Buffer)) ? sizeof(Buffer) : a_Size;
size_t NumBytes = (a_Size > sizeof(Buffer)) ? sizeof(Buffer) : a_Size;
a_Encryptor.ProcessData(Buffer, Data, NumBytes);
bool res = SendData(a_Socket, (const char *)Buffer, NumBytes, a_Peer);
if (!res)
@ -2263,7 +2257,9 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator);
AString ExtraData;
short VelocityX, VelocityY, VelocityZ;
short VelocityX = 0;
short VelocityY = 0;
short VelocityZ = 0;
if (DataIndicator != 0)
{
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SpeedX);
@ -2697,7 +2693,7 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
a_Metadata.push_back(x);
while (x != 0x7f)
{
int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
// int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
int Type = ((unsigned)((unsigned char)x)) >> 5; // Upper 3 bits = type
int Length = 0;
switch (Type)
@ -2772,7 +2768,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
{
int Index = ((unsigned)((unsigned char)a_Metadata[pos])) & 0x1f; // Lower 5 bits = index
int Type = ((unsigned)((unsigned char)a_Metadata[pos])) >> 5; // Upper 3 bits = type
int Length = 0;
// int Length = 0;
switch (Type)
{
case 0:
@ -2827,7 +2823,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
ASSERT(!"Cannot parse item description from metadata");
return;
}
int After = bb.GetReadableSpace();
// int After = bb.GetReadableSpace();
int BytesConsumed = BytesLeft - bb.GetReadableSpace();
Log("%sslot[%d] = %s (%d bytes)", Indent.c_str(), Index, ItemDesc.c_str(), BytesConsumed);

View File

@ -109,7 +109,7 @@ protected:
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, int a_Size, const char * a_Peer);
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);

View File

@ -22,6 +22,8 @@
#define ALIGN_8
#define ALIGN_16
#define FORMATSTRING(formatIndex, va_argsIndex)
#elif defined(__GNUC__)
// TODO: Can GCC explicitly mark classes as abstract (no instances can be created)?
@ -37,6 +39,8 @@
// Some portability macros :)
#define stricmp strcasecmp
#define FORMATSTRING(formatIndex, va_argsIndex)
#else
@ -59,6 +63,9 @@
#define ALIGN_16
*/
#define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
#endif
@ -233,4 +240,4 @@ public:
#define LOGERROR printf
#define LOGINFO printf
#define LOGWARNING printf
#define LOGWARNING printf

View File

@ -90,4 +90,4 @@ private:
std::string md5(const std::string & str);
#endif
#endif

@ -1 +1 @@
Subproject commit 2ceda579893ceb23c5eb0d56df47dc235644e0f4
Subproject commit 2cb1a0c4009ecf368ecc74eb428394e10f9e6d00

View File

@ -5,6 +5,32 @@ project (tolua++)
include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
include_directories ("${PROJECT_SOURCE_DIR}/include/")
include_directories ("${PROJECT_SOURCE_DIR}/../")
include_directories ("${PROJECT_SOURCE_DIR}")
find_program(XXD_EXECUTABLE xxd)
if(NOT XXD_EXECUTABLE STREQUAL "XXD_EXECUTABLE-NOTFOUND")
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/basic_lua.h
COMMAND ${XXD_EXECUTABLE} -i lua/basic.lua | sed 's/unsigned char/static const unsigned char/g' >basic_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/basic.lua)
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/enumerate_lua.h
COMMAND ${XXD_EXECUTABLE} -i lua/enumerate.lua | sed 's/unsigned char/static const unsigned char/g' >enumerate_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/enumerate.lua)
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/function_lua.h
COMMAND ${XXD_EXECUTABLE} -i lua/function.lua | sed 's/unsigned char/static const unsigned char/g' >function_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/function.lua)
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/declaration_lua.h
COMMAND ${XXD_EXECUTABLE} -i lua/declaration.lua | sed 's/unsigned char/static const unsigned char/g' >declaration_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/declaration.lua)
set_property(SOURCE src/bin/toluabind.c APPEND PROPERTY OBJECT_DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/enumerate_lua.h ${PROJECT_SOURCE_DIR}/src/bin/basic_lua.h ${PROJECT_SOURCE_DIR}/src/bin/function_lua.h ${PROJECT_SOURCE_DIR}/src/bin/declaration_lua.h)
else()
message("xxd not found, changes to tolua scripts will be ignored")
endif()
file(GLOB LIB_SOURCE
"src/lib/*.c"
@ -14,6 +40,8 @@ file(GLOB BIN_SOURCE
"src/bin/*.c"
)
add_executable(tolua ${BIN_SOURCE})
add_library(tolualib ${LIB_SOURCE})

View File

@ -0,0 +1,760 @@
static const unsigned char lua_basic_lua[] = {
0x2d, 0x2d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x3a, 0x20, 0x62, 0x61,
0x73, 0x69, 0x63, 0x20, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x2d, 0x2d,
0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x62, 0x79, 0x20,
0x57, 0x61, 0x6c, 0x64, 0x65, 0x6d, 0x61, 0x72, 0x20, 0x43, 0x65, 0x6c,
0x65, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x65, 0x43, 0x47, 0x72, 0x61,
0x66, 0x2f, 0x50, 0x55, 0x43, 0x2d, 0x52, 0x69, 0x6f, 0x0a, 0x2d, 0x2d,
0x20, 0x4a, 0x75, 0x6c, 0x20, 0x31, 0x39, 0x39, 0x38, 0x0a, 0x2d, 0x2d,
0x20, 0x4c, 0x61, 0x73, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x3a, 0x20, 0x41, 0x70, 0x72, 0x20, 0x32, 0x30, 0x30, 0x33, 0x0a, 0x2d,
0x2d, 0x20, 0x24, 0x49, 0x64, 0x3a, 0x20, 0x24, 0x0a, 0x0a, 0x2d, 0x2d,
0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69,
0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77,
0x61, 0x72, 0x65, 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6e,
0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72, 0x20,
0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x20, 0x69, 0x74, 0x2e, 0x0a, 0x2d,
0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61,
0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20,
0x68, 0x65, 0x72, 0x65, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73,
0x20, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x61, 0x73, 0x20, 0x69,
0x73, 0x22, 0x20, 0x62, 0x61, 0x73, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x6e,
0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x20, 0x6f,
0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f,
0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x69,
0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2c, 0x20, 0x73, 0x75,
0x70, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x73, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, 0x65, 0x6e, 0x68, 0x61, 0x6e,
0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x6f, 0x72, 0x20,
0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x2e, 0x0a, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x42, 0x61, 0x73, 0x69,
0x63, 0x20, 0x43, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x75,
0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x41,
0x6c, 0x6c, 0x20, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,
0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x22, 0x63, 0x68, 0x61, 0x72, 0x2a,
0x22, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65,
0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x22, 0x5f,
0x63, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x2d, 0x2d,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x63, 0x63,
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20,
0x22, 0x76, 0x6f, 0x69, 0x64, 0x2a, 0x22, 0x20, 0x77, 0x69, 0x6c, 0x6c,
0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64,
0x20, 0x62, 0x79, 0x20, 0x22, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x64, 0x61,
0x74, 0x61, 0x22, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x3d,
0x20, 0x7b, 0x0a, 0x20, 0x5b, 0x27, 0x76, 0x6f, 0x69, 0x64, 0x27, 0x5d,
0x20, 0x3d, 0x20, 0x27, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x63, 0x68,
0x61, 0x72, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62,
0x65, 0x72, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x69, 0x6e, 0x74, 0x27,
0x5d, 0x20, 0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27,
0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x27, 0x5d,
0x20, 0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c,
0x0a, 0x20, 0x5b, 0x27, 0x6c, 0x6f, 0x6e, 0x67, 0x27, 0x5d, 0x20, 0x3d,
0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c, 0x0a, 0x20,
0x5b, 0x27, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x27, 0x5d,
0x20, 0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c,
0x0a, 0x20, 0x5b, 0x27, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x27, 0x5d, 0x20,
0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c, 0x0a,
0x20, 0x5b, 0x27, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x27, 0x5d, 0x20,
0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c, 0x0a,
0x20, 0x5b, 0x27, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x74, 0x27, 0x5d, 0x20,
0x3d, 0x20, 0x27, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x27, 0x2c, 0x0a,
0x20, 0x5b, 0x27, 0x5f, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x27,
0x5d, 0x20, 0x3d, 0x20, 0x27, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x27,
0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x64, 0x61,
0x74, 0x61, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x75, 0x73, 0x65, 0x72,
0x64, 0x61, 0x74, 0x61, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x63, 0x68,
0x61, 0x72, 0x2a, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x73, 0x74, 0x72,
0x69, 0x6e, 0x67, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x76, 0x6f, 0x69,
0x64, 0x2a, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x75, 0x73, 0x65, 0x72,
0x64, 0x61, 0x74, 0x61, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x62, 0x6f,
0x6f, 0x6c, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x62, 0x6f, 0x6f, 0x6c,
0x65, 0x61, 0x6e, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x6c, 0x75, 0x61,
0x5f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x27, 0x5d, 0x20, 0x3d, 0x20,
0x27, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27,
0x4c, 0x55, 0x41, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x27, 0x5d, 0x20,
0x3d, 0x20, 0x27, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x27, 0x2c, 0x20, 0x20,
0x20, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6d,
0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x77,
0x69, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x20, 0x34, 0x2e,
0x30, 0x0a, 0x20, 0x5b, 0x27, 0x6c, 0x75, 0x61, 0x5f, 0x53, 0x74, 0x61,
0x74, 0x65, 0x2a, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x73, 0x74, 0x61,
0x74, 0x65, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x5f, 0x6c, 0x73, 0x74,
0x61, 0x74, 0x65, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x27, 0x73, 0x74, 0x61,
0x74, 0x65, 0x27, 0x2c, 0x0a, 0x20, 0x5b, 0x27, 0x6c, 0x75, 0x61, 0x5f,
0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x27, 0x5d, 0x20, 0x3d,
0x20, 0x27, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x27, 0x2c, 0x0a, 0x7d, 0x0a,
0x0a, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x63, 0x74, 0x79, 0x70,
0x65, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65,
0x72, 0x20, 0x3d, 0x20, 0x22, 0x6c, 0x75, 0x61, 0x5f, 0x4e, 0x75, 0x6d,
0x62, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x20, 0x3d, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x63,
0x68, 0x61, 0x72, 0x2a, 0x22, 0x2c, 0x0a, 0x20, 0x75, 0x73, 0x65, 0x72,
0x64, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x22, 0x76, 0x6f, 0x69, 0x64,
0x2a, 0x22, 0x2c, 0x0a, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e,
0x20, 0x3d, 0x20, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x22, 0x2c, 0x0a, 0x20,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x69, 0x6e, 0x74,
0x22, 0x2c, 0x0a, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20,
0x22, 0x6c, 0x75, 0x61, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x22,
0x2c, 0x0a, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72,
0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x6f,
0x20, 0x61, 0x20, 0x27, 0x72, 0x61, 0x77, 0x20, 0x70, 0x75, 0x73, 0x68,
0x27, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x74,
0x79, 0x70, 0x65, 0x73, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f,
0x72, 0x61, 0x77, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x20, 0x3d, 0x20, 0x7b,
0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f,
0x66, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e,
0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x0a, 0x2d, 0x2d, 0x20,
0x45, 0x61, 0x63, 0x68, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f,
0x72, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x73, 0x20, 0x74, 0x6f,
0x20, 0x61, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20,
0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x74,
0x6f, 0x72, 0x65, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x74, 0x61, 0x67,
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x5f, 0x75, 0x73, 0x65,
0x72, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a,
0x2d, 0x2d, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74,
0x79, 0x70, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61,
0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6f, 0x6c,
0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x0a, 0x5f, 0x63, 0x6f, 0x6c, 0x6c,
0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d,
0x20, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x79, 0x70,
0x65, 0x73, 0x0a, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d, 0x30, 0x7d,
0x0a, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70,
0x65, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x20, 0x3d, 0x20, 0x7b, 0x7d,
0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66,
0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x0a, 0x5f, 0x67, 0x6c,
0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73,
0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x4c, 0x69,
0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x63,
0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x0a, 0x5f, 0x67, 0x6c,
0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x20, 0x3d,
0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x4c, 0x69, 0x73, 0x74,
0x20, 0x6f, 0x66, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x6e,
0x61, 0x6d, 0x69, 0x6e, 0x67, 0x0a, 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d,
0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x5f, 0x65,
0x6e, 0x75, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e,
0x64, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x73,
0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65,
0x2c, 0x6f, 0x6c, 0x64, 0x2c, 0x6e, 0x65, 0x77, 0x20, 0x3d, 0x20, 0x73,
0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x25, 0x73,
0x2a, 0x28, 0x2e, 0x2d, 0x29, 0x25, 0x73, 0x2a, 0x40, 0x25, 0x73, 0x2a,
0x28, 0x2e, 0x2d, 0x29, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x29, 0x0a, 0x09,
0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x0a, 0x09, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x23,
0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x72, 0x65, 0x6e, 0x61,
0x6d, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x3b,
0x20, 0x69, 0x74, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62,
0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x72,
0x6d, 0x3a, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x40, 0x70,
0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e,
0x64, 0x0a, 0x09, 0x74, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x5f,
0x72, 0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2c, 0x7b, 0x6f, 0x6c,
0x64, 0x3d, 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x3d, 0x6e,
0x65, 0x77, 0x7d, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,
0x72, 0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x73, 0x29,
0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x67, 0x65,
0x74, 0x6e, 0x28, 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67,
0x29, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x20, 0x6d, 0x2c, 0x6e, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28,
0x73, 0x2c, 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x5b,
0x69, 0x5d, 0x2e, 0x6f, 0x6c, 0x64, 0x2c, 0x5f, 0x72, 0x65, 0x6e, 0x61,
0x6d, 0x69, 0x6e, 0x67, 0x5b, 0x69, 0x5d, 0x2e, 0x6e, 0x65, 0x77, 0x29,
0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x20, 0x7e, 0x3d, 0x20, 0x30,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x6d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d,
0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c,
0x65, 0x72, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20,
0x28, 0x73, 0x2c, 0x66, 0x29, 0x0a, 0x69, 0x66, 0x20, 0x5f, 0x63, 0x75,
0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x22, 0x2a, 0x2a, 0x2a,
0x63, 0x75, 0x72, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x6f,
0x72, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x69, 0x73, 0x20, 0x22,
0x2e, 0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x5f,
0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x29, 0x0a,
0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x64, 0x65, 0x62, 0x75, 0x67,
0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x29,
0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x5f, 0x4f, 0x55, 0x54, 0x50,
0x55, 0x54, 0x0a, 0x20, 0x5f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x20,
0x3d, 0x20, 0x5f, 0x53, 0x54, 0x44, 0x45, 0x52, 0x52, 0x0a, 0x20, 0x69,
0x66, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x31,
0x2c, 0x31, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x23, 0x27, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28,
0x22, 0x5c, 0x6e, 0x2a, 0x2a, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x3a,
0x20, 0x22, 0x2e, 0x2e, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73,
0x2c, 0x32, 0x29, 0x2e, 0x2e, 0x22, 0x2e, 0x5c, 0x6e, 0x5c, 0x6e, 0x22,
0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72,
0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x5f, 0x2c,
0x73, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28,
0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x22,
0x5e, 0x25, 0x73, 0x2a, 0x28, 0x2e, 0x2d, 0x5c, 0x6e, 0x29, 0x22, 0x29,
0x20, 0x2d, 0x2d, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20,
0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x20,
0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x3d, 0x3d, 0x6e, 0x69, 0x6c, 0x20,
0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x63, 0x75,
0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28,
0x73, 0x2c, 0x22, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61,
0x22, 0x2c, 0x22, 0x76, 0x6f, 0x69, 0x64, 0x2a, 0x22, 0x29, 0x20, 0x2d,
0x2d, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x27, 0x76, 0x6f, 0x69, 0x64, 0x2a, 0x27, 0x0a, 0x20, 0x20,
0x20, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c,
0x22, 0x5f, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x22,
0x63, 0x68, 0x61, 0x72, 0x2a, 0x22, 0x29, 0x20, 0x20, 0x2d, 0x2d, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20,
0x27, 0x63, 0x68, 0x61, 0x72, 0x2a, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x73,
0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x22, 0x5f,
0x6c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x2c, 0x22, 0x6c, 0x75, 0x61,
0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x22, 0x29, 0x20, 0x20, 0x2d,
0x2d, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x27, 0x6c, 0x75, 0x61, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x65,
0x2a, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28,
0x22, 0x43, 0x6f, 0x64, 0x65, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20,
0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x3a, 0x5c, 0x6e,
0x22, 0x2e, 0x2e, 0x73, 0x2e, 0x2e, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x0a,
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x66, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x22, 0x28, 0x66, 0x20, 0x69,
0x73, 0x20, 0x6e, 0x69, 0x6c, 0x29, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x22, 0x5c, 0x6e, 0x2a,
0x2a, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x20, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x20,
0x22, 0x2e, 0x2e, 0x66, 0x2e, 0x2e, 0x73, 0x2e, 0x2e, 0x22, 0x2e, 0x5c,
0x6e, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
0x72, 0x6e, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x5f, 0x4f, 0x55,
0x54, 0x50, 0x55, 0x54, 0x20, 0x3d, 0x20, 0x6f, 0x75, 0x74, 0x0a, 0x65,
0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x6d, 0x73,
0x67, 0x29, 0x0a, 0x20, 0x69, 0x66, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73,
0x2e, 0x71, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75,
0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x5f, 0x4f, 0x55, 0x54,
0x50, 0x55, 0x54, 0x0a, 0x20, 0x5f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54,
0x20, 0x3d, 0x20, 0x5f, 0x53, 0x54, 0x44, 0x45, 0x52, 0x52, 0x0a, 0x20,
0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x22, 0x5c, 0x6e, 0x2a, 0x2a, 0x20,
0x74, 0x6f, 0x6c, 0x75, 0x61, 0x20, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e,
0x67, 0x3a, 0x20, 0x22, 0x2e, 0x2e, 0x6d, 0x73, 0x67, 0x2e, 0x2e, 0x22,
0x2e, 0x5c, 0x6e, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x5f, 0x4f, 0x55,
0x54, 0x50, 0x55, 0x54, 0x20, 0x3d, 0x20, 0x6f, 0x75, 0x74, 0x0a, 0x65,
0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65,
0x3a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x66, 0x75,
0x6c, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x67, 0x74, 0x79, 0x70, 0x65,
0x20, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x2d, 0x2d, 0x69, 0x66, 0x20, 0x69,
0x73, 0x62, 0x61, 0x73, 0x69, 0x63, 0x28, 0x74, 0x29, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x0a, 0x09, 0x2d, 0x2d, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
0x6e, 0x20, 0x74, 0x0a, 0x09, 0x2d, 0x2d, 0x65, 0x6e, 0x64, 0x0a, 0x09,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66,
0x69, 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x29, 0x0a, 0x0a,
0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x5f, 0x75, 0x73, 0x65,
0x72, 0x74, 0x79, 0x70, 0x65, 0x5b, 0x66, 0x74, 0x5d, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79,
0x70, 0x65, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x74, 0x0a, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x66, 0x75, 0x6c, 0x6c,
0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x76, 0x61, 0x72, 0x28, 0x74,
0x79, 0x70, 0x65, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x6f, 0x72, 0x20, 0x74,
0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x76, 0x6f, 0x69, 0x64,
0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x09, 0x65, 0x6c,
0x73, 0x65, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66,
0x74, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65,
0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20,
0x66, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x74, 0x0a, 0x09, 0x09, 0x65,
0x6e, 0x64, 0x0a, 0x09, 0x09, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79,
0x70, 0x65, 0x5b, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x74,
0x79, 0x70, 0x65, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65,
0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6e,
0x75, 0x6d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x69, 0x73, 0x65, 0x6e, 0x75, 0x6d, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28,
0x74, 0x79, 0x70, 0x65, 0x29, 0x20, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x74,
0x79, 0x70, 0x65, 0x5d, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d,
0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x69, 0x66, 0x20, 0x62, 0x61,
0x73, 0x69, 0x63, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x62, 0x61, 0x73, 0x69,
0x63, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x20, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62,
0x28, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x27, 0x63, 0x6f, 0x6e, 0x73, 0x74,
0x20, 0x27, 0x2c, 0x27, 0x27, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x6d, 0x2c, 0x74, 0x20, 0x3d, 0x20, 0x61, 0x70, 0x70, 0x6c,
0x79, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x28, 0x27, 0x27, 0x2c,
0x20, 0x74, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62,
0x20, 0x3d, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5b, 0x74, 0x5d,
0x0a, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x2c, 0x5f,
0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x63, 0x74, 0x79, 0x70, 0x65, 0x5b,
0x62, 0x5d, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x2d, 0x2d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x20, 0x73, 0x74,
0x72, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61,
0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x20, 0x28, 0x73,
0x2c, 0x74, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c,
0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d, 0x30, 0x7d, 0x0a, 0x20, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x6c,
0x2e, 0x6e, 0x20, 0x3d, 0x20, 0x6c, 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31,
0x0a, 0x20, 0x20, 0x6c, 0x5b, 0x6c, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20,
0x73, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22,
0x22, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x70, 0x20, 0x3d, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x28, 0x2e,
0x2d, 0x29, 0x25, 0x73, 0x2a, 0x22, 0x2e, 0x2e, 0x74, 0x2e, 0x2e, 0x22,
0x25, 0x73, 0x2a, 0x22, 0x0a, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x73,
0x75, 0x62, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2b, 0x22, 0x2c,
0x22, 0x22, 0x29, 0x0a, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75,
0x62, 0x28, 0x73, 0x2c, 0x22, 0x25, 0x73, 0x2b, 0x24, 0x22, 0x2c, 0x22,
0x22, 0x29, 0x0a, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62,
0x28, 0x73, 0x2c, 0x70, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x6c, 0x2e, 0x6e,
0x20, 0x3d, 0x20, 0x6c, 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x20,
0x6c, 0x5b, 0x6c, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75,
0x62, 0x28, 0x73, 0x2c, 0x22, 0x28, 0x25, 0x73, 0x25, 0x73, 0x2a, 0x29,
0x24, 0x22, 0x2c, 0x22, 0x22, 0x29, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75,
0x72, 0x6e, 0x20, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d,
0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x74,
0x72, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61,
0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x2c, 0x20, 0x63, 0x6f,
0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x70, 0x61, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x63, 0x61,
0x73, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x43, 0x20, 0x63, 0x6f, 0x64,
0x65, 0x20, 0x28, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73,
0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70,
0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x65,
0x74, 0x63, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65,
0x72, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x5e, 0x27,
0x20, 0x28, 0x61, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f,
0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68,
0x65, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f,
0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x29, 0x0a,
0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69,
0x70, 0x73, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x73, 0x70, 0x61, 0x63,
0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73,
0x70, 0x6c, 0x69, 0x74, 0x5f, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x73, 0x28, 0x73, 0x2c, 0x20, 0x70, 0x61, 0x74, 0x29, 0x0a, 0x0a, 0x09,
0x73, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67,
0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a,
0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09, 0x73, 0x20, 0x3d, 0x20,
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
0x73, 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22,
0x22, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x20, 0x3d,
0x20, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x31, 0x0a,
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x66, 0x73, 0x20, 0x3d,
0x20, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65,
0x74, 0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d, 0x30, 0x7d, 0x0a, 0x0a, 0x09,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x64, 0x64,
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x28, 0x6f, 0x66, 0x73, 0x29, 0x0a,
0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d,
0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28,
0x73, 0x2c, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x62, 0x65, 0x67,
0x69, 0x6e, 0x2c, 0x20, 0x6f, 0x66, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x74,
0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73,
0x75, 0x62, 0x28, 0x74, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x22,
0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x74, 0x20, 0x3d, 0x20,
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
0x74, 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22,
0x22, 0x29, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x2e, 0x6e, 0x20, 0x3d,
0x20, 0x72, 0x65, 0x74, 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x09,
0x09, 0x72, 0x65, 0x74, 0x5b, 0x72, 0x65, 0x74, 0x2e, 0x6e, 0x5d, 0x20,
0x3d, 0x20, 0x74, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x77,
0x68, 0x69, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x73, 0x20, 0x3c, 0x3d, 0x20,
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x6c, 0x65, 0x6e, 0x28, 0x73,
0x29, 0x20, 0x64, 0x6f, 0x0a, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x73, 0x75, 0x62, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x6f, 0x66,
0x73, 0x2c, 0x20, 0x2d, 0x31, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x75, 0x62,
0x2c, 0x20, 0x22, 0x5e, 0x22, 0x2e, 0x2e, 0x70, 0x61, 0x74, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x61, 0x64, 0x64, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x28, 0x6f, 0x66, 0x73, 0x2d, 0x31, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6f,
0x66, 0x73, 0x20, 0x3d, 0x20, 0x6f, 0x66, 0x73, 0x2b, 0x65, 0x0a, 0x09,
0x09, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x62, 0x65, 0x67, 0x69,
0x6e, 0x20, 0x3d, 0x20, 0x6f, 0x66, 0x73, 0x0a, 0x09, 0x09, 0x65, 0x6c,
0x73, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
0x63, 0x68, 0x61, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x6f, 0x66, 0x73,
0x2c, 0x20, 0x6f, 0x66, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66,
0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x28, 0x22,
0x20, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x3d, 0x3d, 0x20,
0x22, 0x3c, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x09, 0x09,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x68, 0x61,
0x72, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x28, 0x22, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x22, 0x5e,
0x25, 0x62, 0x28, 0x29, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09,
0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x3d, 0x3d,
0x20, 0x22, 0x3c, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x22, 0x5e, 0x25, 0x62, 0x3c, 0x3e,
0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x62,
0x2c, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x75, 0x62, 0x2c, 0x20, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20,
0x6e, 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09,
0x09, 0x09, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x75, 0x6e, 0x74, 0x65, 0x72,
0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x3f, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x66, 0x73, 0x20,
0x3d, 0x20, 0x6f, 0x66, 0x73, 0x2b, 0x31, 0x0a, 0x09, 0x09, 0x09, 0x09,
0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x66,
0x73, 0x20, 0x3d, 0x20, 0x6f, 0x66, 0x73, 0x20, 0x2b, 0x20, 0x65, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x09, 0x09,
0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x66, 0x73,
0x20, 0x3d, 0x20, 0x6f, 0x66, 0x73, 0x2b, 0x31, 0x0a, 0x09, 0x09, 0x09,
0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09,
0x65, 0x6e, 0x64, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x5f, 0x74, 0x6f, 0x6b,
0x65, 0x6e, 0x28, 0x6f, 0x66, 0x73, 0x29, 0x0a, 0x09, 0x2d, 0x2d, 0x69,
0x66, 0x20, 0x72, 0x65, 0x74, 0x2e, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x30,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x09, 0x2d, 0x2d, 0x09, 0x72,
0x65, 0x74, 0x2e, 0x6e, 0x3d, 0x31, 0x0a, 0x09, 0x2d, 0x2d, 0x09, 0x72,
0x65, 0x74, 0x5b, 0x31, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x22, 0x0a, 0x09,
0x2d, 0x2d, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75,
0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x6e,
0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x20,
0x6f, 0x66, 0x20, 0x61, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x63,
0x61, 0x74, 0x20, 0x28, 0x74, 0x2c, 0x66, 0x2c, 0x6c, 0x2c, 0x6a, 0x73,
0x74, 0x72, 0x29, 0x0a, 0x09, 0x6a, 0x73, 0x74, 0x72, 0x20, 0x3d, 0x20,
0x6a, 0x73, 0x74, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x20, 0x22, 0x0a,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x27,
0x27, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x66,
0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x3c, 0x3d, 0x6c,
0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x2e,
0x2e, 0x74, 0x5b, 0x69, 0x5d, 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20,
0x69, 0x2b, 0x31, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x20, 0x3c,
0x3d, 0x20, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x20, 0x3d,
0x20, 0x73, 0x2e, 0x2e, 0x6a, 0x73, 0x74, 0x72, 0x20, 0x65, 0x6e, 0x64,
0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
0x6e, 0x20, 0x73, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20,
0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x6e, 0x61, 0x74, 0x65, 0x20,
0x61, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
0x72, 0x73, 0x2c, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e,
0x67, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x72, 0x75, 0x6c,
0x65, 0x73, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20,
0x28, 0x6c, 0x69, 0x6e, 0x65, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20,
0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x3c, 0x3d, 0x61, 0x72, 0x67,
0x2e, 0x6e, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x5f,
0x63, 0x6f, 0x6e, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74,
0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x5f, 0x63, 0x6f,
0x6e, 0x74, 0x2c, 0x27, 0x5b, 0x25, 0x28, 0x2c, 0x22, 0x5d, 0x27, 0x29,
0x20, 0x61, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74,
0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d,
0x2c, 0x22, 0x5e, 0x5b, 0x25, 0x61, 0x5f, 0x7e, 0x5d, 0x22, 0x29, 0x20,
0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69,
0x6e, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x2e, 0x2e,
0x20, 0x27, 0x20, 0x27, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x6e, 0x65,
0x20, 0x2e, 0x2e, 0x20, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d, 0x0a, 0x20,
0x20, 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d, 0x20, 0x7e,
0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
0x73, 0x75, 0x62, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d, 0x2c, 0x2d,
0x31, 0x2c, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x65,
0x6e, 0x64, 0x0a, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69,
0x6e, 0x64, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x61, 0x72, 0x67, 0x2e, 0x6e,
0x5d, 0x2c, 0x22, 0x5b, 0x25, 0x2f, 0x25, 0x29, 0x25, 0x3b, 0x25, 0x7b,
0x25, 0x7d, 0x5d, 0x24, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x20, 0x20, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x3d, 0x6e, 0x69, 0x6c, 0x20,
0x6c, 0x69, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20,
0x2e, 0x2e, 0x20, 0x27, 0x5c, 0x6e, 0x27, 0x0a, 0x20, 0x65, 0x6e, 0x64,
0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x69, 0x6e,
0x65, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6f, 0x75,
0x74, 0x70, 0x75, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75,
0x74, 0x20, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c,
0x65, 0x20, 0x69, 0x3c, 0x3d, 0x61, 0x72, 0x67, 0x2e, 0x6e, 0x20, 0x64,
0x6f, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x5f, 0x63, 0x6f, 0x6e, 0x74,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x74, 0x72,
0x66, 0x69, 0x6e, 0x64, 0x28, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x2c, 0x27,
0x5b, 0x25, 0x28, 0x2c, 0x22, 0x5d, 0x27, 0x29, 0x20, 0x61, 0x6e, 0x64,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e,
0x64, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d, 0x2c, 0x22, 0x5e, 0x5b,
0x25, 0x61, 0x5f, 0x7e, 0x5d, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x0a, 0x09, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28,
0x27, 0x20, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x69,
0x5d, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x5b,
0x69, 0x5d, 0x20, 0x7e, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x20, 0x3d,
0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x61, 0x72, 0x67, 0x5b,
0x69, 0x5d, 0x2c, 0x2d, 0x31, 0x2c, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b,
0x31, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x69, 0x66, 0x20, 0x73,
0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x61,
0x72, 0x67, 0x2e, 0x6e, 0x5d, 0x2c, 0x22, 0x5b, 0x25, 0x2f, 0x25, 0x29,
0x25, 0x3b, 0x25, 0x7b, 0x25, 0x7d, 0x5d, 0x24, 0x22, 0x29, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x3d,
0x6e, 0x69, 0x6c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x27, 0x5c,
0x6e, 0x27, 0x29, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64,
0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67,
0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f,
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x28, 0x70, 0x74, 0x79, 0x70,
0x65, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x0a, 0x09, 0x69,
0x66, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72,
0x74, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x5f, 0x68,
0x6f, 0x6f, 0x6b, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x67, 0x65, 0x74, 0x5f,
0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x74,
0x68, 0x6f, 0x64, 0x73, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x70, 0x74,
0x79, 0x70, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79,
0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x5f, 0x68, 0x6f, 0x6f,
0x6b, 0x28, 0x70, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x6e, 0x61, 0x6d,
0x65, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x69, 0x66,
0x20, 0x70, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x64,
0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x20, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x2c, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x09,
0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x67, 0x65, 0x74,
0x5f, 0x22, 0x2e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x22, 0x73,
0x65, 0x74, 0x5f, 0x22, 0x2e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x09,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x70, 0x74, 0x79,
0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x74, 0x22, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
0x20, 0x73, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x0a, 0x09, 0x09, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20,
0x22, 0x73, 0x65, 0x74, 0x22, 0x2e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x2e, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x73, 0x74, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x29, 0x2e, 0x2e, 0x73, 0x74, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x6e, 0x61, 0x6d, 0x65,
0x2c, 0x20, 0x32, 0x2c, 0x20, 0x2d, 0x31, 0x29, 0x0a, 0x09, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x70, 0x74, 0x79, 0x70, 0x65,
0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61,
0x64, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x6e,
0x61, 0x6d, 0x65, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x09, 0x09,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65,
0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68,
0x6f, 0x6f, 0x6b, 0x73, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c,
0x6c, 0x65, 0x64, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, 0x66,
0x74, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69,
0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x24, 0x5b, 0x69, 0x63, 0x68,
0x6c, 0x5d, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63,
0x74, 0x69, 0x76, 0x65, 0x73, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, 0x72, 0x69,
0x67, 0x68, 0x74, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x70,
0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e,
0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
0x2d, 0x2d, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65,
0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70,
0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x0a, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x70, 0x72, 0x6f,
0x63, 0x65, 0x73, 0x73, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x70, 0x29,
0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x70, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x20,
0x68, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20,
0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x66,
0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6b, 0x67, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c,
0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x76, 0x65, 0x72,
0x79, 0x20, 0x24, 0x69, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x64, 0x69, 0x72,
0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x61,
0x6b, 0x65, 0x73, 0x20, 0x61, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x27, 0x63, 0x6f,
0x64, 0x65, 0x27, 0x20, 0x69, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x65, 0x78,
0x74, 0x72, 0x61, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20,
0x74, 0x6f, 0x20, 0x24, 0x69, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x20, 0x6e,
0x6f, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65,
0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x74, 0x2c, 0x20, 0x66, 0x69, 0x6c,
0x65, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a,
0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c,
0x6c, 0x65, 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x70, 0x72,
0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x79,
0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73,
0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x28, 0x6c,
0x69, 0x6b, 0x65, 0x20, 0x27, 0x24, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x69,
0x6e, 0x67, 0x27, 0x2c, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x62, 0x65, 0x66,
0x6f, 0x72, 0x65, 0x20, 0x70, 0x61, 0x72, 0x73, 0x69, 0x6e, 0x67, 0x20,
0x74, 0x68, 0x65, 0x20, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x63,
0x6f, 0x64, 0x65, 0x2e, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x61, 0x6b, 0x65,
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67,
0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,
0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x63,
0x6f, 0x64, 0x65, 0x27, 0x20, 0x6b, 0x65, 0x79, 0x2e, 0x20, 0x6e, 0x6f,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70,
0x72, 0x65, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x68, 0x6f, 0x6f, 0x6b,
0x28, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x0a, 0x65,
0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65,
0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x73, 0x74, 0x61,
0x72, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72,
0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x68, 0x6f, 0x6f,
0x6b, 0x28, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c, 0x6c,
0x65, 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x72, 0x69,
0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65,
0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x0a, 0x2d, 0x2d, 0x20,
0x74, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x61,
0x63, 0x6b, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x6f,
0x73, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x68, 0x6f,
0x6f, 0x6b, 0x28, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x29, 0x0a,
0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61,
0x6c, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x27, 0x67,
0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f,
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x27, 0x20, 0x74, 0x6f, 0x20,
0x67, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x68,
0x6f, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69,
0x65, 0x76, 0x65, 0x20, 0x61, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72,
0x74, 0x79, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x72, 0x64,
0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x74, 0x73, 0x20, 0x74,
0x79, 0x70, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74,
0x79, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x5f, 0x68, 0x6f,
0x6f, 0x6b, 0x28, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c,
0x6c, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61,
0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a,
0x64, 0x6f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20,
0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
0x0a, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e,
0x69, 0x6c, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x75, 0x62,
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x5f, 0x68,
0x6f, 0x6f, 0x6b, 0x28, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x66,
0x72, 0x6f, 0x6d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x46, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x73, 0x75, 0x70, 0x63, 0x6f, 0x64,
0x65, 0x2c, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68,
0x65, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68,
0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69,
0x73, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x0a, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x5f, 0x63, 0x61,
0x6c, 0x6c, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x66, 0x29, 0x0a, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c, 0x6c,
0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x73, 0x75,
0x70, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72,
0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f,
0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x0a,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x6f, 0x73,
0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28,
0x66, 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20,
0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72,
0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6f,
0x75, 0x74, 0x70, 0x75, 0x74, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x70, 0x61, 0x63,
0x6b, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
0x2d, 0x2d, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x74, 0x6f,
0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x20, 0x65,
0x72, 0x72, 0x6f, 0x72, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x75,
0x74, 0x70, 0x75, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x68,
0x6f, 0x6f, 0x6b, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x09, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x75, 0x73, 0x74,
0x6f, 0x6d, 0x20, 0x70, 0x75, 0x73, 0x68, 0x65, 0x72, 0x73, 0x0a, 0x0a,
0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x69, 0x73,
0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d,
0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x20, 0x3d,
0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a,
0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b,
0x7d, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x73, 0x5f, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b,
0x7d, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b,
0x7d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
0x5f, 0x62, 0x61, 0x73, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e,
0x63, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f,
0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b,
0x74, 0x5d, 0x0a, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x63,
0x6c, 0x61, 0x73, 0x73, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x69, 0x66,
0x20, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x5b, 0x63, 0x6c, 0x61, 0x73, 0x73,
0x2e, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75,
0x6e, 0x63, 0x73, 0x5b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x74, 0x79,
0x70, 0x65, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09,
0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f,
0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b,
0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x62, 0x74, 0x79, 0x70, 0x65, 0x5d,
0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f,
0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x73,
0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x28, 0x74,
0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68,
0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20,
0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x70, 0x75,
0x73, 0x68, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, 0x72,
0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65,
0x28, 0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f,
0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20,
0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x74, 0x6f,
0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x67, 0x65, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x5f,
0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22,
0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e,
0x20, 0x74, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, 0x72, 0x20,
0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x28,
0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x73, 0x5f,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, 0x6f,
0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x75,
0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, 0x65, 0x6e, 0x64,
0x0a
};
unsigned int lua_basic_lua_len = 9073;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,295 @@
static const unsigned char lua_enumerate_lua[] = {
0x2d, 0x2d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x3a, 0x20, 0x65, 0x6e,
0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e,
0x20, 0x62, 0x79, 0x20, 0x57, 0x61, 0x6c, 0x64, 0x65, 0x6d, 0x61, 0x72,
0x20, 0x43, 0x65, 0x6c, 0x65, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x65,
0x43, 0x47, 0x72, 0x61, 0x66, 0x2f, 0x50, 0x55, 0x43, 0x2d, 0x52, 0x69,
0x6f, 0x0a, 0x2d, 0x2d, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x31, 0x39, 0x39,
0x38, 0x0a, 0x2d, 0x2d, 0x20, 0x24, 0x49, 0x64, 0x3a, 0x20, 0x65, 0x6e,
0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x2e, 0x6c, 0x75, 0x61, 0x2c,
0x76, 0x20, 0x31, 0x2e, 0x33, 0x20, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x30,
0x31, 0x2f, 0x32, 0x34, 0x20, 0x32, 0x30, 0x3a, 0x34, 0x31, 0x3a, 0x31,
0x35, 0x20, 0x63, 0x65, 0x6c, 0x65, 0x73, 0x20, 0x45, 0x78, 0x70, 0x20,
0x24, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63,
0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20,
0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x3b, 0x20, 0x79, 0x6f,
0x75, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e,
0x64, 0x2f, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x20,
0x69, 0x74, 0x2e, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73,
0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6e, 0x64,
0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x20,
0x22, 0x61, 0x73, 0x20, 0x69, 0x73, 0x22, 0x20, 0x62, 0x61, 0x73, 0x69,
0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68,
0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x73,
0x20, 0x6e, 0x6f, 0x20, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63,
0x65, 0x2c, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x0a, 0x2d, 0x2d, 0x20,
0x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, 0x0a, 0x2d, 0x2d,
0x20, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x63,
0x6c, 0x61, 0x73, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x70, 0x72,
0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x68,
0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20,
0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x64, 0x3a, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20,
0x20, 0x7b, 0x69, 0x7d, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20,
0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x20,
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x0a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45,
0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x7b,
0x0a, 0x7d, 0x0a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75, 0x6d,
0x65, 0x72, 0x61, 0x74, 0x65, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75,
0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x0a, 0x73, 0x65, 0x74, 0x6d, 0x65,
0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x2c, 0x63,
0x6c, 0x61, 0x73, 0x73, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29,
0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
0x72, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63,
0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74,
0x65, 0x3a, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x20, 0x28,
0x70, 0x72, 0x65, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f,
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73,
0x73, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x70, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x70, 0x72, 0x65, 0x20, 0x6f, 0x72,
0x20, 0x27, 0x27, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e,
0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x6c, 0x61,
0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e,
0x63, 0x75, 0x72, 0x72, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20,
0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20,
0x09, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x6e, 0x61,
0x6d, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73,
0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x69,
0x5d, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x0a, 0x09, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28,
0x70, 0x72, 0x65, 0x2e, 0x2e, 0x27, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f,
0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x28, 0x74, 0x6f, 0x6c,
0x75, 0x61, 0x5f, 0x53, 0x2c, 0x22, 0x27, 0x2e, 0x2e, 0x73, 0x65, 0x6c,
0x66, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x2e,
0x2e, 0x27, 0x22, 0x2c, 0x27, 0x2e, 0x2e, 0x6e, 0x73, 0x70, 0x61, 0x63,
0x65, 0x2e, 0x2e, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x2e, 0x2e,
0x27, 0x29, 0x3b, 0x27, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x50, 0x72,
0x69, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x0a, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x70,
0x72, 0x69, 0x6e, 0x74, 0x20, 0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2c,
0x63, 0x6c, 0x6f, 0x73, 0x65, 0x29, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e,
0x74, 0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x2e, 0x22, 0x45, 0x6e,
0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x7b, 0x22, 0x29, 0x0a, 0x20,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2e,
0x2e, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x2e,
0x2e, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20,
0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69,
0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74,
0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x2e, 0x22, 0x20, 0x27, 0x22,
0x2e, 0x2e, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x2e, 0x2e, 0x22,
0x27, 0x28, 0x22, 0x2e, 0x2e, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x2e, 0x2e, 0x22, 0x29, 0x2c,
0x22, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31,
0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74,
0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x2e, 0x22, 0x7d, 0x22, 0x2e,
0x2e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x6d,
0x69, 0x74, 0x65, 0x6e, 0x75, 0x6d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74,
0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x20, 0x6f,
0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x69, 0x6e, 0x74, 0x20, 0x74,
0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e, 0x20,
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
0x74, 0x79, 0x70, 0x65, 0x2c, 0x22, 0x3a, 0x3a, 0x22, 0x2c, 0x22, 0x5f,
0x22, 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20, 0x28, 0x6c, 0x75, 0x61,
0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x20, 0x4c, 0x2c, 0x20, 0x69,
0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x64,
0x65, 0x66, 0x2c, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x45, 0x72,
0x72, 0x6f, 0x72, 0x2a, 0x20, 0x65, 0x72, 0x72, 0x29, 0x3b, 0x22, 0x29,
0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61,
0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65, 0x6e, 0x75,
0x6d, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20,
0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
0x74, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75,
0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x73, 0x75, 0x70, 0x63, 0x6f,
0x64, 0x65, 0x20, 0x28, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x5f, 0x67,
0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e,
0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x69, 0x6c,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x5f, 0x67, 0x6c, 0x6f,
0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65,
0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61,
0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x09, 0x6f, 0x75,
0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x69, 0x6e, 0x74, 0x20, 0x74, 0x6f,
0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x73,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73,
0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x3a, 0x3a,
0x22, 0x2c, 0x22, 0x5f, 0x22, 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20,
0x28, 0x6c, 0x75, 0x61, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x20,
0x4c, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x2c, 0x20, 0x69,
0x6e, 0x74, 0x20, 0x64, 0x65, 0x66, 0x2c, 0x20, 0x74, 0x6f, 0x6c, 0x75,
0x61, 0x5f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2a, 0x20, 0x65, 0x72, 0x72,
0x29, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x28, 0x22, 0x7b, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70,
0x75, 0x74, 0x28, 0x22, 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x6f, 0x6c,
0x75, 0x61, 0x5f, 0x69, 0x73, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28,
0x4c, 0x2c, 0x6c, 0x6f, 0x2c, 0x64, 0x65, 0x66, 0x2c, 0x65, 0x72, 0x72,
0x29, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b,
0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28,
0x22, 0x6c, 0x75, 0x61, 0x5f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20,
0x76, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f,
0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x4c, 0x2c, 0x6c,
0x6f, 0x2c, 0x64, 0x65, 0x66, 0x29, 0x3b, 0x22, 0x29, 0x0a, 0x09, 0x09,
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x72, 0x65, 0x74, 0x75,
0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x20, 0x3e, 0x3d, 0x20, 0x22, 0x20,
0x2e, 0x2e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x69, 0x6e, 0x20,
0x2e, 0x2e, 0x20, 0x22, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x76, 0x61,
0x6c, 0x20, 0x3c, 0x3d, 0x20, 0x22, 0x20, 0x2e, 0x2e, 0x73, 0x65, 0x6c,
0x66, 0x2e, 0x6d, 0x61, 0x78, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x2e, 0x30,
0x3b, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x28, 0x22, 0x7d, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65,
0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63,
0x74, 0x6f, 0x72, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x5f, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20,
0x28, 0x74, 0x2c, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
0x20, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c,
0x65, 0x28, 0x74, 0x2c, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75,
0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x29, 0x0a, 0x20, 0x61, 0x70, 0x70,
0x65, 0x6e, 0x64, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x61, 0x70, 0x70, 0x65,
0x6e, 0x64, 0x65, 0x6e, 0x75, 0x6d, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x20,
0x69, 0x66, 0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7e,
0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09,
0x69, 0x66, 0x20, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7e, 0x3d,
0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x2e, 0x6e,
0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61,
0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73,
0x65, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e,
0x73, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x63, 0x75, 0x72, 0x72, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x29, 0x0a, 0x09,
0x09, 0x09, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x28, 0x22, 0x56,
0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x22, 0x2e, 0x2e, 0x6e,
0x73, 0x2e, 0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x2e,
0x22, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3c, 0x61,
0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x20, 0x65, 0x6e, 0x75,
0x6d, 0x3e, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72,
0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x2d, 0x6f,
0x6e, 0x6c, 0x79, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x56, 0x61, 0x72,
0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61,
0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x69, 0x6e,
0x74, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65,
0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64,
0x0a, 0x09, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x72,
0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43,
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72,
0x72, 0x0a, 0x09, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x61,
0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x65,
0x6e, 0x74, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x6d, 0x65, 0x6d, 0x62,
0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x0a, 0x09, 0x09,
0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63,
0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x3a, 0x63, 0x68, 0x65, 0x63,
0x6b, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63,
0x65, 0x73, 0x73, 0x28, 0x29, 0x0a, 0x09, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x0a, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72,
0x75, 0x63, 0x74, 0x6f, 0x72, 0x0a, 0x2d, 0x2d, 0x20, 0x45, 0x78, 0x70,
0x65, 0x63, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x69,
0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65,
0x72, 0x61, 0x74, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x0a, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, 0x75, 0x6d, 0x65,
0x72, 0x61, 0x74, 0x65, 0x20, 0x28, 0x6e, 0x2c, 0x62, 0x2c, 0x76, 0x61,
0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x62, 0x20, 0x3d, 0x20,
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
0x62, 0x2c, 0x20, 0x22, 0x2c, 0x5b, 0x25, 0x73, 0x5c, 0x6e, 0x5d, 0x2a,
0x7d, 0x22, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x7d, 0x22, 0x29, 0x20, 0x2d,
0x2d, 0x20, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20,
0x6c, 0x61, 0x73, 0x74, 0x20, 0x27, 0x2c, 0x27, 0x0a, 0x09, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69,
0x74, 0x28, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x62, 0x2c, 0x32,
0x2c, 0x2d, 0x32, 0x29, 0x2c, 0x27, 0x2c, 0x27, 0x29, 0x20, 0x2d, 0x2d,
0x20, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x62,
0x72, 0x61, 0x63, 0x65, 0x73, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x65, 0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d, 0x30, 0x7d, 0x0a,
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
0x6d, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09,
0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x64,
0x6f, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x74,
0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x74, 0x5b, 0x69,
0x5d, 0x2c, 0x27, 0x3d, 0x27, 0x29, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x64,
0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69,
0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x65,
0x2e, 0x6e, 0x20, 0x3d, 0x20, 0x65, 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31,
0x0a, 0x09, 0x09, 0x65, 0x5b, 0x65, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20,
0x74, 0x74, 0x5b, 0x31, 0x5d, 0x0a, 0x09, 0x09, 0x74, 0x74, 0x5b, 0x32,
0x5d, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x28, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66,
0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x69,
0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x74, 0x74,
0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x20, 0x0a, 0x20, 0x20, 0x09, 0x09, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d,
0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x64, 0x76, 0x61,
0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6c, 0x65,
0x63, 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09,
0x09, 0x69, 0x66, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3e, 0x20,
0x6d, 0x61, 0x78, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74,
0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3c, 0x20, 0x6d, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x20, 0x3d,
0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64,
0x0a, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x09,
0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x74, 0x20,
0x6c, 0x75, 0x61, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x0a, 0x09, 0x69,
0x20, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x65, 0x2e, 0x6c, 0x6e, 0x61,
0x6d, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x09, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x20, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74,
0x63, 0x75, 0x72, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
0x65, 0x28, 0x29, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x65,
0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74,
0x28, 0x65, 0x5b, 0x69, 0x5d, 0x2c, 0x27, 0x40, 0x27, 0x29, 0x0a, 0x09,
0x09, 0x65, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x5b, 0x31, 0x5d,
0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x5b,
0x32, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x74,
0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x72,
0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x28, 0x74, 0x5b, 0x31, 0x5d,
0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x2e,
0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20,
0x74, 0x5b, 0x32, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x5b, 0x31, 0x5d,
0x0a, 0x09, 0x09, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65,
0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x20, 0x6e, 0x73, 0x2e, 0x2e, 0x65, 0x5b,
0x69, 0x5d, 0x20, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x6e, 0x73, 0x2e, 0x2e,
0x65, 0x5b, 0x69, 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20,
0x69, 0x2b, 0x31, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x2e,
0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x0a, 0x09, 0x65, 0x2e,
0x6d, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x0a, 0x09, 0x65,
0x2e, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x0a, 0x09,
0x69, 0x66, 0x20, 0x6e, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73,
0x5b, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09,
0x09, 0x54, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x28, 0x22, 0x69, 0x6e,
0x74, 0x20, 0x22, 0x2e, 0x2e, 0x6e, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64,
0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x45, 0x6e,
0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x28, 0x65, 0x2c, 0x20, 0x76,
0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a
};
unsigned int lua_enumerate_lua_len = 3493;

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ _basic = {
['unsigned'] = 'number',
['float'] = 'number',
['double'] = 'number',
['size_t'] = 'number',
['_cstring'] = 'string',
['_userdata'] = 'userdata',
['char*'] = 'string',
@ -66,6 +67,8 @@ _global_enums = {}
-- List of auto renaming
_renaming = {}
_enums = {}
function appendrenaming (s)
local b,e,old,new = strfind(s,"%s*(.-)%s*@%s*(.-)%s*$")
if not b then
@ -145,6 +148,11 @@ function typevar(type)
end
end
-- is enum
function isenumtype (type)
return _enums[type]
end
-- check if basic type
function isbasic (type)
local t = gsub(type,'const ','')
@ -382,6 +390,7 @@ end
_push_functions = {}
_is_functions = {}
_enums = {}
_to_functions = {}
_base_push_functions = {}
@ -410,5 +419,8 @@ function get_to_function(t)
end
function get_is_function(t)
if _enums[t] then
return "tolua_is" .. t
end
return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype"
end

View File

@ -227,6 +227,8 @@ function classDeclaration:outchecktype (narg)
--else
return '!tolua_istable(tolua_S,'..narg..',0,&tolua_err)'
--end
elseif isenumtype(self.type) ~= nil then
return '!tolua_is'..self.type..'(tolua_S,'..narg..','..def..',&tolua_err)'
elseif t then
return '!tolua_is'..t..'(tolua_S,'..narg..','..def..',&tolua_err)'
else

View File

@ -48,6 +48,25 @@ function classEnumerate:print (ident,close)
print(ident.."}"..close)
end
function emitenumprototype(type)
output("int tolua_is" .. string.gsub(type,"::","_") .. " (lua_State* L, int lo, int def, tolua_Error* err);")
end
_global_output_enums = {}
-- write support code
function classEnumerate:supcode ()
if _global_output_enums[self.name] == nil then
_global_output_enums[self.name] = 1
output("int tolua_is" .. string.gsub(self.name,"::","_") .. " (lua_State* L, int lo, int def, tolua_Error* err)")
output("{")
output("if (!tolua_isnumber(L,lo,def,err)) return 0;")
output("lua_Number val = tolua_tonumber(L,lo,def);")
output("return val >= " .. self.min .. ".0 && val <= " ..self.max .. ".0;")
output("}")
end
end
-- Internal constructor
function _Enumerate (t,varname)
setmetatable(t,classEnumerate)
@ -67,40 +86,57 @@ function _Enumerate (t,varname)
t.access = parent.curr_member_access
t.global_access = t:check_public_access()
end
return t
return t
end
-- Constructor
-- Expects a string representing the enumerate body
function Enumerate (n,b,varname)
b = string.gsub(b, ",[%s\n]*}", "\n}") -- eliminate last ','
local t = split(strsub(b,2,-2),',') -- eliminate braces
local i = 1
local e = {n=0}
while t[i] do
local tt = split(t[i],'=') -- discard initial value
e.n = e.n + 1
e[e.n] = tt[1]
i = i+1
end
-- set lua names
i = 1
e.lnames = {}
local ns = getcurrnamespace()
while e[i] do
local t = split(e[i],'@')
e[i] = t[1]
if not t[2] then
t[2] = applyrenaming(t[1])
local t = split(strsub(b,2,-2),',') -- eliminate braces
local i = 1
local e = {n=0}
local value = 0
local min = 0
local max = 0
while t[i] do
local tt = split(t[i],'=') -- discard initial value
e.n = e.n + 1
e[e.n] = tt[1]
tt[2] = tonumber(tt[2])
if tt[2] == nil then
tt[2] = value
end
value = tt[2] + 1 -- advance the selected value
if tt[2] > max then
max = tt[2]
end
e.lnames[i] = t[2] or t[1]
_global_enums[ ns..e[i] ] = (ns..e[i])
i = i+1
end
if tt[2] < min then
min = tt[2]
end
i = i+1
end
-- set lua names
i = 1
e.lnames = {}
local ns = getcurrnamespace()
while e[i] do
local t = split(e[i],'@')
e[i] = t[1]
if not t[2] then
t[2] = applyrenaming(t[1])
end
e.lnames[i] = t[2] or t[1]
_global_enums[ ns..e[i] ] = (ns..e[i])
i = i+1
end
e.name = n
e.min = min
e.max = max
if n ~= "" then
_enums[n] = true
Typedef("int "..n)
end
return _Enumerate(e, varname)
return _Enumerate(e, varname)
end

View File

@ -50,11 +50,20 @@ end
-- Write binding function
-- Outputs C/C++ binding function.
function classFunction:supcode (local_constructor)
local overload = strsub(self.cname,-2,-1) - 1 -- indicate overloaded func
local nret = 0 -- number of returned values
local class = self:inclass()
local _,_,static = strfind(self.mod,'^%s*(static)')
-- prototypes for enum functions
if self.args[1].type ~= 'void' then
local i=1
while self.args[i] do
if isenumtype(self.args[i].type) then
emitenumprototype(self.args[i].type)
end
i = i+1
end
end
if class then
if self.name == 'new' and self.parent.flags.pure_virtual then

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ typedef unsigned int UInt32;
typedef unsigned short UInt16;
$cfile "../Vector3.h"
$cfile "../ChunkDef.h"
$cfile "../BiomeDef.h"
@ -26,6 +27,7 @@ $cfile "WebPlugin.h"
$cfile "LuaWindow.h"
$cfile "../BlockID.h"
$cfile "../BlockInfo.h"
$cfile "../StringUtils.h"
$cfile "../Defines.h"
$cfile "../ChatColor.h"
@ -57,12 +59,10 @@ $cfile "../BlockEntities/HopperEntity.h"
$cfile "../BlockEntities/JukeboxEntity.h"
$cfile "../BlockEntities/NoteEntity.h"
$cfile "../BlockEntities/SignEntity.h"
$cfile "../BlockEntities/MobHeadEntity.h"
$cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h"
$cfile "../Root.h"
$cfile "../Vector3f.h"
$cfile "../Vector3d.h"
$cfile "../Vector3i.h"
$cfile "../Matrix4f.h"
$cfile "../Cuboid.h"
$cfile "../BoundingBox.h"
$cfile "../Tracer.h"
@ -75,6 +75,7 @@ $cfile "../Mobs/Monster.h"
$cfile "../CompositeChat.h"
$cfile "../Map.h"
$cfile "../MapManager.h"
$cfile "../Scoreboard.h"
@ -93,4 +94,10 @@ typedef unsigned char Byte;
// Aliases
$renaming Vector3<double> @ Vector3d
$renaming Vector3<float> @ Vector3f
$renaming Vector3<int> @ Vector3i

View File

@ -0,0 +1,275 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "DeprecatedBindings.h"
#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
#include "Plugin.h"
#include "PluginLua.h"
#include "PluginManager.h"
#include "LuaWindow.h"
#include "LuaChunkStay.h"
#include "../BlockInfo.h"
/* get function: g_BlockLightValue */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockLightValue
static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
{
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockSpreadLightFalloff */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockSpreadLightFalloff
static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushnumber(tolua_S, (lua_Number)cBlockInfo::GetSpreadLightFalloff((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockTransparent */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockTransparent
static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockOneHitDig */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockOneHitDig
static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, cBlockInfo::IsOneHitDig((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockPistonBreakable */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable
static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, cBlockInfo::IsPistonBreakable((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockIsSnowable */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable
static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, cBlockInfo::IsSnowable((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockRequiresSpecialTool */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool
static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, cBlockInfo::RequiresSpecialTool((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockIsSolid */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid
static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, (bool)cBlockInfo::IsSolid((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockFullyOccupiesVoxel */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockFullyOccupiesVoxel
static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
{
int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
tolua_error(tolua_S, "array indexing out of range.", NULL);
}
tolua_pushboolean(tolua_S, (bool)cBlockInfo::FullyOccupiesVoxel((BLOCKTYPE)BlockType));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
void DeprecatedBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, NULL);
tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, NULL);
tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, NULL);
tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, NULL);
tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, NULL);
tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, NULL);
tolua_array(tolua_S, "g_BlockRequiresSpecialTool", tolua_get_AllToLua_g_BlockRequiresSpecialTool, NULL);
tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, NULL);
tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, NULL);
tolua_endmodule(tolua_S);
}

View File

@ -0,0 +1,8 @@
#pragma once
struct lua_State;
class DeprecatedBindings
{
public:
static void Bind( lua_State* tolua_S );
};

View File

@ -131,9 +131,6 @@ void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPo
void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
// DEBUG:
LOGD("LuaChunkStay: Chunk [%d, %d] is now available, calling the callback...", a_ChunkX, a_ChunkZ);
cPluginLua::cOperation Op(m_Plugin);
Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ);
}

View File

@ -11,9 +11,11 @@ extern "C"
#include "lua/src/lualib.h"
}
#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
#include "Bindings.h"
#include "ManualBindings.h"
#include "DeprecatedBindings.h"
// fwd: SQLite/lsqlite3.c
extern "C"
@ -93,11 +95,20 @@ void cLuaState::Create(void)
}
m_LuaState = lua_open();
luaL_openlibs(m_LuaState);
m_IsOwned = true;
}
void cLuaState::RegisterAPILibs(void)
{
tolua_AllToLua_open(m_LuaState);
ManualBindings::Bind(m_LuaState);
DeprecatedBindings::Bind(m_LuaState);
luaopen_lsqlite3(m_LuaState);
luaopen_lxp(m_LuaState);
m_IsOwned = true;
}
@ -469,6 +480,18 @@ void cLuaState::Push(cEntity * a_Entity)
void cLuaState::Push(cProjectileEntity * a_ProjectileEntity)
{
ASSERT(IsValid());
tolua_pushusertype(m_LuaState, a_ProjectileEntity, "cProjectileEntity");
m_NumCurrentFunctionArgs += 1;
}
void cLuaState::Push(cMonster * a_Monster)
{
ASSERT(IsValid());
@ -675,12 +698,14 @@ void cLuaState::Push(Vector3i * a_Vector)
void cLuaState::Push(void * a_Ptr)
{
UNUSED(a_Ptr);
ASSERT(IsValid());
// Investigate the cause of this - what is the callstack?
LOGWARNING("Lua engine encountered an error - attempting to push a plain pointer");
// One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them
LOGWARNING("Lua engine: attempting to push a plain pointer, pushing nil instead.");
LOGWARNING("This indicates an unimplemented part of MCS bindings");
LogStackTrace();
ASSERT(!"A plain pointer should never be pushed on Lua stack");
lua_pushnil(m_LuaState);
m_NumCurrentFunctionArgs += 1;
@ -714,7 +739,7 @@ void cLuaState::Push(cBlockEntity * a_BlockEntity)
void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal)
{
a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);
}
@ -723,11 +748,13 @@ void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
void cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{
if (lua_isstring(m_LuaState, a_StackPos))
size_t len = 0;
const char * data = lua_tolstring(m_LuaState, a_StackPos, &len);
if (data != NULL)
{
a_ReturnedVal = tolua_tocppstring(m_LuaState, a_StackPos, a_ReturnedVal.c_str());
a_Value.assign(data, len);
}
}
@ -735,7 +762,7 @@ void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
{
@ -747,7 +774,7 @@ void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal)
void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
{
@ -1067,20 +1094,20 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status)
void cLuaState::LogStackTrace(void)
void cLuaState::LogStackTrace(int a_StartingDepth)
{
LogStackTrace(m_LuaState);
LogStackTrace(m_LuaState, a_StartingDepth);
}
void cLuaState::LogStackTrace(lua_State * a_LuaState)
void cLuaState::LogStackTrace(lua_State * a_LuaState, int a_StartingDepth)
{
LOGWARNING("Stack trace:");
lua_Debug entry;
int depth = 0;
int depth = a_StartingDepth;
while (lua_getstack(a_LuaState, depth, &entry))
{
lua_getinfo(a_LuaState, "Sln", &entry);
@ -1272,7 +1299,9 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
{
UNUSED(a_Header); // The param seems unused when compiling for release, so the compiler warns
LOGD((a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
// Format string consisting only of %s is used to appease the compiler
LOGD("%s",(a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
for (int i = lua_gettop(a_LuaState); i > 0; i--)
{
AString Value;
@ -1297,7 +1326,7 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
{
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
LogStackTrace(a_LuaState);
LogStackTrace(a_LuaState, 1);
return 1; // We left the error message on the stack as the return value
}

View File

@ -29,6 +29,8 @@ extern "C"
#include "lua/src/lauxlib.h"
}
#include "../Vector3.h"
@ -36,6 +38,7 @@ extern "C"
class cWorld;
class cPlayer;
class cEntity;
class cProjectileEntity;
class cMonster;
class cItem;
class cItems;
@ -52,7 +55,6 @@ class cWebAdmin;
struct HTTPTemplateRequest;
class cTNTEntity;
class cCreeper;
class Vector3i;
class cHopperEntity;
class cBlockEntity;
@ -139,9 +141,14 @@ public:
/** Allows this object to be used in the same way as a lua_State *, for example in the LuaLib functions */
operator lua_State * (void) { return m_LuaState; }
/** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor */
/** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor.
The regular Lua libs are registered, but the MCS API is not registered (so that Lua can be used as
lite-config as well), use RegisterAPILibs() to do that. */
void Create(void);
/** Registers all the API libraries that MCS provides into m_LuaState. */
void RegisterAPILibs(void);
/** Closes the m_LuaState, if not closed already */
void Close(void);
@ -177,6 +184,7 @@ public:
void Push(cPlayer * a_Player);
void Push(const cPlayer * a_Player);
void Push(cEntity * a_Entity);
void Push(cProjectileEntity * a_ProjectileEntity);
void Push(cMonster * a_Monster);
void Push(cItem * a_Item);
void Push(cItems * a_Items);
@ -197,6 +205,19 @@ public:
void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity);
/** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, bool & a_Value);
/** Retrieve value at a_StackPos, if it is a valid string. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, AString & a_Value);
/** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, int & a_Value);
/** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, double & a_Value);
/** Call any 0-param 0-return Lua function in a single line: */
template <typename FnT>
@ -270,7 +291,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -292,7 +313,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
ASSERT(InitialTop == lua_gettop(m_LuaState));
return true;
@ -315,7 +336,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -338,7 +359,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -362,7 +383,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -387,7 +408,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -414,7 +435,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -442,7 +463,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -471,7 +492,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -501,7 +522,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -532,7 +553,7 @@ public:
{
return false;
}
GetReturn(-1, a_Ret1);
GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@ -553,8 +574,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -576,8 +597,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -601,8 +622,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -627,8 +648,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -654,8 +675,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -683,8 +704,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -713,8 +734,8 @@ public:
{
return false;
}
GetReturn(-2, a_Ret1);
GetReturn(-1, a_Ret2);
GetStackValue(-2, a_Ret1);
GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@ -743,9 +764,9 @@ public:
{
return false;
}
GetReturn(-3, a_Ret1);
GetReturn(-2, a_Ret2);
GetReturn(-1, a_Ret3);
GetStackValue(-3, a_Ret1);
GetStackValue(-2, a_Ret2);
GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3);
return true;
}
@ -775,9 +796,9 @@ public:
{
return false;
}
GetReturn(-3, a_Ret1);
GetReturn(-2, a_Ret2);
GetReturn(-1, a_Ret3);
GetStackValue(-3, a_Ret1);
GetStackValue(-2, a_Ret2);
GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3);
return true;
}
@ -808,11 +829,11 @@ public:
{
return false;
}
GetReturn(-5, a_Ret1);
GetReturn(-4, a_Ret2);
GetReturn(-3, a_Ret3);
GetReturn(-2, a_Ret4);
GetReturn(-1, a_Ret5);
GetStackValue(-5, a_Ret1);
GetStackValue(-4, a_Ret2);
GetStackValue(-3, a_Ret3);
GetStackValue(-2, a_Ret4);
GetStackValue(-1, a_Ret5);
lua_pop(m_LuaState, 5);
return true;
}
@ -849,10 +870,10 @@ public:
static bool ReportErrors(lua_State * a_LuaState, int status);
/** Logs all items in the current stack trace to the server console */
void LogStackTrace(void);
void LogStackTrace(int a_StartingDepth = 0);
/** Logs all items in the current stack trace to the server console */
static void LogStackTrace(lua_State * a_LuaState);
static void LogStackTrace(lua_State * a_LuaState, int a_StartingDepth = 0);
/** Returns the type of the item on the specified position in the stack */
AString GetTypeText(int a_StackPos);
@ -918,18 +939,6 @@ protected:
/** Pushes a usertype of the specified class type onto the stack */
void PushUserType(void * a_Object, const char * a_Type);
/** Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, bool & a_ReturnedVal);
/** Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, AString & a_ReturnedVal);
/** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, int & a_ReturnedVal);
/** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, double & a_ReturnedVal);
/**
Calls the function that has been pushed onto the stack by PushFunction(),
with arguments pushed by PushXXX().

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ManualBindings.h"
#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
#include "Plugin.h"
@ -23,9 +24,11 @@
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "md5/md5.h"
#include "../LineBlockTracer.h"
#include "../WorldStorage/SchematicFileSerializer.h"
#include "../CompositeChat.h"
@ -113,10 +116,44 @@ static int tolua_StringSplitAndTrim(lua_State * tolua_S)
static int tolua_LOG(lua_State* tolua_S)
/** Retrieves the log message from the first param on the Lua stack.
Can take either a string or a cCompositeChat.
*/
static AString GetLogMessage(lua_State * tolua_S)
{
const char* str = tolua_tocppstring(tolua_S,1,0);
cMCLogger::GetInstance()->LogSimple( str, 0 );
tolua_Error err;
if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err))
{
return ((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->ExtractText();
}
else
{
size_t len = 0;
const char * str = lua_tolstring(tolua_S, 1, &len);
if (str != NULL)
{
return AString(str, len);
}
}
return "";
}
static int tolua_LOG(lua_State * tolua_S)
{
// If the param is a cCompositeChat, read the log level from it:
cMCLogger::eLogLevel LogLevel = cMCLogger::llRegular;
tolua_Error err;
if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err))
{
LogLevel = cCompositeChat::MessageTypeToLogLevel(((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->GetMessageType());
}
// Log the message:
cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel);
return 0;
}
@ -124,10 +161,9 @@ static int tolua_LOG(lua_State* tolua_S)
static int tolua_LOGINFO(lua_State* tolua_S)
static int tolua_LOGINFO(lua_State * tolua_S)
{
const char* str = tolua_tocppstring(tolua_S,1,0);
cMCLogger::GetInstance()->LogSimple( str, 1 );
cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llInfo);
return 0;
}
@ -135,10 +171,9 @@ static int tolua_LOGINFO(lua_State* tolua_S)
static int tolua_LOGWARN(lua_State* tolua_S)
static int tolua_LOGWARN(lua_State * tolua_S)
{
const char* str = tolua_tocppstring(tolua_S,1,0);
cMCLogger::GetInstance()->LogSimple( str, 2 );
cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llWarning);
return 0;
}
@ -146,10 +181,9 @@ static int tolua_LOGWARN(lua_State* tolua_S)
static int tolua_LOGERROR(lua_State* tolua_S)
static int tolua_LOGERROR(lua_State * tolua_S)
{
const char* str = tolua_tocppstring(tolua_S,1,0);
cMCLogger::GetInstance()->LogSimple( str, 3 );
cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llError);
return 0;
}
@ -157,6 +191,50 @@ static int tolua_LOGERROR(lua_State* tolua_S)
static int tolua_Base64Encode(lua_State * tolua_S)
{
cLuaState L(tolua_S);
if (
!L.CheckParamString(1) ||
!L.CheckParamEnd(2)
)
{
return 0;
}
AString Src;
L.GetStackValue(1, Src);
AString res = Base64Encode(Src);
L.Push(res);
return 1;
}
static int tolua_Base64Decode(lua_State * tolua_S)
{
cLuaState L(tolua_S);
if (
!L.CheckParamString(1) ||
!L.CheckParamEnd(2)
)
{
return 0;
}
AString Src;
L.GetStackValue(1, Src);
AString res = Base64Decode(Src);
L.Push(res);
return 1;
}
cPluginLua * GetLuaPlugin(lua_State * L)
{
// Get the plugin identification out of LuaState:
@ -1495,7 +1573,8 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
}
Plugin->BindCommand(Command, FnRef);
return 0;
lua_pushboolean(L, true);
return 1;
}
@ -1519,7 +1598,10 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
// Read the arguments to this API call:
tolua_Error tolua_err;
int idx = 1;
if (tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err))
if (
tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err) ||
tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
)
{
idx++;
}
@ -1559,7 +1641,8 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
}
Plugin->BindConsoleCommand(Command, FnRef);
return 0;
lua_pushboolean(L, true);
return 1;
}
@ -2455,7 +2538,7 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S)
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::LoadFromSchematicFile
// Exported manually because function has been moved to SchematicFileSerilizer.cpp
// Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
@ -2482,10 +2565,41 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S)
{
// function cBlockArea::LoadFromSchematicString
// Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
!L.CheckParamString (2) ||
!L.CheckParamEnd (3)
)
{
return 0;
}
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
return 0;
}
AString Data;
L.GetStackValue(2, Data);
bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data);
tolua_pushboolean(tolua_S, res);
return 1;
}
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::SaveToSchematicFile
// Exported manually because function has been moved to SchematicFileSerilizer.cpp
// Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
@ -2511,6 +2625,285 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S)
{
// function cBlockArea::SaveToSchematicString
// Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
!L.CheckParamEnd (2)
)
{
return 0;
}
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
return 0;
}
AString Data;
if (cSchematicFileSerializer::SaveToSchematicString(*self, Data))
{
L.Push(Data);
return 1;
}
return 0;
}
static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
{
// function cCompositeChat:AddRunCommandPart(Message, Command, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2, 3)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", NULL);
return 0;
}
// Add the part:
AString Text, Command, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Command);
L.GetStackValue(4, Style);
self->AddRunCommandPart(Text, Command, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_AddSuggestCommandPart(lua_State * tolua_S)
{
// function cCompositeChat:AddSuggestCommandPart(Message, Command, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2, 3)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", NULL);
return 0;
}
// Add the part:
AString Text, Command, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Command);
L.GetStackValue(4, Style);
self->AddSuggestCommandPart(Text, Command, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_AddTextPart(lua_State * tolua_S)
{
// function cCompositeChat:AddTextPart(Message, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", NULL);
return 0;
}
// Add the part:
AString Text, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Style);
self->AddTextPart(Text, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_AddUrlPart(lua_State * tolua_S)
{
// function cCompositeChat:AddTextPart(Message, Url, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2, 3)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", NULL);
return 0;
}
// Add the part:
AString Text, Url, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Url);
L.GetStackValue(4, Style);
self->AddUrlPart(Text, Url, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_ParseText(lua_State * tolua_S)
{
// function cCompositeChat:ParseText(TextMessage)
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", NULL);
return 0;
}
// Parse the text:
AString Text;
L.GetStackValue(2, Text);
self->ParseText(Text);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
{
// function cCompositeChat:SetMessageType(MessageType)
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamNumber(2)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", NULL);
return 0;
}
// Set the type:
int MessageType;
L.GetStackValue(1, MessageType);
self->SetMessageType((eMessageType)MessageType);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S)
{
// function cCompositeChat:UnderlineUrls()
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (!L.CheckParamUserType(1, "cCompositeChat"))
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", NULL);
return 0;
}
// Call the processing
self->UnderlineUrls();
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
void ManualBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
@ -2521,18 +2914,32 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN);
tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN);
tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR);
tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode);
tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode);
tolua_beginmodule(tolua_S, "cFile");
tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cBlockArea");
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString);
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cCompositeChat");
tolua_function(tolua_S, "AddRunCommandPart", tolua_cCompositeChat_AddRunCommandPart);
tolua_function(tolua_S, "AddSuggestCommandPart", tolua_cCompositeChat_AddSuggestCommandPart);
tolua_function(tolua_S, "AddTextPart", tolua_cCompositeChat_AddTextPart);
tolua_function(tolua_S, "AddUrlPart", tolua_cCompositeChat_AddUrlPart);
tolua_function(tolua_S, "ParseText", tolua_cCompositeChat_ParseText);
tolua_function(tolua_S, "SetMessageType", tolua_cCompositeChat_SetMessageType);
tolua_function(tolua_S, "UnderlineUrls", tolua_cCompositeChat_UnderlineUrls);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cHopperEntity");
@ -2561,7 +2968,8 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>);
tolua_function(tolua_S, "DoWithMobHeadBlockAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadBlockAt>);
tolua_function(tolua_S, "DoWithMobHeadAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>);
tolua_function(tolua_S, "DoWithFlowerPotAt", tolua_DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>);
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
@ -2583,6 +2991,11 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cMapManager");
tolua_function(tolua_S, "DoWithMap", tolua_DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cScoreboard");
tolua_function(tolua_S, "ForEachObjective", tolua_ForEach<cScoreboard, cObjective, &cScoreboard::ForEachObjective>);
tolua_function(tolua_S, "ForEachTeam", tolua_ForEach<cScoreboard, cTeam, &cScoreboard::ForEachTeam>);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlugin");
tolua_function(tolua_S, "Call", tolua_cPlugin_Call);

View File

@ -5,4 +5,4 @@ class ManualBindings
{
public:
static void Bind( lua_State* tolua_S );
};
};

View File

@ -46,6 +46,7 @@ public:
* On all these functions, return true if you want to override default behavior and not call other plugins on that callback.
* You can also return false, so default behavior is used.
**/
virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
virtual bool OnChat (cPlayer * a_Player, AString & a_Message) = 0;
virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0;
@ -89,6 +90,8 @@ public:
virtual bool OnPluginsLoaded (void) = 0;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) = 0;
virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0;
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0;

View File

@ -5,7 +5,11 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#ifdef __APPLE__
#define LUA_USE_MACOSX
#else
#define LUA_USE_POSIX
#endif
#include "PluginLua.h"
#include "../CommandOutput.h"
@ -14,6 +18,7 @@ extern "C"
#include "lua/src/lualib.h"
}
#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
@ -75,6 +80,7 @@ bool cPluginLua::Initialize(void)
if (!m_LuaState.IsValid())
{
m_LuaState.Create();
m_LuaState.RegisterAPILibs();
// Inject the identification global variables into the state:
lua_pushlightuserdata(m_LuaState, this);
@ -194,6 +200,26 @@ void cPluginLua::Tick(float a_Dt)
bool cPluginLua::OnBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source, cLuaState::Return, res);
if (res)
{
return true;
}
}
return false;
}
bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
{
cCSLock Lock(m_CriticalSection);
@ -1087,6 +1113,46 @@ bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a
bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
m_LuaState.Call((int)(**itr), &a_Projectile, cLuaState::Return, res);
if (res)
{
return true;
}
}
return false;
}
bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
m_LuaState.Call((int)(**itr), &a_Projectile, &a_HitEntity, cLuaState::Return, res);
if (res)
{
return true;
}
}
return false;
}
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
@ -1429,6 +1495,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
{
switch (a_HookType)
{
case cPluginManager::HOOK_BLOCK_SPREAD: return "OnBlockSpread";
case cPluginManager::HOOK_BLOCK_TO_PICKUPS: return "OnBlockToPickups";
case cPluginManager::HOOK_CHAT: return "OnChat";
case cPluginManager::HOOK_CHUNK_AVAILABLE: return "OnChunkAvailable";

View File

@ -69,6 +69,7 @@ public:
virtual void Tick(float a_Dt) override;
virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override;
virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override;
virtual bool OnChat (cPlayer * a_Player, AString & a_Message) override;
virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override;
@ -112,6 +113,8 @@ public:
virtual bool OnPluginsLoaded (void) override;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) override;
virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override;
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override;

View File

@ -205,6 +205,27 @@ void cPluginManager::Tick(float a_Dt)
bool cPluginManager::CallHookBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_BLOCK_SPREAD);
if (Plugins == m_Hooks.end())
{
return false;
}
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
if ((*itr)->OnBlockSpread(a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source))
{
return true;
}
}
return false;
}
bool cPluginManager::CallHookBlockToPickups(
cWorld * a_World, cEntity * a_Digger,
int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
@ -248,7 +269,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message)
{
AStringVector Split(StringSplit(a_Message, " "));
ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long
a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", Split[0].c_str()));
a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", a_Message.c_str()));
LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str());
return true; // Cancel sending
}
@ -1133,6 +1154,48 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti
bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_BLOCK);
if (Plugins == m_Hooks.end())
{
return false;
}
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
if ((*itr)->OnProjectileHitBlock(a_Projectile))
{
return true;
}
}
return false;
}
bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_ENTITY);
if (Plugins == m_Hooks.end())
{
return false;
}
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
if ((*itr)->OnProjectileHitEntity(a_Projectile, a_HitEntity))
{
return true;
}
}
return false;
}
bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY);

View File

@ -18,6 +18,9 @@ class cChunkDesc;
// fwd: Entities/Entity.h
class cEntity;
// fwd: Entities/ProjectileEntity.h
class cProjectileEntity;
// fwd: Mobs/Monster.h
class cMonster;
@ -58,6 +61,7 @@ public: // tolua_export
// tolua_begin
enum PluginHook
{
HOOK_BLOCK_SPREAD,
HOOK_BLOCK_TO_PICKUPS,
HOOK_CHAT,
HOOK_CHUNK_AVAILABLE,
@ -101,6 +105,8 @@ public: // tolua_export
HOOK_PLUGINS_LOADED,
HOOK_POST_CRAFTING,
HOOK_PRE_CRAFTING,
HOOK_PROJECTILE_HIT_BLOCK,
HOOK_PROJECTILE_HIT_ENTITY,
HOOK_SPAWNED_ENTITY,
HOOK_SPAWNED_MONSTER,
HOOK_SPAWNING_ENTITY,
@ -127,6 +133,8 @@ public: // tolua_export
class cCommandEnumCallback
{
public:
virtual ~cCommandEnumCallback() {}
/** Called for each command; return true to abort enumeration
For console commands, a_Permission is not used (set to empty string)
*/
@ -154,6 +162,7 @@ public: // tolua_export
unsigned int GetNumPlugins() const; // tolua_export
// Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort
bool CallHookBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source);
bool CallHookBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups);
bool CallHookChat (cPlayer * a_Player, AString & a_Message);
bool CallHookChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
@ -197,6 +206,8 @@ public: // tolua_export
bool CallHookPluginsLoaded (void);
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile);
bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity);
bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity);
bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster);
bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity);

View File

@ -110,4 +110,4 @@ AString cWebPlugin::SafeString( const AString & a_String )
RetVal.push_back( c );
}
return RetVal;
}
}

Binary file not shown.

View File

@ -54,7 +54,7 @@ template<typename Combinator> void InternalMergeBlocks(
/// Combinator used for cBlockArea::msOverwrite merging
static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
@ -65,7 +65,7 @@ static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType,
/// Combinator used for cBlockArea::msFillAir merging
static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_DstType == E_BLOCK_AIR)
{
@ -80,7 +80,7 @@ static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N
/// Combinator used for cBlockArea::msImprint merging
static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_SrcType != E_BLOCK_AIR)
{
@ -95,7 +95,7 @@ static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N
/// Combinator used for cBlockArea::msLake merging
static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// Sponge is the NOP block
if (a_SrcType == E_BLOCK_SPONGE)
@ -158,16 +158,59 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
/** Combinator used for cBlockArea::msSpongePrint merging */
static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// Sponge overwrites nothing, everything else overwrites anything
if (a_SrcType != E_BLOCK_SPONGE)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
}
}
/** Combinator used for cBlockArea::msDifference merging */
static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta))
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
}
else
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
}
}
/** Combinator used for cBlockArea::msMask merging */
static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// If the blocks are the same, keep the dest; otherwise replace with air
if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta))
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBlockArea:
cBlockArea::cBlockArea(void) :
m_OriginX(0),
m_OriginY(0),
m_OriginZ(0),
m_SizeX(0),
m_SizeY(0),
m_SizeZ(0),
m_BlockTypes(NULL),
m_BlockMetas(NULL),
m_BlockLight(NULL),
@ -194,12 +237,8 @@ void cBlockArea::Clear(void)
delete[] m_BlockMetas; m_BlockMetas = NULL;
delete[] m_BlockLight; m_BlockLight = NULL;
delete[] m_BlockSkyLight; m_BlockSkyLight = NULL;
m_OriginX = 0;
m_OriginY = 0;
m_OriginZ = 0;
m_SizeX = 0;
m_SizeY = 0;
m_SizeZ = 0;
m_Origin.Set(0, 0, 0);
m_Size.Set(0, 0, 0);
}
@ -242,12 +281,35 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
m_BlockSkyLight[i] = 0x0f;
}
}
m_SizeX = a_SizeX;
m_SizeY = a_SizeY;
m_SizeZ = a_SizeZ;
m_OriginX = 0;
m_OriginY = 0;
m_OriginZ = 0;
m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
m_Origin.Set(0, 0, 0);
}
void cBlockArea::Create(const Vector3i & a_Size, int a_DataTypes)
{
Create(a_Size.x, a_Size.y, a_Size.z, a_DataTypes);
}
void cBlockArea::SetWEOffset(int a_OffsetX, int a_OffsetY, int a_OffsetZ)
{
m_WEOffset.Set(a_OffsetX, a_OffsetY, a_OffsetZ);
}
void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
{
m_WEOffset.Set(a_Offset.x, a_Offset.y, a_Offset.z);
}
@ -256,9 +318,7 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
{
m_OriginX = a_OriginX;
m_OriginY = a_OriginY;
m_OriginZ = a_OriginZ;
m_Origin.Set(a_OriginX, a_OriginY, a_OriginZ);
}
@ -267,7 +327,7 @@ void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
void cBlockArea::SetOrigin(const Vector3i & a_Origin)
{
SetOrigin(a_Origin.x, a_Origin.y, a_Origin.z);
m_Origin.Set(a_Origin.x, a_Origin.y, a_Origin.z);
}
@ -323,9 +383,7 @@ bool cBlockArea::Read(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinB
{
return false;
}
m_OriginX = a_MinBlockX;
m_OriginY = a_MinBlockY;
m_OriginZ = a_MinBlockZ;
m_Origin.Set(a_MinBlockX, a_MinBlockY, a_MinBlockZ);
cChunkReader Reader(*this);
// Convert block coords to chunks coords:
@ -389,10 +447,10 @@ bool cBlockArea::Write(cForEachChunkProvider * a_ForEachChunkProvider, int a_Min
LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__);
a_MinBlockY = 0;
}
else if (a_MinBlockY > cChunkDef::Height - m_SizeY)
else if (a_MinBlockY > cChunkDef::Height - m_Size.y)
{
LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__);
a_MinBlockY = cChunkDef::Height - m_SizeY;
a_MinBlockY = cChunkDef::Height - m_Size.y;
}
return a_ForEachChunkProvider->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
@ -424,10 +482,8 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
}
a_Into.Clear();
a_Into.SetSize(m_SizeX, m_SizeY, m_SizeZ, GetDataTypes());
a_Into.m_OriginX = m_OriginX;
a_Into.m_OriginY = m_OriginY;
a_Into.m_OriginZ = m_OriginZ;
a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
a_Into.m_Origin = m_Origin;
int BlockCount = GetBlockCount();
if (HasBlockTypes())
{
@ -468,13 +524,13 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
LOGWARNING("cBlockArea: Cannot open file \"%s\" for raw dump", a_FileName.c_str());
return;
}
UInt32 SizeX = ntohl(m_SizeX);
UInt32 SizeY = ntohl(m_SizeY);
UInt32 SizeZ = ntohl(m_SizeZ);
UInt32 SizeX = ntohl(m_Size.x);
UInt32 SizeY = ntohl(m_Size.y);
UInt32 SizeZ = ntohl(m_Size.z);
f.Write(&SizeX, 4);
f.Write(&SizeY, 4);
f.Write(&SizeZ, 4);
unsigned char DataTypes = GetDataTypes();
unsigned char DataTypes = (unsigned char)GetDataTypes();
f.Write(&DataTypes, 1);
int NumBlocks = GetBlockCount();
if (HasBlockTypes())
@ -513,13 +569,13 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
{
if (
(a_AddMinX + a_SubMaxX >= m_SizeX) ||
(a_AddMinY + a_SubMaxY >= m_SizeY) ||
(a_AddMinZ + a_SubMaxZ >= m_SizeZ)
(a_AddMinX + a_SubMaxX >= m_Size.x) ||
(a_AddMinY + a_SubMaxY >= m_Size.y) ||
(a_AddMinZ + a_SubMaxZ >= m_Size.z)
)
{
LOGWARNING("cBlockArea:Crop called with more croping than the dimensions: %d x %d x %d with cropping %d, %d and %d",
m_SizeX, m_SizeY, m_SizeZ,
m_Size.x, m_Size.y, m_Size.z,
a_AddMinX + a_SubMaxX, a_AddMinY + a_SubMaxY, a_AddMinZ + a_SubMaxZ
);
return;
@ -541,12 +597,10 @@ void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY
{
CropNibbles(m_BlockSkyLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
}
m_OriginX += a_AddMinX;
m_OriginY += a_AddMinY;
m_OriginZ += a_AddMinZ;
m_SizeX -= a_AddMinX + a_SubMaxX;
m_SizeY -= a_AddMinY + a_SubMaxY;
m_SizeZ -= a_AddMinZ + a_SubMaxZ;
m_Origin.Move(a_AddMinX, a_AddMinY, a_AddMinZ);
m_Size.x -= a_AddMinX + a_SubMaxX;
m_Size.y -= a_AddMinY + a_SubMaxY;
m_Size.z -= a_AddMinZ + a_SubMaxZ;
}
@ -571,12 +625,10 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
{
ExpandNibbles(m_BlockSkyLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
}
m_OriginX -= a_SubMinX;
m_OriginY -= a_SubMinY;
m_OriginZ -= a_SubMinZ;
m_SizeX += a_SubMinX + a_AddMaxX;
m_SizeY += a_SubMinY + a_AddMaxY;
m_SizeZ += a_SubMinZ + a_AddMaxZ;
m_Origin.Move(-a_SubMinX, -a_SubMinY, -a_SubMinZ);
m_Size.x += a_SubMinX + a_AddMaxX;
m_Size.y += a_SubMinY + a_AddMaxY;
m_Size.z += a_SubMinZ + a_AddMaxZ;
}
@ -626,7 +678,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_SizeX, m_SizeY, m_SizeZ,
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorOverwrite
);
break;
@ -641,7 +693,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_SizeX, m_SizeY, m_SizeZ,
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorFillAir
);
break;
@ -656,7 +708,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_SizeX, m_SizeY, m_SizeZ,
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorImprint
);
break;
@ -671,12 +723,57 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_SizeX, m_SizeY, m_SizeZ,
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorLake
);
break;
} // case msLake
case msSpongePrint:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorSpongePrint
);
break;
} // case msSpongePrint
case msDifference:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorDifference
);
break;
} // case msDifference
case msMask:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorMask
);
break;
} // case msMask
default:
{
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
@ -963,17 +1060,17 @@ void cBlockArea::RotateCCW(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
for (int x = 0; x < m_SizeX; x++)
BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
for (int x = 0; x < m_Size.x; x++)
{
int NewZ = m_SizeX - x - 1;
for (int z = 0; z < m_SizeZ; z++)
int NewZ = m_Size.x - x - 1;
for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
int NewIdx = NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ;
int NewIdx = NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z;
int OldIdx = MakeIndex(x, y, z);
NewTypes[NewIdx] = m_BlockTypes[OldIdx];
NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCCW(m_BlockMetas[OldIdx]);
@ -985,7 +1082,7 @@ void cBlockArea::RotateCCW(void)
delete[] NewTypes;
delete[] NewMetas;
std::swap(m_SizeX, m_SizeZ);
std::swap(m_Size.x, m_Size.z);
}
@ -1008,17 +1105,17 @@ void cBlockArea::RotateCW(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
for (int x = 0; x < m_SizeX; x++)
BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
int NewX = m_SizeZ - z - 1;
for (int y = 0; y < m_SizeY; y++)
int NewX = m_Size.z - z - 1;
for (int y = 0; y < m_Size.y; y++)
{
int NewIdx = NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ;
int NewIdx = NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z;
int OldIdx = MakeIndex(x, y, z);
NewTypes[NewIdx] = m_BlockTypes[OldIdx];
NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCW(m_BlockMetas[OldIdx]);
@ -1030,7 +1127,7 @@ void cBlockArea::RotateCW(void)
delete[] NewTypes;
delete[] NewMetas;
std::swap(m_SizeX, m_SizeZ);
std::swap(m_Size.x, m_Size.z);
}
@ -1053,13 +1150,13 @@ void cBlockArea::MirrorXY(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
int HalfZ = m_SizeZ / 2;
int MaxZ = m_SizeZ - 1;
for (int y = 0; y < m_SizeY; y++)
int HalfZ = m_Size.z / 2;
int MaxZ = m_Size.z - 1;
for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
int Idx1 = MakeIndex(x, y, z);
int Idx2 = MakeIndex(x, y, MaxZ - z);
@ -1093,13 +1190,13 @@ void cBlockArea::MirrorXZ(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
int HalfY = m_SizeY / 2;
int MaxY = m_SizeY - 1;
int HalfY = m_Size.y / 2;
int MaxY = m_Size.y - 1;
for (int y = 0; y < HalfY; y++)
{
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
int Idx1 = MakeIndex(x, y, z);
int Idx2 = MakeIndex(x, MaxY - y, z);
@ -1133,11 +1230,11 @@ void cBlockArea::MirrorYZ(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
int HalfX = m_SizeX / 2;
int MaxX = m_SizeX - 1;
for (int y = 0; y < m_SizeY; y++)
int HalfX = m_Size.x / 2;
int MaxX = m_Size.x - 1;
for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@ -1161,16 +1258,16 @@ void cBlockArea::RotateCCWNoMeta(void)
{
if (HasBlockTypes())
{
BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
for (int x = 0; x < m_SizeX; x++)
BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
for (int x = 0; x < m_Size.x; x++)
{
int NewZ = m_SizeX - x - 1;
for (int z = 0; z < m_SizeZ; z++)
int NewZ = m_Size.x - x - 1;
for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
NewTypes[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)];
NewTypes[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockTypes[MakeIndex(x, y, z)];
} // for y
} // for z
} // for x
@ -1179,23 +1276,23 @@ void cBlockArea::RotateCCWNoMeta(void)
}
if (HasBlockMetas())
{
NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
for (int x = 0; x < m_SizeX; x++)
NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
for (int x = 0; x < m_Size.x; x++)
{
int NewZ = m_SizeX - x - 1;
for (int z = 0; z < m_SizeZ; z++)
int NewZ = m_Size.x - x - 1;
for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
NewMetas[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)];
NewMetas[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockMetas[MakeIndex(x, y, z)];
} // for y
} // for z
} // for x
std::swap(m_BlockMetas, NewMetas);
delete[] NewMetas;
}
std::swap(m_SizeX, m_SizeZ);
std::swap(m_Size.x, m_Size.z);
}
@ -1206,16 +1303,16 @@ void cBlockArea::RotateCWNoMeta(void)
{
if (HasBlockTypes())
{
BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
for (int z = 0; z < m_SizeZ; z++)
BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
for (int z = 0; z < m_Size.z; z++)
{
int NewX = m_SizeZ - z - 1;
for (int x = 0; x < m_SizeX; x++)
int NewX = m_Size.z - z - 1;
for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
NewTypes[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)];
NewTypes[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockTypes[MakeIndex(x, y, z)];
} // for y
} // for x
} // for z
@ -1224,23 +1321,23 @@ void cBlockArea::RotateCWNoMeta(void)
}
if (HasBlockMetas())
{
NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
for (int z = 0; z < m_SizeZ; z++)
NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
for (int z = 0; z < m_Size.z; z++)
{
int NewX = m_SizeZ - z - 1;
for (int x = 0; x < m_SizeX; x++)
int NewX = m_Size.z - z - 1;
for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
NewMetas[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)];
NewMetas[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockMetas[MakeIndex(x, y, z)];
} // for y
} // for x
} // for z
std::swap(m_BlockMetas, NewMetas);
delete[] NewMetas;
}
std::swap(m_SizeX, m_SizeZ);
std::swap(m_Size.x, m_Size.z);
}
@ -1249,15 +1346,15 @@ void cBlockArea::RotateCWNoMeta(void)
void cBlockArea::MirrorXYNoMeta(void)
{
int HalfZ = m_SizeZ / 2;
int MaxZ = m_SizeZ - 1;
int HalfZ = m_Size.z / 2;
int MaxZ = m_Size.z - 1;
if (HasBlockTypes())
{
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, y, MaxZ - z)]);
} // for x
@ -1267,11 +1364,11 @@ void cBlockArea::MirrorXYNoMeta(void)
if (HasBlockMetas())
{
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, y, MaxZ - z)]);
} // for x
@ -1286,15 +1383,15 @@ void cBlockArea::MirrorXYNoMeta(void)
void cBlockArea::MirrorXZNoMeta(void)
{
int HalfY = m_SizeY / 2;
int MaxY = m_SizeY - 1;
int HalfY = m_Size.y / 2;
int MaxY = m_Size.y - 1;
if (HasBlockTypes())
{
for (int y = 0; y < HalfY; y++)
{
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, MaxY - y, z)]);
} // for x
@ -1306,9 +1403,9 @@ void cBlockArea::MirrorXZNoMeta(void)
{
for (int y = 0; y < HalfY; y++)
{
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, MaxY - y, z)]);
} // for x
@ -1323,13 +1420,13 @@ void cBlockArea::MirrorXZNoMeta(void)
void cBlockArea::MirrorYZNoMeta(void)
{
int HalfX = m_SizeX / 2;
int MaxX = m_SizeX - 1;
int HalfX = m_Size.x / 2;
int MaxX = m_Size.x - 1;
if (HasBlockTypes())
{
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@ -1341,9 +1438,9 @@ void cBlockArea::MirrorYZNoMeta(void)
if (HasBlockMetas())
{
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < m_SizeZ; z++)
for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@ -1374,7 +1471,7 @@ void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a
void cBlockArea::SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
{
SetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType);
SetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType);
}
@ -1451,7 +1548,7 @@ BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const
BLOCKTYPE cBlockArea::GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const
{
return GetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ);
return GetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z);
}
@ -1514,7 +1611,7 @@ NIBBLETYPE cBlockArea::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ
void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
SetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta);
SetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
}
@ -1548,7 +1645,7 @@ void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, B
void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
{
return GetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta);
return GetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
}
@ -1651,9 +1748,7 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
return false;
}
}
m_SizeX = a_SizeX;
m_SizeY = a_SizeY;
m_SizeZ = a_SizeZ;
m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
return true;
}
@ -1664,13 +1759,13 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const
{
ASSERT(a_RelX >= 0);
ASSERT(a_RelX < m_SizeX);
ASSERT(a_RelX < m_Size.x);
ASSERT(a_RelY >= 0);
ASSERT(a_RelY < m_SizeY);
ASSERT(a_RelY < m_Size.y);
ASSERT(a_RelZ >= 0);
ASSERT(a_RelZ < m_SizeZ);
ASSERT(a_RelZ < m_Size.z);
return a_RelX + a_RelZ * m_SizeX + a_RelY * m_SizeX * m_SizeZ;
return a_RelX + a_RelZ * m_Size.x + a_RelY * m_Size.x * m_Size.z;
}
@ -1693,7 +1788,7 @@ void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_V
void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array)
{
SetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Value, a_Array);
SetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Value, a_Array);
}
@ -1716,7 +1811,7 @@ NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETY
NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE * a_Array) const
{
return GetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Array);
return GetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Array);
}
@ -1729,9 +1824,7 @@ NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBL
cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) :
m_Area(a_Area),
m_OriginX(a_Area.m_OriginX),
m_OriginY(a_Area.m_OriginY),
m_OriginZ(a_Area.m_OriginZ)
m_Origin(a_Area.m_Origin.x, a_Area.m_Origin.y, a_Area.m_Origin.z)
{
}
@ -1741,8 +1834,8 @@ cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) :
void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc)
{
int SizeY = m_Area.m_SizeY;
int MinY = m_OriginY;
int SizeY = m_Area.m_Size.y;
int MinY = m_Origin.y;
// SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
// OffX, OffZ are the offsets of the current chunk data from the area origin
@ -1751,7 +1844,7 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
int SizeZ = cChunkDef::Width;
int OffX, OffZ;
int BaseX, BaseZ;
OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX;
OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
if (OffX < 0)
{
BaseX = -OffX;
@ -1762,7 +1855,7 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
{
BaseX = 0;
}
OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ;
OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
if (OffZ < 0)
{
BaseZ = -OffZ;
@ -1774,13 +1867,13 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
BaseZ = 0;
}
// If the chunk extends beyond the area in the X or Z axis, cut off the Size:
if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX)
if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
{
SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX);
SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
}
if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ)
if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ);
SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
}
for (int y = 0; y < SizeY; y++)
@ -1824,8 +1917,8 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
return;
}
int SizeY = m_Area.m_SizeY;
int MinY = m_OriginY;
int SizeY = m_Area.m_Size.y;
int MinY = m_Origin.y;
// SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
// OffX, OffZ are the offsets of the current chunk data from the area origin
@ -1834,7 +1927,7 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
int SizeZ = cChunkDef::Width;
int OffX, OffZ;
int BaseX, BaseZ;
OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX;
OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
if (OffX < 0)
{
BaseX = -OffX;
@ -1845,7 +1938,7 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
{
BaseX = 0;
}
OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ;
OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
if (OffZ < 0)
{
BaseZ = -OffZ;
@ -1857,13 +1950,13 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
BaseZ = 0;
}
// If the chunk extends beyond the area in the X or Z axis, cut off the Size:
if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX)
if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
{
SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX);
SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
}
if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ)
if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ);
SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
}
for (int y = 0; y < SizeY; y++)
@ -1983,21 +2076,21 @@ void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX
void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
{
int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX;
int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY;
int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ;
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
int OldIndex = 0;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ;
for (int z = 0; z < m_SizeZ; z++)
int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
for (int z = 0; z < m_Size.z; z++)
{
int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX;
int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
int idx = IndexBaseZ + a_SubMinX;
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
NewBlockTypes[idx++] = m_BlockTypes[OldIndex++];
} // for x
@ -2013,21 +2106,21 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
{
int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX;
int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY;
int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ;
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
int OldIndex = 0;
for (int y = 0; y < m_SizeY; y++)
for (int y = 0; y < m_Size.y; y++)
{
int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ;
for (int z = 0; z < m_SizeZ; z++)
int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
for (int z = 0; z < m_Size.z; z++)
{
int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX;
int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
int idx = IndexBaseZ + a_SubMinX;
for (int x = 0; x < m_SizeX; x++)
for (int x = 0; x < m_Size.x; x++)
{
NewNibbles[idx++] = a_Array[OldIndex++];
} // for x
@ -2038,6 +2131,9 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
}
void cBlockArea::RelSetData(
int a_RelX, int a_RelY, int a_RelZ,
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,

View File

@ -13,13 +13,13 @@
#pragma once
#include "ForEachChunkProvider.h"
#include "Vector3.h"
// fwd:
class cCuboid;
class Vector3i;
@ -43,12 +43,17 @@ public:
baSkyLight = 8,
} ;
/** The per-block strategy to use when merging another block area into this object.
See the Merge function for the description of these */
enum eMergeStrategy
{
msOverwrite,
msFillAir,
msImprint,
msLake,
msSpongePrint,
msDifference,
msMask,
} ;
cBlockArea(void);
@ -57,12 +62,18 @@ public:
/** Clears the data stored to reclaim memory */
void Clear(void);
/** Creates a new area of the specified size and contents.
Origin is set to all zeroes.
/** Creates a new area of the specified size and contents.
Origin is set to all zeroes.
BlockTypes are set to air, block metas to zero, blocklights to zero and skylights to full light.
*/
void Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes = baTypes | baMetas);
/** Creates a new area of the specified size and contents.
Origin is set to all zeroes.
BlockTypes are set to air, block metas to zero, blocklights to zero and skylights to full light.
*/
void Create(const Vector3i & a_Size, int a_DataTypes = baTypes | baMetas);
/** Resets the origin. No other changes are made, contents are untouched. */
void SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ);
@ -119,8 +130,8 @@ public:
- msFillAir overwrites only those blocks that were air
- msImprint overwrites with only those blocks that are non-air
Special strategies:
msLake (evaluate top-down, first match wins):
Special strategies (evaluate top-down, first match wins):
msLake:
| area block | |
| this | Src | result |
+----------+--------+--------+
@ -135,6 +146,22 @@ public:
| mycelium | stone | stone | ... and mycelium
| A | stone | A | ... but nothing else
| A | * | A | Everything else is left as it is
msSpongePrint:
Used for most generators, it allows carving out air pockets, too, and uses the Sponge as the NOP block
| area block | |
| this | Src | result |
+----------+--------+--------+
| A | sponge | A | Sponge is the NOP block
| * | B | B | Everything else overwrites anything
msMask:
Combines two areas, the blocks that are the same are kept, differing ones are reset to air
| area block | |
| this | Src | result |
+------+-------+--------+
| A | A | A | Same blocks are kept
| A | non-A | air | Everything else is replaced with air
*/
void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy);
@ -209,6 +236,8 @@ public:
void SetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight);
void SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight);
void SetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight);
void SetWEOffset (int a_OffsetX, int a_OffsetY, int a_OffsetZ);
void SetWEOffset (const Vector3i & a_Offset);
// Getters:
BLOCKTYPE GetRelBlockType (int a_RelX, int a_RelY, int a_RelZ) const;
@ -219,6 +248,7 @@ public:
NIBBLETYPE GetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
NIBBLETYPE GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const;
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
const Vector3i & GetWEOffset (void) const {return m_WEOffset;}
void SetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@ -229,18 +259,24 @@ public:
void GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
void GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
// GetSize() is already exported manually to return 3 numbers, can't auto-export
const Vector3i & GetSize(void) const { return m_Size; }
// GetOrigin() is already exported manually to return 3 numbers, can't auto-export
const Vector3i & GetOrigin(void) const { return m_Origin; }
// tolua_begin
int GetSizeX(void) const { return m_SizeX; }
int GetSizeY(void) const { return m_SizeY; }
int GetSizeZ(void) const { return m_SizeZ; }
int GetSizeX(void) const { return m_Size.x; }
int GetSizeY(void) const { return m_Size.y; }
int GetSizeZ(void) const { return m_Size.z; }
/** Returns the volume of the area, as number of blocks */
int GetVolume(void) const { return m_SizeX * m_SizeY * m_SizeZ; }
int GetVolume(void) const { return m_Size.x * m_Size.y * m_Size.z; }
int GetOriginX(void) const { return m_OriginX; }
int GetOriginY(void) const { return m_OriginY; }
int GetOriginZ(void) const { return m_OriginZ; }
int GetOriginX(void) const { return m_Origin.x; }
int GetOriginY(void) const { return m_Origin.y; }
int GetOriginZ(void) const { return m_Origin.z; }
/** Returns the datatypes that are stored in the object (bitmask of baXXX values) */
int GetDataTypes(void) const;
@ -258,7 +294,7 @@ public:
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
int GetBlockCount(void) const { return m_SizeX * m_SizeY * m_SizeZ; }
int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
protected:
@ -273,9 +309,7 @@ protected:
protected:
cBlockArea & m_Area;
int m_OriginX;
int m_OriginY;
int m_OriginZ;
Vector3i m_Origin;
int m_CurrentChunkX;
int m_CurrentChunkZ;
@ -292,13 +326,13 @@ protected:
typedef NIBBLETYPE * NIBBLEARRAY;
int m_OriginX;
int m_OriginY;
int m_OriginZ;
int m_SizeX;
int m_SizeY;
int m_SizeZ;
Vector3i m_Origin;
Vector3i m_Size;
/** An extra data value sometimes stored in the .schematic file. Used mainly by the WorldEdit plugin.
cBlockArea doesn't use this value in any way. */
Vector3i m_WEOffset;
BLOCKTYPE * m_BlockTypes;
NIBBLETYPE * m_BlockMetas; // Each meta is stored as a separate byte for faster access
NIBBLETYPE * m_BlockLight; // Each light value is stored as a separate byte for faster access

View File

@ -10,6 +10,7 @@
#include "DispenserEntity.h"
#include "DropperEntity.h"
#include "EnderChestEntity.h"
#include "FlowerPotEntity.h"
#include "FurnaceEntity.h"
#include "HopperEntity.h"
#include "JukeboxEntity.h"
@ -30,6 +31,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);

View File

@ -160,7 +160,7 @@ bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value)
m_Command = a_Value.get("Command", "").asString();
m_LastOutput = a_Value.get("LastOutput", "").asString();
m_Result = a_Value.get("SuccessCount", 0).asInt();
m_Result = (NIBBLETYPE)a_Value.get("SuccessCount", 0).asInt();
return true;
}

View File

@ -116,7 +116,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
{
double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity
m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 80, 0); // 80 ticks fuse, no initial velocity
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
break;
@ -138,6 +138,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
break;
}
case E_ITEM_FIRE_CHARGE:
{
// TODO: Spawn fireball entity
break;
}
default:
{
DropFromSlot(a_Chunk, a_SlotNum);

View File

@ -0,0 +1,134 @@
// FlowerPotEntity.cpp
// Implements the cFlowerPotEntity class representing a single sign in the world
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "json/json.h"
#include "FlowerPotEntity.h"
#include "../Entities/Player.h"
#include "../Item.h"
cFlowerPotEntity::cFlowerPotEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_FLOWER_POT, a_BlockX, a_BlockY, a_BlockZ, a_World)
{
}
// It don't do anything when 'used'
void cFlowerPotEntity::UsedBy(cPlayer * a_Player)
{
if (IsItemInPot())
{
return;
}
cItem SelectedItem = a_Player->GetInventory().GetEquippedItem();
if (IsFlower(SelectedItem.m_ItemType, SelectedItem.m_ItemDamage))
{
m_Item = SelectedItem.CopyOne();
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ, a_Player->GetClientHandle());
}
}
void cFlowerPotEntity::SendTo(cClientHandle & a_Client)
{
a_Client.SendUpdateBlockEntity(*this);
}
void cFlowerPotEntity::Destroy(void)
{
// Drop the contents as pickups:
if (!m_Item.IsEmpty())
{
ASSERT(m_World != NULL);
cItems Pickups;
Pickups.Add(m_Item);
m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
m_Item.Empty();
}
}
bool cFlowerPotEntity::LoadFromJson(const Json::Value & a_Value)
{
m_PosX = a_Value.get("x", 0).asInt();
m_PosY = a_Value.get("y", 0).asInt();
m_PosZ = a_Value.get("z", 0).asInt();
m_Item = cItem();
m_Item.FromJson(a_Value.get("Item", 0));
return true;
}
void cFlowerPotEntity::SaveToJson(Json::Value & a_Value)
{
a_Value["x"] = m_PosX;
a_Value["y"] = m_PosY;
a_Value["z"] = m_PosZ;
Json::Value Item;
m_Item.GetJson(Item);
a_Value["Item"] = Item;
}
bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData)
{
switch (m_ItemType)
{
case E_BLOCK_DANDELION:
case E_BLOCK_FLOWER:
case E_BLOCK_CACTUS:
case E_BLOCK_BROWN_MUSHROOM:
case E_BLOCK_RED_MUSHROOM:
case E_BLOCK_SAPLING:
case E_BLOCK_DEAD_BUSH:
{
return true;
}
case E_BLOCK_TALL_GRASS:
{
return (m_ItemData == (short) 2);
}
default:
{
return false;
}
}
}

View File

@ -0,0 +1,74 @@
// FlowerPotEntity.h
// Declares the cFlowerPotEntity class representing a single sign in the world
#pragma once
#include "BlockEntity.h"
class cItem;
namespace Json
{
class Value;
}
// tolua_begin
class cFlowerPotEntity :
public cBlockEntity
{
typedef cBlockEntity super;
public:
// tolua_end
/** Creates a new flowerpot entity at the specified block coords. a_World may be NULL */
cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World);
bool LoadFromJson( const Json::Value& a_Value );
virtual void SaveToJson(Json::Value& a_Value ) override;
virtual void Destroy(void) override;
// tolua_begin
/** Is a flower in the pot? */
bool IsItemInPot(void) { return !m_Item.IsEmpty(); }
/** Get the item in the flower pot */
cItem GetItem(void) const { return m_Item; }
/** Set the item in the flower pot */
void SetItem(const cItem a_Item) { m_Item = a_Item; }
// tolua_end
virtual void UsedBy(cPlayer * a_Player) override;
virtual void SendTo(cClientHandle & a_Client) override;
static bool IsFlower(short m_ItemType, short m_ItemData);
static const char * GetClassStatic(void) { return "cFlowerPotEntity"; }
private:
cItem m_Item;
} ; // tolua_export

View File

@ -219,7 +219,7 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
Vector3f EntityPos = a_Entity->GetPosition();
Vector3f BlockPos(m_Pos.x + 0.5f, (float)m_Pos.y + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards
float Distance = (EntityPos - BlockPos).Length();
double Distance = (EntityPos - BlockPos).Length();
if (Distance < 0.5)
{

View File

@ -38,10 +38,11 @@ public:
int GetRecord(void);
void SetRecord(int a_Record);
/** Play a Record. Return false, when a_Record isn't a Record */
/** Plays the specified Record. Return false if a_Record isn't a playable Record (E_ITEM_XXX_DISC).
If there is a record already playing, ejects it first. */
bool PlayRecord(int a_Record);
/** Ejects the currently held record as a pickup. Return false when no record inserted. */
/** Ejects the currently held record as a pickup. Return false when no record had been inserted. */
bool EjectRecord(void);
/** Is in the Jukebox a Record? */

View File

@ -12,20 +12,6 @@
NIBBLETYPE g_BlockLightValue[256];
NIBBLETYPE g_BlockSpreadLightFalloff[256];
bool g_BlockTransparent[256];
bool g_BlockOneHitDig[256];
bool g_BlockPistonBreakable[256];
bool g_BlockIsSnowable[256];
bool g_BlockRequiresSpecialTool[256];
bool g_BlockIsSolid[256];
bool g_BlockFullyOccupiesVoxel[256];
class cBlockIDMap
{
// Making the map case-insensitive:
@ -481,389 +467,4 @@ cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const char * a
// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
class cBlockPropertiesInitializer
{
public:
cBlockPropertiesInitializer(void)
{
memset(g_BlockLightValue, 0x00, sizeof(g_BlockLightValue));
memset(g_BlockSpreadLightFalloff, 0x0f, sizeof(g_BlockSpreadLightFalloff)); // 0x0f means total falloff
memset(g_BlockTransparent, 0x00, sizeof(g_BlockTransparent));
memset(g_BlockOneHitDig, 0x00, sizeof(g_BlockOneHitDig));
memset(g_BlockPistonBreakable, 0x00, sizeof(g_BlockPistonBreakable));
memset(g_BlockFullyOccupiesVoxel, 0x00, sizeof(g_BlockFullyOccupiesVoxel));
// Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSnowable); i++)
{
g_BlockIsSnowable[i] = true;
}
memset(g_BlockRequiresSpecialTool, 0x00, sizeof(g_BlockRequiresSpecialTool)); // Set all blocks to false
// Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSolid); i++)
{
g_BlockIsSolid[i] = true;
}
// Emissive blocks
g_BlockLightValue[E_BLOCK_FIRE] = 15;
g_BlockLightValue[E_BLOCK_GLOWSTONE] = 15;
g_BlockLightValue[E_BLOCK_JACK_O_LANTERN] = 15;
g_BlockLightValue[E_BLOCK_LAVA] = 15;
g_BlockLightValue[E_BLOCK_STATIONARY_LAVA] = 15;
g_BlockLightValue[E_BLOCK_END_PORTAL] = 15;
g_BlockLightValue[E_BLOCK_REDSTONE_LAMP_ON] = 15;
g_BlockLightValue[E_BLOCK_TORCH] = 14;
g_BlockLightValue[E_BLOCK_BURNING_FURNACE] = 13;
g_BlockLightValue[E_BLOCK_NETHER_PORTAL] = 11;
g_BlockLightValue[E_BLOCK_REDSTONE_ORE_GLOWING] = 9;
g_BlockLightValue[E_BLOCK_REDSTONE_REPEATER_ON] = 9;
g_BlockLightValue[E_BLOCK_REDSTONE_TORCH_ON] = 7;
g_BlockLightValue[E_BLOCK_BREWING_STAND] = 1;
g_BlockLightValue[E_BLOCK_BROWN_MUSHROOM] = 1;
g_BlockLightValue[E_BLOCK_DRAGON_EGG] = 1;
// Spread blocks
g_BlockSpreadLightFalloff[E_BLOCK_AIR] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_CAKE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_CHEST] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_COBWEB] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_CROPS] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_FENCE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_FENCE_GATE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_FIRE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_GLASS] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_GLASS_PANE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_GLOWSTONE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_IRON_BARS] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_IRON_DOOR] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_LEAVES] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_SIGN_POST] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_TORCH] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_VINES] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_WALLSIGN] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_WOODEN_DOOR] = 1;
// Light in water and lava dissapears faster:
g_BlockSpreadLightFalloff[E_BLOCK_LAVA] = 3;
g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_LAVA] = 3;
g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_WATER] = 3;
g_BlockSpreadLightFalloff[E_BLOCK_WATER] = 3;
// Transparent blocks
g_BlockTransparent[E_BLOCK_ACTIVATOR_RAIL] = true;
g_BlockTransparent[E_BLOCK_AIR] = true;
g_BlockTransparent[E_BLOCK_BIG_FLOWER] = true;
g_BlockTransparent[E_BLOCK_BROWN_MUSHROOM] = true;
g_BlockTransparent[E_BLOCK_CARROTS] = true;
g_BlockTransparent[E_BLOCK_CHEST] = true;
g_BlockTransparent[E_BLOCK_COBWEB] = true;
g_BlockTransparent[E_BLOCK_CROPS] = true;
g_BlockTransparent[E_BLOCK_DANDELION] = true;
g_BlockTransparent[E_BLOCK_DETECTOR_RAIL] = true;
g_BlockTransparent[E_BLOCK_ENDER_CHEST] = true;
g_BlockTransparent[E_BLOCK_FENCE] = true;
g_BlockTransparent[E_BLOCK_FENCE_GATE] = true;
g_BlockTransparent[E_BLOCK_FIRE] = true;
g_BlockTransparent[E_BLOCK_FLOWER] = true;
g_BlockTransparent[E_BLOCK_FLOWER_POT] = true;
g_BlockTransparent[E_BLOCK_GLASS] = true;
g_BlockTransparent[E_BLOCK_GLASS_PANE] = true;
g_BlockTransparent[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_ICE] = true;
g_BlockTransparent[E_BLOCK_IRON_DOOR] = true;
g_BlockTransparent[E_BLOCK_LAVA] = true;
g_BlockTransparent[E_BLOCK_LEAVES] = true;
g_BlockTransparent[E_BLOCK_LEVER] = true;
g_BlockTransparent[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_MELON_STEM] = true;
g_BlockTransparent[E_BLOCK_NETHER_BRICK_FENCE] = true;
g_BlockTransparent[E_BLOCK_NEW_LEAVES] = true;
g_BlockTransparent[E_BLOCK_POTATOES] = true;
g_BlockTransparent[E_BLOCK_POWERED_RAIL] = true;
g_BlockTransparent[E_BLOCK_PISTON_EXTENSION] = true;
g_BlockTransparent[E_BLOCK_PUMPKIN_STEM] = true;
g_BlockTransparent[E_BLOCK_RAIL] = true;
g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true;
g_BlockTransparent[E_BLOCK_SIGN_POST] = true;
g_BlockTransparent[E_BLOCK_SNOW] = true;
g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true;
g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true;
g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true;
g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true;
g_BlockTransparent[E_BLOCK_STONE_BUTTON] = true;
g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_TALL_GRASS] = true;
g_BlockTransparent[E_BLOCK_TORCH] = true;
g_BlockTransparent[E_BLOCK_VINES] = true;
g_BlockTransparent[E_BLOCK_WALLSIGN] = true;
g_BlockTransparent[E_BLOCK_WATER] = true;
g_BlockTransparent[E_BLOCK_WOODEN_BUTTON] = true;
g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true;
g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
// TODO: Any other transparent blocks?
// One hit break blocks:
g_BlockOneHitDig[E_BLOCK_ACTIVE_COMPARATOR] = true;
g_BlockOneHitDig[E_BLOCK_BIG_FLOWER] = true;
g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true;
g_BlockOneHitDig[E_BLOCK_CARROTS] = true;
g_BlockOneHitDig[E_BLOCK_CROPS] = true;
g_BlockOneHitDig[E_BLOCK_DANDELION] = true;
g_BlockOneHitDig[E_BLOCK_FIRE] = true;
g_BlockOneHitDig[E_BLOCK_FLOWER] = true;
g_BlockOneHitDig[E_BLOCK_FLOWER_POT] = true;
g_BlockOneHitDig[E_BLOCK_INACTIVE_COMPARATOR] = true;
g_BlockOneHitDig[E_BLOCK_MELON_STEM] = true;
g_BlockOneHitDig[E_BLOCK_POTATOES] = true;
g_BlockOneHitDig[E_BLOCK_PUMPKIN_STEM] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_ON] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_OFF] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_ON] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_WIRE] = true;
g_BlockOneHitDig[E_BLOCK_RED_MUSHROOM] = true;
g_BlockOneHitDig[E_BLOCK_REEDS] = true;
g_BlockOneHitDig[E_BLOCK_SAPLING] = true;
g_BlockOneHitDig[E_BLOCK_TNT] = true;
g_BlockOneHitDig[E_BLOCK_TALL_GRASS] = true;
g_BlockOneHitDig[E_BLOCK_TORCH] = true;
// Blocks that break when pushed by piston:
g_BlockPistonBreakable[E_BLOCK_ACTIVE_COMPARATOR] = true;
g_BlockPistonBreakable[E_BLOCK_AIR] = true;
g_BlockPistonBreakable[E_BLOCK_BED] = true;
g_BlockPistonBreakable[E_BLOCK_BIG_FLOWER] = true;
g_BlockPistonBreakable[E_BLOCK_BROWN_MUSHROOM] = true;
g_BlockPistonBreakable[E_BLOCK_COBWEB] = true;
g_BlockPistonBreakable[E_BLOCK_CROPS] = true;
g_BlockPistonBreakable[E_BLOCK_DANDELION] = true;
g_BlockPistonBreakable[E_BLOCK_DEAD_BUSH] = true;
g_BlockPistonBreakable[E_BLOCK_FIRE] = true;
g_BlockPistonBreakable[E_BLOCK_FLOWER] = true;
g_BlockPistonBreakable[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockPistonBreakable[E_BLOCK_INACTIVE_COMPARATOR] = true;
g_BlockPistonBreakable[E_BLOCK_IRON_DOOR] = true;
g_BlockPistonBreakable[E_BLOCK_JACK_O_LANTERN] = true;
g_BlockPistonBreakable[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockPistonBreakable[E_BLOCK_LADDER] = true;
g_BlockPistonBreakable[E_BLOCK_LAVA] = true;
g_BlockPistonBreakable[E_BLOCK_LEVER] = true;
g_BlockPistonBreakable[E_BLOCK_MELON] = true;
g_BlockPistonBreakable[E_BLOCK_MELON_STEM] = true;
g_BlockPistonBreakable[E_BLOCK_PUMPKIN] = true;
g_BlockPistonBreakable[E_BLOCK_PUMPKIN_STEM] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_REPEATER_ON] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_OFF] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_ON] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_WIRE] = true;
g_BlockPistonBreakable[E_BLOCK_RED_MUSHROOM] = true;
g_BlockPistonBreakable[E_BLOCK_REEDS] = true;
g_BlockPistonBreakable[E_BLOCK_SNOW] = true;
g_BlockPistonBreakable[E_BLOCK_STATIONARY_LAVA] = true;
g_BlockPistonBreakable[E_BLOCK_STATIONARY_WATER] = true;
g_BlockPistonBreakable[E_BLOCK_STONE_BUTTON] = true;
g_BlockPistonBreakable[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockPistonBreakable[E_BLOCK_TALL_GRASS] = true;
g_BlockPistonBreakable[E_BLOCK_TORCH] = true;
g_BlockPistonBreakable[E_BLOCK_VINES] = true;
g_BlockPistonBreakable[E_BLOCK_WATER] = true;
g_BlockPistonBreakable[E_BLOCK_WOODEN_BUTTON] = true;
g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true;
g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
// Blocks that cannot be snowed over:
g_BlockIsSnowable[E_BLOCK_ACTIVE_COMPARATOR] = false;
g_BlockIsSnowable[E_BLOCK_AIR] = false;
g_BlockIsSnowable[E_BLOCK_BIG_FLOWER] = false;
g_BlockIsSnowable[E_BLOCK_BROWN_MUSHROOM] = false;
g_BlockIsSnowable[E_BLOCK_CACTUS] = false;
g_BlockIsSnowable[E_BLOCK_CHEST] = false;
g_BlockIsSnowable[E_BLOCK_CROPS] = false;
g_BlockIsSnowable[E_BLOCK_DANDELION] = false;
g_BlockIsSnowable[E_BLOCK_FIRE] = false;
g_BlockIsSnowable[E_BLOCK_FLOWER] = false;
g_BlockIsSnowable[E_BLOCK_GLASS] = false;
g_BlockIsSnowable[E_BLOCK_ICE] = false;
g_BlockIsSnowable[E_BLOCK_INACTIVE_COMPARATOR] = false;
g_BlockIsSnowable[E_BLOCK_LAVA] = false;
g_BlockIsSnowable[E_BLOCK_LILY_PAD] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_OFF] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_ON] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_OFF] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_ON] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_WIRE] = false;
g_BlockIsSnowable[E_BLOCK_RED_MUSHROOM] = false;
g_BlockIsSnowable[E_BLOCK_REEDS] = false;
g_BlockIsSnowable[E_BLOCK_SAPLING] = false;
g_BlockIsSnowable[E_BLOCK_SIGN_POST] = false;
g_BlockIsSnowable[E_BLOCK_SNOW] = false;
g_BlockIsSnowable[E_BLOCK_STAINED_GLASS] = false;
g_BlockIsSnowable[E_BLOCK_STAINED_GLASS_PANE] = false;
g_BlockIsSnowable[E_BLOCK_STATIONARY_LAVA] = false;
g_BlockIsSnowable[E_BLOCK_STATIONARY_WATER] = false;
g_BlockIsSnowable[E_BLOCK_TALL_GRASS] = false;
g_BlockIsSnowable[E_BLOCK_TNT] = false;
g_BlockIsSnowable[E_BLOCK_TORCH] = false;
g_BlockIsSnowable[E_BLOCK_VINES] = false;
g_BlockIsSnowable[E_BLOCK_WALLSIGN] = false;
g_BlockIsSnowable[E_BLOCK_WATER] = false;
// 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;
g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_COBWEB] = true;
g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_DOUBLE_STONE_SLAB] = true;
g_BlockRequiresSpecialTool[E_BLOCK_EMERALD_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_END_STONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_GOLD_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_GOLD_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_IRON_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_IRON_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_MOSSY_COBBLESTONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_NETHERRACK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_OBSIDIAN] = true;
g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_SNOW] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICKS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICK_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_SLAB] = true;
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_BIG_FLOWER] = false;
g_BlockIsSolid[E_BLOCK_BROWN_MUSHROOM] = false;
g_BlockIsSolid[E_BLOCK_CARROTS] = false;
g_BlockIsSolid[E_BLOCK_COBWEB] = false;
g_BlockIsSolid[E_BLOCK_CROPS] = false;
g_BlockIsSolid[E_BLOCK_DANDELION] = false;
g_BlockIsSolid[E_BLOCK_DETECTOR_RAIL] = false;
g_BlockIsSolid[E_BLOCK_END_PORTAL] = false;
g_BlockIsSolid[E_BLOCK_FIRE] = false;
g_BlockIsSolid[E_BLOCK_FLOWER] = false;
g_BlockIsSolid[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_LAVA] = false;
g_BlockIsSolid[E_BLOCK_LEVER] = 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_EXTENSION] = false;
g_BlockIsSolid[E_BLOCK_POTATOES] = false;
g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
g_BlockIsSolid[E_BLOCK_RAIL] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_WIRE] = false;
g_BlockIsSolid[E_BLOCK_RED_MUSHROOM] = false;
g_BlockIsSolid[E_BLOCK_REEDS] = false;
g_BlockIsSolid[E_BLOCK_SAPLING] = false;
g_BlockIsSolid[E_BLOCK_SIGN_POST] = false;
g_BlockIsSolid[E_BLOCK_SNOW] = false;
g_BlockIsSolid[E_BLOCK_STATIONARY_LAVA] = false;
g_BlockIsSolid[E_BLOCK_STATIONARY_WATER] = false;
g_BlockIsSolid[E_BLOCK_STONE_BUTTON] = false;
g_BlockIsSolid[E_BLOCK_STONE_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_TALL_GRASS] = false;
g_BlockIsSolid[E_BLOCK_TORCH] = 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_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false;
// Torch placeable blocks:
g_BlockFullyOccupiesVoxel[E_BLOCK_NEW_LOG] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BEDROCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_COAL] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_REDSTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BOOKCASE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BRICK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_CLAY] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_COAL_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_COBBLESTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_COMMAND_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_CRAFTING_TABLE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DIRT] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DISPENSER] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_STONE_SLAB] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_WOODEN_SLAB] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DROPPER] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_END_STONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_FURNACE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GLOWSTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GRASS] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GRAVEL] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HARDENED_CLAY] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HAY_BALE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_BROWN_MUSHROOM] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_RED_MUSHROOM] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_JACK_O_LANTERN] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_JUKEBOX] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_LOG] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_MELON] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_MOSSY_COBBLESTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_MYCELIUM] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NETHERRACK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_BRICK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_QUARTZ_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NOTE_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_OBSIDIAN] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_PACKED_ICE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_PLANKS] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_PUMPKIN] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_QUARTZ_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_OFF] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_ON] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SANDSTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SAND] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SILVERFISH_EGG] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SPONGE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_STAINED_CLAY] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_WOOL] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_STONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_STONE_BRICKS] = true;
}
} BlockPropertiesInitializer;

View File

@ -853,9 +853,30 @@ enum eExplosionSource
esWitherSkullBlue,
esWitherBirth,
esPlugin,
// Obsolete constants, kept for compatibility, will be removed after some time:
esCreeper = esMonster,
} ;
enum eShrapnelLevel
{
slNone,
slGravityAffectedOnly,
slAll
} ;
enum eSpreadSource
{
ssFireSpread,
ssGrassSpread,
ssMushroomSpread,
ssMycelSpread,
ssVineSpread,
} ;
// tolua_end
@ -909,17 +930,3 @@ extern cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const c
// Block properties:
extern NIBBLETYPE g_BlockLightValue[256];
extern NIBBLETYPE g_BlockSpreadLightFalloff[256];
extern bool g_BlockTransparent[256];
extern bool g_BlockOneHitDig[256];
extern bool g_BlockPistonBreakable[256];
extern bool g_BlockIsSnowable[256];
extern bool g_BlockRequiresSpecialTool[256];
extern bool g_BlockIsSolid[256];
extern bool g_BlockFullyOccupiesVoxel[256];

451
src/BlockInfo.cpp Normal file
View File

@ -0,0 +1,451 @@
#include "Globals.h"
#include "BlockInfo.h"
#include "Blocks/BlockHandler.h"
cBlockInfo cBlockInfo::ms_Info[256];
cBlockInfo::cBlockInfo()
: m_LightValue(0x00)
, m_SpreadLightFalloff(0x0f)
, m_Transparent(false)
, m_OneHitDig(false)
, m_PistonBreakable(false)
, m_IsSnowable(true)
, m_RequiresSpecialTool(false)
, m_IsSolid(true)
, m_FullyOccupiesVoxel(false)
, m_Handler(NULL)
{}
cBlockInfo::~cBlockInfo()
{
delete m_Handler;
}
cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
{
return ms_Info[a_Type];
}
void cBlockInfo::Initialize(void)
{
for (unsigned int i = 0; i < 256; ++i)
{
if (ms_Info[i].m_Handler == NULL)
{
ms_Info[i].m_Handler = cBlockHandler::CreateBlockHandler((BLOCKTYPE) i);
}
}
// Emissive blocks
ms_Info[E_BLOCK_FIRE ].m_LightValue = 15;
ms_Info[E_BLOCK_GLOWSTONE ].m_LightValue = 15;
ms_Info[E_BLOCK_JACK_O_LANTERN ].m_LightValue = 15;
ms_Info[E_BLOCK_LAVA ].m_LightValue = 15;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_LightValue = 15;
ms_Info[E_BLOCK_END_PORTAL ].m_LightValue = 15;
ms_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_LightValue = 15;
ms_Info[E_BLOCK_TORCH ].m_LightValue = 14;
ms_Info[E_BLOCK_BURNING_FURNACE ].m_LightValue = 13;
ms_Info[E_BLOCK_NETHER_PORTAL ].m_LightValue = 11;
ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_LightValue = 9;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_LightValue = 9;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_LightValue = 7;
ms_Info[E_BLOCK_BREWING_STAND ].m_LightValue = 1;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_LightValue = 1;
ms_Info[E_BLOCK_DRAGON_EGG ].m_LightValue = 1;
// Spread blocks
ms_Info[E_BLOCK_AIR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_CAKE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_CHEST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_COBWEB ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_CROPS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_FENCE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_FENCE_GATE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_FIRE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_GLASS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_GLASS_PANE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_GLOWSTONE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_WALLSIGN ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_WOODEN_DOOR ].m_SpreadLightFalloff = 1;
// Light in water and lava dissapears faster:
ms_Info[E_BLOCK_LAVA ].m_SpreadLightFalloff = 3;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_SpreadLightFalloff = 3;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_SpreadLightFalloff = 3;
ms_Info[E_BLOCK_WATER ].m_SpreadLightFalloff = 3;
// Transparent blocks
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_AIR ].m_Transparent = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_Transparent = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_Transparent = true;
ms_Info[E_BLOCK_CARROTS ].m_Transparent = true;
ms_Info[E_BLOCK_CHEST ].m_Transparent = true;
ms_Info[E_BLOCK_COBWEB ].m_Transparent = true;
ms_Info[E_BLOCK_CROPS ].m_Transparent = true;
ms_Info[E_BLOCK_DANDELION ].m_Transparent = true;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_ENDER_CHEST ].m_Transparent = true;
ms_Info[E_BLOCK_FENCE ].m_Transparent = true;
ms_Info[E_BLOCK_FENCE_GATE ].m_Transparent = true;
ms_Info[E_BLOCK_FIRE ].m_Transparent = true;
ms_Info[E_BLOCK_FLOWER ].m_Transparent = true;
ms_Info[E_BLOCK_FLOWER_POT ].m_Transparent = true;
ms_Info[E_BLOCK_GLASS ].m_Transparent = true;
ms_Info[E_BLOCK_GLASS_PANE ].m_Transparent = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_ICE ].m_Transparent = true;
ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_MELON_STEM ].m_Transparent = true;
ms_Info[E_BLOCK_NETHER_BRICK_FENCE ].m_Transparent = true;
ms_Info[E_BLOCK_NEW_LEAVES ].m_Transparent = true;
ms_Info[E_BLOCK_POTATOES ].m_Transparent = true;
ms_Info[E_BLOCK_POWERED_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_PISTON_EXTENSION ].m_Transparent = true;
ms_Info[E_BLOCK_PUMPKIN_STEM ].m_Transparent = true;
ms_Info[E_BLOCK_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_Transparent = true;
ms_Info[E_BLOCK_SIGN_POST ].m_Transparent = true;
ms_Info[E_BLOCK_SNOW ].m_Transparent = true;
ms_Info[E_BLOCK_STAINED_GLASS ].m_Transparent = true;
ms_Info[E_BLOCK_STAINED_GLASS_PANE ].m_Transparent = true;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_Transparent = true;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true;
ms_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true;
ms_Info[E_BLOCK_TORCH ].m_Transparent = true;
ms_Info[E_BLOCK_VINES ].m_Transparent = true;
ms_Info[E_BLOCK_WALLSIGN ].m_Transparent = true;
ms_Info[E_BLOCK_WATER ].m_Transparent = true;
ms_Info[E_BLOCK_WOODEN_BUTTON ].m_Transparent = true;
ms_Info[E_BLOCK_WOODEN_DOOR ].m_Transparent = true;
ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_Transparent = true;
// TODO: Any other transparent blocks?
// One hit break blocks:
ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_OneHitDig = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_OneHitDig = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_OneHitDig = true;
ms_Info[E_BLOCK_CARROTS ].m_OneHitDig = true;
ms_Info[E_BLOCK_CROPS ].m_OneHitDig = true;
ms_Info[E_BLOCK_DANDELION ].m_OneHitDig = true;
ms_Info[E_BLOCK_FIRE ].m_OneHitDig = true;
ms_Info[E_BLOCK_FLOWER ].m_OneHitDig = true;
ms_Info[E_BLOCK_FLOWER_POT ].m_OneHitDig = true;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_OneHitDig = true;
ms_Info[E_BLOCK_MELON_STEM ].m_OneHitDig = true;
ms_Info[E_BLOCK_POTATOES ].m_OneHitDig = true;
ms_Info[E_BLOCK_PUMPKIN_STEM ].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_OneHitDig = true;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_OneHitDig = true;
ms_Info[E_BLOCK_REEDS ].m_OneHitDig = true;
ms_Info[E_BLOCK_SAPLING ].m_OneHitDig = true;
ms_Info[E_BLOCK_TNT ].m_OneHitDig = true;
ms_Info[E_BLOCK_TALL_GRASS ].m_OneHitDig = true;
ms_Info[E_BLOCK_TORCH ].m_OneHitDig = true;
// Blocks that break when pushed by piston:
ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_AIR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BED ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_COBWEB ].m_PistonBreakable = true;
ms_Info[E_BLOCK_CROPS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_DANDELION ].m_PistonBreakable = true;
ms_Info[E_BLOCK_DEAD_BUSH ].m_PistonBreakable = true;
ms_Info[E_BLOCK_FIRE ].m_PistonBreakable = true;
ms_Info[E_BLOCK_FLOWER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_JACK_O_LANTERN ].m_PistonBreakable = true;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_LADDER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_LAVA ].m_PistonBreakable = true;
ms_Info[E_BLOCK_LEVER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_MELON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_MELON_STEM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_PUMPKIN ].m_PistonBreakable = true;
ms_Info[E_BLOCK_PUMPKIN_STEM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_PistonBreakable = true;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REEDS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_SNOW ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STONE_BUTTON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_TALL_GRASS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_TORCH ].m_PistonBreakable = true;
ms_Info[E_BLOCK_VINES ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WATER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WOODEN_BUTTON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WOODEN_DOOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_PistonBreakable = true;
// Blocks that cannot be snowed over:
ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_IsSnowable = false;
ms_Info[E_BLOCK_AIR ].m_IsSnowable = false;
ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSnowable = false;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSnowable = false;
ms_Info[E_BLOCK_CACTUS ].m_IsSnowable = false;
ms_Info[E_BLOCK_CHEST ].m_IsSnowable = false;
ms_Info[E_BLOCK_CROPS ].m_IsSnowable = false;
ms_Info[E_BLOCK_DANDELION ].m_IsSnowable = false;
ms_Info[E_BLOCK_FIRE ].m_IsSnowable = false;
ms_Info[E_BLOCK_FLOWER ].m_IsSnowable = false;
ms_Info[E_BLOCK_GLASS ].m_IsSnowable = false;
ms_Info[E_BLOCK_ICE ].m_IsSnowable = false;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_IsSnowable = false;
ms_Info[E_BLOCK_LAVA ].m_IsSnowable = false;
ms_Info[E_BLOCK_LILY_PAD ].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSnowable = false;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_IsSnowable = false;
ms_Info[E_BLOCK_REEDS ].m_IsSnowable = false;
ms_Info[E_BLOCK_SAPLING ].m_IsSnowable = false;
ms_Info[E_BLOCK_SIGN_POST ].m_IsSnowable = false;
ms_Info[E_BLOCK_SNOW ].m_IsSnowable = false;
ms_Info[E_BLOCK_STAINED_GLASS ].m_IsSnowable = false;
ms_Info[E_BLOCK_STAINED_GLASS_PANE ].m_IsSnowable = false;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSnowable = false;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_IsSnowable = false;
ms_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false;
ms_Info[E_BLOCK_TNT ].m_IsSnowable = false;
ms_Info[E_BLOCK_TORCH ].m_IsSnowable = false;
ms_Info[E_BLOCK_VINES ].m_IsSnowable = false;
ms_Info[E_BLOCK_WALLSIGN ].m_IsSnowable = false;
ms_Info[E_BLOCK_WATER ].m_IsSnowable = false;
ms_Info[E_BLOCK_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_COBWEB ].m_IsSnowable = false;
// Blocks that don't drop without a special tool:
ms_Info[E_BLOCK_BRICK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_CAULDRON ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COAL_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBBLESTONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBBLESTONE_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBWEB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DIAMOND_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_EMERALD_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_END_STONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_GOLD_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_GOLD_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_IRON_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_IRON_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LAPIS_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LAPIS_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_NETHERRACK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_NETHER_BRICK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_NETHER_BRICK_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_OBSIDIAN ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_REDSTONE_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_SANDSTONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_SANDSTONE_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_SNOW ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_BRICKS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_BRICK_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_SLAB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_VINES ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_FURNACE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LIT_FURNACE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_ANVIL ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_ENCHANTMENT_TABLE ].m_RequiresSpecialTool = true;
// Nonsolid blocks:
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_AIR ].m_IsSolid = false;
ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false;
ms_Info[E_BLOCK_CARROTS ].m_IsSolid = false;
ms_Info[E_BLOCK_COBWEB ].m_IsSolid = false;
ms_Info[E_BLOCK_CROPS ].m_IsSolid = false;
ms_Info[E_BLOCK_DANDELION ].m_IsSolid = false;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_END_PORTAL ].m_IsSolid = false;
ms_Info[E_BLOCK_FIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_FLOWER ].m_IsSolid = false;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_LAVA ].m_IsSolid = false;
ms_Info[E_BLOCK_LEVER ].m_IsSolid = false;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_MELON_STEM ].m_IsSolid = false;
ms_Info[E_BLOCK_NETHER_PORTAL ].m_IsSolid = false;
ms_Info[E_BLOCK_PISTON_EXTENSION ].m_IsSolid = false;
ms_Info[E_BLOCK_POTATOES ].m_IsSolid = false;
ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSolid = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSolid = false;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_IsSolid = false;
ms_Info[E_BLOCK_REEDS ].m_IsSolid = false;
ms_Info[E_BLOCK_SAPLING ].m_IsSolid = false;
ms_Info[E_BLOCK_SIGN_POST ].m_IsSolid = false;
ms_Info[E_BLOCK_SNOW ].m_IsSolid = false;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSolid = false;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_IsSolid = false;
ms_Info[E_BLOCK_STONE_BUTTON ].m_IsSolid = false;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_TALL_GRASS ].m_IsSolid = false;
ms_Info[E_BLOCK_TORCH ].m_IsSolid = false;
ms_Info[E_BLOCK_TRIPWIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_VINES ].m_IsSolid = false;
ms_Info[E_BLOCK_WALLSIGN ].m_IsSolid = false;
ms_Info[E_BLOCK_WATER ].m_IsSolid = false;
ms_Info[E_BLOCK_WOODEN_BUTTON ].m_IsSolid = false;
ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_WOODEN_SLAB ].m_IsSolid = false;
// Blocks that fully occupy their voxel - used as a guide for torch placeable blocks, amongst other things:
ms_Info[E_BLOCK_NEW_LOG ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BEDROCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BLOCK_OF_COAL ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BLOCK_OF_REDSTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BOOKCASE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BRICK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_CLAY ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_COAL_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_COBBLESTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_COMMAND_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_CRAFTING_TABLE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DIAMOND_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DIRT ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DISPENSER ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DOUBLE_WOODEN_SLAB ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DROPPER ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_EMERALD_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_EMERALD_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_END_STONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_FURNACE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GLOWSTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GOLD_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GOLD_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GRASS ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GRAVEL ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HARDENED_CLAY ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HAY_BALE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_ICE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_IRON_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_IRON_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_JACK_O_LANTERN ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_JUKEBOX ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_LAPIS_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_LAPIS_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_LOG ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_MELON ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_MYCELIUM ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NETHERRACK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NETHER_BRICK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NETHER_QUARTZ_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NOTE_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_OBSIDIAN ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_PACKED_ICE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_PLANKS ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_PUMPKIN ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_QUARTZ_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SANDSTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SAND ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SILVERFISH_EGG ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SPONGE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_STAINED_CLAY ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_WOOL ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_STONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_STONE_BRICKS ].m_FullyOccupiesVoxel = true;
}
// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
class cBlockInfoInitializer
{
public:
cBlockInfoInitializer(void)
{
cBlockInfo::Initialize();
}
} BlockInfoInitializer;

103
src/BlockInfo.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
// fwd:
class cBlockHandler;
// tolua_begin
class cBlockInfo
{
public:
// tolua_end
cBlockInfo();
~cBlockInfo();
/** (Re-)Initializes the internal BlockInfo structures. */
static void Initialize(void);
// tolua_begin
/** Returns the associated BlockInfo structure. */
static cBlockInfo & Get(BLOCKTYPE a_Type);
/** How much light do the blocks emit on their own? */
NIBBLETYPE m_LightValue;
/** How much light do the blocks consume? */
NIBBLETYPE m_SpreadLightFalloff;
/** Is a block completely transparent? (light doesn't get decreased(?)) */
bool m_Transparent;
/** Is a block destroyed after a single hit? */
bool m_OneHitDig;
/** Can a piston break this block? */
bool m_PistonBreakable;
/** Can this block hold snow atop? */
bool m_IsSnowable;
/** Does this block require a tool to drop? */
bool m_RequiresSpecialTool;
/** Is this block solid (player cannot walk through)? */
bool m_IsSolid;
/** Does this block fully occupy its voxel - is it a 'full' block? */
bool m_FullyOccupiesVoxel;
// tolua_end
/** Associated block handler. */
cBlockHandler * m_Handler;
// tolua_begin
inline static NIBBLETYPE GetLightValue (BLOCKTYPE a_Type) { return Get(a_Type).m_LightValue; }
inline static NIBBLETYPE GetSpreadLightFalloff(BLOCKTYPE a_Type) { return Get(a_Type).m_SpreadLightFalloff; }
inline static bool IsTransparent (BLOCKTYPE a_Type) { return Get(a_Type).m_Transparent; }
inline static bool IsOneHitDig (BLOCKTYPE a_Type) { return Get(a_Type).m_OneHitDig; }
inline static bool IsPistonBreakable (BLOCKTYPE a_Type) { return Get(a_Type).m_PistonBreakable; }
inline static bool IsSnowable (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSnowable; }
inline static bool RequiresSpecialTool (BLOCKTYPE a_Type) { return Get(a_Type).m_RequiresSpecialTool; }
inline static bool IsSolid (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSolid; }
inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; }
// tolua_end
inline static cBlockHandler * GetHandler (BLOCKTYPE a_Type) { return Get(a_Type).m_Handler; }
protected:
// TODO xdot: Change to std::vector to support dynamic block IDs
static cBlockInfo ms_Info[256];
}; // tolua_export
// Shortcut to get the blockhandler for a specific block
inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
{
return cBlockInfo::Get(a_BlockType).m_Handler;
}

View File

@ -28,6 +28,9 @@ public:
class cCallbacks abstract
{
public:
// Force a virtual destructor in descendants:
virtual ~cCallbacks() {}
/** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted.
*/

61
src/Blocks/BlockAnvil.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include "BlockHandler.h"
#include "../World.h"
#include "../Entities/Player.h"
class cBlockAnvilHandler :
public cBlockHandler
{
public:
cBlockAnvilHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
a_BlockType = m_BlockType;
NIBBLETYPE HighBits = a_BlockMeta & 0x0c; // Only highest two bits are preserved
int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 1.5) & 0x3;
switch (Direction)
{
case 0: a_BlockMeta = 0x2 | HighBits; break;
case 1: a_BlockMeta = 0x3 | HighBits; break;
case 2: a_BlockMeta = 0x0 | HighBits; break;
case 3: a_BlockMeta = 0x1 | HighBits; break;
default:
{
return false;
}
}
return true;
}
virtual bool IsUseable() override
{
return true;
}
} ;

View File

@ -51,6 +51,49 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
class cTimeFastForwardTester :
public cPlayerListCallback
{
virtual bool Item(cPlayer * a_Player) override
{
if (!a_Player->IsInBed())
{
return true;
}
return false;
}
};
class cPlayerBedStateUnsetter :
public cPlayerListCallback
{
public:
cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) :
m_Position(a_Position), m_WorldInterface(a_WorldInterface)
{
}
virtual bool Item(cPlayer * a_Player) override
{
a_Player->SetIsInBed(false);
m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
return false;
}
private:
Vector3i m_Position;
cWorldInterface & m_WorldInterface;
};
void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
if (a_WorldInterface.GetDimension() != dimOverworld)
@ -69,6 +112,8 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
}
else
{
Vector3i PillowDirection(0, 0, 0);
if (Meta & 0x8)
{
// Is pillow
@ -77,16 +122,30 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
else
{
// Is foot end
Vector3i Direction = MetaDataToDirection( Meta & 0x7 );
if (a_ChunkInterface.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
PillowDirection = MetaDataToDirection(Meta & 0x7);
if (a_ChunkInterface.GetBlock(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
{
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z);
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z);
}
}
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (Meta | (1 << 2)));
}
} else {
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
a_Player->SetIsInBed(true);
cTimeFastForwardTester Tester;
if (a_WorldInterface.ForEachPlayer(Tester))
{
cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
a_WorldInterface.ForEachPlayer(Unsetter);
a_WorldInterface.SetTimeOfDay(0);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0xB); // Where 0xB = 1011, and zero is to make sure 'occupied' bit is always unset
}
}
}
else
{
a_Player->SendMessageFailure("You can only sleep at night");
}
}

View File

@ -4,6 +4,7 @@
#include "BlockHandler.h"
#include "ChunkInterface.h"
#include "WorldInterface.h"
#include "MetaRotator.h"
#include "../Entities/Player.h"
@ -11,11 +12,11 @@
class cBlockBedHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockBedHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
{
}

View File

@ -2,16 +2,17 @@
#include "BlockHandler.h"
#include "Chunk.h"
#include "MetaRotator.h"
class cBlockButtonHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{
public:
cBlockButtonHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{
}
@ -101,7 +102,7 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]);
return (a_RelY > 0) && (cBlockInfo::IsSolid(BlockIsOn));
}
} ;

View File

@ -54,7 +54,7 @@ public:
NIBBLETYPE BlockMeta;
if (
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
(g_BlockIsSolid[BlockType])
cBlockInfo::IsSolid(BlockType)
)
{
return false;

55
src/Blocks/BlockCake.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include "BlockHandler.h"
class cBlockCakeHandler :
public cBlockHandler
{
public:
cBlockCakeHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (!a_Player->Feed(2, 0.1))
{
return;
}
if (Meta >= 5)
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
}
else
{
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta + 1);
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Give nothing
}
virtual bool IsUseable(void) override
{
return true;
}
virtual const char * GetStepSound(void) override
{
return "step.cloth";
}
} ;

View File

@ -23,7 +23,7 @@ public:
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
char Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
switch (a_Player->GetEquippedItem().m_ItemType)
{
case E_ITEM_WATER_BUCKET:

View File

@ -4,17 +4,18 @@
#include "BlockEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
#include "MetaRotator.h"
class cBlockChestHandler :
public cBlockEntityHandler
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockChestHandler(BLOCKTYPE a_BlockType)
: cBlockEntityHandler(a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}

View File

@ -3,17 +3,18 @@
#include "BlockHandler.h"
#include "BlockRedstoneRepeater.h"
#include "MetaRotator.h"
class cBlockComparatorHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{
public:
cBlockComparatorHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{
}
@ -26,6 +27,13 @@ public:
}
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
UNUSED(a_ChunkInterface);
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "../MersenneTwister.h"
#include "../FastRandom.h"
@ -21,7 +21,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
{
MTRand rand;
cFastRandom rand;
if (a_Meta == 0x7)
{
@ -31,18 +31,18 @@ public:
case E_BLOCK_CROPS:
{
a_Pickups.push_back(cItem(E_ITEM_WHEAT, 1, 0));
a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2
a_Pickups.push_back(cItem(E_ITEM_SEEDS, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
break;
}
case E_BLOCK_CARROTS:
{
a_Pickups.push_back(cItem(E_ITEM_CARROT, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2
a_Pickups.push_back(cItem(E_ITEM_CARROT, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
break;
}
case E_BLOCK_POTATOES:
{
a_Pickups.push_back(cItem(E_ITEM_POTATO, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2
if (rand.randInt(20) == 0)
a_Pickups.push_back(cItem(E_ITEM_POTATO, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
if (rand.NextInt(21) == 0)
{
// With a 5% chance, drop a poisonous potato as well
a_Pickups.push_back(cItem(E_ITEM_POISONOUS_POTATO, 1, 0));

View File

@ -2,8 +2,8 @@
#pragma once
#include "BlockHandler.h"
#include "../MersenneTwister.h"
#include "BlockSlab.h"
#include "../FastRandom.h"
@ -39,7 +39,7 @@ public:
BLOCKTYPE Above;
NIBBLETYPE AboveMeta;
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY + 1, a_RelZ, Above, AboveMeta);
if ((!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above] && !(cBlockSlabHandler::IsAnySlabType(Above) && (AboveMeta & 0x8))) || IsBlockWater(Above))
if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above) && !(cBlockSlabHandler::IsAnySlabType(Above) && (AboveMeta & 0x8))) || IsBlockWater(Above))
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL);
return;
@ -47,12 +47,12 @@ public:
}
// Grass spreads to adjacent dirt blocks:
MTRand rand; // TODO: Replace with cFastRandom
cFastRandom rand;
for (int i = 0; i < 2; i++) // Pick two blocks to grow to
{
int OfsX = rand.randInt(2) - 1; // [-1 .. 1]
int OfsY = rand.randInt(4) - 3; // [-3 .. 1]
int OfsZ = rand.randInt(2) - 1; // [-1 .. 1]
int OfsX = rand.NextInt(3, a_RelX) - 1; // [-1 .. 1]
int OfsY = rand.NextInt(5, a_RelY) - 3; // [-3 .. 1]
int OfsZ = rand.NextInt(3, a_RelZ) - 1; // [-1 .. 1]
BLOCKTYPE DestBlock;
NIBBLETYPE DestMeta;
@ -80,9 +80,12 @@ public:
BLOCKTYPE AboveDest;
NIBBLETYPE AboveMeta;
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
if ((g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest] || ((cBlockSlabHandler::IsAnySlabType(AboveDest)) && (AboveMeta & 0x8))) && !IsBlockWater(AboveDest))
if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest) || ((cBlockSlabHandler::IsAnySlabType(AboveDest)) && (AboveMeta & 0x8))) && !IsBlockWater(AboveDest))
{
Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread))
{
Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
}
}
} // for i - repeat twice
}

View File

@ -9,7 +9,7 @@
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: super(a_BlockType)
{
}
@ -55,6 +55,29 @@ void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
{
UNUSED(a_ChunkInterface);
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (Meta & 8)
{
// Current block is top of the door
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
}
else
{
// Current block is bottom of the door
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
}
}
void cBlockDoorHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -87,3 +110,87 @@ const char * cBlockDoorHandler::GetStepSound(void)
NIBBLETYPE cBlockDoorHandler::MetaRotateCCW(NIBBLETYPE a_Meta)
{
if (a_Meta & 0x08)
{
return a_Meta;
}
else
{
return super::MetaRotateCCW(a_Meta);
}
}
NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta)
{
if (a_Meta & 0x08)
{
return a_Meta;
}
else
{
return super::MetaRotateCW(a_Meta);
}
}
NIBBLETYPE cBlockDoorHandler::MetaMirrorXY(NIBBLETYPE a_Meta)
{
// Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data
// Return a_Meta if panel is a top panel (0x08 bit is set to 1)
// Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored
// in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,
// so the function can only see either the hinge position or orientation, but not both, at any given time. The class itself
// needs extra datamembers.
if (a_Meta & 0x08) return a_Meta;
// Holds open/closed meta data. 0x0C == 1100.
NIBBLETYPE OtherMeta = a_Meta & 0x0C;
// Mirrors according to a table. 0x03 == 0011.
switch (a_Meta & 0x03)
{
case 0x03: return 0x01 + OtherMeta; // South -> North
case 0x01: return 0x03 + OtherMeta; // North -> South
}
// Not Facing North or South; No change.
return a_Meta;
}
NIBBLETYPE cBlockDoorHandler::MetaMirrorYZ(NIBBLETYPE a_Meta)
{
// Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data
// Return a_Meta if panel is a top panel (0x08 bit is set to 1)
// Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored
// in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,
// so the function can only see either the hinge position or orientation, but not both, at any given time.The class itself
// needs extra datamembers.
if (a_Meta & 0x08) return a_Meta;
// Holds open/closed meta data. 0x0C == 1100.
NIBBLETYPE OtherMeta = a_Meta & 0x0C;
// Mirrors according to a table. 0x03 == 0011.
switch (a_Meta & 0x03)
{
case 0x00: return 0x02 + OtherMeta; // West -> East
case 0x02: return 0x00 + OtherMeta; // East -> West
}
// Not Facing North or South; No change.
return a_Meta;
}

View File

@ -4,20 +4,27 @@
#include "BlockHandler.h"
#include "../Entities/Player.h"
#include "Chunk.h"
#include "MetaRotator.h"
class cBlockDoorHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
{
typedef cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
public:
cBlockDoorHandler(BLOCKTYPE a_BlockType);
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
virtual const char * GetStepSound(void) override;
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
@ -139,14 +146,14 @@ public:
static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_X, int a_Y, int a_Z)
{
NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_X, a_Y, a_Z);
a_ChunkInterface.SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData));
if (OldMetaData & 8)
{
// Current block is top of the door
BLOCKTYPE BottomBlock = a_ChunkInterface.GetBlock(a_X, a_Y - 1, a_Z);
NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z);
NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z);
if (IsDoor(BottomBlock) && !(BottomMeta & 8))
{
@ -165,8 +172,6 @@ public:
}
}
}
} ;

View File

@ -6,17 +6,18 @@
#pragma once
#include "../Piston.h"
#include "MetaRotator.h"
class cBlockDropSpenserHandler :
public cBlockEntityHandler
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) :
cBlockEntityHandler(a_BlockType)
cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@ -34,6 +35,20 @@ public:
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
NIBBLETYPE OtherMeta = a_Meta & 0x08;
// Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
switch (a_Meta & 0x07)
{
case 0x00: return 0x01 + OtherMeta; // Down -> Up
case 0x01: return 0x00 + OtherMeta; // Up -> Down
}
// Not Facing Up or Down; No change.
return a_Meta;
}
} ;

View File

@ -2,17 +2,17 @@
#pragma once
#include "BlockEntity.h"
#include "MetaRotator.h"
class cBlockEnderchestHandler :
public cBlockEntityHandler
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
: cBlockEntityHandler(a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}

View File

@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
class cBlockFenceGateHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType)
cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
@ -48,6 +48,12 @@ public:
}
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual bool IsUseable(void) override
{
return true;

View File

@ -17,25 +17,27 @@ public:
}
/// Portal boundary and direction variables
int XZP, XZM, Dir; // For wont of a better name...
// 2014_03_30 _X: What are these used for? Why do we need extra variables?
int XZP, XZM;
NIBBLETYPE Dir;
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
/*
PORTAL FINDING ALGORITH
=======================
-Get clicked base block
-Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
Uses this value as a reference (the 'ceiling')
-For both directions (if one fails, try the other), BASE (clicked) block:
-Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
-If a border was encountered, go the other direction and repeat above
-Write borders to XZP and XZM, write direction portal faces to Dir
-Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
- Get clicked base block
- Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
Uses this value as a reference (the 'ceiling')
- For both directions (if one fails, try the other), BASE (clicked) block:
- Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
- If a border was encountered, go the other direction and repeat above
- Write borders to XZP and XZM, write direction portal faces to Dir
- Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
*/
a_BlockY--; // Because we want the block below the fire
FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface); // Brought to you by Aperture Science
FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface);
}
virtual void OnDigging(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override

View File

@ -2,101 +2,24 @@
#pragma once
#include "BlockHandler.h"
#include "BlockEntity.h"
class cBlockFlowerPotHandler :
public cBlockHandler
public cBlockEntityHandler
{
public:
cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType)
cBlockEntityHandler(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0));
if (a_BlockMeta == 0)
{
return;
}
cItem Plant;
switch (a_BlockMeta)
{
case 1: Plant = cItem(E_BLOCK_RED_ROSE, 1, 0); break;
case 2: Plant = cItem(E_BLOCK_YELLOW_FLOWER, 1, 0); break;
case 3: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_APPLE); break;
case 4: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_CONIFER); break;
case 5: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_BIRCH); break;
case 6: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_JUNGLE); break;
case 7: Plant = cItem(E_BLOCK_RED_MUSHROOM, 1, 0); break;
case 8: Plant = cItem(E_BLOCK_BROWN_MUSHROOM, 1, 0); break;
case 9: Plant = cItem(E_BLOCK_CACTUS, 1, 0); break;
case 10: Plant = cItem(E_BLOCK_DEAD_BUSH, 1, 0); break;
case 11: Plant = cItem(E_BLOCK_TALL_GRASS, 1, E_META_TALL_GRASS_FERN); break;
default: return;
}
a_Pickups.push_back(Plant);
}
void OnUse(cWorld * a_World, cWorldInterface * a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{
NIBBLETYPE Meta = a_World->GetBlockMeta( a_BlockX, a_BlockY, a_BlockZ );
if (Meta != 0)
{
// Already filled
return;
}
switch (a_Player->GetEquippedItem().m_ItemType)
{
case E_BLOCK_RED_ROSE: Meta = 1; break;
case E_BLOCK_YELLOW_FLOWER: Meta = 2; break;
case E_BLOCK_SAPLING:
{
switch (a_Player->GetEquippedItem().m_ItemDamage)
{
case E_META_SAPLING_APPLE: Meta = 3; break;
case E_META_SAPLING_CONIFER: Meta = 4; break;
case E_META_SAPLING_BIRCH: Meta = 5; break;
case E_META_SAPLING_JUNGLE: Meta = 6; break;
}
break;
}
case E_BLOCK_RED_MUSHROOM: Meta = 7; break;
case E_BLOCK_BROWN_MUSHROOM: Meta = 8; break;
case E_BLOCK_CACTUS: Meta = 9; break;
case E_BLOCK_DEAD_BUSH: Meta = 10; break;
case E_BLOCK_TALL_GRASS:
{
if (a_Player->GetEquippedItem().m_ItemDamage == E_META_TALL_GRASS_FERN)
{
Meta = 11;
}
else
{
return;
}
break;
}
}
if (a_Player->GetGameMode() != gmCreative)
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
}
virtual bool IsUseable(void) override
{
return true;
}
} ;

View File

@ -93,6 +93,7 @@ public:
// Check if it's fuel:
BLOCKTYPE BlockType;
if (
((a_RelY + y < 0) || (a_RelY + y > cChunkDef::Height)) ||
!a_Chunk.UnboundedRelGetBlockType(a_RelX + x, a_RelY + y, a_RelZ + z, BlockType) ||
!cFireSimulator::IsFuel(BlockType)
)
@ -119,6 +120,7 @@ public:
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
{
if (
((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y <= cChunkDef::Height)) &&
a_Chunk.UnboundedRelGetBlockType(RelX + CrossCoords[i].x, RelY + CrossCoords[i].y, RelZ + CrossCoords[i].z, BlockType) &&
(BlockType == E_BLOCK_AIR)
)

View File

@ -4,17 +4,17 @@
#include "BlockEntity.h"
#include "../World.h"
#include "../Piston.h"
#include "MetaRotator.h"
class cBlockFurnaceHandler :
public cBlockEntityHandler
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockFurnaceHandler(BLOCKTYPE a_BlockType) :
cBlockEntityHandler(a_BlockType)
cBlockFurnaceHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}

View File

@ -6,10 +6,12 @@
#include "../Root.h"
#include "../Bindings/PluginManager.h"
#include "../Chunk.h"
#include "BlockAnvil.h"
#include "BlockBed.h"
#include "BlockBrewingStand.h"
#include "BlockButton.h"
#include "BlockCactus.h"
#include "BlockCake.h"
#include "BlockCarpet.h"
#include "BlockCauldron.h"
#include "BlockChest.h"
@ -39,6 +41,7 @@
#include "BlockIce.h"
#include "BlockLadder.h"
#include "BlockLeaves.h"
#include "BlockLilypad.h"
#include "BlockNewLeaves.h"
#include "BlockLever.h"
#include "BlockMelon.h"
@ -57,6 +60,7 @@
#include "BlockRedstoneLamp.h"
#include "BlockRedstoneRepeater.h"
#include "BlockRedstoneTorch.h"
#include "BlockTNT.h"
#include "BlockSand.h"
#include "BlockSapling.h"
#include "BlockSideways.h"
@ -77,33 +81,6 @@
bool cBlockHandler::m_HandlerInitialized = false;
cBlockHandler * cBlockHandler::m_BlockHandler[256];
cBlockHandler * cBlockHandler::GetBlockHandler(BLOCKTYPE a_BlockType)
{
if (!m_HandlerInitialized)
{
// We have to initialize
memset(m_BlockHandler, 0, sizeof(m_BlockHandler));
m_HandlerInitialized = true;
}
if (m_BlockHandler[a_BlockType] != NULL)
{
return m_BlockHandler[a_BlockType];
}
return m_BlockHandler[a_BlockType] = CreateBlockHandler(a_BlockType);
}
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
@ -111,12 +88,14 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
// Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType);
case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BROWN_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_CACTUS: return new cBlockCactusHandler (a_BlockType);
case E_BLOCK_CAKE: return new cBlockCakeHandler (a_BlockType);
case E_BLOCK_CARROTS: return new cBlockCropsHandler (a_BlockType);
case E_BLOCK_CARPET: return new cBlockCarpetHandler (a_BlockType);
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);
@ -164,6 +143,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LAPIS_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType);
case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType);
case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType);
case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType);
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
@ -172,6 +152,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType);
case E_BLOCK_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_NEW_LEAVES: return new cBlockNewLeavesHandler (a_BlockType);
case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType);
@ -192,7 +173,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_REDSTONE_REPEATER_ON: return new cBlockRedstoneRepeaterHandler(a_BlockType);
case E_BLOCK_REDSTONE_TORCH_OFF: return new cBlockRedstoneTorchHandler (a_BlockType);
case E_BLOCK_REDSTONE_TORCH_ON: return new cBlockRedstoneTorchHandler (a_BlockType);
case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
case E_BLOCK_RED_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_RED_ROSE: return new cBlockFlowerHandler (a_BlockType);
case E_BLOCK_SAND: return new cBlockSandHandler (a_BlockType);
@ -212,6 +193,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType);
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
@ -231,20 +213,6 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
void cBlockHandler::Deinit()
{
for (int i = 0; i < 256; i++)
{
delete m_BlockHandler[i];
}
memset(m_BlockHandler, 0, sizeof(m_BlockHandler)); // Don't leave any dangling pointers around, just in case
m_HandlerInitialized = false;
}
cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType)
{
m_BlockType = a_BlockType;
@ -329,7 +297,7 @@ void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_Bl
{
if ((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height))
{
GetBlockHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
}
}
@ -361,6 +329,14 @@ void cBlockHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface &
void cBlockHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
{
}
void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
// Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this.

View File

@ -23,6 +23,8 @@ class cBlockHandler
{
public:
cBlockHandler(BLOCKTYPE a_BlockType);
virtual ~cBlockHandler() {}
/// Called when the block gets ticked either by a random tick or by a queued tick.
/// Note that the coords are chunk-relative!
@ -69,6 +71,9 @@ public:
/// Called if the user right clicks the block and the block is useable
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
/** Called when a Right Click to this Block is cancelled */
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
/// <summary>Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents</summary>
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
@ -136,31 +141,15 @@ public:
/// <returns>Block meta following mirroring</returns>
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; }
/// <summary>Get the blockhandler for a specific block id</summary>
static cBlockHandler * GetBlockHandler(BLOCKTYPE a_BlockType);
/// <summary>Deletes all initialised block handlers</summary>
static void Deinit();
protected:
BLOCKTYPE m_BlockType;
// Creates a new blockhandler for the given block type. For internal use only, use ::GetBlockHandler() instead.
static cBlockHandler *CreateBlockHandler(BLOCKTYPE a_BlockType);
static cBlockHandler *m_BlockHandler[256];
static bool m_HandlerInitialized; //used to detect if the blockhandlers are initialized
static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType);
friend class cBlockInfo;
};
// Shortcut to get the blockhandler for a specific block
inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
{
return cBlockHandler::GetBlockHandler(a_BlockType);
}

View File

@ -3,16 +3,16 @@
// Declares the cBlockHopperHandler class representing the handler for the Hopper block
#include "MetaRotator.h"
class cBlockHopperHandler :
public cBlockEntityHandler
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockHopperHandler(BLOCKTYPE a_BlockType)
: cBlockEntityHandler(a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@ -39,6 +39,21 @@ public:
}
return true;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
NIBBLETYPE OtherMeta = a_Meta & 0x08;
// Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
switch (a_Meta & 0x07)
{
case 0x00: return 0x01 + OtherMeta; // Down -> Up
case 0x01: return 0x00 + OtherMeta; // Up -> Down
}
// Not Facing Up or Down; No change.
return a_Meta;
}
} ;

View File

@ -9,11 +9,11 @@
class cBlockLadderHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockLadderHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@ -91,7 +91,7 @@ public:
AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true);
return g_BlockIsSolid[a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)];
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ));
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "BlockHandler.h"
#include "../MersenneTwister.h"
#include "../FastRandom.h"
#include "../World.h"
#include "../BlockArea.h"
@ -16,6 +16,7 @@
{ \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \
case E_BLOCK_NEW_LOG: return true; \
}
bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
@ -36,16 +37,18 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
MTRand rand;
cFastRandom rand;
// Only the first 2 bits contain the display information, the others are for growing
if (rand.randInt(5) == 0)
if (rand.NextInt(6) == 0)
{
a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 3));
}
if ((a_BlockMeta & 3) == E_META_SAPLING_APPLE)
// 1 % chance of dropping an apple, if the leaves' type is Apple Leaves
if ((a_BlockMeta & 3) == E_META_LEAVES_APPLE)
{
if (rand.rand(100) == 0)
if (rand.NextInt(101) == 0)
{
a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));
}
@ -57,11 +60,10 @@ public:
{
cBlockHandler::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ);
//0.5% chance of dropping an apple
// 0.5% chance of dropping an apple, if the leaves' type is Apple Leaves:
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
//check if Oak (0x1 and 0x2 bit not set)
MTRand rand;
if(!(Meta & 3) && rand.randInt(200) == 100)
cFastRandom rand;
if (((Meta & 3) == E_META_LEAVES_APPLE) && (rand.NextInt(201) == 100))
{
cItems Drops;
Drops.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));

View File

@ -1,17 +1,18 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
class cBlockLeverHandler :
public cBlockHandler
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>
{
typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false> super;
public:
cBlockLeverHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>(a_BlockType)
{
}
@ -102,7 +103,37 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]);
return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn);
}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
switch (a_Meta)
{
case 0x00: return 0x07; // Ceiling rotation
case 0x07: return 0x00;
case 0x05: return 0x06; // Ground rotation
case 0x06: return 0x05;
default: return super::MetaRotateCCW(a_Meta); // Wall Rotation
}
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
switch (a_Meta)
{
case 0x00: return 0x07; // Ceiling rotation
case 0x07: return 0x00;
case 0x05: return 0x06; // Ground rotation
case 0x06: return 0x05;
default: return super::MetaRotateCCW(a_Meta); // Wall Rotation
}
}
} ;

28
src/Blocks/BlockLilypad.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include "BlockHandler.h"
#include "Entities/Pickup.h"
class cBlockLilypadHandler :
public cBlockHandler
{
public:
cBlockLilypadHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(E_BLOCK_LILY_PAD, 1, 0));
}
};

Some files were not shown because too many files have changed in this diff Show More