summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@hotmail.co.uk>2014-04-03 20:18:34 +0200
committerTiger Wang <ziwei.tiger@hotmail.co.uk>2014-04-03 20:18:34 +0200
commite1ba51e6ca1cdff477279b7064fc0e0b5117c085 (patch)
treeeaad9f451838b75cd990b548b93f8287fbd75865
parentFixed some bugs (diff)
parentFixed a few MSVC type warnings. (diff)
downloadcuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.tar
cuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.tar.gz
cuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.tar.bz2
cuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.tar.lz
cuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.tar.xz
cuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.tar.zst
cuberite-e1ba51e6ca1cdff477279b7064fc0e0b5117c085.zip
Diffstat (limited to '')
-rw-r--r--Android/jni/Android.mk24
-rw-r--r--LICENSE197
-rw-r--r--MCServer/.gitignore1
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua97
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua40
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua24
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua25
-rw-r--r--MCServer/Plugins/APIDump/SettingUpZeroBrane.html46
-rw-r--r--MCServer/Plugins/APIDump/Static/zbs_logo.pngbin0 -> 1306 bytes
-rw-r--r--MCServer/Plugins/APIDump/Static/zbs_workspace.pngbin0 -> 72631 bytes
-rw-r--r--MCServer/Plugins/APIDump/main_APIDump.lua4
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua40
-rw-r--r--MCServer/Plugins/InfoReg.lua51
-rw-r--r--SetFlags.cmake1
-rw-r--r--lib/md5/md5.h2
-rw-r--r--lib/tolua++/CMakeLists.txt15
-rw-r--r--src/Bindings/DeprecatedBindings.cpp363
-rw-r--r--src/Bindings/LuaState.cpp13
-rw-r--r--src/Bindings/LuaState.h2
-rw-r--r--src/Bindings/ManualBindings.cpp102
-rw-r--r--src/Bindings/ManualBindings.h2
-rw-r--r--src/Bindings/Plugin.h3
-rw-r--r--src/Bindings/PluginLua.cpp66
-rw-r--r--src/Bindings/PluginLua.h3
-rw-r--r--src/Bindings/PluginManager.cpp63
-rw-r--r--src/Bindings/PluginManager.h11
-rw-r--r--src/Bindings/WebPlugin.cpp2
-rw-r--r--src/Bindings/lua51.dll (renamed from src/Bindings/lua5.1.dll)bin167424 -> 167424 bytes
-rw-r--r--src/Bindings/tolua++.exebin185856 -> 200192 bytes
-rw-r--r--src/BlockArea.cpp437
-rw-r--r--src/BlockArea.h69
-rw-r--r--src/BlockEntities/CommandBlockEntity.cpp2
-rw-r--r--src/BlockID.h13
-rw-r--r--src/BlockInfo.cpp3
-rw-r--r--src/BlockTracer.h3
-rw-r--r--src/Blocks/BlockAnvil.h20
-rw-r--r--src/Blocks/BlockBed.h6
-rw-r--r--src/Blocks/BlockButton.h6
-rw-r--r--src/Blocks/BlockCauldron.h2
-rw-r--r--src/Blocks/BlockChest.h6
-rw-r--r--src/Blocks/BlockComparator.h6
-rw-r--r--src/Blocks/BlockCrops.h12
-rw-r--r--src/Blocks/BlockDirt.h15
-rw-r--r--src/Blocks/BlockDoor.cpp84
-rw-r--r--src/Blocks/BlockDoor.h72
-rw-r--r--src/Blocks/BlockDropSpenser.h6
-rw-r--r--src/Blocks/BlockEnderchest.h6
-rw-r--r--src/Blocks/BlockFenceGate.h6
-rw-r--r--src/Blocks/BlockFire.h22
-rw-r--r--src/Blocks/BlockFluid.h2
-rw-r--r--src/Blocks/BlockFurnace.h8
-rw-r--r--src/Blocks/BlockHandler.cpp2
-rw-r--r--src/Blocks/BlockHopper.h21
-rw-r--r--src/Blocks/BlockLadder.h4
-rw-r--r--src/Blocks/BlockLeaves.h19
-rw-r--r--src/Blocks/BlockLever.h37
-rw-r--r--src/Blocks/BlockLilypad.h28
-rw-r--r--src/Blocks/BlockMobHead.h122
-rw-r--r--src/Blocks/BlockMushroom.h3
-rw-r--r--src/Blocks/BlockMycelium.h2
-rw-r--r--src/Blocks/BlockNetherWart.h15
-rw-r--r--src/Blocks/BlockPluginInterface.h6
-rw-r--r--src/Blocks/BlockPumpkin.h6
-rw-r--r--src/Blocks/BlockRail.h136
-rw-r--r--src/Blocks/BlockRedstoneRepeater.h6
-rw-r--r--src/Blocks/BlockSideways.h8
-rw-r--r--src/Blocks/BlockSign.h31
-rw-r--r--src/Blocks/BlockSlab.h55
-rw-r--r--src/Blocks/BlockStairs.h10
-rw-r--r--src/Blocks/BlockStems.h3
-rw-r--r--src/Blocks/BlockTorch.h6
-rw-r--r--src/Blocks/BlockTrapdoor.h6
-rw-r--r--src/Blocks/BlockVine.h15
-rw-r--r--src/Blocks/BroadcastInterface.h3
-rw-r--r--src/Blocks/MetaRotator.h (renamed from src/Blocks/MetaRotater.h)16
-rw-r--r--src/Blocks/WorldInterface.h3
-rw-r--r--src/CMakeLists.txt29
-rw-r--r--src/Chunk.cpp13
-rw-r--r--src/ClientHandle.cpp22
-rw-r--r--src/ClientHandle.h4
-rw-r--r--src/CompositeChat.cpp56
-rw-r--r--src/CompositeChat.h11
-rw-r--r--src/DeadlockDetect.cpp5
-rw-r--r--src/Entities/Boat.cpp2
-rw-r--r--src/Entities/Effects.h2
-rw-r--r--src/Entities/EnderCrystal.cpp56
-rw-r--r--src/Entities/EnderCrystal.h33
-rw-r--r--src/Entities/Entity.h24
-rw-r--r--src/Entities/ExpOrb.h2
-rw-r--r--src/Entities/Floater.h2
-rw-r--r--src/Entities/Player.cpp1
-rw-r--r--src/Entities/ProjectileEntity.cpp12
-rw-r--r--src/ForEachChunkProvider.h2
-rw-r--r--src/Generating/ChunkDesc.cpp6
-rw-r--r--src/Generating/ComposableGenerator.cpp17
-rw-r--r--src/Generating/MineShafts.cpp2
-rw-r--r--src/Generating/NetherFortGen.cpp275
-rw-r--r--src/Generating/NetherFortGen.h86
-rw-r--r--src/Generating/Prefab.cpp316
-rw-r--r--src/Generating/Prefab.h105
-rw-r--r--src/Generating/Prefabs/CMakeLists.txt13
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.cpp2758
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.h15
-rw-r--r--src/Globals.h13
-rw-r--r--src/Group.cpp2
-rw-r--r--src/HTTPServer/EnvelopeParser.h3
-rw-r--r--src/HTTPServer/HTTPFormParser.h3
-rw-r--r--src/HTTPServer/HTTPServer.h4
-rw-r--r--src/HTTPServer/MultipartParser.h3
-rw-r--r--src/Inventory.h2
-rw-r--r--src/Item.h2
-rw-r--r--src/ItemGrid.h46
-rw-r--r--src/Items/ItemBoat.h26
-rw-r--r--src/Items/ItemBucket.h8
-rw-r--r--src/Items/ItemHandler.cpp2
-rw-r--r--src/Items/ItemLilypad.h109
-rw-r--r--src/Items/ItemMinecart.h6
-rw-r--r--src/LightingThread.h6
-rw-r--r--src/MCLogger.cpp23
-rw-r--r--src/MCLogger.h33
-rw-r--r--src/MobSpawner.cpp13
-rw-r--r--src/Mobs/Blaze.cpp2
-rw-r--r--src/Mobs/Blaze.h4
-rw-r--r--src/Mobs/Monster.cpp19
-rw-r--r--src/Mobs/Skeleton.cpp2
-rw-r--r--src/Mobs/Villager.h2
-rw-r--r--src/Mobs/Wither.cpp78
-rw-r--r--src/Mobs/Wither.h17
-rw-r--r--src/OSSupport/Errors.cpp2
-rw-r--r--src/OSSupport/File.cpp20
-rw-r--r--src/OSSupport/GZipFile.cpp4
-rw-r--r--src/OSSupport/ListenThread.h20
-rw-r--r--src/OSSupport/Sleep.h2
-rw-r--r--src/OSSupport/Thread.h2
-rw-r--r--src/Protocol/Protocol125.cpp31
-rw-r--r--src/Protocol/Protocol17x.cpp10
-rw-r--r--src/RCONServer.h2
-rw-r--r--src/Root.cpp1
-rw-r--r--src/Simulator/FireSimulator.cpp14
-rw-r--r--src/Simulator/FluidSimulator.cpp1
-rw-r--r--src/StringCompression.cpp8
-rw-r--r--src/StringCompression.h4
-rw-r--r--src/StringUtils.h4
-rw-r--r--src/UI/WindowOwner.h4
-rw-r--r--src/Vector3.h7
-rw-r--r--src/World.cpp3
-rw-r--r--src/World.h26
-rw-r--r--src/WorldStorage/FireworksSerializer.h2
-rw-r--r--src/WorldStorage/MapSerializer.cpp6
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp21
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp43
-rw-r--r--src/WorldStorage/WSSAnvil.cpp27
-rw-r--r--src/WorldStorage/WSSAnvil.h1
154 files changed, 6127 insertions, 1003 deletions
diff --git a/Android/jni/Android.mk b/Android/jni/Android.mk
index 3542e588b..ce142d446 100644
--- a/Android/jni/Android.mk
+++ b/Android/jni/Android.mk
@@ -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/ \
.. \
diff --git a/LICENSE b/LICENSE
index 566c55b46..69b3c7390 100644
--- a/LICENSE
+++ b/LICENSE
@@ -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.
diff --git a/MCServer/.gitignore b/MCServer/.gitignore
index 64f062ef7..69826ef06 100644
--- a/MCServer/.gitignore
+++ b/MCServer/.gitignore
@@ -6,6 +6,7 @@
MCServer
MCServer_debug
CommLogs/
+GalExports/
logs
players
world*
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 74e7bf860..451b7364a 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -200,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 =
{
@@ -247,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>
@@ -258,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>
@@ -293,7 +310,39 @@ 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
@@ -1826,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}}." },
@@ -2646,11 +2696,31 @@ 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." },
@@ -2767,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
@@ -2836,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" },
}
} ;
diff --git a/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua b/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua
new file mode 100644
index 000000000..ed0b5f46f
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua
@@ -0,0 +1,40 @@
+return
+{
+ HOOK_BLOCK_SPREAD =
+ {
+ CalledWhen = "Called when a block spreads based on world conditions",
+ DefaultFnName = "OnBlockSpread", -- also used as pagename
+ Desc = [[
+ This hook is called when a block spreads.</p>
+ <p>
+ The spread carries with it the type of its source - whether it's a block spreads.
+ It also carries the identification of the actual source. The exact type of the identification
+ depends on the source kind:
+ <table>
+ <tr><th>Source</th><th>Notes</th></tr>
+ <tr><td>ssFireSpread</td><td>Fire spreading</td></tr>
+ <tr><td>ssGrassSpread</td><td>Grass spreading</td></tr>
+ <tr><td>ssMushroomSpread</td><td>Mushroom spreading</td></tr>
+ <tr><td>ssMycelSpread</td><td>Mycel spreading</td></tr>
+ <tr><td>ssVineSpread</td><td>Vine spreading</td></tr>
+ </table></p>
+ ]],
+ Params =
+ {
+ { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the block resides" },
+ { Name = "BlockX", Type = "number", Notes = "X-coord of the block" },
+ { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" },
+ { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" },
+ { Name = "Source", Type = "eSpreadSource", Notes = "Source of the spread. See the table above." },
+ },
+ Returns = [[
+ If the function returns false or no value, the next plugin's callback is called, and finally
+ MCServer will process the spread. If the function
+ returns true, no other callback is called for this event and the spread will not occur.
+ ]],
+ }, -- HOOK_BLOCK_SPREAD
+}
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua
new file mode 100644
index 000000000..1588d420c
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua
@@ -0,0 +1,24 @@
+return
+{
+ HOOK_PROJECTILE_HIT_BLOCK =
+ {
+ CalledWhen = "A projectile hits a solid block.",
+ DefaultFnName = "OnProjectileHitBlock", -- also used as pagename
+ Desc = [[
+ This hook is called when a {{cProjectileEntity|projectile}} hits a solid block..
+ ]],
+ Params =
+ {
+ { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
+ },
+ Returns = [[
+ If the function returns false or no value, the next plugin's callback is called. If the function
+ returns true, no other callback is called for this event and the projectile flies through block..
+ ]],
+ }, -- HOOK_PROJECTILE_HIT_BLOCK
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua
new file mode 100644
index 000000000..dd949fb46
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua
@@ -0,0 +1,25 @@
+return
+{
+ HOOK_PROJECTILE_HIT_ENTITY =
+ {
+ CalledWhen = "A projectile hits another entity.",
+ DefaultFnName = "OnProjectileHitEntity", -- also used as pagename
+ Desc = [[
+ This hook is called when a {{cProjectileEntity|projectile}} hits another entity.
+ ]],
+ Params =
+ {
+ { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
+ { Name = "Entity", Type = "{{cEntity}}", Notes = "The entity wich was hit." },
+ },
+ Returns = [[
+ If the function returns false or no value, the next plugin's callback is called. If the function
+ returns true, no other callback is called for this event and the projectile flies through the entity.
+ ]],
+ }, -- HOOK_PROJECTILE_HIT_ENTITY
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/SettingUpZeroBrane.html b/MCServer/Plugins/APIDump/SettingUpZeroBrane.html
new file mode 100644
index 000000000..4ebbcb6e6
--- /dev/null
+++ b/MCServer/Plugins/APIDump/SettingUpZeroBrane.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>MCServer - Setting up ZeroBrane Studio</title>
+ <link rel="stylesheet" type="text/css" href="main.css" />
+ <link rel="stylesheet" type="text/css" href="prettify.css" />
+ <script src="prettify.js"></script>
+ <script src="lang-lua.js"></script>
+ <meta charset="UTF-8">
+ </head>
+ <body>
+ <div id="content">
+ <h1>Setting up the ZeroBrane Studio IDE</h1>
+ <p>
+ This article will explain how to set up ZeroBrane Studio, an IDE for writing Lua code, so that you can develop MCServer plugins with the comfort of an IDE.</p>
+
+ <h2><img src="Static/zbs_logo.png" /> About ZeroBrane Studio</h2>
+
+ <p>To quickly introduce ZeroBrane Studio, it is an IDE for writing Lua code. It has the basic features expected of an IDE - it allows you to manage groups of files as a project, you can edit multiple files in a tabbed editor, the code is syntax-highlighted. Code completion, symbol browsing, and more. It also features a Lua debugger that allows you to debug your Lua code within any application that uses Lua and can load Lua packages. It is written using the multiplatform WxWidgets toolkit, and runs on multiple platforms, including Windows, Linux and MacOS.</p>
+ <p>Here's a screenshot of a default ZBS window with the debugger stepping through the code (scaled down):<br />
+ <img src="Static/zbs_workspace.png" /></p>
+ <p>As you can see, you can set breakpoints in the code, inspect variables' values, view the Lua call-stacks.</p>
+ <p>ZBS is open-source, the sources are on GitHub: <a href="https://github.com/pkulchenko/ZeroBraneStudio">https://github.com/pkulchenko/ZeroBraneStudio</a>. The project's homepage is at <a href="http://studio.zerobrane.com/">http://studio.zerobrane.com/</a>.
+
+ <h2><img src="Static/zbs_logo.png" /> First-time setup</h2>
+ <p>Since ZBS is a universal Lua IDE, you need to first set it up so that it is ready for MCS plugin development. For that, you need to download one file, <a href="https://raw.githubusercontent.com/pkulchenko/ZeroBranePackage/master/mcserver.lua">mcserver.lua</a> from the <a href="https://github.com/pkulchenko/ZeroBranePackage">ZBS's plugin repository</a>. Place that file in the "packages" folder inside your ZBS's folder. Note that there are other useful plugins in the repository and you may want to have a look there later on to further customize your ZBS. To install them, simply save them into the same folder.</p>
+ <p>Next you should install the code-completion support specific for MCServer. You should repeat this step from time to time, because the API evolves in time so new functions and classes are added to it quite often. You should have an APIDump plugin in your MCServer installation. Enable the APIDump plugin in the server settings, it's very cheap to keep it enabled and it doesn't cost any performance during normal gameplay. To generate the code-completion support file, enter the <code style="background: #ddd; border: 1px solid #aaa">api</code> command into the server console. This will create a new file, "mcserver_api.lua", next to the MCS executable. Move that file into the "api/lua" subfolder inside your ZBS's folder.</p>
+ <p>After you download the mcserver.lua file and install the completion support, you need to restart ZBS in order for the plugin to load. If there are no errors, you should see two new items in the Project -> Lua Interpreter submenu: "MCServer - debug mode" and "MCServer - release mode". The only difference between the two is which filename they use to launch MCServer - mcserver_debug(.exe) for the debug option and "mcserver(.exe)" for the release option. If you built your own MCServer executable and you built it in debug mode, you should select the debug mode option. In all other cases, including if you downloaded the already-compiled MCServer executable from the internet, you should select the release mode option.</p>
+ <p>For a first time user, it might be a bit overwhelming that there are no GUI settings in the ZBS, yet the IDE is very configurable. There are two files that you edit in order to change settings, either system-wide (all users of the computer share those settings) or user-wide (the settings are only for a specific user of the computer). Those files are regular Lua sources and you can quickly locate them and edit them from within the IDE itself, select Edit -> Preferences -> Settings: XYZ from the menu, with XYZ being either System or User.</p>
+ <p>There is a documentation on most of the settings on ZBS's webpage, have a look at <a href="http://studio.zerobrane.com/documentation.html">http://studio.zerobrane.com/documentation.html</a>, especially the Preferences section. Personally I recommend setting editor.usetabs to true and possibly adjusting the editor.tabwidth, turn off the editor.smartindent feature and for debugging the option debugger.alloweditting should be set to true unless you feel like punishing yourself.</p>
+
+ <h2><img src="Static/zbs_logo.png" /> Project management</h2>
+ <p>ZBS works with projects, it considers all files and subfolder in a specific folder to be a project. There's no need for a special project file nor for adding individual files to the workspace, all files are added automatically. To open a MCS plugin as the project, click the triple-dot button in the Project pane, or select Project -> Project directory -> Choose... from the menu. Browse and select the MCS plugin's folder. ZBS will load all the files in the plugin's folder and you can start editting code.</p>
+ <p>Note that although ZBS allows you to work with subfolders in your plugins (and you should, especially with larger plugins), the current mcserver ZBS plugin will not be able to start debugging unless you have a file open in the editor that is at the root level of the MCS plugin's folder.</p>
+
+ <h2><img src="Static/zbs_logo.png" /> Debugging</h2>
+ <p>You are now ready to debug your code. Before doing that, though, don't forget to save your project files. If you haven't done so already, enable your plugin in the settings.ini file. If you want the program to break at a certain line, it is best to set the breakpoint before starting the program. Set the cursor on the line and hit F9 (or use menu Project -> Toggle Breakpoint) to toggle a breakpoint on that line. Finally, hit F5, or select menu Project -> Start Debugging to launch MCServer under the debugger. The MCServer window comes up and loads your plugin. If the window doesn't come up, inspect the Output pane in ZBS, there are usually two reasons for failure:<ul>
+ <li>Your code in the currently open file has a hard syntax error. These are reported as "Compilation error" in the Output pane, double-click the line to go to the error</li>
+ <li>ZBS cannot find the MCServer executable. Make sure you are editting a file two levels down the folder hierarchy from the MCS executable and that the MCS executable is named properly (mcserver[.exe] or mcserver_debug[.exe]). Also make sure you have selected the right Interpreter (menu Project -> Lua Interpreter).</li>
+ </ul></p>
+ <p>Once running, if the execution hits a breakpoint, the ZBS window will come up and a green arrow is displayed next to the breakpoint line. You can step through the code using F10 (Step Into) and Shift+F10 (Step Over). You can also use the Watch window to inspect variable values, or simply hover your mouse over a variable to display its value in the tooltip. Use the Remote console pane to execute commands directly *inside* the MCServer's plugin context.</p>
+ <p>You can also use the Project -> Break menu item to break into the debugger as soon as possible. You can also set breakpoints while the MCS plugin is running. Note that due to the way in which the debugger is implemented, MCS may execute some more Lua code before the break / breakpoint comes into effect. If MCS is not executing any Lua code in your plugin, it will not break until the plugin code kicks in again. This may result in missed breakpoints and delays before the Break command becomes effective. Therefore it's best to set breakpoints before running the program, or while the program is waiting in another breakpoint.</p>
+ </div>
+ </body>
+</html>
diff --git a/MCServer/Plugins/APIDump/Static/zbs_logo.png b/MCServer/Plugins/APIDump/Static/zbs_logo.png
new file mode 100644
index 000000000..c8d6d6278
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Static/zbs_logo.png
Binary files differ
diff --git a/MCServer/Plugins/APIDump/Static/zbs_workspace.png b/MCServer/Plugins/APIDump/Static/zbs_workspace.png
new file mode 100644
index 000000000..9ce17e35a
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Static/zbs_workspace.png
Binary files differ
diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua
index 7455c3cd2..52199740b 100644
--- a/MCServer/Plugins/APIDump/main_APIDump.lua
+++ b/MCServer/Plugins/APIDump/main_APIDump.lua
@@ -1408,9 +1408,9 @@ end
--- Dumps the entire API table into a file in the ZBS format
local function DumpAPIZBS(a_API)
LOG("Dumping ZBS API description...")
- local f, err = io.open("mcserver.lua", "w")
+ local f, err = io.open("mcserver_api.lua", "w")
if (f == nil) then
- LOG("Cannot open mcserver.lua for writing, ZBS API will not be dumped. " .. err)
+ LOG("Cannot open mcserver_lua.lua for writing, ZBS API will not be dumped. " .. err)
return
end
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index fe3efa306..064d5d772 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -27,11 +27,13 @@ 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");
PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool");
@@ -67,12 +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;
@@ -241,6 +253,24 @@ 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...");
diff --git a/MCServer/Plugins/InfoReg.lua b/MCServer/Plugins/InfoReg.lua
index b3717884a..27e63aa5b 100644
--- a/MCServer/Plugins/InfoReg.lua
+++ b/MCServer/Plugins/InfoReg.lua
@@ -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,9 +73,11 @@ 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
-- If the handler is not valid, check the next sublevel:
@@ -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
diff --git a/SetFlags.cmake b/SetFlags.cmake
index bbd8254ad..c5a3a0697 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -198,6 +198,7 @@ macro(set_exe_flags)
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()
diff --git a/lib/md5/md5.h b/lib/md5/md5.h
index ad5ad5384..3aa88ac22 100644
--- a/lib/md5/md5.h
+++ b/lib/md5/md5.h
@@ -90,4 +90,4 @@ private:
std::string md5(const std::string & str);
-#endif \ No newline at end of file
+#endif
diff --git a/lib/tolua++/CMakeLists.txt b/lib/tolua++/CMakeLists.txt
index 75a301a53..e5c8ce3e8 100644
--- a/lib/tolua++/CMakeLists.txt
+++ b/lib/tolua++/CMakeLists.txt
@@ -7,25 +7,28 @@ include_directories ("${PROJECT_SOURCE_DIR}/include/")
include_directories ("${PROJECT_SOURCE_DIR}/../")
include_directories ("${PROJECT_SOURCE_DIR}")
-if(UNIX)
+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 -i lua/basic.lua | sed 's/unsigned char/static const unsigned char/g' >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 -i lua/enumerate.lua | sed 's/unsigned char/static const unsigned char/g' >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 -i lua/function.lua | sed 's/unsigned char/static const unsigned char/g' >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 -i lua/declaration.lua | sed 's/unsigned char/static const unsigned char/g' >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)
- message(hello)
+else()
+ message("xxd not found, changes to tolua scripts will be ignored")
endif()
diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp
index 408b1b84a..d51ba2da3 100644
--- a/src/Bindings/DeprecatedBindings.cpp
+++ b/src/Bindings/DeprecatedBindings.cpp
@@ -2,6 +2,7 @@
#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"
@@ -20,47 +21,23 @@
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockLightValue
static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S)
{
- int tolua_index;
+ 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
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockLightValue */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockLightValue
-static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_LightValue = ((unsigned char) tolua_tonumber(tolua_S,3,0));
- return 0;
+ tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -72,7 +49,7 @@ static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockSpreadLightFalloff
static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -80,39 +57,13 @@ static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetSpreadLightFalloff(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockSpreadLightFalloff */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockSpreadLightFalloff
-static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_SpreadLightFalloff = ((unsigned char) tolua_tonumber(tolua_S,3,0));
- return 0;
+ tolua_pushnumber(tolua_S, (lua_Number)cBlockInfo::GetSpreadLightFalloff((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -124,7 +75,7 @@ static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockTransparent
static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -132,39 +83,13 @@ static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockTransparent */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockTransparent
-static int tolua_set_AllToLua_g_BlockTransparent(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_Transparent = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -176,7 +101,7 @@ static int tolua_set_AllToLua_g_BlockTransparent(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockOneHitDig
static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -184,39 +109,13 @@ static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsOneHitDig(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockOneHitDig */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockOneHitDig
-static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_OneHitDig = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, cBlockInfo::IsOneHitDig((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -228,7 +127,7 @@ static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable
static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -236,39 +135,13 @@ static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsPistonBreakable(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockPistonBreakable */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockPistonBreakable
-static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_PistonBreakable = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, cBlockInfo::IsPistonBreakable((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -280,7 +153,7 @@ static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable
static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -288,39 +161,13 @@ static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsSnowable(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockIsSnowable */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSnowable
-static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_IsSnowable = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, cBlockInfo::IsSnowable((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -332,7 +179,7 @@ static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool
static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -340,39 +187,13 @@ static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S,(bool)cBlockInfo::RequiresSpecialTool(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockRequiresSpecialTool */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockRequiresSpecialTool
-static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_RequiresSpecialTool = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, cBlockInfo::RequiresSpecialTool((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -384,7 +205,7 @@ static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid
static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -392,39 +213,13 @@ static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsSolid(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockIsSolid */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSolid
-static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_IsSolid = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, (bool)cBlockInfo::IsSolid((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -436,7 +231,7 @@ static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockFullyOccupiesVoxel
static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
{
- int tolua_index;
+ int BlockType;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
@@ -444,39 +239,13 @@ static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- tolua_pushboolean(tolua_S,(bool)cBlockInfo::FullyOccupiesVoxel(tolua_index));
- return 1;
-}
-#endif //#ifndef TOLUA_DISABLE
-
-
-
-
-
-/* set function: g_BlockFullyOccupiesVoxel */
-#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockFullyOccupiesVoxel
-static int tolua_set_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
-{
- int tolua_index;
- #ifndef TOLUA_RELEASE
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
{
- tolua_Error tolua_err;
- if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
- tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
}
- #endif
- tolua_index = (int)tolua_tonumber(tolua_S,2,0);
- #ifndef TOLUA_RELEASE
- if (tolua_index<0 || tolua_index>=256)
- tolua_error(tolua_S,"array indexing out of range.",NULL);
- #endif
- cBlockInfo::Get(tolua_index).m_FullyOccupiesVoxel = (tolua_toboolean(tolua_S,3,0) != 0);
- return 0;
+ tolua_pushboolean(tolua_S, (bool)cBlockInfo::FullyOccupiesVoxel((BLOCKTYPE)BlockType));
+ return 1;
}
#endif //#ifndef TOLUA_DISABLE
@@ -488,15 +257,15 @@ void DeprecatedBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
- tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, tolua_set_AllToLua_g_BlockLightValue);
- tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, tolua_set_AllToLua_g_BlockSpreadLightFalloff);
- tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, tolua_set_AllToLua_g_BlockTransparent);
- tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, tolua_set_AllToLua_g_BlockOneHitDig);
- tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, tolua_set_AllToLua_g_BlockPistonBreakable);
- tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, tolua_set_AllToLua_g_BlockIsSnowable);
- tolua_array(tolua_S, "g_BlockRequiresSpecialTool", tolua_get_AllToLua_g_BlockRequiresSpecialTool, tolua_set_AllToLua_g_BlockRequiresSpecialTool);
- tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, tolua_set_AllToLua_g_BlockIsSolid);
- tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, tolua_set_AllToLua_g_BlockFullyOccupiesVoxel);
+ 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);
}
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 47380b8a7..a33459ad2 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -11,6 +11,7 @@ extern "C"
#include "lua/src/lualib.h"
}
+#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
#include "Bindings.h"
#include "ManualBindings.h"
@@ -479,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());
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index f0047b362..b9ca2f29b 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -38,6 +38,7 @@ extern "C"
class cWorld;
class cPlayer;
class cEntity;
+class cProjectileEntity;
class cMonster;
class cItem;
class cItems;
@@ -183,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);
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 20bbc48f2..92b410481 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -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"
@@ -115,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;
}
@@ -126,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;
}
@@ -137,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;
}
@@ -148,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;
}
@@ -159,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:
@@ -2838,6 +2914,8 @@ 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);
diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h
index e6594947e..f38e26267 100644
--- a/src/Bindings/ManualBindings.h
+++ b/src/Bindings/ManualBindings.h
@@ -5,4 +5,4 @@ class ManualBindings
{
public:
static void Bind( lua_State* tolua_S );
-}; \ No newline at end of file
+};
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 949e4693a..df0bd4dcc 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -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;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index cccbc3c93..dcc816839 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -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"
@@ -195,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);
@@ -1088,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);
@@ -1430,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";
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index a177f5288..59542d23a 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -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;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index b9cf160c4..6a5356c0b 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -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,
@@ -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);
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index 44bc5a8d7..512bc1351 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -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);
diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp
index 3b71d553c..bf45405ba 100644
--- a/src/Bindings/WebPlugin.cpp
+++ b/src/Bindings/WebPlugin.cpp
@@ -110,4 +110,4 @@ AString cWebPlugin::SafeString( const AString & a_String )
RetVal.push_back( c );
}
return RetVal;
-} \ No newline at end of file
+}
diff --git a/src/Bindings/lua5.1.dll b/src/Bindings/lua51.dll
index 515cf8b30..515cf8b30 100644
--- a/src/Bindings/lua5.1.dll
+++ b/src/Bindings/lua51.dll
Binary files differ
diff --git a/src/Bindings/tolua++.exe b/src/Bindings/tolua++.exe
index 86ab1d70f..1e3cc7789 100644
--- a/src/Bindings/tolua++.exe
+++ b/src/Bindings/tolua++.exe
Binary files differ
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index 406e18a3b..40cca8882 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -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,17 +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_WEOffset(0, 0, 0),
m_BlockTypes(NULL),
m_BlockMetas(NULL),
m_BlockLight(NULL),
@@ -195,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);
}
@@ -243,12 +281,17 @@ 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);
}
@@ -275,9 +318,7 @@ void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
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);
}
@@ -286,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);
}
@@ -342,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:
@@ -408,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);
@@ -443,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())
{
@@ -487,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())
@@ -532,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;
@@ -560,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;
}
@@ -590,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;
}
@@ -645,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;
@@ -660,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;
@@ -675,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;
@@ -690,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);
@@ -982,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]);
@@ -1004,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);
}
@@ -1027,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]);
@@ -1049,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);
}
@@ -1072,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);
@@ -1112,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);
@@ -1152,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++)
{
@@ -1180,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
@@ -1198,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);
}
@@ -1225,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
@@ -1243,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);
}
@@ -1268,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
@@ -1286,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
@@ -1305,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
@@ -1325,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
@@ -1342,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++)
{
@@ -1360,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++)
{
@@ -1393,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);
}
@@ -1470,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);
}
@@ -1533,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);
}
@@ -1567,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);
}
@@ -1670,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;
}
@@ -1683,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;
}
@@ -1712,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);
}
@@ -1735,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);
}
@@ -1748,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)
{
}
@@ -1760,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
@@ -1770,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;
@@ -1781,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;
@@ -1793,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++)
@@ -1843,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
@@ -1853,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;
@@ -1864,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;
@@ -1876,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++)
@@ -2002,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
@@ -2032,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
@@ -2057,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,
diff --git a/src/BlockArea.h b/src/BlockArea.h
index e0e8fe972..c48175b8c 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -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);
@@ -232,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;
@@ -261,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:
@@ -276,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;
@@ -295,12 +326,8 @@ 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. */
diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp
index d395997a6..96ca0ac37 100644
--- a/src/BlockEntities/CommandBlockEntity.cpp
+++ b/src/BlockEntities/CommandBlockEntity.cpp
@@ -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;
}
diff --git a/src/BlockID.h b/src/BlockID.h
index 8adefcfba..2fec512e2 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -866,6 +866,19 @@ enum eShrapnelLevel
slAll
} ;
+
+
+
+
+enum eSpreadSource
+{
+ ssFireSpread,
+ ssGrassSpread,
+ ssMushroomSpread,
+ ssMycelSpread,
+ ssVineSpread,
+} ;
+
// tolua_end
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 7d438ba3e..6fb5aa5b3 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -365,7 +365,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_WOODEN_SLAB ].m_IsSolid = false;
- // Torch placeable blocks:
+ // 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;
@@ -397,6 +397,7 @@ void cBlockInfo::Initialize(void)
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;
diff --git a/src/BlockTracer.h b/src/BlockTracer.h
index 40d80da1a..a18c8df4d 100644
--- a/src/BlockTracer.h
+++ b/src/BlockTracer.h
@@ -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.
*/
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
index 9f5f84be0..93a796ef7 100644
--- a/src/Blocks/BlockAnvil.h
+++ b/src/Blocks/BlockAnvil.h
@@ -18,11 +18,13 @@ public:
{
}
+
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,
@@ -31,27 +33,23 @@ public:
) override
{
a_BlockType = m_BlockType;
-
- int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3;
- int RawMeta = a_BlockMeta >> 2;
-
- Direction++;
- Direction %= 4;
+ 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 | RawMeta << 2; break;
- case 1: a_BlockMeta = 0x3 | RawMeta << 2; break;
- case 2: a_BlockMeta = 0x0 | RawMeta << 2; break;
- case 3: a_BlockMeta = 0x1 | RawMeta << 2; break;
+ 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;
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index 6daa94730..92804aaac 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -4,7 +4,7 @@
#include "BlockHandler.h"
#include "ChunkInterface.h"
#include "WorldInterface.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
#include "../Entities/Player.h"
@@ -12,11 +12,11 @@
class cBlockBedHandler :
- public cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
+ public cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockBedHandler(BLOCKTYPE a_BlockType)
- : cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h
index 740cbe3c4..4b2f6f618 100644
--- a/src/Blocks/BlockButton.h
+++ b/src/Blocks/BlockButton.h
@@ -2,17 +2,17 @@
#include "BlockHandler.h"
#include "Chunk.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockButtonHandler :
- public cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
+ public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{
public:
cBlockButtonHandler(BLOCKTYPE a_BlockType)
- : cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h
index 2e1032d2b..41b79b6c3 100644
--- a/src/Blocks/BlockCauldron.h
+++ b/src/Blocks/BlockCauldron.h
@@ -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:
diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h
index 30588d8fc..a1ded4c26 100644
--- a/src/Blocks/BlockChest.h
+++ b/src/Blocks/BlockChest.h
@@ -4,18 +4,18 @@
#include "BlockEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockChestHandler :
- public cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockChestHandler(BLOCKTYPE a_BlockType)
- : cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h
index e570ff302..4dd05366d 100644
--- a/src/Blocks/BlockComparator.h
+++ b/src/Blocks/BlockComparator.h
@@ -3,18 +3,18 @@
#include "BlockHandler.h"
#include "BlockRedstoneRepeater.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockComparatorHandler :
- public cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
+ public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{
public:
cBlockComparatorHandler(BLOCKTYPE a_BlockType)
- : cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h
index ffc2b3f8b..8606cf3f3 100644
--- a/src/Blocks/BlockCrops.h
+++ b/src/Blocks/BlockCrops.h
@@ -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));
diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h
index 544424a04..aa24b8668 100644
--- a/src/Blocks/BlockDirt.h
+++ b/src/Blocks/BlockDirt.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
+#include "../FastRandom.h"
@@ -44,12 +44,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;
@@ -79,7 +79,10 @@ public:
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !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
}
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 4e38ef334..479c68153 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -110,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;
+}
+
+
+
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index 981774c17..797fe484c 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -4,15 +4,15 @@
#include "BlockHandler.h"
#include "../Entities/Player.h"
#include "Chunk.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockDoorHandler :
- public cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
+ public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
{
- typedef cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
+ typedef cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
public:
cBlockDoorHandler(BLOCKTYPE a_BlockType);
@@ -21,6 +21,10 @@ 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;
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,
@@ -142,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))
{
@@ -168,62 +172,6 @@ public:
}
}
}
-
-
- virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
- {
- if (a_Meta & 0x08)
- {
- return a_Meta;
- }
- else
- {
- return super::MetaRotateCCW(a_Meta);
- }
- }
-
-
-
- virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
- {
- if (a_Meta & 0x08)
- {
- return a_Meta;
- }
- else
- {
- return super::MetaRotateCW(a_Meta);
- }
- }
-
-
-
- virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
- {
- if (a_Meta & 0x08)
- {
- return a_Meta;
- }
- else
- {
- return super::MetaMirrorXY(a_Meta);
- }
- }
-
-
-
- virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
- {
- if (a_Meta & 0x08)
- {
- return a_Meta;
- }
- else
- {
- return super::MetaMirrorYZ(a_Meta);
- }
- }
-
} ;
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index 7e0ad0e55..88b61a418 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -6,18 +6,18 @@
#pragma once
#include "../Piston.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockDropSpenserHandler :
- public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) :
- cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
+ cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h
index 97cf484fb..67955f8ce 100644
--- a/src/Blocks/BlockEnderchest.h
+++ b/src/Blocks/BlockEnderchest.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockEntity.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockEnderchestHandler :
- public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
- : cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index e3162bbd6..e202c6610 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockFenceGateHandler :
- public cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
+ public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
- cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
+ cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h
index a25b87858..c8f158e7e 100644
--- a/src/Blocks/BlockFire.h
+++ b/src/Blocks/BlockFire.h
@@ -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
diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h
index 37885e4de..d486d642d 100644
--- a/src/Blocks/BlockFluid.h
+++ b/src/Blocks/BlockFluid.h
@@ -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)
)
diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h
index 27ef2689f..a7a807957 100644
--- a/src/Blocks/BlockFurnace.h
+++ b/src/Blocks/BlockFurnace.h
@@ -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)
{
}
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 4f74e2f45..7fd8c183c 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -41,6 +41,7 @@
#include "BlockIce.h"
#include "BlockLadder.h"
#include "BlockLeaves.h"
+#include "BlockLilypad.h"
#include "BlockNewLeaves.h"
#include "BlockLever.h"
#include "BlockMelon.h"
@@ -142,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);
diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h
index 59b84aa0e..a882bb077 100644
--- a/src/Blocks/BlockHopper.h
+++ b/src/Blocks/BlockHopper.h
@@ -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;
+ }
} ;
diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h
index a3e9edc6b..a605edf3f 100644
--- a/src/Blocks/BlockLadder.h
+++ b/src/Blocks/BlockLadder.h
@@ -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)
{
}
diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h
index a6d3373c1..8af14686e 100644
--- a/src/Blocks/BlockLeaves.h
+++ b/src/Blocks/BlockLeaves.h
@@ -1,6 +1,6 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
+#include "../FastRandom.h"
#include "../World.h"
#include "../BlockArea.h"
@@ -37,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));
}
@@ -58,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));
diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h
index ef6e102cd..ad2ae29e5 100644
--- a/src/Blocks/BlockLever.h
+++ b/src/Blocks/BlockLever.h
@@ -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)
{
}
@@ -104,6 +105,36 @@ public:
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
+ }
+ }
} ;
diff --git a/src/Blocks/BlockLilypad.h b/src/Blocks/BlockLilypad.h
new file mode 100644
index 000000000..2dd4ec768
--- /dev/null
+++ b/src/Blocks/BlockLilypad.h
@@ -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));
+ }
+};
+
+
+
+
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index 2b128f13b..acd1c88fb 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -21,6 +21,103 @@ public:
{
a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
}
+
+ bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
+ {
+ if (a_BlockY < 2)
+ {
+ return false;
+ }
+
+ class cCallback : public cMobHeadCallback
+ {
+ bool m_IsWither;
+
+ virtual bool Item (cMobHeadEntity * a_MobHeadEntity)
+ {
+ m_IsWither = (a_MobHeadEntity->GetType() == SKULL_TYPE_WITHER);
+
+ return false;
+ }
+
+ public:
+ cCallback () : m_IsWither(false) {}
+
+ bool IsWither(void) const { return m_IsWither; }
+
+ void Reset(void) { m_IsWither = false; }
+ } CallbackA, CallbackB;
+
+ a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
+
+ if (!CallbackA.IsWither())
+ {
+ return false;
+ }
+
+ CallbackA.Reset();
+
+ BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
+ BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ);
+
+ if ((BlockY1 != E_BLOCK_SOULSAND) || (BlockY2 != E_BLOCK_SOULSAND))
+ {
+ return false;
+ }
+
+ a_World->DoWithMobHeadAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA);
+ a_World->DoWithMobHeadAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB);
+
+ BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ);
+ BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ);
+
+ if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
+
+ // Block entities
+ a_World->SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+
+ // Spawn the wither:
+ a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+
+ return true;
+ }
+
+ CallbackA.Reset();
+ CallbackB.Reset();
+
+ a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA);
+ a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB);
+
+ Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1);
+ Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1);
+
+ if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
+
+ // Block entities
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
+
+ // Spawn the wither:
+ a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+
+ return true;
+ }
+
+ return false;
+ }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
@@ -50,18 +147,37 @@ public:
}
public:
- cCallback (cPlayer * a_Player, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) :
- m_Player(a_Player),
+ cCallback (cPlayer * a_CBPlayer, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) :
+ m_Player(a_CBPlayer),
m_OldBlockMeta(a_OldBlockMeta),
m_NewBlockMeta(a_NewBlockMeta)
{}
};
cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace));
- a_BlockMeta = a_BlockFace;
+ a_BlockMeta = (NIBBLETYPE)a_BlockFace;
cWorld * World = (cWorld *) &a_WorldInterface;
World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
+
+ if (a_BlockMeta == SKULL_TYPE_WITHER)
+ {
+ static const Vector3i Coords[] =
+ {
+ Vector3i( 0, 0, 0),
+ Vector3i( 1, 0, 0),
+ Vector3i(-1, 0, 0),
+ Vector3i( 0, 0, 1),
+ Vector3i( 0, 0, -1),
+ };
+ for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i)
+ {
+ if (TrySpawnWither(a_ChunkInterface, World, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z))
+ {
+ break;
+ }
+ } // for i - Coords[]
+ }
}
} ;
diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h
index c30c1a401..135d418d7 100644
--- a/src/Blocks/BlockMushroom.h
+++ b/src/Blocks/BlockMushroom.h
@@ -17,6 +17,9 @@ public:
}
+ // TODO: Add Mushroom Spread
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
diff --git a/src/Blocks/BlockMycelium.h b/src/Blocks/BlockMycelium.h
index 7f897c72a..2a8ef5fca 100644
--- a/src/Blocks/BlockMycelium.h
+++ b/src/Blocks/BlockMycelium.h
@@ -16,6 +16,8 @@ public:
{
}
+ // TODO: Add Mycel Spread
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0));
diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h
index 923180e19..812cf906f 100644
--- a/src/Blocks/BlockNetherWart.h
+++ b/src/Blocks/BlockNetherWart.h
@@ -2,14 +2,13 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
+#include "../FastRandom.h"
#include "../World.h"
-/// Common class that takes care of carrots, potatoes and wheat
class cBlockNetherWartHandler :
public cBlockHandler
{
@@ -22,12 +21,12 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
{
- MTRand rand;
+ cFastRandom rand;
if (a_Meta == 0x7)
{
- // Is fully grown, drop the entire produce:
- a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0));
+ // Fully grown, drop the entire produce:
+ a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, (char)(1 + (rand.NextInt(3) + rand.NextInt(3))) / 2, 0));
}
else
{
@@ -35,18 +34,20 @@ public:
}
}
+
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
- NIBBLETYPE Meta = a_Chunk.GetMeta (a_RelX, a_RelY, a_RelZ);
-
+ NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
if (Meta < 7)
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_NETHER_WART, ++Meta);
}
}
+
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
+ // Needs to be placed on top of a Soulsand block:
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND));
}
} ;
diff --git a/src/Blocks/BlockPluginInterface.h b/src/Blocks/BlockPluginInterface.h
index 7428c9a7a..3a36c40b1 100644
--- a/src/Blocks/BlockPluginInterface.h
+++ b/src/Blocks/BlockPluginInterface.h
@@ -1,8 +1,14 @@
#pragma once
+/** This interface is used to decouple block handlers from the cPluginManager dependancy through cWorld.
+The block handlers call this interface, which is then implemented by the specific classes that
+the caller provides.
+*/
class cBlockPluginInterface
{
public:
+ virtual ~cBlockPluginInterface() {}
+
virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
};
diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h
index 349f52605..ac2b9817a 100644
--- a/src/Blocks/BlockPumpkin.h
+++ b/src/Blocks/BlockPumpkin.h
@@ -1,16 +1,16 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockPumpkinHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x07, 0x02, 0x03, 0x00, 0x01, false>
{
public:
cBlockPumpkinHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x07, 0x02, 0x03, 0x00, 0x01, false>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h
index 07e9814cd..ad78d290a 100644
--- a/src/Blocks/BlockRail.h
+++ b/src/Blocks/BlockRail.h
@@ -431,9 +431,145 @@ public:
}
break;
}
+ default: break;
}
return true;
}
+
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag when a_Meta is in the range 0x00--0x05 and 0x0A--0x0F.
+ // Bit 0x08 specifies direction when a_Meta is in the range 0x06-0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Rotates according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // North/South -> East/West
+ case 0x01: return 0x00 + OtherMeta; // East/West -> North/South
+
+ case 0x02: return 0x04 + OtherMeta; // Asc. East -> Asc. North
+ case 0x04: return 0x03 + OtherMeta; // Asc. North -> Asc. West
+ case 0x03: return 0x05 + OtherMeta; // Asc. West -> Asc. South
+ case 0x05: return 0x02 + OtherMeta; // Asc. South -> Asc. East
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr.
+ case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr.
+ case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr.
+ case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Rotates according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // North/South -> East/West
+ case 0x01: return 0x00 + OtherMeta; // East/West -> North/South
+
+ case 0x02: return 0x05 + OtherMeta; // Asc. East -> Asc. South
+ case 0x05: return 0x03 + OtherMeta; // Asc. South -> Asc. West
+ case 0x03: return 0x04 + OtherMeta; // Asc. West -> Asc. North
+ case 0x04: return 0x02 + OtherMeta; // Asc. North -> Asc. East
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr.
+ case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr.
+ case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr.
+ case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x05: return 0x04 + OtherMeta; // Asc. South -> Asc. North
+ case 0x04: return 0x05 + OtherMeta; // Asc. North -> Asc. South
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr.
+ case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr.
+ case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr.
+ case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x02: return 0x03 + OtherMeta; // Asc. East -> Asc. West
+ case 0x03: return 0x02 + OtherMeta; // Asc. West -> Asc. East
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr.
+ case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr.
+ case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr.
+ case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h
index 1e2a86949..fe6cd21b9 100644
--- a/src/Blocks/BlockRedstoneRepeater.h
+++ b/src/Blocks/BlockRedstoneRepeater.h
@@ -3,17 +3,17 @@
#include "BlockHandler.h"
#include "Chunk.h"
-
+#include "MetaRotator.h"
class cBlockRedstoneRepeaterHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{
public:
cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h
index 69c0a7230..d67c3aa24 100644
--- a/src/Blocks/BlockSideways.h
+++ b/src/Blocks/BlockSideways.h
@@ -29,7 +29,13 @@ public:
return true;
}
-
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3);
+ }
+
+
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_WoodMeta)
{
switch (a_BlockFace)
diff --git a/src/Blocks/BlockSign.h b/src/Blocks/BlockSign.h
index cd0c02a40..6c0becfd6 100644
--- a/src/Blocks/BlockSign.h
+++ b/src/Blocks/BlockSign.h
@@ -71,6 +71,37 @@ public:
{
a_Player->GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
}
+
+
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
+ {
+ return (++a_Meta) & 0x0F;
+ }
+
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
+ {
+ return (--a_Meta) & 0x0F;
+ }
+
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
+ {
+ // Mirrors signs over the XY plane (North-South Mirroring)
+
+ // There are 16 meta values which correspond to different directions.
+ // These values are equated to angles on a circle; 0x08 = 180 degrees.
+ return (a_Meta < 0x08) ? 0x08 + a_Meta : 0x08 - a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
+ {
+ // Mirrors signs over the YZ plane (East-West Mirroring)
+
+ // There are 16 meta values which correspond to different directions.
+ // These values are equated to angles on a circle; 0x10 = 360 degrees.
+ return 0x10 - a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h
index 7cd2c97b2..76f5ed0e7 100644
--- a/src/Blocks/BlockSlab.h
+++ b/src/Blocks/BlockSlab.h
@@ -11,8 +11,7 @@
#include "BlockHandler.h"
#include "../Items/ItemHandler.h"
-
-
+#include "Root.h"
@@ -40,41 +39,9 @@ public:
) override
{
a_BlockType = m_BlockType;
- BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE Meta = (NIBBLETYPE) a_Player->GetEquippedItem().m_ItemDamage;
- // HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type));
-
- // Check if the block at the coordinates is a slab. Eligibility for combining has already been processed in ClientHandle
- if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)))
- {
- // Call the function in ClientHandle that places a block when the client sends the packet,
- // so that plugins may interfere with the placement.
-
- if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM))
- {
- // Top and bottom faces need no parameter modification
- a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
- }
- else
- {
- // The other faces need to distinguish between top and bottom cursor positions
- if (a_CursorY > 7)
- {
- // Edit the call to use BLOCK_FACE_BOTTOM, otherwise it places incorrectly
- a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_TOP, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
- }
- else
- {
- // Edit the call to use BLOCK_FACE_TOP, otherwise it places incorrectly
- a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_BOTTOM, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
- }
- }
- return false; // Cancel the event, because dblslabs were already placed, nothing else needed
- }
-
- // Place the single-slab with correct metas:
+ // Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet)
switch (a_BlockFace)
{
case BLOCK_FACE_TOP:
@@ -105,7 +72,16 @@ public:
a_BlockMeta = Meta & 0x7; break;
}
}
+ case BLOCK_FACE_NONE: return false;
} // switch (a_BlockFace)
+
+ // Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle
+ // Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time
+ if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ a_BlockType = GetDoubleSlabType(m_BlockType);
+ }
+
return true;
}
@@ -184,6 +160,15 @@ public:
ASSERT(!"Unhandled double slab type!");
return "";
}
+
+
+ virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
+ {
+ NIBBLETYPE OtherMeta = a_Meta & 0x07; // Contains unrelated meta data.
+
+ // 8th bit is up/down. 1 right-side-up, 0 is up-side-down.
+ return (a_Meta & 0x08) ? 0x00 + OtherMeta : 0x01 + OtherMeta;
+ }
} ;
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index ea8405597..09ff254a6 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockStairsHandler :
- public cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
+ public cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
{
public:
cBlockStairsHandler(BLOCKTYPE a_BlockType) :
- cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
+ cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
{
}
@@ -30,9 +30,7 @@ public:
UNUSED(a_BlockY);
UNUSED(a_BlockZ);
UNUSED(a_CursorX);
- UNUSED(a_CursorY);
UNUSED(a_CursorZ);
- UNUSED(a_BlockMeta);
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
@@ -51,10 +49,12 @@ public:
}
break;
}
+ case BLOCK_FACE_NONE: return false;
}
return true;
}
+
virtual const char * GetStepSound(void) override
{
if (
diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h
index 705436345..b726a0901 100644
--- a/src/Blocks/BlockStems.h
+++ b/src/Blocks/BlockStems.h
@@ -17,9 +17,10 @@ public:
{
}
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
- int ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS;
+ short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS;
a_Pickups.push_back(cItem(ItemType, 1, 0));
}
diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h
index d32c77629..8ddec8de1 100644
--- a/src/Blocks/BlockTorch.h
+++ b/src/Blocks/BlockTorch.h
@@ -2,17 +2,17 @@
#include "BlockHandler.h"
#include "../Chunk.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
class cBlockTorchHandler :
- public cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
+ public cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
{
public:
cBlockTorchHandler(BLOCKTYPE a_BlockType)
- : cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h
index 9bae92c4d..6a36ab874 100644
--- a/src/Blocks/BlockTrapdoor.h
+++ b/src/Blocks/BlockTrapdoor.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockTrapdoorHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>
{
public:
cBlockTrapdoorHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index 8041d9359..7bb9dc484 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -1,7 +1,7 @@
#pragma once
#include "BlockHandler.h"
-#include "MetaRotater.h"
+#include "MetaRotator.h"
@@ -83,7 +83,7 @@ public:
static const struct
{
int x, z;
- int Bit;
+ NIBBLETYPE Bit;
} Coords[] =
{
{ 0, 1, 1}, // south, ZP
@@ -91,7 +91,7 @@ public:
{ 0, -1, 4}, // north, ZM
{ 1, 0, 8}, // east, XP
} ;
- int res = 0;
+ NIBBLETYPE res = 0;
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
{
BLOCKTYPE BlockType;
@@ -175,7 +175,10 @@ public:
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
if (Block == E_BLOCK_AIR)
{
- a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
+ if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX * cChunkDef::Width, a_RelY - 1, a_RelZ * cChunkDef::Width, ssVineSpread))
+ {
+ a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
+ }
}
}
@@ -194,14 +197,14 @@ public:
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
// Bits 2 and 4 stay, bits 1 and 3 swap
- return ((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2));
+ return (NIBBLETYPE)((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2));
}
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
// Bits 1 and 3 stay, bits 2 and 4 swap
- return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
+ return (NIBBLETYPE)((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
}
} ;
diff --git a/src/Blocks/BroadcastInterface.h b/src/Blocks/BroadcastInterface.h
index 01966ffbd..b1b450690 100644
--- a/src/Blocks/BroadcastInterface.h
+++ b/src/Blocks/BroadcastInterface.h
@@ -4,7 +4,8 @@
class cBroadcastInterface
{
public:
-
+ virtual ~cBroadcastInterface() {}
+
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
diff --git a/src/Blocks/MetaRotater.h b/src/Blocks/MetaRotator.h
index dde88e6db..899c583e1 100644
--- a/src/Blocks/MetaRotater.h
+++ b/src/Blocks/MetaRotator.h
@@ -1,4 +1,4 @@
-// MetaRotater.h
+// MetaRotator.h
// Provides a mixin for rotations and reflections
@@ -21,15 +21,15 @@ Inherit from this class providing your base class as Base, the BitMask for the d
*/
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
-class cMetaRotater : public Base
+class cMetaRotator : public Base
{
public:
- cMetaRotater(BLOCKTYPE a_BlockType) :
+ cMetaRotator(BLOCKTYPE a_BlockType) :
Base(a_BlockType)
{}
- virtual ~cMetaRotater() {}
+ virtual ~cMetaRotator() {}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
@@ -42,7 +42,7 @@ public:
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
-NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
@@ -64,7 +64,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
-NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
@@ -86,7 +86,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
-NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
@@ -103,7 +103,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
-NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index 580339d32..bfbb053d9 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -9,7 +9,8 @@ class cItems;
class cWorldInterface
{
public:
-
+ virtual ~cWorldInterface() {}
+
virtual Int64 GetTimeOfDay(void) const = 0;
virtual Int64 GetWorldAge(void) const = 0;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 448dc4b70..30e9dbfd4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -6,14 +6,14 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
-set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
+set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
if (NOT MSVC)
- #Bindings needs to reference other folders so are done here
+ # Bindings need to reference other folders, so they are done here instead
- #lib dependecies are not included
+ # lib dependencies are not included
set(BINDING_DEPENDECIES
tolua
@@ -104,7 +104,6 @@ if (NOT MSVC)
Bindings/PluginLua
Bindings/PluginManager
Bindings/WebPlugin
- Bindings/WebPlugin
)
target_link_libraries(Bindings lua sqlite tolualib)
@@ -138,6 +137,7 @@ if (NOT MSVC)
else ()
+ # MSVC-specific handling: Put all files into one project, separate by the folders:
# Generate the Bindings if they don't exist:
if (NOT EXISTS "${PROJECT_SOURCE_DIR}/Bindings/Bindings.cpp")
@@ -149,6 +149,14 @@ else ()
)
endif()
+ # Get all files in this folder:
+ file(GLOB_RECURSE SOURCE
+ "*.cpp"
+ "*.h"
+ "*.pkg"
+ )
+ source_group("" FILES ${SOURCE})
+
# Add all subfolders as solution-folders:
list(APPEND FOLDERS "Resources")
list(APPEND FOLDERS "Bindings")
@@ -159,23 +167,16 @@ else ()
"${PATH}/*.rc"
"${PATH}/*.pkg"
)
- source_group("${PATH}" FILES ${FOLDER_FILES})
+ string(REPLACE "/" "\\" PROJECT_PATH ${PATH})
+ source_group("${PROJECT_PATH}" FILES ${FOLDER_FILES})
endfunction(includefolder)
foreach(folder ${FOLDERS})
includefolder(${folder})
endforeach(folder)
- file(GLOB_RECURSE SOURCE
- "*.cpp"
- "*.h"
- "*.pkg"
- )
-
include_directories("${PROJECT_SOURCE_DIR}")
- source_group("" FILES ${SOURCE})
-
# Precompiled headers (1st part)
SET_SOURCE_FILES_PROPERTIES(
Globals.cpp PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
@@ -231,7 +232,7 @@ endif ()
if (NOT MSVC)
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
- target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage)
+ target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
endif ()
if (WIN32)
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index d80e93702..6e6b7ed20 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -942,7 +942,7 @@ void cChunk::ApplyWeatherToTop()
FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1);
}
}
- else if (cBlockInfo::IsSnowable(TopBlock))
+ else if (cBlockInfo::IsSnowable(TopBlock) && (Height + 1 < cChunkDef::Height))
{
SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0);
}
@@ -2589,6 +2589,17 @@ cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ)
cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
{
+ // If the relative coords are too far away, use the parent's chunk lookup instead:
+ if ((a_RelX < 128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128))
+ {
+ int BlockX = m_PosX * cChunkDef::Width + a_RelX;
+ int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
+ int BlockY, ChunkX, ChunkZ;
+ AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ }
+
+ // Walk the neighbors:
bool ReturnThis = true;
if (a_RelX < 0)
{
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 46c10ae82..23ba4dbab 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -941,6 +941,8 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
}
return;
}
+
+ m_NumBlockChangeInteractionsThisTick++;
if (!CheckBlockInteractionsRate())
{
@@ -960,7 +962,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
);
// Let's send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block
- if (a_BlockFace > -1)
+ if (a_BlockFace != BLOCK_FACE_NONE)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
@@ -988,7 +990,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
- if (ItemHandler->IsPlaceable() && (a_BlockFace > -1))
+ if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE))
{
HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
}
@@ -1026,6 +1028,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler)
{
+ BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType);
if (a_BlockFace < 0)
{
// Clicked in air
@@ -1036,7 +1039,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
BLOCKTYPE ClickedBlock;
NIBBLETYPE ClickedBlockMeta;
- BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage);
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
@@ -1053,8 +1055,8 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab?
((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type?
(
- (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
- (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab
+ (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
+ (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab
)
)
{
@@ -1062,7 +1064,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
// If clicked top face and slab occupies the top voxel, we want a slab to be placed above it (therefore increment Y)
// Else if clicked bottom face and slab occupies the bottom voxel, decrement Y for the same reason
// Don't touch coordinates if anything else because a dblslab opportunity is present
- if((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP))
+ if ((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP))
{
++a_BlockY;
}
@@ -1138,7 +1140,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
// The actual block placement:
World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- if (m_Player->GetGameMode() != gmCreative)
+ if (!m_Player->IsGameModeCreative())
{
m_Player->GetInventory().RemoveOneEquippedItem();
}
@@ -1606,10 +1608,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
} // for itr - Chunks[]
- // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock
- // Instead, the chunks will be streamed when the client is moved to the new world's Tick list,
- // by setting state to csAuthenticated
- m_State = csAuthenticated;
+ // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set
+ // Meanwhile here, we set last streamed values to bogus ones so everything is resent
m_LastStreamedChunkX = 0x7fffffff;
m_LastStreamedChunkZ = 0x7fffffff;
m_HasSentPlayerChunk = false;
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 8366caa16..5496e61a7 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -230,10 +230,10 @@ public:
/** Called when the player moves into a different world; queues sreaming the new chunks */
void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket);
+private:
+
/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */
void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);
-
-private:
/** The type used for storing the names of registered plugin channels. */
typedef std::set<AString> cChannels;
diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp
index a917ee70f..c70ef1070 100644
--- a/src/CompositeChat.cpp
+++ b/src/CompositeChat.cpp
@@ -112,8 +112,8 @@ cCompositeChat::cCompositeChat(void) :
-cCompositeChat::cCompositeChat(const AString & a_ParseText) :
- m_MessageType(mtCustom)
+cCompositeChat::cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType) :
+ m_MessageType(a_MessageType)
{
ParseText(a_ParseText);
}
@@ -314,6 +314,58 @@ void cCompositeChat::UnderlineUrls(void)
+AString cCompositeChat::ExtractText(void) const
+{
+ AString Msg;
+ for (cParts::const_iterator itr = m_Parts.begin(), end = m_Parts.end(); itr != end; ++itr)
+ {
+ switch ((*itr)->m_PartType)
+ {
+ case ptText:
+ case ptClientTranslated:
+ case ptRunCommand:
+ case ptSuggestCommand:
+ {
+ Msg.append((*itr)->m_Text);
+ break;
+ }
+ case ptUrl:
+ {
+ Msg.append(((cUrlPart *)(*itr))->m_Url);
+ break;
+ }
+ } // switch (PartType)
+ } // for itr - m_Parts[]
+ return Msg;
+}
+
+
+
+
+
+cMCLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType)
+{
+ switch (a_MessageType)
+ {
+ case mtCustom: return cMCLogger::llRegular;
+ case mtFailure: return cMCLogger::llWarning;
+ case mtInformation: return cMCLogger::llInfo;
+ case mtSuccess: return cMCLogger::llRegular;
+ case mtWarning: return cMCLogger::llWarning;
+ case mtFatal: return cMCLogger::llError;
+ case mtDeath: return cMCLogger::llRegular;
+ case mtPrivateMessage: return cMCLogger::llRegular;
+ case mtJoin: return cMCLogger::llRegular;
+ case mtLeave: return cMCLogger::llRegular;
+ }
+ ASSERT(!"Unhandled MessageType");
+ return cMCLogger::llError;
+}
+
+
+
+
+
void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle)
{
if (a_AddStyle.empty())
diff --git a/src/CompositeChat.h b/src/CompositeChat.h
index 27319490d..5b9c5f612 100644
--- a/src/CompositeChat.h
+++ b/src/CompositeChat.h
@@ -117,7 +117,7 @@ public:
/** Creates a new chat message and parses the text into parts.
Recognizes "http:" and "https:" links and @color-codes.
Uses ParseText() for the actual parsing. */
- cCompositeChat(const AString & a_ParseText);
+ cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom);
~cCompositeChat();
@@ -164,10 +164,19 @@ public:
/** Returns the message type set previously by SetMessageType(). */
eMessageType GetMessageType(void) const { return m_MessageType; }
+ /** Returns the text from the parts that comprises the human-readable data.
+ Used for older protocols that don't support composite chat
+ and for console-logging. */
+ AString ExtractText(void) const;
+
// tolua_end
const cParts & GetParts(void) const { return m_Parts; }
+ /** Converts the MessageType to a LogLevel value.
+ Used by the logging bindings when logging a cCompositeChat object. */
+ static cMCLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType);
+
protected:
/** All the parts that */
cParts m_Parts;
diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp
index 4dc7bfde6..322084dc4 100644
--- a/src/DeadlockDetect.cpp
+++ b/src/DeadlockDetect.cpp
@@ -7,7 +7,7 @@
#include "DeadlockDetect.h"
#include "Root.h"
#include "World.h"
-# include <cstdlib>
+#include <cstdlib>
@@ -16,9 +16,6 @@
/// Number of milliseconds per cycle
const int CYCLE_MILLISECONDS = 100;
-/// When the number of cycles for the same world age hits this value, it is considered a deadlock
-const int NUM_CYCLES_LIMIT = 200; // 200 = twenty seconds
-
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 94b24c5af..921252253 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -122,5 +122,3 @@ void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways)
AddSpeed(ToAddSpeed);
}
-
- \ No newline at end of file
diff --git a/src/Entities/Effects.h b/src/Entities/Effects.h
index e7611847d..baf3302fb 100644
--- a/src/Entities/Effects.h
+++ b/src/Entities/Effects.h
@@ -27,4 +27,4 @@ enum ENUM_ENTITY_EFFECT
E_EFFECT_ABSORPTION = 22,
E_EFFECT_SATURATION = 23,
} ;
-// tolua_end \ No newline at end of file
+// tolua_end
diff --git a/src/Entities/EnderCrystal.cpp b/src/Entities/EnderCrystal.cpp
new file mode 100644
index 000000000..a640b236c
--- /dev/null
+++ b/src/Entities/EnderCrystal.cpp
@@ -0,0 +1,56 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "EnderCrystal.h"
+#include "ClientHandle.h"
+#include "Player.h"
+#include "../Chunk.h"
+
+
+
+
+
+cEnderCrystal::cEnderCrystal(double a_X, double a_Y, double a_Z)
+ : cEntity(etEnderCrystal, a_X, a_Y, a_Z, 1.0, 1.0)
+{
+ SetMaxHealth(5);
+}
+
+
+
+
+
+void cEnderCrystal::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ a_ClientHandle.SendSpawnObject(*this, 51, 0, (Byte)GetYaw(), (Byte)GetPitch());
+}
+
+
+
+
+
+void cEnderCrystal::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ UNUSED(a_Dt);
+
+ a_Chunk.SetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT, E_BLOCK_FIRE, 0);
+
+ // No further processing (physics e.t.c.) is needed
+}
+
+
+
+
+
+void cEnderCrystal::KilledBy(cEntity * a_Killer)
+{
+ super::KilledBy(a_Killer);
+
+ m_World->DoExplosionAt(6.0, GetPosX(), GetPosY(), GetPosZ(), true, esEnderCrystal, this);
+
+ Destroy();
+}
+
+
+
+
diff --git a/src/Entities/EnderCrystal.h b/src/Entities/EnderCrystal.h
new file mode 100644
index 000000000..5b86df987
--- /dev/null
+++ b/src/Entities/EnderCrystal.h
@@ -0,0 +1,33 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cEnderCrystal :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+ CLASS_PROTODEF(cEnderCrystal);
+
+ cEnderCrystal(double a_X, double a_Y, double a_Z);
+
+private:
+
+ // cEntity overrides:
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void KilledBy(cEntity * a_Killer) override;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index df80093e5..e41f74b09 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -69,6 +69,7 @@ public:
enum eEntityType
{
etEntity, // For all other types
+ etEnderCrystal,
etPlayer,
etPickup,
etMonster,
@@ -130,18 +131,19 @@ public:
eEntityType GetEntityType(void) const { return m_EntityType; }
- bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
- bool IsPickup (void) const { return (m_EntityType == etPickup); }
- bool IsMob (void) const { return (m_EntityType == etMonster); }
+ bool IsEnderCrystal(void) const { return (m_EntityType == etEnderCrystal); }
+ bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
+ bool IsPickup (void) const { return (m_EntityType == etPickup); }
+ bool IsMob (void) const { return (m_EntityType == etMonster); }
bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
- bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
- bool IsBoat (void) const { return (m_EntityType == etBoat); }
- bool IsTNT (void) const { return (m_EntityType == etTNT); }
- bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
- bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
- bool IsFloater (void) const { return (m_EntityType == etFloater); }
- bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
- bool IsPainting (void) const { return (m_EntityType == etPainting); }
+ bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
+ bool IsBoat (void) const { return (m_EntityType == etBoat); }
+ bool IsTNT (void) const { return (m_EntityType == etTNT); }
+ bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
+ bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
+ bool IsFloater (void) const { return (m_EntityType == etFloater); }
+ bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
+ bool IsPainting (void) const { return (m_EntityType == etPainting); }
/// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true)
virtual bool IsA(const char * a_ClassName) const;
diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h
index c1150bd03..e76274ac9 100644
--- a/src/Entities/ExpOrb.h
+++ b/src/Entities/ExpOrb.h
@@ -42,4 +42,4 @@ protected:
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer;
-} ; // tolua_export \ No newline at end of file
+} ; // tolua_export
diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h
index f3b51d77b..547d503f1 100644
--- a/src/Entities/Floater.h
+++ b/src/Entities/Floater.h
@@ -43,4 +43,4 @@ protected:
// Entity IDs
int m_PlayerID;
int m_AttachedMobID;
-} ; // tolua_export \ No newline at end of file
+} ; // tolua_export
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 863aaa799..646aad50f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1489,6 +1489,7 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
// Add player to all the necessary parts of the new world
SetWorld(World);
+ m_ClientHandle->StreamChunks();
World->AddEntity(this);
World->AddPlayer(this);
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index f4ab825f2..a9735a53c 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -4,6 +4,7 @@
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
#include "Globals.h"
+#include "../Bindings/PluginManager.h"
#include "ProjectileEntity.h"
#include "../ClientHandle.h"
#include "Player.h"
@@ -66,6 +67,11 @@ protected:
eBlockFace Face;
if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face))
{
+ if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile))
+ {
+ return false;
+ }
+
Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff;
m_Projectile->OnHitSolidBlock(Intersection, Face);
return true;
@@ -147,7 +153,11 @@ public:
}
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks)
- // TODO: Allow plugins to interfere about which entities can be hit
+ if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity))
+ {
+ // A plugin disagreed.
+ return false;
+ }
if (LineCoeff < m_MinCoeff)
{
diff --git a/src/ForEachChunkProvider.h b/src/ForEachChunkProvider.h
index 6017173ee..7a6e8c5c6 100644
--- a/src/ForEachChunkProvider.h
+++ b/src/ForEachChunkProvider.h
@@ -24,6 +24,8 @@ class cBlockArea;
class cForEachChunkProvider
{
public:
+ virtual ~cForEachChunkProvider() {}
+
/** Calls the callback for each chunk in the specified range. */
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) = 0;
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index 308fbe423..7711723fc 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -343,9 +343,9 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
int SizeY = a_MaxRelY - a_MinRelY;
int SizeZ = a_MaxRelZ - a_MinRelZ;
a_Dest.Clear();
- a_Dest.m_OriginX = m_ChunkX * cChunkDef::Width + a_MinRelX;
- a_Dest.m_OriginY = a_MinRelY;
- a_Dest.m_OriginZ = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
+ a_Dest.m_Origin.x = m_ChunkX * cChunkDef::Width + a_MinRelX;
+ a_Dest.m_Origin.y = a_MinRelY;
+ a_Dest.m_Origin.z = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
a_Dest.SetSize(SizeX, SizeY, SizeZ, cBlockArea::baTypes | cBlockArea::baMetas);
for (int y = 0; y < SizeY; y++)
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 6c00b5905..2e886336f 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -21,6 +21,7 @@
#include "DistortedHeightmap.h"
#include "EndGen.h"
#include "MineShafts.h"
+#include "NetherFortGen.h"
#include "Noise3DGenerator.h"
#include "POCPieceGenerator.h"
#include "Ravines.h"
@@ -191,9 +192,11 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap());
}
+ bool ShouldUpdateHeightmap = false;
if (a_ChunkDesc.IsUsingDefaultComposition())
{
m_CompositionGen->ComposeTerrain(a_ChunkDesc);
+ ShouldUpdateHeightmap = true;
}
if (a_ChunkDesc.IsUsingDefaultFinish())
@@ -202,6 +205,12 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
{
(*itr)->GenFinish(a_ChunkDesc);
} // for itr - m_FinishGens[]
+ ShouldUpdateHeightmap = true;
+ }
+
+ if (ShouldUpdateHeightmap)
+ {
+ a_ChunkDesc.UpdateHeightmap();
}
}
@@ -349,7 +358,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
m_FinishGens.push_back(new cStructGenMineShafts(
- Seed, GridSize, MaxSystemSize,
+ Seed, GridSize, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
));
}
@@ -361,6 +370,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
}
+ else if (NoCaseCompare(*itr, "NetherForts") == 0)
+ {
+ int GridSize = a_IniFile.GetValueSetI("Generator", "NetherFortsGridSize", 512);
+ int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12);
+ m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxDepth));
+ }
else if (NoCaseCompare(*itr, "OreNests") == 0)
{
m_FinishGens.push_back(new cStructGenOreNests(Seed));
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index 28dc37567..231295c3f 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -1340,7 +1340,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk(
BaseX -= NEIGHBORHOOD_SIZE / 2;
BaseZ -= NEIGHBORHOOD_SIZE / 2;
- // Walk the cache, move each cave system that we want into a_Caves:
+ // Walk the cache, move each cave system that we want into a_Mineshafts:
int StartX = BaseX * m_GridSize;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
int StartZ = BaseZ * m_GridSize;
diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp
new file mode 100644
index 000000000..02779a8a3
--- /dev/null
+++ b/src/Generating/NetherFortGen.cpp
@@ -0,0 +1,275 @@
+
+// NetherFortGen.cpp
+
+// Implements the cNetherFortGen class representing the nether fortress generator
+
+#include "Globals.h"
+#include "NetherFortGen.h"
+#include "Prefabs/NetherFortPrefabs.h"
+
+
+
+
+
+static const int NEIGHBORHOOD_SIZE = 3;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen::cNetherFort:
+
+class cNetherFortGen::cNetherFort
+{
+public:
+ cNetherFortGen & m_ParentGen;
+ int m_BlockX, m_BlockZ;
+ int m_GridSize;
+ int m_Seed;
+ cPlacedPieces m_Pieces;
+
+
+ cNetherFort(cNetherFortGen & a_ParentGen, int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxDepth, int a_Seed) :
+ m_ParentGen(a_ParentGen),
+ m_BlockX(a_BlockX),
+ m_BlockZ(a_BlockZ),
+ m_GridSize(a_GridSize),
+ m_Seed(a_Seed)
+ {
+ // TODO: Proper Y-coord placement
+ int BlockY = 64;
+
+ // Generate pieces:
+ for (int i = 0; m_Pieces.size() < (size_t)(a_MaxDepth * a_MaxDepth / 8 + a_MaxDepth); i++)
+ {
+ cBFSPieceGenerator pg(m_ParentGen, a_Seed + i);
+ pg.PlacePieces(a_BlockX, BlockY, a_BlockZ, a_MaxDepth, m_Pieces);
+ }
+ }
+
+
+ ~cNetherFort()
+ {
+ cPieceGenerator::FreePieces(m_Pieces);
+ }
+
+
+ /** Carves the system into the chunk data */
+ void ProcessChunk(cChunkDesc & a_Chunk)
+ {
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ const cPrefab & Prefab = (const cPrefab &)((*itr)->GetPiece());
+ Prefab.Draw(a_Chunk, *itr);
+ } // for itr - m_PlacedPieces[]
+ }
+};
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen:
+
+cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) :
+ m_Seed(a_Seed),
+ m_Noise(a_Seed),
+ m_GridSize(a_GridSize),
+ m_MaxDepth(a_MaxDepth)
+{
+ // Initialize the prefabs:
+ for (size_t i = 0; i < g_NetherFortPrefabs1Count; i++)
+ {
+ cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs1[i]);
+ m_AllPieces.push_back(Prefab);
+ if (Prefab->HasConnectorType(0))
+ {
+ m_OuterPieces.push_back(Prefab);
+ }
+ if (Prefab->HasConnectorType(1))
+ {
+ m_InnerPieces.push_back(Prefab);
+ }
+ }
+
+ // Initialize the starting piece prefabs:
+ for (size_t i = 0; i < g_NetherFortStartingPrefabs1Count; i++)
+ {
+ m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs1[i]));
+ }
+
+ // DEBUG: Try one round of placement:
+ cPlacedPieces Pieces;
+ cBFSPieceGenerator pg(*this, a_Seed);
+ pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces);
+}
+
+
+
+
+
+cNetherFortGen::~cNetherFortGen()
+{
+ ClearCache();
+ for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - m_AllPieces[]
+ m_AllPieces.clear();
+}
+
+
+
+
+
+void cNetherFortGen::ClearCache(void)
+{
+ // TODO
+}
+
+
+
+
+
+void cNetherFortGen::GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts)
+{
+ int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize;
+ int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize;
+ if (BaseX < 0)
+ {
+ --BaseX;
+ }
+ if (BaseZ < 0)
+ {
+ --BaseZ;
+ }
+ BaseX -= NEIGHBORHOOD_SIZE / 2;
+ BaseZ -= NEIGHBORHOOD_SIZE / 2;
+
+ // Walk the cache, move each cave system that we want into a_Forts:
+ int StartX = BaseX * m_GridSize;
+ int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ int StartZ = BaseZ * m_GridSize;
+ int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ for (cNetherForts::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
+ {
+ if (
+ ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
+ ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
+ )
+ {
+ // want
+ a_Forts.push_back(*itr);
+ itr = m_Cache.erase(itr);
+ }
+ else
+ {
+ // don't want
+ ++itr;
+ }
+ } // for itr - m_Cache[]
+
+ // Create those forts that haven't been in the cache:
+ for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
+ {
+ int RealX = (BaseX + x) * m_GridSize;
+ for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
+ {
+ int RealZ = (BaseZ + z) * m_GridSize;
+ bool Found = false;
+ for (cNetherForts::const_iterator itr = a_Forts.begin(), end = a_Forts.end(); itr != end; ++itr)
+ {
+ if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
+ {
+ Found = true;
+ break;
+ }
+ } // for itr - a_Mineshafts
+ if (!Found)
+ {
+ a_Forts.push_back(new cNetherFort(*this, RealX, RealZ, m_GridSize, m_MaxDepth, m_Seed));
+ }
+ } // for z
+ } // for x
+
+ // Copy a_Forts into m_Cache to the beginning:
+ cNetherForts FortsCopy (a_Forts);
+ m_Cache.splice(m_Cache.begin(), FortsCopy, FortsCopy.begin(), FortsCopy.end());
+
+ // Trim the cache if it's too long:
+ if (m_Cache.size() > 100)
+ {
+ cNetherForts::iterator itr = m_Cache.begin();
+ std::advance(itr, 100);
+ for (cNetherForts::iterator end = m_Cache.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ itr = m_Cache.begin();
+ std::advance(itr, 100);
+ m_Cache.erase(itr, m_Cache.end());
+ }
+}
+
+
+
+
+
+void cNetherFortGen::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int ChunkX = a_ChunkDesc.GetChunkX();
+ int ChunkZ = a_ChunkDesc.GetChunkZ();
+ cNetherForts Forts;
+ GetFortsForChunk(ChunkX, ChunkZ, Forts);
+ for (cNetherForts::const_iterator itr = Forts.begin(); itr != Forts.end(); ++itr)
+ {
+ (*itr)->ProcessChunk(a_ChunkDesc);
+ } // for itr - Forts[]
+}
+
+
+
+
+
+cPieces cNetherFortGen::GetPiecesWithConnector(int a_ConnectorType)
+{
+ switch (a_ConnectorType)
+ {
+ case 0: return m_OuterPieces;
+ case 1: return m_InnerPieces;
+ default: return cPieces();
+ }
+}
+
+
+
+
+
+cPieces cNetherFortGen::GetStartingPieces(void)
+{
+ return m_StartingPieces;
+}
+
+
+
+
+
+void cNetherFortGen::PiecePlaced(const cPiece & a_Piece)
+{
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cNetherFortGen::Reset(void)
+{
+ // Nothing needed
+}
+
+
+
+
diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h
new file mode 100644
index 000000000..10ba01396
--- /dev/null
+++ b/src/Generating/NetherFortGen.h
@@ -0,0 +1,86 @@
+
+// NetherFortGen.h
+
+// Declares the cNetherFortGen class representing the nether fortress generator
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+class cNetherFortGen :
+ public cFinishGen,
+ public cPiecePool
+{
+public:
+ cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth);
+
+ virtual ~cNetherFortGen();
+
+protected:
+ class cNetherFort; // fwd: NetherFortGen.cpp
+ typedef std::list<cNetherFort *> cNetherForts;
+
+
+ /** The seed used for generating*/
+ int m_Seed;
+
+ /** The noise used for generating */
+ cNoise m_Noise;
+
+ /** Average spacing between the fortresses*/
+ int m_GridSize;
+
+ /** Maximum depth of the piece-generator tree */
+ int m_MaxDepth;
+
+ /** Cache of the most recently used systems. MoveToFront used. */
+ cNetherForts m_Cache;
+
+ /** All the pieces that are allowed for building.
+ This is the list that's used for memory allocation and deallocation for the pieces. */
+ cPieces m_AllPieces;
+
+ /** The pieces that are used as starting pieces.
+ This list is not shared and the pieces need deallocation. */
+ cPieces m_StartingPieces;
+
+ /** The pieces that have an "outer" connector.
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPieces m_OuterPieces;
+
+ /** The pieces that have an "inner" connector.
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPieces m_InnerPieces;
+
+
+ /** Clears everything from the cache.
+ Also invalidates the forst returned by GetFortsForChunk(). */
+ void ClearCache(void);
+
+ /** Returns all forts that *may* intersect the given chunk.
+ The returned forts live within m_Cache.They are valid until the next call
+ to this function (which may delete some of the pointers). */
+ void GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts);
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
new file mode 100644
index 000000000..131b6acb2
--- /dev/null
+++ b/src/Generating/Prefab.cpp
@@ -0,0 +1,316 @@
+
+// Prefab.cpp
+
+/*
+Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+*/
+
+#include "Globals.h"
+#include "Prefab.h"
+#include "../WorldStorage/SchematicFileSerializer.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+// Create one static prefab to test the parser:
+static const cPrefab::sDef g_TestPrefabDef =
+{
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* 0 */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 3, 2: 4\n"
+ "0: 2, 3, 0: 2\n",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msImprint
+};
+
+static cPrefab g_TestPrefab(g_TestPrefabDef);
+#endif
+
+
+
+
+
+cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
+ m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
+ m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
+ m_AllowedRotations(a_Def.m_AllowedRotations),
+ m_MergeStrategy(a_Def.m_MergeStrategy)
+{
+ m_BlockArea[0].Create(m_Size);
+ CharMap cm;
+ ParseCharMap(cm, a_Def.m_CharMap);
+ ParseBlockImage(cm, a_Def.m_Image);
+ ParseConnectors(a_Def.m_Connectors);
+
+ // 1 CCW rotation:
+ if ((m_AllowedRotations & 0x01) != 0)
+ {
+ m_BlockArea[1].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[1].RotateCCW();
+ }
+
+ // 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
+ if ((m_AllowedRotations & 0x02) != 0)
+ {
+ m_BlockArea[2].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[2].MirrorXY();
+ m_BlockArea[2].MirrorYZ();
+ }
+
+ // 3 CCW rotations = 1 CW rotation:
+ if ((m_AllowedRotations & 0x04) != 0)
+ {
+ m_BlockArea[3].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[3].RotateCW();
+ }
+}
+
+
+
+
+
+void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
+{
+ Vector3i Placement = a_Placement->GetCoords();
+ int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
+ int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
+ Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
+ a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);
+
+}
+
+
+
+
+
+bool cPrefab::HasConnectorType(int a_ConnectorType) const
+{
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Type == a_ConnectorType)
+ {
+ return true;
+ }
+ } // for itr - m_Connectors[]
+ return false;
+}
+
+
+
+
+
+void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
+{
+ ASSERT(a_CharMapDef != NULL);
+
+ // Initialize the charmap to all-invalid values:
+ for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
+ {
+ a_CharMapOut[i].m_BlockType = 0;
+ a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise
+ }
+
+ // Process the lines in the definition:
+ AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ AStringVector CharDef = StringSplitAndTrim(*itr, ":");
+ size_t NumElements = CharDef.size();
+ if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
+ {
+ LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ unsigned char Src = (unsigned char)CharDef[0][0];
+ ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet?
+ a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
+ NIBBLETYPE BlockMeta = 0;
+ if ((NumElements >= 3) && !CharDef[2].empty())
+ {
+ BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
+ ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
+ }
+ a_CharMapOut[Src].m_BlockMeta = BlockMeta;
+ } // for itr - Lines[]
+}
+
+
+
+
+
+void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
+{
+ // Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
+ for (int y = 0; y < m_Size.y; y++)
+ {
+ for (int z = 0; z < m_Size.z; z++)
+ {
+ const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
+ for (int x = 0; x < m_Size.x; x++)
+ {
+ const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
+ ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap?
+ m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
+{
+ ASSERT(a_ConnectorsDef != NULL);
+
+ AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ continue;
+ }
+ // Split into components: "Type: X, Y, Z: Face":
+ AStringVector Defs = StringSplitAndTrim(*itr, ":");
+ if (Defs.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
+ if (Coords.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
+ continue;
+ }
+
+ // Check that the BlockFace is within range:
+ int BlockFace = atoi(Defs[2].c_str());
+ if ((BlockFace < 0) || (BlockFace >= 6))
+ {
+ LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
+ continue;
+ }
+
+ // Add the connector:
+ m_Connectors.push_back(cPiece::cConnector(
+ atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()), // Connector pos
+ atoi(Defs[0].c_str()), // Connector type
+ (eBlockFace)BlockFace
+ ));
+ } // for itr - Lines[]
+}
+
+
+
+
+
+cPiece::cConnectors cPrefab::GetConnectors(void) const
+{
+ return m_Connectors;
+}
+
+
+
+
+
+Vector3i cPrefab::GetSize(void) const
+{
+ return m_Size;
+}
+
+
+
+
+
+cCuboid cPrefab::GetHitBox(void) const
+{
+ return m_HitBox;
+}
+
+
+
+
+
+bool cPrefab::CanRotateCCW(int a_NumRotations) const
+{
+ // Either zero rotations
+ // Or the proper bit in m_AllowedRotations is set
+ return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
+}
+
+
+
+
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
new file mode 100644
index 000000000..04c4f09da
--- /dev/null
+++ b/src/Generating/Prefab.h
@@ -0,0 +1,105 @@
+
+// Prefab.h
+
+/*
+Declares the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+The class can be constructed from data that is stored directly in the executable, in a sPrefabDef structure
+declared in this file as well; the Gallery server exports areas in this format.
+*/
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "../BlockArea.h"
+
+
+
+
+
+// fwd:
+class cChunkDesc;
+
+
+
+
+
+class cPrefab :
+ public cPiece
+{
+public:
+ struct sDef
+ {
+ int m_SizeX;
+ int m_SizeY;
+ int m_SizeZ;
+ const char * m_CharMap;
+ const char * m_Image;
+ const char * m_Connectors;
+ int m_AllowedRotations;
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+ };
+
+ cPrefab(const sDef & a_Def);
+
+ /** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */
+ void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const;
+
+ /** Returns true if the prefab has any connector of the specified type. */
+ bool HasConnectorType(int a_ConnectorType) const;
+
+protected:
+ /** Packs complete definition of a single block, for per-letter assignment. */
+ struct sBlockTypeDef
+ {
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
+ };
+
+ /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
+ typedef sBlockTypeDef CharMap[256];
+
+
+ /** The cBlockArea that contains the block definitions for the prefab.
+ The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
+ cBlockArea m_BlockArea[4];
+
+ /** The size of the prefab */
+ Vector3i m_Size;
+
+ /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
+ cCuboid m_HitBox;
+
+ /** The connectors through which the piece connects to other pieces */
+ cConnectors m_Connectors;
+
+ /** Bitmask, bit N set -> N rotations CCW supported */
+ int m_AllowedRotations;
+
+ /** The merge strategy to use when drawing the prefab into a block area */
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override;
+ virtual Vector3i GetSize(void) const override;
+ virtual cCuboid GetHitBox(void) const override;
+ virtual bool CanRotateCCW(int a_NumRotations) const override;
+
+ /** Parses the CharMap in the definition into a CharMap binary data used for translating the definition into BlockArea. */
+ void ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef);
+
+ /** Parses the Image in the definition into m_BlockArea[0]'s block types and metas, using the specified CharMap. */
+ void ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage);
+
+ /** Parses the connectors definition text into m_Connectors member. */
+ void ParseConnectors(const char * a_ConnectorsDef);
+};
+
+
+
+
diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt
new file mode 100644
index 000000000..1e60447e7
--- /dev/null
+++ b/src/Generating/Prefabs/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+cmake_minimum_required (VERSION 2.6)
+project (MCServer)
+
+include_directories ("${PROJECT_SOURCE_DIR}/../../")
+
+file(GLOB SOURCE
+ "*.cpp"
+)
+
+add_library(Generating_Prefabs ${SOURCE})
+
+target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks)
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp
new file mode 100644
index 000000000..5e8685e32
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp
@@ -0,0 +1,2758 @@
+
+// NetherFortPrefabs.cpp
+
+// Defines all the prefabs for nether forts
+
+#include "Globals.h"
+#include "NetherFortPrefabs.h"
+
+
+
+
+
+/*
+The nether fortress has two types of connectors, Outer and Inner. Outer is Type 0, Inner is Type 1.
+*/
+
+
+
+
+
+const cPrefab::sDef g_NetherFortPrefabs1[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyCorridor:
+ // The data has been exported from gallery Nether, area index 37, ID 288
+ {
+ // Size:
+ 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ "b: 19: 0\n" /* sponge */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 7\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "f: 44: 6\n" /* step */
+ "g:113: 0\n" /* netherbrickfence */
+ "h:114: 2\n" /* netherbrickstairs */
+ "i:114: 3\n" /* netherbrickstairs */
+ "j:114: 0\n" /* netherbrickstairs */
+ "k:114: 1\n" /* netherbrickstairs */
+ ".: 0: 0\n" /* air */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "bbbbaaaaabbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaa.aaa.aaaa"
+ "bbcdaaaaadebb"
+ "bbbcdddddebbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+
+ // Level 3
+ "aaaaaaaaaaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaa.fff.aaaa"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+
+ // Level 4
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bbg.......gbb"
+ "bbg.......gbb"
+ "bbgggggggggbb"
+
+ // Level 5
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bb.........bb"
+ "bb.........bb"
+ "bb.........bb"
+
+ // Level 6
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bb.........bb"
+ "bb.........bb"
+ "bb.........bb"
+
+ // Level 7
+ "hhhhhhhhhhhhh"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "iijaaaaaaaiii"
+ "bbjiiiiiiikbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb",
+
+ // Connections:
+ "1: 0, 2, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 2, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BalconyCorridor
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyTee2:
+ // The data has been exported from gallery Nether, area index 38, ID 289
+ {
+ // Size:
+ 13, 7, 11, // SizeX = 13, SizeY = 7, SizeZ = 11
+
+ // Block definitions:
+ "a: 19: 0\n" /* sponge */
+ "b:112: 0\n" /* netherbrick */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 7\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "f: 44: 6\n" /* step */
+ "g:113: 0\n" /* netherbrickfence */
+ "h:114: 0\n" /* netherbrickstairs */
+ "i:114: 1\n" /* netherbrickstairs */
+ "j:114: 2\n" /* netherbrickstairs */
+ "k:114: 3\n" /* netherbrickstairs */
+ ".: 0: 0\n" /* air */,
+
+ // Block data:
+ // Level 1
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbb.bbb.bbbb"
+ "aacdbbbbbdeaa"
+ "aaacdddddeaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "aaaab...baaaa"
+ "aaaab...baaaa"
+ "bbbbb...bbbbb"
+ "............."
+ "............."
+ "............."
+ "bbbb.fff.bbbb"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+
+ // Level 4
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aag.......gaa"
+ "aag.......gaa"
+ "aagggggggggaa"
+
+ // Level 5
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aa.........aa"
+ "aa.........aa"
+ "aa.........aa"
+
+ // Level 6
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aa.........aa"
+ "aa.........aa"
+ "aa.........aa"
+
+ // Level 7
+ "aaaahbbbiaaaa"
+ "aaaahbbbiaaaa"
+ "jjjjjbbbjjjjj"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "kkhbbbbbbbkkk"
+ "aahkkkkkkkiaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 2, 4: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 2, 4: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 6, 2, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BalconyTee2
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatform
+ // The data has been exported from gallery Nether, area index 26, ID 276
+ {
+ // Size:
+ 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 52: 0\n" /* mobspawner */
+ "c:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ ".........."
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ ".........."
+
+ // Level 2
+ ".........."
+ "aaaaaaaaaa"
+ "..aaaaaaaa"
+ "..aaaaaaaa"
+ "..aaaaaaaa"
+ "aaaaaaaaaa"
+ ".........."
+
+ // Level 3
+ "....aaaaaa"
+ "aaaaaaaaaa"
+ "...aaaaaaa"
+ "...aaaaaaa"
+ "...aaaaaaa"
+ "aaaaaaaaaa"
+ "....aaaaaa"
+
+ // Level 4
+ "....aaaaaa"
+ "..aaa....a"
+ ".........a"
+ "......b..a"
+ ".........a"
+ "..aaa....a"
+ "....aaaaaa"
+
+ // Level 5
+ "....cccccc"
+ "...cc....c"
+ ".........c"
+ ".........c"
+ ".........c"
+ "...cc....c"
+ "....cccccc"
+
+ // Level 6
+ ".........."
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........."
+
+ // Level 7
+ ".........."
+ ".........."
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........."
+ "..........",
+
+ // Connections:
+ "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BlazePlatform
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatformOverhang:
+ // The data has been exported from gallery Nether, area index 20, ID 162
+ {
+ // Size:
+ 14, 9, 7, // SizeX = 14, SizeY = 9, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */
+ "f:114: 0\n" /* netherbrickstairs */
+ "g:114: 4\n" /* netherbrickstairs */
+ "h:113: 0\n" /* netherbrickfence */
+ "i: 52: 0\n" /* mobspawner */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 4
+ "mmmmmmmmmmmmmm"
+ "dddddddmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "eeeeeeemmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 5
+ "mmmmmmmmmmmmmm"
+ "aaaaaaadmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaaemmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 6
+ "mmmmmmmmmmmmmm"
+ "aaaaaaaabddddm"
+ "......faaaaabm"
+ "......faaaaabm"
+ "......faaaaabm"
+ "aaaaaaaaabeebm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 7
+ "mmmmmmmmgdddbm"
+ "......aaaaaaad"
+ ".......faaaaab"
+ ".......faaaaab"
+ ".......faaaaab"
+ "......aaaaaaae"
+ "mmmmmmmmgeeebm"
+
+ // Level 8
+ "mmmmmmmmaaaaam"
+ "......haa...aa"
+ ".............a"
+ "..........i..a"
+ ".............a"
+ "......haa...aa"
+ "mmmmmmmmaaaaam"
+
+ // Level 9
+ "mmmmmmmmhhhhhm"
+ "......hhh...hh"
+ ".............h"
+ ".............h"
+ ".............h"
+ "......hhh...hh"
+ "mmmmmmmmhhhhhm",
+
+ // Connections:
+ "0: 0, 5, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BlazePlatformOverhang
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrossing:
+ // The data has been exported from gallery Nether, area index 17, ID 159
+ {
+ // Size:
+ 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 7\n" /* netherbrickstairs */
+ "c:114: 5\n" /* netherbrickstairs */
+ "d:114: 4\n" /* netherbrickstairs */
+ "e:114: 6\n" /* netherbrickstairs */
+ "f: 44:14\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 2
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmbbbmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aacmmmmmmmmmdaa"
+ "aacmmmmmmmmmdaa"
+ "aacmmmmmmmmmdaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 3
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmbbbmmmmmm"
+ "mmmmmmfffmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aaacfmmmmmfdaaa"
+ "aaacfmmmmmfdaaa"
+ "aaacfmmmmmfdaaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmfffmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 4
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "eeeeeeaaaeeeeee"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "bbbbbdaaacbbbbb"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+
+ // Level 5
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+
+ // Level 6
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "aaaaaa...aaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaa...aaaaaa"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+
+ // Level 7
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+
+ // Level 8
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm",
+
+ // Connections:
+ "0: 0, 5, 7: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 7, 5, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 14, 5, 7: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 7, 5, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrossing
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble1:
+ // The data has been exported from gallery Nether, area index 19, ID 161
+ {
+ // Size:
+ 9, 6, 5, // SizeX = 9, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 19: 0\n" /* sponge */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "........."
+ "aa......."
+ "aa......."
+ "aa......."
+ "........."
+
+ // Level 2
+ "........."
+ "aab......"
+ "aab......"
+ "aab......"
+ "........."
+
+ // Level 3
+ "........."
+ "aaabc...."
+ "aaabc...."
+ "aaabc...."
+ "........."
+
+ // Level 4
+ "ddddddd.."
+ "aaaaaaaa."
+ "aaaaaaaaa"
+ "aaaaaaa.."
+ "eeeee...."
+
+ // Level 5
+ "aaaaaaaaa"
+ "aaaaa...."
+ "aaaaaa..."
+ "aaaaaa..."
+ "aaaaaaaa."
+
+ // Level 6
+ "aaaaaa..."
+ "........."
+ "........."
+ "........."
+ "aaaaaaa..",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrumble1
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble2
+ // The data has been exported from gallery Nether, area index 18, ID 160
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 19: 0\n" /* sponge */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "............."
+ "aa..........."
+ "aa..........."
+ "aa..........."
+ "............."
+
+ // Level 2
+ "............."
+ "aab.........."
+ "aab.........."
+ "aab.........."
+ "............."
+
+ // Level 3
+ "............."
+ "aaabc........"
+ "aaabc........"
+ "aaabc........"
+ "............."
+
+ // Level 4
+ "ddddddddd...."
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaa...."
+ "aaaaaaaaaaaa."
+ "eeeeeeeee...."
+
+ // Level 5
+ "aaaaaaaaaaaa."
+ "aaaaaaaaaa..."
+ "aaaaaaaaaaa.."
+ "aaaaaaaaa...."
+ "aaaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaa...."
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaa...",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrumble2
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeSegment:
+ // The data has been exported from gallery Nether, area index 16, ID 158
+ {
+ // Size:
+ 15, 8, 5, // SizeX = 15, SizeY = 8, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d: 44:14\n" /* step */
+ "e:114: 6\n" /* netherbrickstairs */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmmm"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmmm"
+ "aaabdmmmmmdcaaa"
+ "aaabdmmmmmdcaaa"
+ "aaabdmmmmmdcaaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 4
+ "eeeeeeeeeeeeeee"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "fffffffffffffff"
+
+ // Level 5
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmmmmmmmmmmm"
+
+ // Level 8
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmmmmmmmmmmm",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeSegment
+
+
+ // BridgeTee:
+ // The data has been exported from gallery Nether, area index 39, ID 290
+ {
+ // Size:
+ 15, 8, 10, // SizeX = 15, SizeY = 8, SizeZ = 10
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e: 44:14\n" /* step */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmmm"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmdddmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmmm"
+ "aaabemmmmmecaaa"
+ "aaabemmmmmecaaa"
+ "aaabemmmmmecaaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmdddmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 4
+ "ddddddddddddddd"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "fffffcaaabfffff"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+
+ // Level 5
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaa...aaaaaa"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+
+ // Level 7
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+
+ // Level 8
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 7, 5, 9: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeTee
+
+
+ // Corridor11:
+ // The data has been exported from gallery Nether, area index 36, ID 287
+ {
+ // Size:
+ 11, 6, 5, // SizeX = 11, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 3\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "..........."
+ "..........."
+ "..........."
+ "aaaaaaaaaaa"
+
+ // Level 3
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 4
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 5
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 6
+ "ccccccccccc"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "ddddddddddd",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Corridor11
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Corridor13:
+ // The data has been exported from gallery Nether, area index 35, ID 286
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ ".: 0: 0\n" /* air */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 4
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 5
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 6
+ "ddddddddddddd"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "eeeeeeeeeeeee",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Corridor13
+
+
+ // CorridorCorner5:
+ // The data has been exported from gallery Nether, area index 10, ID 40
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "a.........."
+ "a.........."
+ "a.........."
+ "a...aaaaaaa"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+
+ // Level 3
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 4
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 5
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 6
+ "ccccccccccc"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaeeeeeee"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm",
+
+ // Connections:
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorCorner5
+
+
+ // CorridorCorner5:
+ // The data has been exported from gallery Nether, area index 10, ID 40
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g: 54: 5\n" /* chest */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "ag........."
+ "a.........."
+ "a.........."
+ "a...aaaaaaa"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+
+ // Level 3
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 4
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 5
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 6
+ "ccccccccccc"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaeeeeeee"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm",
+
+ // Connections:
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorCorner5Chest
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorStairs:
+ // The data has been exported from gallery Nether, area index 12, ID 42
+ {
+ // Size:
+ 9, 13, 5, // SizeX = 9, SizeY = 13, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 0\n" /* netherbrickstairs */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaa"
+ ".baaaaaaa"
+ ".baaaaaaa"
+ ".baaaaaaa"
+ "aaaaaaaaa"
+
+ // Level 3
+ "acaaaaaaa"
+ "..baaaaaa"
+ "..baaaaaa"
+ "..baaaaaa"
+ "acaaaaaaa"
+
+ // Level 4
+ "acaaaaaaa"
+ "...baaaaa"
+ "...baaaaa"
+ "...baaaaa"
+ "acaaaaaaa"
+
+ // Level 5
+ "acacaaaaa"
+ "....baaaa"
+ "....baaaa"
+ "....baaaa"
+ "acacaaaaa"
+
+ // Level 6
+ "aaacaaaaa"
+ ".....baaa"
+ ".....baaa"
+ ".....baaa"
+ "aaacaaaaa"
+
+ // Level 7
+ "daacacaaa"
+ "a.....baa"
+ "a.....baa"
+ "a.....baa"
+ "eaacacaaa"
+
+ // Level 8
+ "fdaaacaaa"
+ "fa.....ba"
+ "fa.....ba"
+ "fa.....ba"
+ "feaaacaaa"
+
+ // Level 9
+ "ffdaacaca"
+ "ffa......"
+ "ffa......"
+ "ffa......"
+ "ffeaacaca"
+
+ // Level 10
+ "fffdaaaca"
+ "fffa....."
+ "fffa....."
+ "fffa....."
+ "fffeaaaca"
+
+ // Level 11
+ "ffffdaaca"
+ "ffffa...."
+ "ffffa...."
+ "ffffa...."
+ "ffffeaaca"
+
+ // Level 12
+ "fffffdaaa"
+ "fffffa..."
+ "fffffa..."
+ "fffffa..."
+ "fffffeaaa"
+
+ // Level 13
+ "ffffffddd"
+ "ffffffaaa"
+ "ffffffaaa"
+ "ffffffaaa"
+ "ffffffeee",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 8, 8, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorStairs
+
+
+ // LavaStaircase:
+ // The data has been exported from gallery Nether, area index 28, ID 278
+ {
+ // Size:
+ 15, 11, 15, // SizeX = 15, SizeY = 11, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c: 11: 0\n" /* lava */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaa...aaaa"
+ "aaaaa.........a"
+ "aaaaa.........a"
+ "aaaaab........a"
+ "accca...aaaa..a"
+ "accca...acca..a"
+ "acccaaaaacca..a"
+ "acccccccccca..a"
+ "acccaaaaacca..a"
+ "accca...acca..a"
+ "accca...aaaa..a"
+ "aaaaab........a"
+ "aaaaa.........a"
+ "aaaaa.........a"
+ "aaaaaaaa...aaaa"
+
+ // Level 3
+ "aaaaaaaa...aaaa"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaabb........a"
+ "aaaa..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaabb........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaaaaaa...aaaa"
+
+ // Level 4
+ "aaaaaaaa...aaaa"
+ "a.............a"
+ "a.............a"
+ "a..bb.........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..bb.........a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaa...aaaa"
+
+ // Level 5
+ "aaaaaaaabbbaaaa"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "a..b..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaabbbaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "a..b..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaaaaa"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "...b..........a"
+ "...b..........a"
+ "...b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 8
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 9
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 10
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 11
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 6, 7: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "0: 9, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 9, 1, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // LavaStaircase
+
+
+ // LavaStaircaseBig:
+ // The data has been exported from gallery Nether, area index 31, ID 282
+ {
+ // Size:
+ 12, 15, 15, // SizeX = 12, SizeY = 15, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 10: 0\n" /* lava */
+ "c:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaaaaaa"
+ "abbbbbbaaaaa"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbbaaaaa"
+ "abbbbb.aaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 3
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaaaaaa"
+ "abbbbbba...a"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...a"
+ "abbbbb.aaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 4
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaa...a"
+ "abbbbbba...a"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...a"
+ "abbbbbaa...a"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 5
+ "aaaaaaaaaaaa"
+ "aaaaa......a"
+ "aaaaa......a"
+ "aaaaacc....a"
+ "a.....cc...a"
+ "a......c...a"
+ "a......c...."
+ "a......c...."
+ "a......c...."
+ "a......c...a"
+ "a.....cc...a"
+ "aaaaacc....a"
+ "aaaaa......a"
+ "aaaaa......a"
+ "aaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaa"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaacc.....a"
+ "aaaa.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaacc.....a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..cc......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..cc......a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 8
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "a..c.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 9
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "a..c.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 10
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "...c.......a"
+ "...c.......a"
+ "...c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 11
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 12
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 13
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 14
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 15
+ "aaaaaaaaaaaa"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "aaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 9, 7: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 11, 1, 7: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // LavaStaircaseBig
+
+
+ // MidStaircase:
+ // The data has been exported from gallery Nether, area index 23, ID 165
+ {
+ // Size:
+ 13, 8, 13, // SizeX = 13, SizeY = 8, SizeZ = 13
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 88: 0\n" /* soulsand */
+ "c:115: 7\n" /* netherwartblock */
+ "d:114: 3\n" /* netherbrickstairs */
+ "e:114: 0\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g:114: 2\n" /* netherbrickstairs */
+ "h: 10: 0\n" /* lava */
+ "i:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaacccccaaaa"
+ "addecccccfdda"
+ "...eaaaaad..."
+ "...eaaaaa...."
+ "...eaaaaag..."
+ "agggcccccfgga"
+ "aaaacccccaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "aaaaaaaaaaaaa"
+ "aha.......aha"
+ "aaa.......aaa"
+ "a...........a"
+ "a...........a"
+ "....eaaaa...."
+ "....eaaaa...."
+ "....eaaaa...."
+ "a...........a"
+ "a...........a"
+ "aaa.......aaa"
+ "aha.......aha"
+ "aaaaaaaaaaaaa"
+
+ // Level 4
+ "aaaiiaaaiiaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ ".....eaaa...."
+ ".....eaaa...."
+ ".....eaaa...."
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaiiaaaiiaaa"
+
+ // Level 5
+ "aaaiiaaaiiaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "......eaa...."
+ "......eaa...."
+ "......eaa...."
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaiiaaaiiaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a......ea...a"
+ "a......ea...a"
+ "a......ea...a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaa....eaaaa"
+ "aaaa....eaaaa"
+ "aaaa....eaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 8
+ "iaiaiaiaiaiai"
+ "a...........a"
+ "i...........i"
+ "a...........a"
+ "i...........i"
+ "a............"
+ "i............"
+ "a............"
+ "i...........i"
+ "a...........a"
+ "i...........i"
+ "a...........a"
+ "iaiaiaiaiaiai",
+
+ // Connections:
+ "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 12, 7, 6: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // MidStaircase
+
+
+ // StairsToOpen1:
+ // The data has been exported from gallery Nether, area index 27, ID 277
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a.aaaaa"
+ "aabaaba"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a..aaaa"
+ "aabaaba"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a...aaa"
+ "aabaaba"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a....aa"
+ "aaaaaaa"
+
+ // Level 7
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 8
+ "aaaaaaa"
+ "a.....a"
+ "a......"
+ "a......"
+ "a......"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 9
+ "mmmmmmm"
+ "m.....m"
+ "m......"
+ "m......"
+ "m......"
+ "m.....m"
+ "mmmmmmm"
+
+ // Level 10
+ "mmmmmmm"
+ "m.....m"
+ "m......"
+ "m......"
+ "m......"
+ "m.....m"
+ "mmmmmmm",
+
+ // Connections:
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 6, 7, 3: 5\n" /* Type 0, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // StairsToOpen1
+
+
+ // StairsToOpen2:
+ // The data has been exported from gallery Nether, area index 8, ID 35
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a.aaaaa"
+ "aabaaba"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a..aaaa"
+ "aabaaba"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a...aaa"
+ "aabaaba"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a....aa"
+ "aaaaaaa"
+
+ // Level 7
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 8
+ "aaaaaaa"
+ "a.....a"
+ "......a"
+ "......a"
+ "......a"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 9
+ "mmmmmmm"
+ "m.....m"
+ "......m"
+ "......m"
+ "......m"
+ "m.....m"
+ "mmmmmmm"
+
+ // Level 10
+ "mmmmmmm"
+ "m.....m"
+ "......m"
+ "......m"
+ "......m"
+ "m.....m"
+ "mmmmmmm",
+
+ // Connections:
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 0, 7, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // StairsToOpen2
+
+
+ // Tee2x4:
+ // The data has been exported from gallery Nether, area index 40, ID 291
+ {
+ // Size:
+ 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "aaaaa...aaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 4
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 5
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 6
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "eeeecaaadeeee"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "fffffffffffff",
+
+ // Connections:
+ "1: 0, 1, 4: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */
+ "1: 12, 1, 4: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Tee2x4
+
+
+ // Tee4x4:
+ // The data has been exported from gallery Nether, area index 41, ID 292
+ {
+ // Size:
+ 13, 6, 9, // SizeX = 13, SizeY = 6, SizeZ = 9
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "aaaaa...aaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 4
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 5
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 6
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "eeeecaaadeeee"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "fffffffffffff",
+
+ // Connections:
+ "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Tee4x4
+
+ // Turret:
+ // The data has been exported from gallery Nether, area index 7, ID 34
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 6, 1, 3: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 3, 1, 6: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Turret
+
+} ; // g_NetherFortPrefabs1
+
+
+
+
+
+const cPrefab::sDef g_NetherFortStartingPrefabs1[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CentralRoom:
+ // The data has been exported from gallery Nether, area index 22, ID 164
+ {
+ // Size:
+ 13, 9, 13, // SizeX = 13, SizeY = 9, SizeZ = 13
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ "b: 0: 0\n" /* air */
+ "c: 10: 0\n" /* lava */
+ "d:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaabbbaaaaa"
+ "aaaaabbbaaaaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbaaabbbaa"
+ "aabbbacabbbaa"
+ "aabbbaaabbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aaaaabbbaaaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 3
+ "aaaaabbbaaaaa"
+ "aaadabbbadaaa"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "aaadabbbadaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 4
+ "aaaaabbbaaaaa"
+ "aaadabbbadaaa"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "aaadabbbadaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 5
+ "adadadddadada"
+ "daaaabbbaaaad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "daaaabbbaaaad"
+ "adadabbbadada"
+
+ // Level 6
+ "adadaaaaadada"
+ "daaaaaaaaaaad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "daaaaaaaaaaad"
+ "adadaaaaadada"
+
+ // Level 7
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 8
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 9
+ "dadadadadadad"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dadadadadadad",
+
+ // Connections:
+ "0: 6, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "1: 6, 1, 12: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ },
+} ; // g_NetherFortStartingPrefabs1
+
+const size_t g_NetherFortPrefabs1Count = ARRAYCOUNT(g_NetherFortPrefabs1);
+const size_t g_NetherFortStartingPrefabs1Count = ARRAYCOUNT(g_NetherFortStartingPrefabs1);
+
+
+
+
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.h b/src/Generating/Prefabs/NetherFortPrefabs.h
new file mode 100644
index 000000000..37a91689d
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.h
@@ -0,0 +1,15 @@
+
+// NetherFortPrefabs.h
+
+// Declares the data used for nether fortress prefabs
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_NetherFortPrefabs1[];
+extern const cPrefab::sDef g_NetherFortStartingPrefabs1[];
+extern const size_t g_NetherFortPrefabs1Count;
+extern const size_t g_NetherFortStartingPrefabs1Count;
diff --git a/src/Globals.h b/src/Globals.h
index 3e62832b7..26a0d87a9 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -29,6 +29,9 @@
// Disabling this warning, because we know what we're doing when we're doing this:
#pragma warning(disable: 4355) // 'this' used in initializer list
+
+ // Disabled because it's useless:
+ #pragma warning(disable: 4512) // 'class': assignment operator could not be generated - reported for each class that has a reference-type member
// 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places
// #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data
@@ -264,11 +267,17 @@ template class SizeChecker<UInt16, 2>;
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
#endif
-/// A generic interface used mainly in ForEach() functions
+
+
+
+
+/** A generic interface used mainly in ForEach() functions */
template <typename Type> class cItemCallback
{
public:
- /// Called for each item in the internal list; return true to stop the loop, or false to continue enumerating
+ virtual ~cItemCallback() {}
+
+ /** Called for each item in the internal list; return true to stop the loop, or false to continue enumerating */
virtual bool Item(Type * a_Type) = 0;
} ;
diff --git a/src/Group.cpp b/src/Group.cpp
index 5f1f25782..9c2467144 100644
--- a/src/Group.cpp
+++ b/src/Group.cpp
@@ -38,4 +38,4 @@ void cGroup::InheritFrom( cGroup* a_Group )
void cGroup::ClearPermission()
{
m_Permissions.clear();
-} \ No newline at end of file
+}
diff --git a/src/HTTPServer/EnvelopeParser.h b/src/HTTPServer/EnvelopeParser.h
index 6430fbebf..866bed11d 100644
--- a/src/HTTPServer/EnvelopeParser.h
+++ b/src/HTTPServer/EnvelopeParser.h
@@ -19,6 +19,9 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a full header line is parsed
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) = 0;
} ;
diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h
index a554ca5a4..f2a509cb8 100644
--- a/src/HTTPServer/HTTPFormParser.h
+++ b/src/HTTPServer/HTTPFormParser.h
@@ -36,6 +36,9 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a new file part is encountered in the form data
virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) = 0;
diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h
index 24baf8c95..383abb4b6 100644
--- a/src/HTTPServer/HTTPServer.h
+++ b/src/HTTPServer/HTTPServer.h
@@ -37,6 +37,8 @@ public:
class cCallbacks
{
public:
+ virtual ~cCallbacks() {}
+
/** Called when a new request arrives over a connection and its headers have been parsed.
The request body needn't have arrived yet.
*/
@@ -50,7 +52,7 @@ public:
} ;
cHTTPServer(void);
- ~cHTTPServer();
+ virtual ~cHTTPServer();
/// Initializes the server on the specified ports
bool Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6);
diff --git a/src/HTTPServer/MultipartParser.h b/src/HTTPServer/MultipartParser.h
index d853929ed..77695fe4a 100644
--- a/src/HTTPServer/MultipartParser.h
+++ b/src/HTTPServer/MultipartParser.h
@@ -22,6 +22,9 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a new part starts
virtual void OnPartStart(void) = 0;
diff --git a/src/Inventory.h b/src/Inventory.h
index fd2089a13..1ad7c4776 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -52,6 +52,8 @@ public:
cInventory(cPlayer & a_Owner);
+ virtual ~cInventory() {}
+
// tolua_begin
/// Removes all items from the entire inventory
diff --git a/src/Item.h b/src/Item.h
index 4bdfb12dd..910ecb382 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -209,7 +209,7 @@ public:
void Add (const cItem & a_Item) {push_back(a_Item); }
void Delete(int a_Idx);
void Clear (void) {clear(); }
- int Size (void) {return size(); }
+ size_t Size (void) {return size(); }
void Set (int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage);
void Add (short a_ItemType, char a_ItemCount, short a_ItemDamage)
diff --git a/src/ItemGrid.h b/src/ItemGrid.h
index b344e3daf..c34d5e9e2 100644
--- a/src/ItemGrid.h
+++ b/src/ItemGrid.h
@@ -20,11 +20,13 @@ class cItemGrid
public:
// tolua_end
- /// This class is used as a callback for when a slot changes
+ /** This class is used as a callback for when a slot changes */
class cListener
{
public:
- /// Called whenever a slot changes
+ virtual ~cListener() {}
+
+ /** Called whenever a slot changes */
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) = 0;
} ;
typedef std::vector<cListener *> cListeners;
@@ -38,12 +40,12 @@ public:
int GetHeight (void) const { return m_Height; }
int GetNumSlots(void) const { return m_NumSlots; }
- /// Converts XY coords into slot number; returns -1 on invalid coords
+ /** Converts XY coords into slot number; returns -1 on invalid coords */
int GetSlotNum(int a_X, int a_Y) const;
// tolua_end
- /// Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp
+ /** Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp */
void GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const;
// tolua_begin
@@ -62,16 +64,16 @@ public:
void EmptySlot(int a_X, int a_Y);
void EmptySlot(int a_SlotNum);
- /// Returns true if the specified slot is empty or the slot doesn't exist
+ /** Returns true if the specified slot is empty or the slot doesn't exist */
bool IsSlotEmpty(int a_SlotNum) const;
- /// Returns true if the specified slot is empty or the slot doesn't exist
+ /** Returns true if the specified slot is empty or the slot doesn't exist */
bool IsSlotEmpty(int a_X, int a_Y) const;
- /// Sets all items as empty
+ /** Sets all items as empty */
void Clear(void);
- /// Returns number of items out of a_ItemStack that can fit in the storage
+ /** Returns number of items out of a_ItemStack that can fit in the storage */
int HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks = true);
/** Adds as many items out of a_ItemStack as can fit.
@@ -117,37 +119,37 @@ public:
*/
cItem RemoveOneItem(int a_X, int a_Y);
- /// Returns the number of items of type a_Item that are stored
+ /** Returns the number of items of type a_Item that are stored */
int HowManyItems(const cItem & a_Item);
- /// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack
+ /** Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack */
bool HasItems(const cItem & a_ItemStack);
- /// Returns the index of the first empty slot; -1 if all full
+ /** Returns the index of the first empty slot; -1 if all full */
int GetFirstEmptySlot(void) const;
- /// Returns the index of the first non-empty slot; -1 if all empty
+ /** Returns the index of the first non-empty slot; -1 if all empty */
int GetFirstUsedSlot(void) const;
- /// Returns the index of the last empty slot; -1 if all full
+ /** Returns the index of the last empty slot; -1 if all full */
int GetLastEmptySlot(void) const;
- /// Returns the index of the last used slot; -1 if all empty
+ /** Returns the index of the last used slot; -1 if all empty */
int GetLastUsedSlot(void) const;
- /// Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked)
+ /** Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked) */
int GetNextEmptySlot(int a_StartFrom) const;
- /// Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked)
+ /** Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked) */
int GetNextUsedSlot(int a_StartFrom) const;
- /// Copies the contents into a cItems object; preserves the original a_Items contents
+ /** Copies the contents into a cItems object; preserves the original a_Items contents */
void CopyToItems(cItems & a_Items) const;
- /// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
+ /** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
bool DamageItem(int a_SlotNum, short a_Amount);
- /// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
+ /** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
bool DamageItem(int a_X, int a_Y, short a_Amount);
// tolua_end
@@ -159,10 +161,10 @@ public:
*/
void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed);
- /// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
+ /** Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback! */
void AddListener(cListener & a_Listener);
- /// Removes a slot-change-callback. Must not be called from within the listener callback!
+ /** Removes a slot-change-callback. Must not be called from within the listener callback! */
void RemoveListener(cListener & a_Listener);
// tolua_begin
@@ -177,7 +179,7 @@ protected:
cCriticalSection m_CSListeners; ///< CS that guards the m_Listeners against multi-thread access
bool m_IsInTriggerListeners; ///< Set to true while TriggerListeners is running, to detect attempts to manipulate listener list while triggerring
- /// Calls all m_Listeners for the specified slot number
+ /** Calls all m_Listeners for the specified slot number */
void TriggerListeners(int a_SlotNum);
/** Adds up to a_Num items out of a_ItemStack, as many as can fit, in specified slot
diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h
index a28ec8e22..42f4ffc8f 100644
--- a/src/Items/ItemBoat.h
+++ b/src/Items/ItemBoat.h
@@ -39,12 +39,20 @@ public:
public cBlockTracer::cCallbacks
{
public:
- Vector3d Pos;
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ Vector3d m_Pos;
+ bool m_HasFound;
+
+ cCallbacks(void) :
+ m_HasFound(false)
{
- if (a_BlockType != E_BLOCK_AIR)
+ }
+
+ virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override
+ {
+ if (a_CBBlockType != E_BLOCK_AIR)
{
- Pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
+ m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ);
+ m_HasFound = true;
return true;
}
return false;
@@ -57,15 +65,15 @@ public:
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
- double x = Callbacks.Pos.x;
- double y = Callbacks.Pos.y;
- double z = Callbacks.Pos.z;
-
- if ((x == 0) && (y == 0) && (z == 0))
+ if (!Callbacks.m_HasFound)
{
return false;
}
+ double x = Callbacks.m_Pos.x;
+ double y = Callbacks.m_Pos.y;
+ double z = Callbacks.m_Pos.z;
+
cBoat * Boat = new cBoat(x + 0.5, y + 1, z + 0.5);
Boat->Initialize(a_World);
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
index 72cb8fa0a..68c89dd85 100644
--- a/src/Items/ItemBucket.h
+++ b/src/Items/ItemBucket.h
@@ -172,12 +172,12 @@ public:
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
- if (a_BlockMeta != 0) // Even if it was a water block it would not be a source.
- {
- return false;
- }
if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType))
{
+ if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source
+ {
+ return false;
+ }
m_HasHitFluid = true;
m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ);
return true;
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 454fabdd7..337b3a83c 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -27,6 +27,7 @@
#include "ItemHoe.h"
#include "ItemLeaves.h"
#include "ItemLighter.h"
+#include "ItemLilypad.h"
#include "ItemMap.h"
#include "ItemMinecart.h"
#include "ItemNetherWart.h"
@@ -115,6 +116,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
+ case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h
new file mode 100644
index 000000000..5a29abe94
--- /dev/null
+++ b/src/Items/ItemLilypad.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "ItemHandler.h"
+#include "../Entities/Player.h"
+#include "Vector3.h"
+#include "../LineBlockTracer.h"
+#include "BlockInfo.h"
+
+
+
+
+
+class cItemLilypadHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemLilypadHandler(BLOCKTYPE a_BlockType)
+ : cItemHandler(a_BlockType)
+ {
+
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return false; // Set as not placeable so OnItemUse is called
+ }
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ if (a_BlockFace > BLOCK_FACE_NONE)
+ {
+ // Clicked on the side of a submerged block; vanilla allows placement, so should we
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0);
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ return true;
+ }
+
+ class cCallbacks :
+ public cBlockTracer::cCallbacks
+ {
+ public:
+ cCallbacks(cWorld * a_World) :
+ m_HasHitFluid(false),
+ m_World(a_World)
+ {
+ }
+
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ {
+ if (IsBlockWater(a_BlockType))
+ {
+ if ((a_BlockMeta != 0) || (a_EntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged
+ {
+ return false;
+ }
+ a_EntryFace = BLOCK_FACE_YP; // Always place pad at top of water block
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, (eBlockFace)a_EntryFace);
+ BLOCKTYPE Block = m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (
+ !IsBlockWater(Block) &&
+ cBlockInfo::FullyOccupiesVoxel(Block)
+ )
+ {
+ // Can't place lilypad on air/in another block!
+ return true;
+ }
+ m_HasHitFluid = true;
+ m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ);
+ return true;
+ }
+ return false;
+ }
+
+ Vector3i m_Pos;
+ bool m_HasHitFluid;
+ cWorld * m_World;
+
+ };
+
+ cCallbacks Callbacks(a_World);
+ cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks);
+ Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
+ Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
+
+ Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
+
+ if (Callbacks.m_HasHitFluid)
+ {
+ a_World->SetBlock(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z, E_BLOCK_LILY_PAD, 0);
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ return true;
+ }
+
+ return false;
+ }
+};
+
+
+
+
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
index bcaa5635a..25500aeb9 100644
--- a/src/Items/ItemMinecart.h
+++ b/src/Items/ItemMinecart.h
@@ -1,4 +1,3 @@
-
// ItemMinecart.h
// Declares the various minecart ItemHandlers
@@ -72,6 +71,11 @@ public:
}
} // switch (m_ItemType)
Minecart->Initialize(a_World);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
return true;
}
diff --git a/src/LightingThread.h b/src/LightingThread.h
index 198f27248..3209ad9b2 100644
--- a/src/LightingThread.h
+++ b/src/LightingThread.h
@@ -160,14 +160,14 @@ protected:
inline void PropagateLight(
NIBBLETYPE * a_Light,
- int a_SrcIdx, int a_DstIdx,
+ unsigned int a_SrcIdx, unsigned int a_DstIdx,
int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
)
{
ASSERT(a_SrcIdx >= 0);
- ASSERT(a_SrcIdx < (int)ARRAYCOUNT(m_SkyLight));
+ ASSERT(a_SrcIdx < ARRAYCOUNT(m_SkyLight));
ASSERT(a_DstIdx >= 0);
- ASSERT(a_DstIdx < (int)ARRAYCOUNT(m_BlockTypes));
+ ASSERT(a_DstIdx < ARRAYCOUNT(m_BlockTypes));
if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]))
{
diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp
index 4f3e5dc0f..80fa7b173 100644
--- a/src/MCLogger.cpp
+++ b/src/MCLogger.cpp
@@ -93,25 +93,30 @@ void cMCLogger::InitLog(const AString & a_FileName)
-void cMCLogger::LogSimple(const char* a_Text, int a_LogType /* = 0 */ )
+void cMCLogger::LogSimple(const char * a_Text, eLogLevel a_LogLevel)
{
- switch( a_LogType )
+ switch (a_LogLevel)
{
- case 0:
+ case llRegular:
+ {
LOG("%s", a_Text);
break;
- case 1:
+ }
+ case llInfo:
+ {
LOGINFO("%s", a_Text);
break;
- case 2:
+ }
+ case llWarning:
+ {
LOGWARN("%s", a_Text);
break;
- case 3:
+ }
+ case llError:
+ {
LOGERROR("%s", a_Text);
break;
- default:
- LOG("(#%d#: %s", a_LogType, a_Text);
- break;
+ }
}
}
diff --git a/src/MCLogger.h b/src/MCLogger.h
index 996e60329..c0150c124 100644
--- a/src/MCLogger.h
+++ b/src/MCLogger.h
@@ -10,25 +10,36 @@ class cLog;
-class cMCLogger // tolua_export
-{ // tolua_export
-public: // tolua_export
- /// Creates a logger with the default filename, "logs/LOG_<timestamp>.log"
+// tolua_begin
+class cMCLogger
+{
+public:
+ enum eLogLevel
+ {
+ llRegular,
+ llInfo,
+ llWarning,
+ llError,
+ };
+ // tolua_end
+
+ /** Creates a logger with the default filename, "logs/LOG_<timestamp>.log" */
cMCLogger(void);
- /// Creates a logger with the specified filename inside "logs" folder
+ /** Creates a logger with the specified filename inside "logs" folder */
cMCLogger(const AString & a_FileName); // tolua_export
~cMCLogger(); // tolua_export
- void Log(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
- void Info(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
- void Warn(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
- void Error(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Log (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Info (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Warn (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Error(const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
- void LogSimple(const char* a_Text, int a_LogType = 0 ); // tolua_export
+ /** Logs the simple text message at the specified log level. */
+ void LogSimple(const char * a_Text, eLogLevel a_LogLevel = llRegular); // tolua_export
- static cMCLogger* GetInstance();
+ static cMCLogger * GetInstance();
private:
enum eColorScheme
{
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index a0d0f5c54..05da5d01c 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -129,6 +129,11 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
BLOCKTYPE TargetBlock = E_BLOCK_AIR;
if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock))
{
+ if ((a_RelY + 1 > cChunkDef::Height) || (a_RelY - 1 < 0))
+ {
+ return false;
+ }
+
NIBBLETYPE BlockLight = a_Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
NIBBLETYPE SkyLight = a_Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
BLOCKTYPE BlockAbove = a_Chunk->GetBlock(a_RelX, a_RelY + 1, a_RelZ);
@@ -200,7 +205,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
case cMonster::mtSpider:
{
bool CanSpawn = true;
- bool HaveFloor = false;
+ bool HasFloor = false;
for (int x = 0; x < 2; ++x)
{
for(int z = 0; z < 2; ++z)
@@ -211,8 +216,8 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
{
return false;
}
- HaveFloor = (
- HaveFloor ||
+ HasFloor = (
+ HasFloor ||
(
a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock) &&
!cBlockInfo::IsTransparent(TargetBlock)
@@ -220,7 +225,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
);
}
}
- return CanSpawn && HaveFloor && (SkyLight <= 7) && (BlockLight <= 7);
+ return CanSpawn && HasFloor && (SkyLight <= 7) && (BlockLight <= 7);
}
case cMonster::mtCreeper:
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index ac42cf40b..84ff8929b 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -53,4 +53,4 @@ void cBlaze::Attack(float a_Dt)
m_AttackInterval = 0.0;
// ToDo: Shoot 3 fireballs instead of 1.
}
-} \ No newline at end of file
+}
diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h
index cdb3a1306..5970451c7 100644
--- a/src/Mobs/Blaze.h
+++ b/src/Mobs/Blaze.h
@@ -20,7 +20,3 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void Attack(float a_Dt) override;
} ;
-
-
-
-
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 16d6aed1f..aa6071515 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -111,9 +111,9 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
void cMonster::TickPathFinding()
{
- int PosX = (int)floor(GetPosX());
- int PosY = (int)floor(GetPosY());
- int PosZ = (int)floor(GetPosZ());
+ const int PosX = (int)floor(GetPosX());
+ const int PosY = (int)floor(GetPosY());
+ const int PosZ = (int)floor(GetPosZ());
m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z);
@@ -130,14 +130,16 @@ void cMonster::TickPathFinding()
{ 0, 1},
{ 0,-1},
} ;
+
+ if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
+ {
+ // Too low/high, can't really do anything
+ FinishPathFinding();
+ return;
+ }
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{
- if ((gCrossCoords[i].x + PosX == PosX) && (gCrossCoords[i].z + PosZ == PosZ))
- {
- continue;
- }
-
if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ)))
{
continue;
@@ -758,6 +760,7 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
case mtSquid: return mfWater;
case mtVillager: return mfPassive;
case mtWitch: return mfHostile;
+ case mtWither: return mfHostile;
case mtWolf: return mfHostile;
case mtZombie: return mfHostile;
case mtZombiePigman: return mfHostile;
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index 47fcdbb26..1685f40c5 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -88,4 +88,4 @@ void cSkeleton::Attack(float a_Dt)
m_World->BroadcastSpawnEntity(*Arrow);
m_AttackInterval = 0.0;
}
-} \ No newline at end of file
+}
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index b99ae876f..5bba4d4ba 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -29,7 +29,7 @@ public:
CLASS_PROTODEF(cVillager);
- // Override functions
+ // cEntity overrides
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index c46e0beab..8f5d28b68 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -2,14 +2,90 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Wither.h"
+#include "../World.h"
cWither::cWither(void) :
- super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0)
+ super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
+ m_InvulnerableTicks(220)
{
+ SetMaxHealth(300);
+}
+
+
+
+
+
+bool cWither::IsArmored(void) const
+{
+ return GetHealth() <= (GetMaxHealth() / 2);
+}
+
+
+
+
+
+bool cWither::Initialize(cWorld * a_World)
+{
+ // Set health before BroadcastSpawnEntity()
+ SetHealth(GetMaxHealth() / 3);
+
+ return super::Initialize(a_World);
+}
+
+
+
+
+
+void cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (a_TDI.DamageType == dtDrowning)
+ {
+ return;
+ }
+
+ if (m_InvulnerableTicks > 0)
+ {
+ return;
+ }
+
+ if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
+ {
+ return;
+ }
+
+ super::DoTakeDamage(a_TDI);
+}
+
+
+
+
+
+void cWither::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_InvulnerableTicks > 0)
+ {
+ unsigned int NewTicks = m_InvulnerableTicks - 1;
+
+ if (NewTicks == 0)
+ {
+ m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
+ }
+
+ m_InvulnerableTicks = NewTicks;
+
+ if ((NewTicks % 10) == 0)
+ {
+ Heal(10);
+ }
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
}
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index 56effc6bb..bc78bfaad 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -16,8 +16,25 @@ public:
cWither(void);
CLASS_PROTODEF(cWither);
+
+ unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; }
+
+ void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
+
+ /** Returns whether the wither is invulnerable to arrows. */
+ bool IsArmored(void) const;
+ // cEntity overrides
+ virtual bool Initialize(cWorld * a_World) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ /** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
+ unsigned int m_InvulnerableTicks;
+
} ;
diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp
index 2e05f1df1..6072b6ac6 100644
--- a/src/OSSupport/Errors.cpp
+++ b/src/OSSupport/Errors.cpp
@@ -22,7 +22,7 @@ AString GetOSErrorString( int a_ErrNo )
// According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
- #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
+ #if !defined(__APPLE__) && ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
if( res != NULL )
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 17070030f..7f0f0ad2f 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -152,7 +152,7 @@ int cFile::Read (void * iBuffer, int iNumBytes)
return -1;
}
- return fread(iBuffer, 1, iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count
+ return (int)fread(iBuffer, 1, (size_t)iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count
}
@@ -168,7 +168,7 @@ int cFile::Write(const void * iBuffer, int iNumBytes)
return -1;
}
- int res = fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
+ int res = (int)fwrite(iBuffer, 1, (size_t)iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
return res;
}
@@ -189,7 +189,7 @@ int cFile::Seek (int iPosition)
{
return -1;
}
- return ftell(m_File);
+ return (int)ftell(m_File);
}
@@ -206,7 +206,7 @@ int cFile::Tell (void) const
return -1;
}
- return ftell(m_File);
+ return (int)ftell(m_File);
}
@@ -222,7 +222,7 @@ int cFile::GetSize(void) const
return -1;
}
- int CurPos = ftell(m_File);
+ int CurPos = Tell();
if (CurPos < 0)
{
return -1;
@@ -231,8 +231,8 @@ int cFile::GetSize(void) const
{
return -1;
}
- int res = ftell(m_File);
- if (fseek(m_File, CurPos, SEEK_SET) != 0)
+ int res = Tell();
+ if (fseek(m_File, (long)CurPos, SEEK_SET) != 0)
{
return -1;
}
@@ -255,7 +255,7 @@ int cFile::ReadRestOfFile(AString & a_Contents)
int DataSize = GetSize() - Tell();
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
- a_Contents.assign(DataSize, '\0');
+ a_Contents.assign((size_t)DataSize, '\0');
return Read((void *)a_Contents.data(), DataSize);
}
@@ -350,7 +350,7 @@ int cFile::GetSize(const AString & a_FileName)
struct stat st;
if (stat(a_FileName.c_str(), &st) == 0)
{
- return st.st_size;
+ return (int)st.st_size;
}
return -1;
}
@@ -456,7 +456,7 @@ int cFile::Printf(const char * a_Fmt, ...)
va_start(args, a_Fmt);
AppendVPrintf(buf, a_Fmt, args);
va_end(args);
- return Write(buf.c_str(), buf.length());
+ return Write(buf.c_str(), (int)buf.length());
}
diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp
index b13e519e0..7a8433f4f 100644
--- a/src/OSSupport/GZipFile.cpp
+++ b/src/OSSupport/GZipFile.cpp
@@ -78,7 +78,7 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents)
while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0)
{
TotalBytes += NumBytesRead;
- a_Contents.append(Buffer, NumBytesRead);
+ a_Contents.append(Buffer, (size_t)NumBytesRead);
}
// NumBytesRead is < 0 on error
return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead;
@@ -102,7 +102,7 @@ bool cGZipFile::Write(const char * a_Contents, int a_Size)
return false;
}
- return (gzwrite(m_File, a_Contents, a_Size) != 0);
+ return (gzwrite(m_File, a_Contents, (unsigned int)a_Size) != 0);
}
diff --git a/src/OSSupport/ListenThread.h b/src/OSSupport/ListenThread.h
index 4e337d814..b2d806c82 100644
--- a/src/OSSupport/ListenThread.h
+++ b/src/OSSupport/ListenThread.h
@@ -29,43 +29,45 @@ class cListenThread :
typedef cIsThread super;
public:
- /// Used as the callback for connection events
+ /** Used as the callback for connection events */
class cCallback
{
public:
- /// This callback is called whenever a socket connection is accepted
+ virtual ~cCallback() {}
+
+ /** This callback is called whenever a socket connection is accepted */
virtual void OnConnectionAccepted(cSocket & a_Socket) = 0;
} ;
cListenThread(cCallback & a_Callback, cSocket::eFamily a_Family, const AString & a_ServiceName = "");
~cListenThread();
- /// Creates all the sockets, returns trus if successful, false if not.
+ /** Creates all the sockets, returns trus if successful, false if not. */
bool Initialize(const AString & a_PortsString);
bool Start(void);
void Stop(void);
- /// Call before Initialize() to set the "reuse" flag on the sockets
+ /** Call before Initialize() to set the "reuse" flag on the sockets */
void SetReuseAddr(bool a_Reuse = true);
protected:
typedef std::vector<cSocket> cSockets;
- /// The callback which to notify of incoming connections
+ /** The callback which to notify of incoming connections */
cCallback & m_Callback;
- /// Socket address family to use
+ /** Socket address family to use */
cSocket::eFamily m_Family;
- /// Sockets that are being monitored
+ /** Sockets that are being monitored */
cSockets m_Sockets;
- /// If set to true, the SO_REUSEADDR socket option is set to true
+ /** If set to true, the SO_REUSEADDR socket option is set to true */
bool m_ShouldReuseAddr;
- /// Name of the service that's listening on the ports; for logging purposes only
+ /** Name of the service that's listening on the ports; for logging purposes only */
AString m_ServiceName;
diff --git a/src/OSSupport/Sleep.h b/src/OSSupport/Sleep.h
index 5298c15da..0ec0adf9d 100644
--- a/src/OSSupport/Sleep.h
+++ b/src/OSSupport/Sleep.h
@@ -4,4 +4,4 @@ class cSleep
{
public:
static void MilliSleep( unsigned int a_MilliSeconds );
-}; \ No newline at end of file
+};
diff --git a/src/OSSupport/Thread.h b/src/OSSupport/Thread.h
index 3c9316424..4153b2427 100644
--- a/src/OSSupport/Thread.h
+++ b/src/OSSupport/Thread.h
@@ -23,4 +23,4 @@ private:
cEvent* m_StopEvent;
AString m_ThreadName;
-}; \ No newline at end of file
+};
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 69f4934d8..fe6280218 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -239,32 +239,11 @@ void cProtocol125::SendChat(const AString & a_Message)
void cProtocol125::SendChat(const cCompositeChat & a_Message)
{
// This version doesn't support composite messages, just extract each part's text and use it:
- AString Msg;
- const cCompositeChat::cParts & Parts = a_Message.GetParts();
- for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr)
- {
- switch ((*itr)->m_PartType)
- {
- case cCompositeChat::ptText:
- case cCompositeChat::ptClientTranslated:
- case cCompositeChat::ptRunCommand:
- case cCompositeChat::ptSuggestCommand:
- {
- Msg.append((*itr)->m_Text);
- break;
- }
- case cCompositeChat::ptUrl:
- {
- Msg.append(((cCompositeChat::cUrlPart *)(*itr))->m_Url);
- break;
- }
- } // switch (PartType)
- } // for itr - Parts[]
// Send the message:
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_CHAT);
- WriteString(Msg);
+ WriteString(a_Message.ExtractText());
Flush();
}
@@ -1972,6 +1951,14 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything
break;
}
+ case cMonster::mtWither:
+ {
+ WriteByte(0x54); // Int at index 20
+ WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
+ WriteByte(0x66); // Float at index 6
+ WriteFloat((float)(a_Mob.GetHealth()));
+ break;
+ }
case cMonster::mtSlime:
case cMonster::mtMagmaCube:
{
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 721ed349e..c678fc9a0 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -2535,6 +2535,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteByte(Frame.GetRotation());
break;
}
+ default: break;
}
}
@@ -2659,6 +2660,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0);
break;
}
+
+ case cMonster::mtWither:
+ {
+ WriteByte(0x54); // Int at index 20
+ WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
+ WriteByte(0x66); // Float at index 6
+ WriteFloat((float)(a_Mob.GetHealth()));
+ break;
+ }
case cMonster::mtSlime:
{
diff --git a/src/RCONServer.h b/src/RCONServer.h
index 0e89800a2..88aac4b5f 100644
--- a/src/RCONServer.h
+++ b/src/RCONServer.h
@@ -29,7 +29,7 @@ class cRCONServer :
{
public:
cRCONServer(cServer & a_Server);
- ~cRCONServer();
+ virtual ~cRCONServer();
void Initialize(cIniFile & a_IniFile);
diff --git a/src/Root.cpp b/src/Root.cpp
index 3555afb45..ba4398b35 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -304,6 +304,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile)
{
if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld")
{
+ IniFile.DeleteKeyComment("Worlds", 0);
IniFile.AddKeyComment("Worlds", " World=secondworld");
}
}
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 26712e6e6..470dfc791 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -6,6 +6,8 @@
#include "../BlockID.h"
#include "../Defines.h"
#include "../Chunk.h"
+#include "Root.h"
+#include "../Bindings/PluginManager.h"
@@ -315,9 +317,15 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int
*/
if (CanStartFireInBlock(a_Chunk, x, y, z))
{
- FLOG("FS: Starting new fire at {%d, %d, %d}.",
- x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width
- );
+ int a_PosX = x + a_Chunk->GetPosX() * cChunkDef::Width;
+ int a_PosZ = z + a_Chunk->GetPosZ() * cChunkDef::Width;
+
+ if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(&m_World, a_PosX, y, a_PosZ, ssFireSpread))
+ {
+ return;
+ }
+
+ FLOG("FS: Starting new fire at {%d, %d, %d}.", a_PosX, y, a_PosZ);
a_Chunk->UnboundedRelSetBlock(x, y, z, E_BLOCK_FIRE, 0);
}
} // for y
diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp
index 61c93ed73..7779573d7 100644
--- a/src/Simulator/FluidSimulator.cpp
+++ b/src/Simulator/FluidSimulator.cpp
@@ -36,6 +36,7 @@ bool cFluidSimulator::CanWashAway(BLOCKTYPE a_BlockType)
case E_BLOCK_COBWEB:
case E_BLOCK_CROPS:
case E_BLOCK_DEAD_BUSH:
+ case E_BLOCK_LILY_PAD:
case E_BLOCK_RAIL:
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp
index 5b9a3bb0a..2a85649a1 100644
--- a/src/StringCompression.cpp
+++ b/src/StringCompression.cpp
@@ -53,7 +53,7 @@ int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed
-int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed)
+int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed)
{
// Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2()
@@ -83,6 +83,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
{
// Some data has been compressed. Consume the buffer and continue compressing
a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
+ strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
if (strm.avail_in == 0)
{
@@ -116,7 +117,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
-extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed)
+extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
{
// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
@@ -139,13 +140,14 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U
for (;;)
{
- res = inflate(&strm, Z_FINISH);
+ res = inflate(&strm, Z_NO_FLUSH);
switch (res)
{
case Z_OK:
{
// Some data has been uncompressed. Consume the buffer and continue uncompressing
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
+ strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
if (strm.avail_in == 0)
{
diff --git a/src/StringCompression.h b/src/StringCompression.h
index 3f4e12d2d..c3a9eca91 100644
--- a/src/StringCompression.h
+++ b/src/StringCompression.h
@@ -16,10 +16,10 @@ extern int CompressString(const char * a_Data, int a_Length, AString & a_Compres
extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);
/// Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
-extern int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed);
+extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed);
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
-extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed);
+extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 4feff7553..da395e5b5 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -79,10 +79,10 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut
extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway
/// Decodes a Base64-encoded string into the raw data
-extern AString Base64Decode(const AString & a_Base64String);
+extern AString Base64Decode(const AString & a_Base64String); // Exported manually due to embedded NULs and extra parameter
/// Encodes a string into Base64
-extern AString Base64Encode(const AString & a_Input);
+extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter
/// Reads two bytes from the specified memory location and interprets them as BigEndian short
extern short GetBEShort(const char * a_Mem);
diff --git a/src/UI/WindowOwner.h b/src/UI/WindowOwner.h
index d41abf66d..e3c73edc4 100644
--- a/src/UI/WindowOwner.h
+++ b/src/UI/WindowOwner.h
@@ -33,6 +33,10 @@ public:
{
}
+ virtual ~cWindowOwner()
+ {
+ }
+
void CloseWindow(void)
{
m_Window = NULL;
diff --git a/src/Vector3.h b/src/Vector3.h
index ba4abe3eb..a00e14508 100644
--- a/src/Vector3.h
+++ b/src/Vector3.h
@@ -121,6 +121,13 @@ public:
z += a_Z;
}
+ inline void Move(const Vector3<T> & a_Diff)
+ {
+ x += a_Diff.x;
+ y += a_Diff.y;
+ z += a_Diff.z;
+ }
+
// tolua_end
inline void operator += (const Vector3<T> & a_Rhs)
diff --git a/src/World.cpp b/src/World.cpp
index 3f157157a..e39a605bb 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -60,9 +60,6 @@
-/// Up to this many m_SpreadQueue elements are handled each world tick
-const int MAX_LIGHTING_SPREAD_PER_TICK = 10;
-
const int TIME_SUNSET = 12000;
const int TIME_NIGHT_START = 13187;
const int TIME_NIGHT_END = 22812;
diff --git a/src/World.h b/src/World.h
index 46aece18f..b3ee94a27 100644
--- a/src/World.h
+++ b/src/World.h
@@ -497,16 +497,16 @@ public:
/** Does an explosion with the specified strength at the specified coordinate
a_SourceData exact type depends on the a_Source:
- | esOther | void * |
- | esPrimedTNT | cTNTEntity * |
- | esMonster | cMonster * |
- | esBed | cVector3i * |
- | esEnderCrystal | Vector3i * |
- | esGhastFireball | cGhastFireball * |
- | esWitherSkullBlack | TBD |
- | esWitherSkullBlue | TBD |
- | esWitherBirth | TBD |
- | esPlugin | void * |
+ | esOther | void * |
+ | esPrimedTNT | cTNTEntity * |
+ | esMonster | cMonster * |
+ | esBed | cVector3i * |
+ | esEnderCrystal | Vector3i * |
+ | esGhastFireball | cGhastFireball * |
+ | esWitherSkullBlack | TBD |
+ | esWitherSkullBlue | TBD |
+ | esWitherBirth | cMonster * |
+ | esPlugin | void * |
*/
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export // override, cannot specify due to tolua
@@ -646,9 +646,9 @@ public:
// Various queues length queries (cannot be const, they lock their CS):
inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export
- inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
- inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
- inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
+ inline size_t GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
+ inline size_t GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
+ inline size_t GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
void InitializeSpawn(void);
diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h
index 5b87bafdb..cbc544a14 100644
--- a/src/WorldStorage/FireworksSerializer.h
+++ b/src/WorldStorage/FireworksSerializer.h
@@ -89,4 +89,4 @@ public:
short m_FlightTimeInTicks;
std::vector<int> m_Colours;
std::vector<int> m_FadeColours;
-}; \ No newline at end of file
+};
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index a4a0aab57..df72d1cc9 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -141,7 +141,11 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
{
eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
- ASSERT(Dimension == m_Map->m_World->GetDimension());
+ if (Dimension != m_Map->m_World->GetDimension())
+ {
+ // TODO 2014-03-20 xdot: We should store nether maps in nether worlds, e.t.c.
+ return false;
+ }
}
CurrLine = a_NBT.FindChildByName(Data, "width");
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index acca96ba8..415693ae2 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -23,6 +23,7 @@
#include "../BlockEntities/FlowerPotEntity.h"
#include "../Entities/Entity.h"
+#include "../Entities/EnderCrystal.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
@@ -43,6 +44,7 @@
#include "../Mobs/Slime.h"
#include "../Mobs/Skeleton.h"
#include "../Mobs/Villager.h"
+#include "../Mobs/Wither.h"
#include "../Mobs/Wolf.h"
#include "../Mobs/Zombie.h"
@@ -335,6 +337,17 @@ void cNBTChunkSerializer::AddBoatEntity(cBoat * a_Boat)
+void cNBTChunkSerializer::AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_EnderCrystal, "EnderCrystal");
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
{
m_Writer.BeginCompound("");
@@ -422,7 +435,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
case cMonster::mtSquid: EntityClass = "Squid"; break;
case cMonster::mtVillager: EntityClass = "Villager"; break;
case cMonster::mtWitch: EntityClass = "Witch"; break;
- case cMonster::mtWither: EntityClass = "Wither"; break;
+ case cMonster::mtWither: EntityClass = "WitherBoss"; break;
case cMonster::mtWolf: EntityClass = "Wolf"; break;
case cMonster::mtZombie: EntityClass = "Zombie"; break;
case cMonster::mtZombiePigman: EntityClass = "PigZombie"; break;
@@ -501,6 +514,11 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
break;
}
+ case cMonster::mtWither:
+ {
+ m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks());
+ break;
+ }
case cMonster::mtWolf:
{
m_Writer.AddString("Owner", ((const cWolf *)a_Monster)->GetOwner());
@@ -729,6 +747,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
switch (a_Entity->GetEntityType())
{
case cEntity::etBoat: AddBoatEntity ((cBoat *) a_Entity); break;
+ case cEntity::etEnderCrystal: AddEnderCrystalEntity((cEnderCrystal *) a_Entity); break;
case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *) a_Entity); break;
case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break;
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index c1134cd00..51d104970 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -24,6 +24,7 @@ class cChestEntity;
class cCommandBlockEntity;
class cDispenserEntity;
class cDropperEntity;
+class cEnderCrystal;
class cFurnaceEntity;
class cHopperEntity;
class cJukeboxEntity;
@@ -106,6 +107,7 @@ protected:
// Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);
void AddBoatEntity (cBoat * a_Boat);
+ void AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal);
void AddFallingBlockEntity(cFallingBlock * a_FallingBlock);
void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster);
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index ef67fdb13..9d594a084 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -14,6 +14,39 @@
+#ifdef SELF_TEST
+
+static class cSchematicStringSelfTest
+{
+public:
+ cSchematicStringSelfTest(void)
+ {
+ cBlockArea ba;
+ ba.Create(21, 256, 21);
+ ba.RelLine(0, 0, 0, 9, 8, 7, cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_WOODEN_STAIRS, 1);
+ AString Schematic;
+ if (!cSchematicFileSerializer::SaveToSchematicString(ba, Schematic))
+ {
+ assert_test(!"Schematic failed to save!");
+ }
+ cBlockArea ba2;
+ if (!cSchematicFileSerializer::LoadFromSchematicString(ba2, Schematic))
+ {
+ assert_test(!"Schematic failed to load!");
+ }
+ }
+} g_SelfTest;
+
+#endif
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSchematicFileSerializer:
+
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
{
// Un-GZip the contents:
@@ -197,7 +230,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
// Copy the block types and metas:
- int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
+ int NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
{
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
@@ -209,7 +242,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
if (AreMetasPresent)
{
- int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
+ int NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
{
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
@@ -230,9 +263,9 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea)
{
cFastNBTWriter Writer("Schematic");
- Writer.AddShort("Width", a_BlockArea.m_SizeX);
- Writer.AddShort("Height", a_BlockArea.m_SizeY);
- Writer.AddShort("Length", a_BlockArea.m_SizeZ);
+ Writer.AddShort("Width", a_BlockArea.m_Size.x);
+ Writer.AddShort("Height", a_BlockArea.m_Size.y);
+ Writer.AddShort("Length", a_BlockArea.m_Size.z);
Writer.AddString("Materials", "Alpha");
if (a_BlockArea.HasBlockTypes())
{
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 7a2366755..48934d074 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -32,6 +32,7 @@
#include "../Mobs/IncludeAllMonsters.h"
#include "../Entities/Boat.h"
+#include "../Entities/EnderCrystal.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
@@ -1057,6 +1058,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadBoatFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "EnderCrystal", a_IDTagLength) == 0)
+ {
+ LoadEnderCrystalFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "FallingBlock", a_IDTagLength) == 0)
{
LoadFallingBlockFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1238,7 +1243,7 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadWitchFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
- else if (strncmp(a_IDTag, "Wither", a_IDTagLength) == 0)
+ else if (strncmp(a_IDTag, "WitherBoss", a_IDTagLength) == 0)
{
LoadWitherFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
@@ -1275,6 +1280,20 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
+void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0));
+ if (!LoadEntityBaseFromNBT(*EnderCrystal.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+ a_Entities.push_back(EnderCrystal.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID");
@@ -2250,6 +2269,12 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
return;
}
+ int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
+ if (CurrLine > 0)
+ {
+ Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine));
+ }
+
a_Entities.push_back(Monster.release());
}
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 50d0e555e..1773ee882 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -148,6 +148,7 @@ protected:
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);