summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules2
-rw-r--r--.travis.yml14
-rw-r--r--Android/jni/Android.mk24
-rwxr-xr-xCIbuild.sh11
-rw-r--r--CMakeLists.txt11
-rw-r--r--COMPILING.md41
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--CoverityModel.cpp17
-rw-r--r--LICENSE197
-rw-r--r--MCServer/.gitignore6
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua121
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua24
-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/UsingChunkStays.html167
-rw-r--r--MCServer/Plugins/APIDump/WebWorldThreads.html48
-rw-r--r--MCServer/Plugins/APIDump/main.css3
-rw-r--r--MCServer/Plugins/APIDump/main_APIDump.lua10
m---------MCServer/Plugins/Core0
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua36
-rw-r--r--MCServer/Plugins/InfoReg.lua12
-rw-r--r--MCServer/monsters.ini11
-rw-r--r--MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.cmd11
-rwxr-xr-xMCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh10
-rw-r--r--MakeLuaAPI.cmd2
-rw-r--r--README.md29
-rw-r--r--SetFlags.cmake90
-rw-r--r--Tools/MCADefrag/Globals.h15
-rw-r--r--Tools/ProtoProxy/CMakeLists.txt14
-rw-r--r--Tools/ProtoProxy/Connection.cpp52
-rw-r--r--Tools/ProtoProxy/Connection.h12
-rw-r--r--Tools/ProtoProxy/Globals.h20
-rw-r--r--Tools/ProtoProxy/ProtoProxy.txt2
-rw-r--r--Tools/ProtoProxy/Server.h6
-rw-r--r--lib/cmake-coverage/CodeCoverage.cmake160
-rw-r--r--lib/cmake-coverage/LICENSE23
-rw-r--r--lib/expat/CMakeLists.txt7
-rw-r--r--lib/inifile/CMakeLists.txt8
-rw-r--r--lib/inifile/iniFile.cpp11
-rw-r--r--lib/lua/CMakeLists.txt6
-rw-r--r--lib/luaexpat/CMakeLists.txt1
-rw-r--r--lib/md5/CMakeLists.txt1
-rw-r--r--lib/md5/md5.h2
m---------lib/polarssl0
-rw-r--r--lib/polarssl.cmake8
-rw-r--r--lib/sqlite/CMakeLists.txt4
-rw-r--r--lib/tolua++/CMakeLists.txt6
-rw-r--r--lib/tolua++/src/bin/container_lua.h1476
-rw-r--r--lib/tolua++/src/bin/function_lua.h285
-rw-r--r--lib/tolua++/src/bin/lua/container.lua20
-rw-r--r--lib/tolua++/src/bin/lua/function.lua4
-rw-r--r--lib/tolua++/src/bin/toluabind.c1166
-rw-r--r--lib/zlib/CMakeLists.txt1
-rw-r--r--src/Authenticator.cpp267
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/DeprecatedBindings.cpp363
-rw-r--r--src/Bindings/LuaChunkStay.cpp2
-rw-r--r--src/Bindings/LuaFunctions.h4
-rw-r--r--src/Bindings/LuaState.cpp1
-rw-r--r--src/Bindings/ManualBindings.cpp151
-rw-r--r--src/Bindings/ManualBindings.h2
-rw-r--r--src/Bindings/Plugin.h2
-rw-r--r--src/Bindings/PluginLua.cpp11
-rw-r--r--src/Bindings/PluginLua.h2
-rw-r--r--src/Bindings/PluginManager.cpp13
-rw-r--r--src/Bindings/PluginManager.h4
-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++.exebin200192 -> 200704 bytes
-rw-r--r--src/BiomeDef.cpp180
-rw-r--r--src/BiomeDef.h9
-rw-r--r--src/BlockArea.cpp550
-rw-r--r--src/BlockArea.h36
-rw-r--r--src/BlockEntities/BeaconEntity.cpp116
-rw-r--r--src/BlockEntities/BeaconEntity.h44
-rw-r--r--src/BlockEntities/BlockEntity.cpp2
-rw-r--r--src/BlockEntities/CMakeLists.txt1
-rw-r--r--src/BlockEntities/CommandBlockEntity.cpp5
-rw-r--r--src/BlockEntities/DispenserEntity.cpp9
-rw-r--r--src/BlockEntities/FurnaceEntity.cpp7
-rw-r--r--src/BlockEntities/HopperEntity.cpp11
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp2
-rw-r--r--src/BlockID.cpp7
-rw-r--r--src/BlockID.h4
-rw-r--r--src/BlockInfo.cpp14
-rw-r--r--src/BlockTracer.h3
-rw-r--r--src/Blocks/BlockAnvil.h27
-rw-r--r--src/Blocks/BlockBed.h13
-rw-r--r--src/Blocks/BlockBigFlower.h131
-rw-r--r--src/Blocks/BlockButton.h6
-rw-r--r--src/Blocks/BlockCauldron.h2
-rw-r--r--src/Blocks/BlockChest.h7
-rw-r--r--src/Blocks/BlockComparator.h6
-rw-r--r--src/Blocks/BlockCrops.h12
-rw-r--r--src/Blocks/BlockDirt.h18
-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/BlockEnchantmentTable.h37
-rw-r--r--src/Blocks/BlockEnderchest.h6
-rw-r--r--src/Blocks/BlockFarmland.h4
-rw-r--r--src/Blocks/BlockFenceGate.h6
-rw-r--r--src/Blocks/BlockFire.h41
-rw-r--r--src/Blocks/BlockFluid.h8
-rw-r--r--src/Blocks/BlockFurnace.h8
-rw-r--r--src/Blocks/BlockHandler.cpp15
-rw-r--r--src/Blocks/BlockHandler.h3
-rw-r--r--src/Blocks/BlockHopper.h21
-rw-r--r--src/Blocks/BlockLadder.h4
-rw-r--r--src/Blocks/BlockLeaves.h26
-rw-r--r--src/Blocks/BlockLever.h37
-rw-r--r--src/Blocks/BlockLilypad.h28
-rw-r--r--src/Blocks/BlockMobHead.h142
-rw-r--r--src/Blocks/BlockNetherWart.h15
-rw-r--r--src/Blocks/BlockPluginInterface.h6
-rw-r--r--src/Blocks/BlockPortal.h14
-rw-r--r--src/Blocks/BlockPumpkin.h6
-rw-r--r--src/Blocks/BlockRail.h138
-rw-r--r--src/Blocks/BlockRedstoneRepeater.h6
-rw-r--r--src/Blocks/BlockSign.h35
-rw-r--r--src/Blocks/BlockSlab.h61
-rw-r--r--src/Blocks/BlockStairs.h15
-rw-r--r--src/Blocks/BlockStems.h3
-rw-r--r--src/Blocks/BlockTallGrass.h24
-rw-r--r--src/Blocks/BlockTorch.h6
-rw-r--r--src/Blocks/BlockTrapdoor.h6
-rw-r--r--src/Blocks/BlockVine.h10
-rw-r--r--src/Blocks/CMakeLists.txt1
-rw-r--r--src/Blocks/MetaRotator.h (renamed from src/Blocks/MetaRotater.h)16
-rw-r--r--src/BoundingBox.cpp2
-rw-r--r--src/ByteBuffer.cpp39
-rw-r--r--src/ByteBuffer.h46
-rw-r--r--src/CMakeLists.txt42
-rw-r--r--src/Chunk.cpp149
-rw-r--r--src/Chunk.h44
-rw-r--r--src/ChunkData.cpp592
-rw-r--r--src/ChunkData.h125
-rw-r--r--src/ChunkDataCallback.h127
-rw-r--r--src/ChunkDef.h211
-rw-r--r--src/ChunkMap.cpp93
-rw-r--r--src/ChunkMap.h3
-rw-r--r--src/ChunkSender.h1
-rw-r--r--src/ChunkStay.cpp8
-rw-r--r--src/ChunkStay.h4
-rw-r--r--src/ClientHandle.cpp434
-rw-r--r--src/ClientHandle.h45
-rw-r--r--src/CompositeChat.cpp81
-rw-r--r--src/CompositeChat.h39
-rw-r--r--src/CraftingRecipes.cpp16
-rw-r--r--src/Crypto.cpp509
-rw-r--r--src/Crypto.h198
-rw-r--r--src/DeadlockDetect.cpp15
-rw-r--r--src/Defines.h20
-rw-r--r--src/Enchantments.cpp827
-rw-r--r--src/Enchantments.h81
-rw-r--r--src/Endianness.h31
-rw-r--r--src/Entities/ArrowEntity.cpp194
-rw-r--r--src/Entities/ArrowEntity.h96
-rw-r--r--src/Entities/Boat.cpp10
-rw-r--r--src/Entities/Boat.h2
-rw-r--r--src/Entities/CMakeLists.txt3
-rw-r--r--src/Entities/Effects.h2
-rw-r--r--src/Entities/Entity.cpp463
-rw-r--r--src/Entities/Entity.h152
-rw-r--r--src/Entities/ExpBottleEntity.cpp27
-rw-r--r--src/Entities/ExpBottleEntity.h33
-rw-r--r--src/Entities/ExpOrb.cpp2
-rw-r--r--src/Entities/ExpOrb.h2
-rw-r--r--src/Entities/FallingBlock.cpp8
-rw-r--r--src/Entities/FireChargeEntity.cpp50
-rw-r--r--src/Entities/FireChargeEntity.h36
-rw-r--r--src/Entities/FireworkEntity.cpp73
-rw-r--r--src/Entities/FireworkEntity.h40
-rw-r--r--src/Entities/Floater.h2
-rw-r--r--src/Entities/GhastFireballEntity.cpp44
-rw-r--r--src/Entities/GhastFireballEntity.h38
-rw-r--r--src/Entities/Minecart.cpp52
-rw-r--r--src/Entities/Minecart.h2
-rw-r--r--src/Entities/Pickup.cpp73
-rw-r--r--src/Entities/Pickup.h3
-rw-r--r--src/Entities/Player.cpp368
-rw-r--r--src/Entities/Player.h37
-rw-r--r--src/Entities/ProjectileEntity.cpp506
-rw-r--r--src/Entities/ProjectileEntity.h298
-rw-r--r--src/Entities/TNTEntity.cpp2
-rw-r--r--src/Entities/ThrownEggEntity.cpp59
-rw-r--r--src/Entities/ThrownEggEntity.h37
-rw-r--r--src/Entities/ThrownEnderPearlEntity.cpp54
-rw-r--r--src/Entities/ThrownEnderPearlEntity.h37
-rw-r--r--src/Entities/ThrownSnowballEntity.cpp48
-rw-r--r--src/Entities/ThrownSnowballEntity.h34
-rw-r--r--src/FastRandom.cpp13
-rw-r--r--src/FastRandom.h3
-rw-r--r--src/FurnaceRecipe.cpp1
-rw-r--r--src/Generating/BioGen.cpp2
-rw-r--r--src/Generating/CMakeLists.txt1
-rw-r--r--src/Generating/Caves.cpp283
-rw-r--r--src/Generating/Caves.h22
-rw-r--r--src/Generating/ComposableGenerator.cpp28
-rw-r--r--src/Generating/GridStructGen.cpp168
-rw-r--r--src/Generating/GridStructGen.h124
-rw-r--r--src/Generating/MineShafts.cpp167
-rw-r--r--src/Generating/MineShafts.h34
-rw-r--r--src/Generating/NetherFortGen.cpp131
-rw-r--r--src/Generating/NetherFortGen.h45
-rw-r--r--src/Generating/POCPieceGenerator.cpp5
-rw-r--r--src/Generating/PieceGenerator.cpp124
-rw-r--r--src/Generating/PieceGenerator.h69
-rw-r--r--src/Generating/Prefab.cpp310
-rw-r--r--src/Generating/Prefab.h119
-rw-r--r--src/Generating/PrefabPiecePool.cpp158
-rw-r--r--src/Generating/PrefabPiecePool.h85
-rw-r--r--src/Generating/Prefabs/AlchemistVillagePrefabs.cpp3184
-rw-r--r--src/Generating/Prefabs/AlchemistVillagePrefabs.h15
-rw-r--r--src/Generating/Prefabs/CMakeLists.txt14
-rw-r--r--src/Generating/Prefabs/JapaneseVillagePrefabs.cpp3200
-rw-r--r--src/Generating/Prefabs/JapaneseVillagePrefabs.h15
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.cpp5495
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.h15
-rw-r--r--src/Generating/Prefabs/PlainsVillagePrefabs.cpp6114
-rw-r--r--src/Generating/Prefabs/PlainsVillagePrefabs.h15
-rw-r--r--src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp1558
-rw-r--r--src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h15
-rw-r--r--src/Generating/Prefabs/SandVillagePrefabs.cpp2133
-rw-r--r--src/Generating/Prefabs/SandVillagePrefabs.h15
-rw-r--r--src/Generating/Ravines.cpp226
-rw-r--r--src/Generating/Ravines.h24
-rw-r--r--src/Generating/StructGen.cpp28
-rw-r--r--src/Generating/Trees.cpp36
-rw-r--r--src/Generating/VillageGen.cpp430
-rw-r--r--src/Generating/VillageGen.h57
-rw-r--r--src/Globals.h91
-rw-r--r--src/Group.cpp6
-rw-r--r--src/Group.h8
-rw-r--r--src/GroupManager.cpp55
-rw-r--r--src/GroupManager.h4
-rw-r--r--src/HTTPServer/CMakeLists.txt1
-rw-r--r--src/HTTPServer/EnvelopeParser.cpp4
-rw-r--r--src/HTTPServer/EnvelopeParser.h30
-rw-r--r--src/HTTPServer/HTTPConnection.cpp27
-rw-r--r--src/HTTPServer/HTTPConnection.h16
-rw-r--r--src/HTTPServer/HTTPFormParser.cpp6
-rw-r--r--src/HTTPServer/HTTPFormParser.h11
-rw-r--r--src/HTTPServer/HTTPMessage.cpp30
-rw-r--r--src/HTTPServer/HTTPMessage.h18
-rw-r--r--src/HTTPServer/HTTPServer.cpp52
-rw-r--r--src/HTTPServer/HTTPServer.h20
-rw-r--r--src/HTTPServer/MultipartParser.cpp8
-rw-r--r--src/HTTPServer/MultipartParser.h39
-rw-r--r--src/HTTPServer/NameValueParser.cpp10
-rw-r--r--src/HTTPServer/NameValueParser.h4
-rw-r--r--src/HTTPServer/SslHTTPConnection.cpp107
-rw-r--r--src/HTTPServer/SslHTTPConnection.h45
-rw-r--r--src/Inventory.cpp11
-rw-r--r--src/Inventory.h41
-rw-r--r--src/Item.cpp160
-rw-r--r--src/Item.h39
-rw-r--r--src/Items/CMakeLists.txt7
-rw-r--r--src/Items/ItemArmor.h110
-rw-r--r--src/Items/ItemBoat.h26
-rw-r--r--src/Items/ItemBow.h2
-rw-r--r--src/Items/ItemBucket.h8
-rw-r--r--src/Items/ItemEmptyMap.h2
-rw-r--r--src/Items/ItemFishingRod.h10
-rw-r--r--src/Items/ItemHandler.cpp45
-rw-r--r--src/Items/ItemHandler.h37
-rw-r--r--src/Items/ItemLilypad.h108
-rw-r--r--src/Items/ItemMap.h2
-rw-r--r--src/Items/ItemMinecart.h8
-rw-r--r--src/Items/ItemPickaxe.h14
-rw-r--r--src/Items/ItemShovel.h14
-rw-r--r--src/Items/ItemSpawnEgg.h40
-rw-r--r--src/Items/ItemSword.h13
-rw-r--r--src/Items/ItemThrowable.h17
-rw-r--r--src/LightingThread.cpp14
-rw-r--r--src/LightingThread.h8
-rw-r--r--src/LineBlockTracer.cpp1
-rw-r--r--src/MCLogger.cpp37
-rw-r--r--src/MCLogger.h34
-rw-r--r--src/Map.cpp2
-rw-r--r--src/Map.h2
-rw-r--r--src/MapManager.cpp6
-rw-r--r--src/MapManager.h2
-rw-r--r--src/MobCensus.cpp2
-rw-r--r--src/MobFamilyCollecter.cpp2
-rw-r--r--src/MobProximityCounter.cpp8
-rw-r--r--src/MobProximityCounter.h4
-rw-r--r--src/MobSpawner.cpp23
-rw-r--r--src/Mobs/AggressiveMonster.cpp16
-rw-r--r--src/Mobs/AggressiveMonster.h4
-rw-r--r--src/Mobs/Blaze.cpp3
-rw-r--r--src/Mobs/Blaze.h4
-rw-r--r--src/Mobs/CMakeLists.txt1
-rw-r--r--src/Mobs/CaveSpider.cpp (renamed from src/Mobs/Cavespider.cpp)11
-rw-r--r--src/Mobs/CaveSpider.h (renamed from src/Mobs/Cavespider.h)5
-rw-r--r--src/Mobs/Creeper.cpp8
-rw-r--r--src/Mobs/Creeper.h2
-rw-r--r--src/Mobs/Ghast.cpp1
-rw-r--r--src/Mobs/IncludeAllMonsters.h6
-rw-r--r--src/Mobs/MagmaCube.cpp (renamed from src/Mobs/Magmacube.cpp)3
-rw-r--r--src/Mobs/MagmaCube.h (renamed from src/Mobs/Magmacube.h)1
-rw-r--r--src/Mobs/Monster.cpp100
-rw-r--r--src/Mobs/Monster.h9
-rw-r--r--src/Mobs/PassiveAggressiveMonster.cpp8
-rw-r--r--src/Mobs/PassiveAggressiveMonster.h2
-rw-r--r--src/Mobs/PassiveMonster.cpp8
-rw-r--r--src/Mobs/PassiveMonster.h2
-rw-r--r--src/Mobs/Sheep.cpp9
-rw-r--r--src/Mobs/Skeleton.cpp3
-rw-r--r--src/Mobs/Villager.cpp11
-rw-r--r--src/Mobs/Villager.h2
-rw-r--r--src/Mobs/Wither.cpp78
-rw-r--r--src/Mobs/Wither.h13
-rw-r--r--src/Mobs/Wolf.cpp13
-rw-r--r--src/Mobs/Wolf.h4
-rw-r--r--src/Mobs/ZombiePigman.cpp (renamed from src/Mobs/Zombiepigman.cpp)3
-rw-r--r--src/Mobs/ZombiePigman.h (renamed from src/Mobs/Zombiepigman.h)1
-rw-r--r--src/MonsterConfig.cpp3
-rw-r--r--src/Noise.cpp30
-rw-r--r--src/Noise.h8
-rw-r--r--src/OSSupport/BlockingTCPLink.cpp142
-rw-r--r--src/OSSupport/BlockingTCPLink.h28
-rw-r--r--src/OSSupport/CMakeLists.txt1
-rw-r--r--src/OSSupport/Errors.cpp2
-rw-r--r--src/OSSupport/File.cpp38
-rw-r--r--src/OSSupport/File.h4
-rw-r--r--src/OSSupport/GZipFile.cpp6
-rw-r--r--src/OSSupport/IsThread.cpp31
-rw-r--r--src/OSSupport/IsThread.h2
-rw-r--r--src/OSSupport/ListenThread.cpp2
-rw-r--r--src/OSSupport/Sleep.h2
-rw-r--r--src/OSSupport/Socket.cpp18
-rw-r--r--src/OSSupport/Socket.h4
-rw-r--r--src/OSSupport/SocketThreads.cpp2
-rw-r--r--src/OSSupport/SocketThreads.h6
-rw-r--r--src/OSSupport/Thread.cpp23
-rw-r--r--src/OSSupport/Thread.h2
-rw-r--r--src/PolarSSL++/AesCfb128Decryptor.cpp67
-rw-r--r--src/PolarSSL++/AesCfb128Decryptor.h52
-rw-r--r--src/PolarSSL++/AesCfb128Encryptor.cpp68
-rw-r--r--src/PolarSSL++/AesCfb128Encryptor.h50
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.cpp195
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.h80
-rw-r--r--src/PolarSSL++/BufferedSslContext.cpp93
-rw-r--r--src/PolarSSL++/BufferedSslContext.h52
-rw-r--r--src/PolarSSL++/CMakeLists.txt40
-rw-r--r--src/PolarSSL++/CallbackSslContext.cpp59
-rw-r--r--src/PolarSSL++/CallbackSslContext.h64
-rw-r--r--src/PolarSSL++/CryptoKey.cpp149
-rw-r--r--src/PolarSSL++/CryptoKey.h76
-rw-r--r--src/PolarSSL++/CtrDrbgContext.cpp49
-rw-r--r--src/PolarSSL++/CtrDrbgContext.h63
-rw-r--r--src/PolarSSL++/EntropyContext.cpp29
-rw-r--r--src/PolarSSL++/EntropyContext.h31
-rw-r--r--src/PolarSSL++/RsaPrivateKey.cpp176
-rw-r--r--src/PolarSSL++/RsaPrivateKey.h67
-rw-r--r--src/PolarSSL++/Sha1Checksum.cpp138
-rw-r--r--src/PolarSSL++/Sha1Checksum.h52
-rw-r--r--src/PolarSSL++/SslContext.cpp303
-rw-r--r--src/PolarSSL++/SslContext.h156
-rw-r--r--src/PolarSSL++/X509Cert.cpp38
-rw-r--r--src/PolarSSL++/X509Cert.h41
-rw-r--r--src/ProbabDistrib.cpp2
-rw-r--r--src/Protocol/Authenticator.cpp309
-rw-r--r--src/Protocol/Authenticator.h (renamed from src/Authenticator.h)36
-rw-r--r--src/Protocol/CMakeLists.txt1
-rw-r--r--src/Protocol/ChunkDataSerializer.cpp4
-rw-r--r--src/Protocol/Protocol.h34
-rw-r--r--src/Protocol/Protocol125.cpp286
-rw-r--r--src/Protocol/Protocol125.h26
-rw-r--r--src/Protocol/Protocol132.cpp105
-rw-r--r--src/Protocol/Protocol132.h9
-rw-r--r--src/Protocol/Protocol14x.cpp18
-rw-r--r--src/Protocol/Protocol16x.cpp55
-rw-r--r--src/Protocol/Protocol16x.h2
-rw-r--r--src/Protocol/Protocol17x.cpp469
-rw-r--r--src/Protocol/Protocol17x.h39
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp60
-rw-r--r--src/Protocol/ProtocolRecognizer.h11
-rw-r--r--src/RCONServer.cpp11
-rw-r--r--src/RCONServer.h2
-rw-r--r--src/Root.cpp19
-rw-r--r--src/Root.h4
-rw-r--r--src/Scoreboard.cpp6
-rw-r--r--src/Scoreboard.h6
-rw-r--r--src/Server.cpp43
-rw-r--r--src/Server.h12
-rw-r--r--src/Simulator/CMakeLists.txt1
-rw-r--r--src/Simulator/DelayedFluidSimulator.cpp2
-rw-r--r--src/Simulator/FireSimulator.cpp12
-rw-r--r--src/Simulator/FloodyFluidSimulator.cpp4
-rw-r--r--src/Simulator/FloodyFluidSimulator.h13
-rw-r--r--src/Simulator/FluidSimulator.cpp3
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp1250
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.h91
-rw-r--r--src/Simulator/SandSimulator.cpp6
-rw-r--r--src/Simulator/VanillaFluidSimulator.cpp10
-rw-r--r--src/Simulator/VanillaFluidSimulator.h2
-rw-r--r--src/StackWalker.cpp3
-rw-r--r--src/Statistics.cpp196
-rw-r--r--src/Statistics.h164
-rw-r--r--src/StringCompression.cpp22
-rw-r--r--src/StringCompression.h8
-rw-r--r--src/StringUtils.cpp46
-rw-r--r--src/StringUtils.h13
-rw-r--r--src/Tracer.cpp6
-rw-r--r--src/UI/CMakeLists.txt1
-rw-r--r--src/UI/SlotArea.cpp839
-rw-r--r--src/UI/SlotArea.h83
-rw-r--r--src/UI/Window.cpp107
-rw-r--r--src/UI/Window.h61
-rw-r--r--src/Vector3.h52
-rw-r--r--src/WebAdmin.cpp16
-rw-r--r--src/WebAdmin.h10
-rw-r--r--src/World.cpp120
-rw-r--r--src/World.h35
-rw-r--r--src/WorldStorage/CMakeLists.txt1
-rw-r--r--src/WorldStorage/FastNBT.cpp46
-rw-r--r--src/WorldStorage/FastNBT.h78
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp10
-rw-r--r--src/WorldStorage/FireworksSerializer.h4
-rw-r--r--src/WorldStorage/MapSerializer.cpp8
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp100
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h4
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp43
-rw-r--r--src/WorldStorage/StatSerializer.cpp146
-rw-r--r--src/WorldStorage/StatSerializer.h55
-rw-r--r--src/WorldStorage/WSSAnvil.cpp81
-rw-r--r--src/WorldStorage/WSSAnvil.h4
-rw-r--r--src/WorldStorage/WSSCompact.cpp47
-rw-r--r--src/WorldStorage/WSSCompact.h7
-rw-r--r--src/WorldStorage/WorldStorage.cpp3
-rw-r--r--src/main.cpp4
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/ChunkData/ArraytoCoord.cpp89
-rw-r--r--tests/ChunkData/CMakeLists.txt29
-rw-r--r--tests/ChunkData/Coordinates.cpp143
-rw-r--r--tests/ChunkData/Copies.cpp134
-rw-r--r--tests/ChunkData/CopyBlocks.cpp76
-rw-r--r--tests/ChunkData/creatable.cpp9
-rwxr-xr-xuploadCoverage.sh9
443 files changed, 40874 insertions, 7695 deletions
diff --git a/.gitignore b/.gitignore
index c544f394d..859ef28ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@ world_nether
CMakeFiles/
cmake_install.cmake
CMakeCache.txt
+CTestTestfile.cmake
Makefile
*.a
diff --git a/.gitmodules b/.gitmodules
index 2c7ec209b..2aaee3624 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -9,4 +9,4 @@
url = https://github.com/bearbin/transapi.git
[submodule "lib/polarssl"]
path = lib/polarssl
- url = https://github.com/polarssl/polarssl
+ url = https://github.com/mc-server/polarssl
diff --git a/.travis.yml b/.travis.yml
index 0ab25ae3b..5260cfd17 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,8 +2,15 @@ language: cpp
compiler:
- gcc
- clang
+
+before_install:
+ - if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]; then sudo pip install cpp_coveralls; fi
+
# Build MCServer
-script: cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | $MCSERVER_PATH)
+script: ./CIbuild.sh
+
+after_success:
+ - ./uploadCoverage.sh
env:
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
@@ -11,6 +18,11 @@ env:
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer_debug
+matrix:
+ include:
+ - compiler: gcc
+ env: TRAVIS_MCSERVER_BUILD_TYPE=COVERAGE MCSERVER_PATH=./MCServer
+
# Notification Settings
notifications:
email:
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/CIbuild.sh b/CIbuild.sh
new file mode 100755
index 000000000..683c1fc74
--- /dev/null
+++ b/CIbuild.sh
@@ -0,0 +1,11 @@
+ #!/usr/bin/env bash
+
+set -e
+
+cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1;
+make -j 2;
+make -j 2 test;
+cd MCServer/;
+if [ "$TRAVIS_MCSERVER_BUILD_TYPE" != "COVERAGE" ]
+ then echo stop | $MCSERVER_PATH;
+fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9a860920c..56dea1a34 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.2)
# Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html )
enable_language(CXX C)
@@ -14,6 +14,10 @@ if(DEFINED ENV{TRAVIS_MCSERVER_FORCE32})
set(FORCE32 $ENV{TRAVIS_MCSERVER_FORCE32})
endif()
+if(DEFINED ENV{TRAVIS_BUILD_WITH_COVERAGE})
+ set(BUILD_WITH_COVERAGE $ENV{TRAVIS_BUILD_WITH_COVERAGE})
+endif()
+
# This has to be done before any flags have been set up.
if(${BUILD_TOOLS})
add_subdirectory(Tools/MCADefrag/)
@@ -69,3 +73,8 @@ set_exe_flags()
add_subdirectory (src)
+if(${SELF_TEST})
+ enable_testing()
+ add_subdirectory (tests)
+endif()
+
diff --git a/COMPILING.md b/COMPILING.md
index 139f1a0ee..ea6b580d5 100644
--- a/COMPILING.md
+++ b/COMPILING.md
@@ -45,7 +45,30 @@ It is possible to use an external profiler to learn more about how the code perf
There's a script file, `MCServer/profile_run.cmd` that encapsulates most of the profiling work, have a look at the comments at the top of that script for details on how to get it to work. You'll need to change to a profiled configuration (both debug and release can be profiled).
-## Linux, MacOS, FreeBSD etc. ##
+## OSX ##
+Install git from its [website](http://git-scm.com) or homebrew: `brew install git`.
+
+Install Xcode (commandline tools are recommended) from the App Store or https://developer.apple.com/downloads.
+
+Install CMake from its [website](http://cmake.org) or homebrew: `brew install cmake`.
+
+### Getting the sources ###
+```
+mkdir MCServer
+cd MCServer
+git clone https://github.com/mc-server/MCServer.git .
+git submodule init
+git submodule update
+```
+
+### Building ###
+
+Follow the instructions at [CMake on Unix-based platforms](#cmake-on-unix-based-platforms), using Xcode as cmake's generator. If no generator is specified, CMake will use the Makefile generator, in which case you must build with the `make` command.
+
+After doing so, run the command `xcodebuild lib/polarssl/POLARSSL.xcodeproj` in the build directory, in order to build polarssl, a library that is required by MCServer. Lastly, run the command `xcodebuild` to build MCServer. Optionally, you may open the project files for polarssl and then MCServer in Xcode and build there.
+
+
+## Linux, FreeBSD etc. ##
Install git, cmake and gcc or clang, using your platform's package manager:
```
@@ -61,6 +84,14 @@ git submodule init
git submodule update
```
+### Building ###
+
+Follow the instructions at [CMake on Unix-based platforms](#cmake-on-unix-based-platforms).
+
+After doing so, run the command `make` in the build directory, and MCServer will build.
+
+## CMake on Unix-based platforms ###
+
### Release Mode ###
Release mode is preferred for almost all cases, it has much better speed and less console spam. However, if you are developing MCServer actively, debug mode might be better.
@@ -69,8 +100,10 @@ Assuming you are in the MCServer folder created in the initial setup step, you n
```
mkdir Release
cd Release
-cmake -DCMAKE_BUILD_TYPE=RELEASE .. && make
+cmake -DCMAKE_BUILD_TYPE=RELEASE ..
```
+NOTE: CMake can generate project files for many different programs, such as Xcode, eclipse, and ninja. To use a different generator, first type `cmake --help`, and at the end, cmake will output the different generators that are available. To specify one, add `-G` followed by the name of the generator, in the `cmake` command. Note that the name is case-sensitive.
+
The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer`.
### Debug Mode ###
@@ -81,8 +114,10 @@ Assuming you are in the MCServer folder created in the Getting the sources step,
```
mkdir Debug
cd Debug
-cmake -DCMAKE_BUILD_TYPE=DEBUG .. && make
+cmake -DCMAKE_BUILD_TYPE=DEBUG ..
```
+NOTE: CMake can generate project files for many different programs, such as Xcode, eclipse, and ninja. To use a different generator, first type `cmake --help`, and at the end, cmake will output the different generators that are available. To specify one, add `-G` followed by the name of the generator, in the `cmake` command. Note that the name is case-sensitive.
+
The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer_debug`.
### 32 Bit Mode switch ###
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0c36be8b7..03481ec48 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -27,7 +27,7 @@ Code Stuff
- The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form.
- These two rules really mean that indent is governed by braces
* Add an empty last line in all source files (GCC and GIT can complain otherwise)
- * Use doxy-comments for functions in the header file, format as `/** Description */`
+ * All new public functions in all classes need documenting comments on what they do and what behavior they follow, use doxy-comments formatted as `/** Description */`. Do not use asterisks on additional lines in multi-line comments.
* Use spaces after the comment markers: `// Comment` instead of `//Comment`
diff --git a/CoverityModel.cpp b/CoverityModel.cpp
new file mode 100644
index 000000000..3ee6447ee
--- /dev/null
+++ b/CoverityModel.cpp
@@ -0,0 +1,17 @@
+
+
+extern "C" {
+ struct lua_State;
+ struct tolua_Error
+ {
+ int index;
+ int array;
+ const char* type;
+ };
+
+ void tolua_error (lua_State* L, const char* msg, tolua_Error* err)
+ {
+ __coverity_panic__();
+ }
+
+}
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 69826ef06..6da9aa7c7 100644
--- a/MCServer/.gitignore
+++ b/MCServer/.gitignore
@@ -28,3 +28,9 @@ motd.txt
*.deuser
*.dmp
*.xml
+mcserver_api.lua
+
+# Ignore the webadmin certs / privkey, so that no-one commits theirs by accident:
+webadmin/httpscert.crt
+webadmin/httpskey.pem
+
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 01f000182..1423d64bc 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
@@ -502,7 +551,22 @@ end
{{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p>
<p>
Note that most of the functions in this class are so-called modifiers - they modify the object and
- then return the object itself, so that they can be chained one after another.
+ then return the object itself, so that they can be chained one after another. See the Chaining
+ example below for details.</p>
+ <p>
+ Each part of the composite chat message takes a "Style" parameter, this is a string that describes
+ the formatting. It uses the following strings, concatenated together:
+ <table>
+ <tr><th>String</th><th>Style</th></tr>
+ <tr><td>b</td><td>Bold text</td></tr>
+ <tr><td>i</td><td>Italic text</td></tr>
+ <tr><td>u</td><td>Underlined text</td></tr>
+ <tr><td>s</td><td>Strikethrough text</td></tr>
+ <tr><td>o</td><td>Obfuscated text</td></tr>
+ <tr><td>@X</td><td>color X (X is 0 - 9 or a - f, same as dye meta</td></tr>
+ </table>
+ The following picture, taken from MineCraft Wiki, illustrates the color codes:</p>
+ <img src="http://hydra-media.cursecdn.com/minecraft.gamepedia.com/4/4c/Colors.png?version=34a0f56789a95326e1f7d82047b12232" />
]],
Functions =
{
@@ -516,6 +580,7 @@ end
AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." },
AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." },
Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" },
+ ExtractText = { Params = "", Return = "string", Notes = "Returns the text from the parts that comprises the human-readable data. Used for older protocols that don't support composite chat and for console-logging." },
GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" },
ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." },
SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." },
@@ -634,7 +699,7 @@ end</pre>
GetLevel = { Params = "EnchantmentNumID", Return = "number", Notes = "Returns the level of the specified enchantment stored in this object; 0 if not stored" },
IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if the object stores no enchantments" },
SetLevel = { Params = "EnchantmentNumID, Level", Return = "", Notes = "Sets the level for the specified enchantment, adding it if not stored before or removing it if level < = 0" },
- StringToEnchantmentID = { Params = "EnchantmentTextID", Return = "number", Notes = "(static) Returns the enchantment numerical ID, -1 if not understood. Case insensitive" },
+ StringToEnchantmentID = { Params = "EnchantmentTextID", Return = "number", Notes = "(static) Returns the enchantment numerical ID, -1 if not understood. Case insensitive. Also understands plain numbers." },
ToString = { Params = "", Return = "string", Notes = "Returns the string description of all the enchantments stored in this object, in numerical-ID form" },
},
Constants =
@@ -728,14 +793,14 @@ end</pre>
GetMass = { Params = "", Return = "number", Notes = "Returns the mass of the entity. Currently unused." },
GetMaxHealth = { Params = "", Return = "number", Notes = "Returns the maximum number of hitpoints this entity is allowed to have." },
GetParentClass = { Params = "", Return = "string", Notes = "Returns the name of the direct parent class for this entity" },
- GetPitch = { Params = "", Return = "number", Notes = "Returns the pitch (nose-down rotation) of the entity" },
+ GetPitch = { Params = "", Return = "number", Notes = "Returns the pitch (nose-down rotation) of the entity. Measured in degrees, normal values range from -90 to +90. +90 means looking down, 0 means looking straight ahead, -90 means looking up." },
GetPosition = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the entity's pivot position as a 3D vector" },
GetPosX = { Params = "", Return = "number", Notes = "Returns the X-coord of the entity's pivot" },
GetPosY = { Params = "", Return = "number", Notes = "Returns the Y-coord of the entity's pivot" },
GetPosZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the entity's pivot" },
GetRawDamageAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the raw damage that this entity's equipment would cause when attacking the ReceiverEntity. This includes this entity's weapon {{cEnchantments|enchantments}}, but excludes the receiver's armor or potion effects. See {{TakeDamageInfo}} for more information on attack damage." },
GetRoll = { Params = "", Return = "number", Notes = "Returns the roll (sideways rotation) of the entity. Currently unused." },
- GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the entire rotation vector (Yaw, Pitch, Roll)" },
+ GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "(OBSOLETE) Returns the entire rotation vector (Yaw, Pitch, Roll)" },
GetSpeed = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the complete speed vector of the entity" },
GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" },
GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" },
@@ -743,7 +808,7 @@ end</pre>
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity within the running server. Note that this ID is not persisted to the data files." },
GetWidth = { Params = "", Return = "number", Notes = "Returns the width (X and Z size) of the entity." },
GetWorld = { Params = "", Return = "{{cWorld}}", Notes = "Returns the world where the entity resides" },
- GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity." },
+ GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. Measured in degrees, values range from -180 to +180. 0 means ZP, 90 means XM, -180 means ZM, -90 means XP." },
Heal = { Params = "Hitpoints", Return = "", Notes = "Heals the specified number of hitpoints. Hitpoints is expected to be a positive number." },
IsA = { Params = "ClassName", Return = "bool", Notes = "Returns true if the entity class is a descendant of the specified class name, or the specified class itself" },
IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." },
@@ -2151,7 +2216,7 @@ end
CastThunderbolt = { Params = "X, Y, Z", Return = "", Notes = "Creates a thunderbolt at the specified coords" },
ChangeWeather = { Params = "", Return = "", Notes = "Forces the weather to change in the next game tick. Weather is changed according to the normal rules: wSunny <-> wRain <-> wStorm" },
ChunkStay = { Params = "ChunkCoordTable, OnChunkAvailable, OnAllChunksAvailable", Return = "", Notes = "Queues the specified chunks to be loaded or generated and calls the specified callbacks once they are loaded. ChunkCoordTable is an arra-table of chunk coords, each coord being a table of 2 numbers: { {Chunk1x, Chunk1z}, {Chunk2x, Chunk2z}, ...}. When any of those chunks are made available (including being available at the start of this call), the OnChunkAvailable() callback is called. When all the chunks are available, the OnAllChunksAvailable() callback is called. The function signatures are: <pre class=\"prettyprint lang-lua\">function OnChunkAvailable(ChunkX, ChunkZ)\nfunction OnAllChunksAvailable()</pre> All return values from the callbacks are ignored." },
- CreateProjectile = { Params = "X, Y, Z, {{cProjectileEntity|ProjectileKind}}, {{cEntity|Creator}}, [{{Vector3d|Speed}}]", Return = "", Notes = "Creates a new projectile of the specified kind at the specified coords. The projectile's creator is set to Creator (may be nil). Optional speed indicates the initial speed for the projectile." },
+ CreateProjectile = { Params = "X, Y, Z, {{cProjectileEntity|ProjectileKind}}, {{cEntity|Creator}}, {{cItem|Originating Item}}, [{{Vector3d|Speed}}]", Return = "", Notes = "Creates a new projectile of the specified kind at the specified coords. The projectile's creator is set to Creator (may be nil). The item that created the projectile entity, commonly the {{cPlayer|player}}'s currently equipped item, is used at present for fireworks to correctly set their entity metadata. It is not used for any other projectile. Optional speed indicates the initial speed for the projectile." },
DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." },
DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." },
DoWithBlockEntityAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
@@ -2647,11 +2712,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." },
@@ -2844,8 +2929,10 @@ 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 = "WebWorldThreads.html", Title = "Webserver vs World threads" },
+ { FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" },
+ { FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" },
+ { FileName = "UsingChunkStays.html", Title = "Using ChunkStays" },
+ { FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
}
} ;
diff --git a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua
index a3301a8c6..204cb63d2 100644
--- a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua
+++ b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua
@@ -2,23 +2,33 @@ return
{
HOOK_DISCONNECT =
{
- CalledWhen = "A player has explicitly disconnected.",
+ CalledWhen = [[
+ A client has disconnected, either by explicitly sending the disconnect packet (in older protocols) or
+ their connection was terminated
+ ]],
DefaultFnName = "OnDisconnect", -- also used as pagename
Desc = [[
- This hook is called when a client is about to be disconnected from the server, for whatever reason.
-
- <p><b>Note that this hook will be removed after <1.7 protocol support is removed, as it was originally a hook for
- the client sending the server a disconnect packet, which no longer happens.</b></p>
+ This hook is called when a client has disconnected from the server, for whatever reason. It is also
+ called when the client sends the Disconnect packet (only in pre-1.7 protocols). This hook is not called
+ for server ping connections.</p>
+ <p>
+ Note that the hook is called even for connections to players who failed to auth. In such a case there's
+ no {{cPlayer}} object associated with the client.</p>
+ <p>
+ See also the {{OnHandshake|HOOK_HANDSHAKE}} hook which is called when the client connects (and presents
+ a handshake message, so that they are not just status-pinging). If you need to store a per-player
+ object, use the {{OnPlayerJoined|HOOK_PLAYER_JOINED}} and {{OnPlayerDestroyed|HOOK_PLAYER_DESTROYED}}
+ hooks instead, those are guaranteed to have the {{cPlayer}} object associated.
]],
Params =
{
- { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has disconnected" },
+ { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client who has disconnected" },
{ Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" },
},
Returns = [[
If the function returns false or no value, MCServer calls other plugins' callbacks for this event.
If the function returns true, no other plugins are called for this event. In either case,
- the player is disconnected.
+ the client is disconnected.
]],
}, -- HOOK_DISCONNECT
}
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/UsingChunkStays.html b/MCServer/Plugins/APIDump/UsingChunkStays.html
new file mode 100644
index 000000000..d3ecc6674
--- /dev/null
+++ b/MCServer/Plugins/APIDump/UsingChunkStays.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>MCServer - Using ChunkStays</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>Using ChunkStays</h1>
+ <p>
+ A plugin may need to manipulate data in arbitrary chunks, and it needs a way to make the server
+ guarantee that the chunks are available in memory.</p>
+
+ <h2>The problem</h2>
+ <p>
+ Usually when plugins want to manipulate larger areas of world data, they need to make sure that the
+ server has the appropriate chunks loaded in the memory. When the data being manipulated can be further
+ away from the connected players, or the data is being manipulated from a console handler, there is a
+ real chance that the chunks are not loaded.</p>
+ <p>
+ This gets even more important when using the <a href="cBlockArea.html">cBlockArea</a> class for reading
+ and writing. Those functions will fail when any of the required chunks aren't valid. This means that
+ either the block area has incomplete data (Read() failed) or incomplete data has been written to the
+ world (Write() failed). Recovery from this is near impossible - you can't simply read or write again
+ later, because the world may have changed in the meantime.</p>
+
+ <h2>The solution</h2>
+ <p>
+ The naive solution would be to monitor chunk loads and unloads, and postpone the operations until all
+ the chunks are available. This would be quite ineffective and also very soon it would become very
+ difficult to maintain, if there were multiple code paths requiring this handling.</p>
+ <p>
+ An alternate approach has been implemented, accessible through a single (somewhat hidden) function
+ call: <a href="cWorld.html">cWorld:ChunkStay()</a>. All that this call basically does is, it tells the
+ server "Load these chunks for me, and call this callback function once you have them all." And the
+ server does exactly that - it remembers the callback and asks the world loader / generator to provide
+ the chunks. Once the chunks become available, it calls the callback function for the plugin.</p>
+ <p>
+ There are a few gotcha-s, though. If the code that was requesting the read or write had access to some
+ of the volatile objects, such as <a href="cPlayer.html">cPlayer</a> or
+ <a href="cEntity.html">cEntity</a> objects, those cannot be accessed by the callback anymore, because
+ they may have become invalid in the meantime - the player may have disconnected, the entity may have
+ despawned. So the callback must use the longer way to access such objects, such as calling
+ <a href="cWorld.html">cWorld:DoWithEntityByID()</a> or
+ <a href="cWorld.html">cWorld:DoWithPlayer()</a>.</p>
+
+ <h2>The example</h2>
+ <p>
+ As a simple example, consider a theoretical plugin that allows a player to save the immediate
+ surroundings of the spawn into a schematic file. The player issues a command to initiate the save, and
+ the plugin reads a 50 x 50 x 50 block area around the spawn into a cBlockArea and saves it on the disk
+ as "<PlayerName>_spawn.schematic". When it's done with the saving, it wants to send a message to the
+ player to let them know the command has succeeded.</p>
+ <p>
+ The first attempt shows the naive approach. It simply reads the block area and saves it, then sends the
+ message. I'll repeat once more, this code is <b>the wrong way</b> to do it!</p>
+<pre class="prettyprint lang-lua">
+function HandleCommandSaveSpawn(a_Split, a_Player)
+ -- Get the coords for the spawn:
+ local SpawnX = a_Player:GetWorld():GetSpawnX()
+ local SpawnY = a_Player:GetWorld():GetSpawnY()
+ local SpawnZ = a_Player:GetWorld():GetSpawnZ()
+ local Bounds = cCuboid(SpawnX - 25, SpawnY - 25, SpawnZ - 25, SpawnX + 25, SpawnY + 25, SpawnZ + 25)
+ Bounds:ClampY(0, 255)
+
+ -- Read the area around spawn into a cBlockArea, save to file:
+ local Area = cBlockArea()
+ local FileName = a_Player:GetName() .. "_spawn.schematic"
+ Area:Read(a_Player:GetWorld(), Bounds, cBlockArea.baTypes + cBlockArea.baMetas)
+ Area:SaveToSchematicFile(FileName)
+
+ -- Notify the player:
+ a_Player:SendMessage(cCompositeChat("The spawn has been saved", mtInfo))
+ return true
+end
+</pre>
+ <p>
+ Now if the player goes exploring far and uses the command to save their spawn, the chunks aren't
+ loaded, so the BlockArea reading fails, the BlockArea contains bad data. Note that the plugin fails to
+ do any error checking and if the area isn't read from the world, it happily saves the incomplete data
+ and says "hey, everything's right", althought it has just trashed any previous backup of the spawn
+ schematic with nonsense data.</p>
+ <hr/>
+ <p>
+ The following script uses the ChunkStay method to alleviate chunk-related problems. This is <b>the
+ right way</b> of doing it:</p>
+<pre class="prettyprint lang-lua">
+function HandleCommandSaveSpawn(a_Split, a_Player)
+ -- Get the coords for the spawn:
+ local SpawnX = a_Player:GetWorld():GetSpawnX()
+ local SpawnY = a_Player:GetWorld():GetSpawnY()
+ local SpawnZ = a_Player:GetWorld():GetSpawnZ()
+ local Bounds = cCuboid(SpawnX - 25, SpawnY - 25, SpawnZ - 25, SpawnX + 25, SpawnY + 25, SpawnZ + 25)
+ Bounds:ClampY(0, 255)
+
+ -- Get a list of chunks that we need loaded:
+ local MinChunkX = math.floor((SpawnX - 25) / 16)
+ local MaxChunkX = math.ceil ((SpawnX + 25) / 16)
+ local MinChunkZ = math.floor((SpawnZ - 25) / 16)
+ local MaxChunkZ = math.ceil ((SpawnZ + 25) / 16)
+ local Chunks = {}
+ for x = MinChunkX, MaxChunkX do
+ for z = MinChunkZ, MaxChunkZ do
+ table.insert(Chunks, {x, z})
+ end
+ end -- for x
+
+ -- Store the player's name and world to use in the callback, because the a_Player object may no longer be valid:
+ local PlayerName = a_Player:GetName()
+ local World = a_Player:GetWorld()
+
+ -- This is the callback that is executed once all the chunks are loaded:
+ local OnAllChunksAvailable = function()
+ -- Read the area around spawn into a cBlockArea, save to file:
+ local Area = cBlockArea()
+ local FileName = PlayerName .. "_spawn.schematic"
+ if (Area:Read(World, Bounds, cBlockArea.baTypes + cBlockArea.baMetas)) then
+ Area:SaveToSchematicFile(FileName)
+ Msg = cCompositeChat("The spawn has been saved", mtInfo)
+ else
+ Msg = cCompositeChat("Cannot save the spawn", mtFailure)
+ end
+
+ -- Notify the player:
+ -- Note that we cannot use a_Player here, because it may no longer be valid (if the player disconnected before the command completes)
+ World:DoWithPlayer(PlayerName,
+ function (a_CBPlayer)
+ a_CBPlayer:SendMessage(Msg)
+ end
+ )
+ end
+
+ -- Ask the server to load our chunks and notify us once it's done:
+ World:ChunkStay(Chunks, nil, OnAllChunksAvailable)
+
+ -- Note that code here may get executed before the callback is called!
+ -- The ChunkStay says "once you have the chunks", not "wait until you have the chunks"
+ -- So you can't notify the player here, because the saving needn't have occurred yet.
+
+ return true
+end
+</pre>
+ <p>
+ Note that this code does its error checking of the Area:Read() function, and it will not overwrite the
+ previous file unless it actually has the correct data. If you're wondering how the reading could fail
+ when we've got the chunks loaded, there's still the issue of free RAM - if the memory for the area
+ cannot be allocated, it cannot be read even with all the chunks present. So we still do need that
+ check.</p>
+
+ <h2>The conclusion</h2>
+ <p>
+ Although it makes the code a little bit longer and is a bit more difficult to grasp at first, the
+ ChunkStay is a useful technique to add to your repertoire. It is to be used whenever you need access to
+ chunks that may potentially be inaccessible, and you really need the data.</p>
+ <p>Possibly the biggest hurdle in using the ChunkStay is the fact that it does its work in the
+ background, thus invalidating all cPlayer and cEntity objects your function may hold, so you need to
+ re-acquire them from their IDs and names. This is the penalty for using multi-threaded code.</p>
+ <script>
+ prettyPrint();
+ </script>
+ </div>
+ </body>
+</html>
diff --git a/MCServer/Plugins/APIDump/WebWorldThreads.html b/MCServer/Plugins/APIDump/WebWorldThreads.html
index fc80a6178..ee0b172e6 100644
--- a/MCServer/Plugins/APIDump/WebWorldThreads.html
+++ b/MCServer/Plugins/APIDump/WebWorldThreads.html
@@ -39,31 +39,31 @@
<h2>Example</h2>
The Core has the facility to kick players using the web interface. It used the following code for the kicking (inside the webadmin handler):
- <pre class="prettyprint lang-lua">
- local KickPlayerName = Request.Params["players-kick"]
- local FoundPlayerCallback = function(Player)
- if (Player:GetName() == KickPlayerName) then
- Player:GetClientHandle():Kick("You were kicked from the game!")
- end
+<pre class="prettyprint lang-lua">
+local KickPlayerName = Request.Params["players-kick"]
+local FoundPlayerCallback = function(Player)
+ if (Player:GetName() == KickPlayerName) then
+ Player:GetClientHandle():Kick("You were kicked from the game!")
+ end
+end
+cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback)
+</pre>
+The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds:
+<pre class="prettyprint lang-lua">
+cRoot:Get():ForEachWorld( -- For each world...
+ function(World)
+ World:QueueTask( -- ... queue a task...
+ function(a_World)
+ a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist...
+ function (a_Player)
+ a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player
end
- cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback)
- </pre>
- The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds:
- <pre class="prettyprint lang-lua">
- cRoot:Get():ForEachWorld( -- For each world...
- function(World)
- World:QueueTask( -- ... queue a task...
- function(a_World)
- a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist...
- function (a_Player)
- a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player
- end
- )
- end
- )
- end
- )
- </pre>
+ )
+ end
+ )
+ end
+)
+</pre>
<script>
prettyPrint();
</script>
diff --git a/MCServer/Plugins/APIDump/main.css b/MCServer/Plugins/APIDump/main.css
index aa26bd186..8041e0d01 100644
--- a/MCServer/Plugins/APIDump/main.css
+++ b/MCServer/Plugins/APIDump/main.css
@@ -39,7 +39,8 @@ pre
body
{
- min-width: 800px;
+ min-width: 400px;
+ max-width: 1200px;
width: 95%;
margin: 10px auto;
background-color: white;
diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua
index 7455c3cd2..a25bab9cf 100644
--- a/MCServer/Plugins/APIDump/main_APIDump.lua
+++ b/MCServer/Plugins/APIDump/main_APIDump.lua
@@ -27,10 +27,14 @@ local function LoadAPIFiles(a_Folder, a_DstTable)
-- We only want .lua files from the folder:
if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then
local TablesFn, Err = loadfile(FileName);
- if (TablesFn == nil) then
+ if (type(TablesFn) ~= "function") then
LOGWARNING("Cannot load API descriptions from " .. FileName .. ", Lua error '" .. Err .. "'.");
else
local Tables = TablesFn();
+ if (type(Tables) ~= "table") then
+ LOGWARNING("Cannot load API descriptions from " .. FileName .. ", returned object is not a table (" .. type(Tables) .. ").");
+ break
+ end
for k, cls in pairs(Tables) do
a_DstTable[k] = cls;
end
@@ -1408,9 +1412,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/Core b/MCServer/Plugins/Core
-Subproject 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be5
+Subproject 3790f78d3f7503ff33a423b8e73e81a27556278
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index 2cb014875..064d5d772 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -69,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;
@@ -243,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 27e63aa5b..da5a9972c 100644
--- a/MCServer/Plugins/InfoReg.lua
+++ b/MCServer/Plugins/InfoReg.lua
@@ -16,22 +16,22 @@ local function ListSubcommands(a_Player, a_Subcommands, a_CmdString)
end
-- Enum all the subcommands:
- local Verbs = {};
+ local Verbs = {}
for cmd, info in pairs(a_Subcommands) do
- if (a_Player:HasPermission(info.Permission or "")) then
- table.insert(Verbs, " " .. a_CmdString .. " " .. cmd);
+ if ((a_Player == nil) or (a_Player:HasPermission(info.Permission or ""))) then
+ table.insert(Verbs, a_CmdString .. " " .. cmd)
end
end
- table.sort(Verbs);
+ table.sort(Verbs)
-- Send the list:
if (a_Player == nil) then
for idx, verb in ipairs(Verbs) do
- LOGINFO(verb);
+ LOGINFO(" " .. verb)
end
else
for idx, verb in ipairs(Verbs) do
- a_Player:SendMessage(verb);
+ a_Player:SendMessage(cCompositeChat(" ", mtInfo):AddSuggestCommandPart(verb, verb))
end
end
end
diff --git a/MCServer/monsters.ini b/MCServer/monsters.ini
index 8cd956157..b631fc1a9 100644
--- a/MCServer/monsters.ini
+++ b/MCServer/monsters.ini
@@ -47,14 +47,15 @@ AttackDamage=4.0
SightDistance=25.0
MaxHealth=40
-[Zombiepigman]
+[ZombiePigman]
AttackRange=2.0
AttackRate=1
AttackDamage=7.0
SightDistance=25.0
MaxHealth=20
+IsFireproof=1
-[Cavespider]
+[CaveSpider]
AttackRange=2.0
AttackRate=1
AttackDamage=2.0
@@ -74,6 +75,7 @@ AttackRate=1
AttackDamage=0.0
SightDistance=50.0
MaxHealth=10
+IsFireproof=1
[Silverfish]
AttackRange=2.0
@@ -115,6 +117,7 @@ AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=20
+IsFireproof=1
[Villager]
AttackRange=2.0
@@ -122,6 +125,7 @@ AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=20
+IsFireproof=0
[Witch]
AttackRange=2.0
@@ -145,12 +149,13 @@ AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
-[Magmacube]
+[MagmaCube]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=16
+IsFireproof=1
[Horse]
AttackRange=2.0
diff --git a/MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.cmd b/MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.cmd
new file mode 100644
index 000000000..3ea6963b4
--- /dev/null
+++ b/MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.cmd
@@ -0,0 +1,11 @@
+echo This script generates the certificate and private key for the https webadmin
+echo Note that the generated certificate is self-signed, and therefore not trusted by browsers
+echo Note that this script requires openssl to be installed and in PATH
+echo.
+echo When OpenSSL asks you for Common Name, you need to enter the fully qualified domain name of the server, that is, e. g. gallery.xoft.cz
+echo.
+echo If OpenSSL fails with an error, "WARNING: can't open config file: /usr/local/ssl/openssl.cnf", you need to run this script as an administrator
+echo.
+
+openssl req -x509 -newkey rsa:2048 -keyout httpskey.pem -out httpscert.crt -days 3650 -nodes
+pause
diff --git a/MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh b/MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh
new file mode 100755
index 000000000..5cf1237c8
--- /dev/null
+++ b/MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+echo "This script generates the certificate and private key for the https webadmin"
+echo "Note that the generated certificate is self-signed, and therefore not trusted by browsers"
+echo "Note that this script requires openssl to be installed and in PATH"
+echo ""
+echo "When OpenSSL asks you for Common Name, you need to enter the fully qualified domain name of the server, that is, e. g. gallery.xoft.cz"
+echo ""
+
+openssl req -x509 -newkey rsa:2048 -keyout httpskey.pem -out httpscert.crt -days 3650 -nodes
diff --git a/MakeLuaAPI.cmd b/MakeLuaAPI.cmd
index 7054977a0..90b8cf53e 100644
--- a/MakeLuaAPI.cmd
+++ b/MakeLuaAPI.cmd
@@ -30,7 +30,7 @@ if "a%ftpsite%" == "a" (
cd MCServer
copy /Y settings_apidump.ini settings.ini
-echo stop | MCServer
+echo api | MCServer
cd ..
diff --git a/README.md b/README.md
index a16062574..e6d9492f0 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,39 @@
-MCServer
+MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
========
-**Current Protocol Supported:** Minecraft v1.2 -> v1.7
-
-MCServer is a performant C++ Minecraft server designed for use in memory and cpu-limited places, or just to make regular server perform better.
+MCServer is a Minecraft server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API.
MCServer can run on PCs, Macs, and *nix. This includes android phones and tablets as well as Raspberry Pis.
+We currently support the protocol from Minecraft 1.2 all the way up to Minecraft 1.7.9.
+
Installation
------------
-To install MCServer, you can either download the repository and compile it, or download a pre-compiled version.
-
-If you've cloned the repository using Git, you need to pull down the submodules (core plugins, some dependencies). This can be achieved with `git submodule init` and then on a regular basis (to keep up to date) `git submodule update`.
+Normally, you will want to download a pre-compiled version of MCServer from one of the buildservers:
-If you downloaded a ZIP file of the sources instead, you will need to download PolarSSL, too, from https://github.com/polarssl/polarssl , and unpack it into the `lib/polarssl` folder. You will also need to manually download all the plugins that you want included.
+ * [Linux and Raspberry Pi](http://ci.bearbin.net) (Bearbin's CI Server)
+ * [Windows](http://mc-server.xoft.cz) (xoft's nightly build service)
-Compilation instructions are available in the COMPILING file.
+You simply need to download and extract these files before you can use the server.
-Linux builds can be downloaded from [Bearbin's CI Service](http://ci.bearbin.net) and Windows builds from xoft's [nightly build service](http://mc-server.xoft.cz).
-
-After you've extracted the files, simply run the MCServer executable.
+If you're a more advanced user, you may want to compile the server yourself for more performance. See the [COMPILING.md](https://github.com/mc-server/MCServer/blob/master/COMPILING.md) file for more details.
Contributing
------------
MCServer is licensed under the Apache license V2, and we welcome anybody to fork and submit a Pull Request back with their changes, and if you want to join as a permanent member we can add you to the team.
+Check out the [CONTRIBUTING.md](https://github.com/mc-server/MCServer/blob/master/CONTRIBUTING.md) file for more details.
+
Other Stuff
-----------
-For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [wiki](http://wiki.mc-server.org/).
+For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [Plugin API](http://mc-server.xoft.cz/LuaAPI/).
Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
-Travis CI: [![Build Status](https://travis-ci.org/mc-server/MCServer.png?branch=master)](https://travis-ci.org/mc-server/MCServer)
+Support Us on Gittip: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team)
+
+Travis CI: [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer)
diff --git a/SetFlags.cmake b/SetFlags.cmake
index bbd8254ad..6e2417a51 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -1,32 +1,41 @@
macro (add_flags_lnk FLAGS)
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
- set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${FLAGS}")
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAGS}")
- set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${FLAGS}")
- set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAGS}")
- set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE "${CMAKE_MODULE_LINKER_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${FLAGS}")
endmacro()
macro(add_flags_cxx FLAGS)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}")
endmacro()
macro(set_flags)
# Add the preprocessor macros used for distinguishing between debug and release builds (CMake does this automatically for MSVC):
if (NOT MSVC)
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/lib/cmake-coverage/")
+ include(CodeCoverage)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -D_DEBUG")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} -D_DEBUG")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
endif()
if(MSVC)
@@ -42,9 +51,12 @@ macro(set_flags)
elseif(APPLE)
#on os x clang adds pthread for us but we need to add it for gcc
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
+ add_flags_cxx("-stdlib=libc++")
+ add_flags_lnk("-stdlib=libc++")
else()
add_flags_cxx("-pthread")
endif()
@@ -55,6 +67,7 @@ macro(set_flags)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
endif()
@@ -95,10 +108,12 @@ macro(set_lib_flags)
string(REPLACE "/W3" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/W3" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
else()
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -w")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -w")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -w")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -w")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -w")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -w")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -w")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -w")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -w")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} -w")
endif()
# On Unix we use two dynamic loading libraries dl and ltdl.
@@ -116,8 +131,8 @@ endmacro()
macro(enable_profile)
# Declare the flags used for profiling builds:
if (MSVC)
- set (CXX_PROFILING "")
- set (LNK_PROFILING "/PROFILE")
+ set (CXX_PROFILING "/Zi")
+ set (LNK_PROFILING "/PROFILE /DEBUG")
else()
set (CXX_PROFILING "-pg")
set (LNK_PROFILING "-pg")
@@ -126,7 +141,7 @@ macro(enable_profile)
# Declare the profiling configurations:
SET(CMAKE_CXX_FLAGS_DEBUGPROFILE
- "${CMAKE_CXX_FLAGS_DEBUG} ${PCXX_ROFILING}"
+ "${CMAKE_CXX_FLAGS_DEBUG} ${CXX_PROFILING}"
CACHE STRING "Flags used by the C++ compiler during profile builds."
FORCE )
SET(CMAKE_C_FLAGS_DEBUGPROFILE
@@ -169,7 +184,11 @@ macro(enable_profile)
CMAKE_EXE_LINKER_FLAGS_RELEASEPROFILE
CMAKE_SHARED_LINKER_FLAGS_RELEASEPROFILE )
# The configuration types need to be set after their respective c/cxx/linker flags and before the project directive
- set(CMAKE_CONFIGURATION_TYPES "Debug;Release;DebugProfile;ReleaseProfile" CACHE STRING "" FORCE)
+ if(MSVC)
+ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;DebugProfile;ReleaseProfile" CACHE STRING "" FORCE)
+ else()
+ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;DebugProfile;ReleaseProfile;Coverage" CACHE STRING "" FORCE)
+ endif()
endmacro()
macro(set_exe_flags)
@@ -178,10 +197,12 @@ macro(set_exe_flags)
# We do not do that for MSVC since MSVC produces an awful lot of warnings for its own STL headers;
# the important warnings are turned on using #pragma in Globals.h
if (NOT MSVC)
- string(REPLACE "-w" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
- string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
- string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
- string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "-w" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+ string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+ string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "-w" "" CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE}")
+ string(REPLACE "-w" "" CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE}")
add_flags_cxx("-Wall -Wextra -Wno-unused-parameter -Wno-error=switch")
# we support non-IEEE 754 fpus so can make no guarentees about error
@@ -198,6 +219,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/Tools/MCADefrag/Globals.h b/Tools/MCADefrag/Globals.h
index 0f31de7e3..f70a90d17 100644
--- a/Tools/MCADefrag/Globals.h
+++ b/Tools/MCADefrag/Globals.h
@@ -22,6 +22,15 @@
#define ALIGN_8
#define ALIGN_16
+ #define FORMATSTRING(formatIndex, va_argsIndex)
+
+ // MSVC has its own custom version of zu format
+ #define SIZE_T_FMT "%Iu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "Iu"
+ #define SIZE_T_FMT_HEX "%Ix"
+
+ #define NORETURN __declspec(noreturn)
+
#elif defined(__GNUC__)
// TODO: Can GCC explicitly mark classes as abstract (no instances can be created)?
@@ -39,6 +48,12 @@
#define stricmp strcasecmp
#define FORMATSTRING(formatIndex,va_argsIndex)
+
+ #define SIZE_T_FMT "%zu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
+ #define SIZE_T_FMT_HEX "%zx"
+
+ #define NORETURN __attribute((__noreturn__))
#else
#error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt
index 01f1e88ad..f0796363c 100644
--- a/Tools/ProtoProxy/CMakeLists.txt
+++ b/Tools/ProtoProxy/CMakeLists.txt
@@ -36,14 +36,24 @@ set(SHARED_SRC
../../src/StringUtils.cpp
../../src/Log.cpp
../../src/MCLogger.cpp
- ../../src/Crypto.cpp
+ ../../src/PolarSSL++/AesCfb128Decryptor.cpp
+ ../../src/PolarSSL++/AesCfb128Encryptor.cpp
+ ../../src/PolarSSL++/CryptoKey.cpp
+ ../../src/PolarSSL++/CtrDrbgContext.cpp
+ ../../src/PolarSSL++/EntropyContext.cpp
+ ../../src/PolarSSL++/RsaPrivateKey.cpp
)
set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
../../src/Log.h
../../src/MCLogger.h
- ../../src/Crypto.h
+ ../../src/PolarSSL++/AesCfb128Decryptor.h
+ ../../src/PolarSSL++/AesCfb128Encryptor.h
+ ../../src/PolarSSL++/CryptoKey.h
+ ../../src/PolarSSL++/CtrDrbgContext.h
+ ../../src/PolarSSL++/EntropyContext.h
+ ../../src/PolarSSL++/RsaPrivateKey.h
)
set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp
index f02b503f1..c5916c1ca 100644
--- a/Tools/ProtoProxy/Connection.cpp
+++ b/Tools/ProtoProxy/Connection.cpp
@@ -7,6 +7,7 @@
#include "Connection.h"
#include "Server.h"
#include <iostream>
+#include "PolarSSL++/CryptoKey.h"
#ifdef _WIN32
#include <direct.h> // For _mkdir()
@@ -387,6 +388,8 @@ bool cConnection::RelayFromServer(void)
return CLIENTSEND(Buffer, res);
}
}
+ ASSERT(!"Unhandled server state while relaying from server");
+ return false;
}
@@ -423,6 +426,8 @@ bool cConnection::RelayFromClient(void)
return SERVERSEND(Buffer, res);
}
}
+ ASSERT(!"Unhandled server state while relaying from client");
+ return false;
}
@@ -438,11 +443,11 @@ double cConnection::GetRelativeTime(void)
-bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, int a_Size, const char * a_Peer)
+bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, size_t a_Size, const char * a_Peer)
{
- DataLog(a_Data, a_Size, "Sending data to %s, %d bytes", a_Peer, a_Size);
+ DataLog(a_Data, a_Size, "Sending data to %s, %u bytes", a_Peer, (unsigned)a_Size);
- int res = send(a_Socket, a_Data, a_Size, 0);
+ int res = send(a_Socket, a_Data, (int)a_Size, 0);
if (res <= 0)
{
Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, SocketError);
@@ -467,7 +472,7 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
-bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
+bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
{
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
const Byte * Data = (const Byte *)a_Data;
@@ -491,7 +496,7 @@ bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryp
-bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
+bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
{
AString All;
a_Data.ReadAll(All);
@@ -2193,11 +2198,39 @@ bool cConnection::HandleServerSpawnMob(void)
+struct sSpawnData
+{
+ AString m_Name;
+ AString m_Value;
+ AString m_Signature;
+ sSpawnData(const AString & a_Name, const AString & a_Value, const AString & a_Signature) :
+ m_Name(a_Name),
+ m_Value(a_Value),
+ m_Signature(a_Signature)
+ {
+ }
+};
+
+typedef std::vector<sSpawnData> sSpawnDatas;
+
+
+
+
+
bool cConnection::HandleServerSpawnNamedEntity(void)
{
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID);
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, DataCount);
+ sSpawnDatas Data;
+ for (UInt32 i = 0; i < DataCount; i++)
+ {
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Name)
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Value)
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Signature)
+ Data.push_back(sSpawnData(Name, Value, Signature));
+ }
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
@@ -2215,6 +2248,13 @@ bool cConnection::HandleServerSpawnNamedEntity(void)
Log(" EntityID = %u (0x%x)", EntityID, EntityID);
Log(" UUID = \"%s\"", EntityUUID.c_str());
Log(" Name = \"%s\"", EntityName.c_str());
+ Log(" NumData = %u", DataCount);
+ for (sSpawnDatas::const_iterator itr = Data.begin(), end = Data.end(); itr != end; ++itr)
+ {
+ Log(" Name = \"%s\", Value = \"%s\", Signature = \"%s\"",
+ itr->m_Name.c_str(), itr->m_Value.c_str(), itr->m_Signature.c_str()
+ );
+ } // for itr - Data[]
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch);
Log(" CurrentItem = %d", CurrentItem);
@@ -2860,7 +2900,7 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
Byte SharedSecret[16];
Byte EncryptedSecret[128];
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
- cPublicKey PubKey(a_ServerPublicKey);
+ cCryptoKey PubKey(a_ServerPublicKey);
int res = PubKey.Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
if (res < 0)
{
diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h
index 70b759d0f..1fc9536de 100644
--- a/Tools/ProtoProxy/Connection.h
+++ b/Tools/ProtoProxy/Connection.h
@@ -11,6 +11,8 @@
#include "ByteBuffer.h"
#include "OSSupport/Timer.h"
+#include "PolarSSL++/AesCfb128Decryptor.h"
+#include "PolarSSL++/AesCfb128Encryptor.h"
@@ -66,8 +68,8 @@ protected:
cByteBuffer m_ClientBuffer;
cByteBuffer m_ServerBuffer;
- cAESCFBDecryptor m_ServerDecryptor;
- cAESCFBEncryptor m_ServerEncryptor;
+ cAesCfb128Decryptor m_ServerDecryptor;
+ cAesCfb128Encryptor m_ServerEncryptor;
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
@@ -103,16 +105,16 @@ protected:
double GetRelativeTime(void);
/// Sends data to the specified socket. If sending fails, prints a fail message using a_Peer and returns false.
- bool SendData(SOCKET a_Socket, const char * a_Data, int a_Size, const char * a_Peer);
+ bool SendData(SOCKET a_Socket, const char * a_Data, size_t a_Size, const char * a_Peer);
/// Sends data to the specified socket. If sending fails, prints a fail message using a_Peer and returns false.
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
- bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
+ bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
- bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
+ bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
/// Decodes packets coming from the client, sends appropriate counterparts to the server; returns false if the connection is to be dropped
bool DecodeClientsPackets(const char * a_Data, int a_Size);
diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h
index e2f5aa860..a9b5aa1b1 100644
--- a/Tools/ProtoProxy/Globals.h
+++ b/Tools/ProtoProxy/Globals.h
@@ -216,6 +216,20 @@ typedef unsigned char Byte;
// Pretty much the same as ASSERT() but stays in Release builds
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
+// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
+// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
+#if (defined(_MSC_VER) && (_MSC_VER < 1600))
+ // MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
+ #define SharedPtr std::tr1::shared_ptr
+#elif (defined(_MSC_VER) || (__cplusplus >= 201103L))
+ // C++11 has std::shared_ptr in <memory>, included earlier
+ #define SharedPtr std::shared_ptr
+#else
+ // C++03 has std::tr1::shared_ptr in <tr1/memory>
+ #include <tr1/memory>
+ #define SharedPtr std::tr1::shared_ptr
+#endif
+
@@ -232,12 +246,6 @@ public:
-#include "../../src/Crypto.h"
-
-
-
-
-
#define LOGERROR printf
#define LOGINFO printf
#define LOGWARNING printf
diff --git a/Tools/ProtoProxy/ProtoProxy.txt b/Tools/ProtoProxy/ProtoProxy.txt
index e25d513f3..ee52f393e 100644
--- a/Tools/ProtoProxy/ProtoProxy.txt
+++ b/Tools/ProtoProxy/ProtoProxy.txt
@@ -20,7 +20,7 @@ You need to set the server *not* to verify usernames ("online-mode=false" in ser
ProtoProxy is not much dependent on the protocol - it will work with unknown packets, it just won't parse them into human-readable format.
-The latest protocol which has been tested is 1.6.1 (#73).
+The latest protocol which has been tested is 1.7.9 (#5).
*/
diff --git a/Tools/ProtoProxy/Server.h b/Tools/ProtoProxy/Server.h
index 85f817a4d..8adc7093d 100644
--- a/Tools/ProtoProxy/Server.h
+++ b/Tools/ProtoProxy/Server.h
@@ -9,6 +9,8 @@
#pragma once
+#include "PolarSSL++/RsaPrivateKey.h"
+
@@ -17,7 +19,7 @@
class cServer
{
SOCKET m_ListenSocket;
- cRSAPrivateKey m_PrivateKey;
+ cRsaPrivateKey m_PrivateKey;
AString m_PublicKeyDER;
short m_ConnectPort;
@@ -27,7 +29,7 @@ public:
int Init(short a_ListenPort, short a_ConnectPort);
void Run(void);
- cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
+ cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
short GetConnectPort(void) const { return m_ConnectPort; }
diff --git a/lib/cmake-coverage/CodeCoverage.cmake b/lib/cmake-coverage/CodeCoverage.cmake
new file mode 100644
index 000000000..edf927fec
--- /dev/null
+++ b/lib/cmake-coverage/CodeCoverage.cmake
@@ -0,0 +1,160 @@
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim Söderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# USAGE:
+# 1. Copy this file into your cmake modules path.
+#
+# 2. Add the following line to your CMakeLists.txt:
+# INCLUDE(CodeCoverage)
+#
+# 3. Set compiler flags to turn off optimization and enable coverage:
+# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+#
+# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target
+# which runs your test executable and produces a lcov code coverage report:
+# Example:
+# SETUP_TARGET_FOR_COVERAGE(
+# my_coverage_target # Name for custom target.
+# test_driver # Name of the test driver executable that runs the tests.
+# # NOTE! This should always have a ZERO as exit code
+# # otherwise the coverage generation will not complete.
+# coverage # Name of output directory.
+# )
+#
+# 4. Build a Debug build:
+# cmake -DCMAKE_BUILD_TYPE=Debug ..
+# make
+# make my_coverage_target
+#
+#
+
+# Check prereqs
+FIND_PROGRAM( GCOV_PATH gcov )
+FIND_PROGRAM( LCOV_PATH lcov )
+FIND_PROGRAM( GENHTML_PATH genhtml )
+FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
+
+IF(NOT GCOV_PATH)
+MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
+ENDIF() # NOT GCOV_PATH
+
+IF(NOT CMAKE_COMPILER_IS_GNUCXX)
+# Clang version 3.0.0 and greater now supports gcov as well.
+MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
+
+IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+ENDIF()
+ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX
+
+SET(CMAKE_CXX_FLAGS_COVERAGE
+ "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
+ CACHE STRING "Flags used by the C++ compiler during coverage builds."
+ FORCE )
+SET(CMAKE_C_FLAGS_COVERAGE
+ "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
+ CACHE STRING "Flags used by the C compiler during coverage builds."
+ FORCE )
+SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used for linking binaries during coverage builds."
+ FORCE )
+SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used by the shared libraries linker during coverage builds."
+ FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_COVERAGE
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
+
+IF ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "Coverage"))
+ MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
+ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
+
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests.
+# MUST return ZERO always, even on errors.
+# If not, no coverage report will be created!
+# Param _outputname lcov output is generated as _outputname.info
+# HTML report is generated in _outputname/index.html
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
+
+IF(NOT LCOV_PATH)
+MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
+ENDIF() # NOT LCOV_PATH
+
+IF(NOT GENHTML_PATH)
+MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
+ENDIF() # NOT GENHTML_PATH
+
+# Setup target
+ADD_CUSTOM_TARGET(${_targetname}
+
+# Cleanup lcov
+${LCOV_PATH} --directory . --zerocounters
+
+# Run tests
+COMMAND ${_testrunner} ${ARGV3}
+
+# Capturing lcov counters and generating report
+COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
+COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned
+COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
+COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
+
+WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
+)
+
+# Show info where to find the report
+ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+COMMAND ;
+COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
+)
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests
+# Param _outputname cobertura output is generated as _outputname.xml
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname)
+
+IF(NOT PYTHON_EXECUTABLE)
+MESSAGE(FATAL_ERROR "Python not found! Aborting...")
+ENDIF() # NOT PYTHON_EXECUTABLE
+
+IF(NOT GCOVR_PATH)
+MESSAGE(FATAL_ERROR "gcovr not found! Aborting...")
+ENDIF() # NOT GCOVR_PATH
+
+ADD_CUSTOM_TARGET(${_targetname}
+
+# Run tests
+${_testrunner} ${ARGV3}
+
+# Running gcovr
+COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml
+WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+COMMENT "Running gcovr to produce Cobertura code coverage report."
+)
+
+# Show info where to find the report
+ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+COMMAND ;
+COMMENT "Cobertura code coverage report saved in ${_outputname}.xml."
+)
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
diff --git a/lib/cmake-coverage/LICENSE b/lib/cmake-coverage/LICENSE
new file mode 100644
index 000000000..36b7cd93c
--- /dev/null
+++ b/lib/cmake-coverage/LICENSE
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/lib/expat/CMakeLists.txt b/lib/expat/CMakeLists.txt
index 667804b9a..a23f16609 100644
--- a/lib/expat/CMakeLists.txt
+++ b/lib/expat/CMakeLists.txt
@@ -4,12 +4,11 @@ project (expat)
file(GLOB SOURCE
"*.c"
+ "*.h"
)
-# add headers to MSVC project files:
-if (WIN32)
- file(GLOB HEADERS "*.h")
- set(SOURCE ${SOURCE} ${HEADERS})
+# Set files to go to a "Sources" folder in MSVC project files:
+if (MSVC)
source_group("Sources" FILES ${SOURCE})
endif()
diff --git a/lib/inifile/CMakeLists.txt b/lib/inifile/CMakeLists.txt
index efbd09796..321d501d7 100644
--- a/lib/inifile/CMakeLists.txt
+++ b/lib/inifile/CMakeLists.txt
@@ -1,7 +1,11 @@
-
cmake_minimum_required (VERSION 2.6)
project (iniFile)
include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
-add_library(iniFile iniFile)
+file(GLOB SOURCE
+ "*.h"
+ "*.cpp"
+)
+
+add_library(iniFile ${SOURCE})
diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp
index cf8b63987..ea03f5d35 100644
--- a/lib/inifile/iniFile.cpp
+++ b/lib/inifile/iniFile.cpp
@@ -154,7 +154,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
case ';':
case '#':
{
- if (names.size() == 0)
+ if (names.empty())
{
AddHeaderComment(line.substr(pLeft + 1));
}
@@ -168,8 +168,9 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
} // while (getline())
f.close();
- if (names.size() == 0)
+ if (keys.empty() && names.empty() && comments.empty())
{
+ // File be empty or unreadable, equivalent to nonexistant
return false;
}
@@ -242,7 +243,7 @@ int cIniFile::FindKey(const AString & a_KeyName) const
{
if (CheckCase(names[keyID]) == CaseKeyName)
{
- return keyID;
+ return (int)keyID;
}
}
return noID;
@@ -278,7 +279,7 @@ int cIniFile::AddKeyName(const AString & keyname)
{
names.resize(names.size() + 1, keyname);
keys.resize(keys.size() + 1);
- return names.size() - 1;
+ return (int)names.size() - 1;
}
@@ -682,7 +683,7 @@ int cIniFile::GetNumKeyComments(const int keyID) const
{
if (keyID < (int)keys.size())
{
- return keys[keyID].comments.size();
+ return (int)keys[keyID].comments.size();
}
return 0;
}
diff --git a/lib/lua/CMakeLists.txt b/lib/lua/CMakeLists.txt
index db112d557..6e5e0f565 100644
--- a/lib/lua/CMakeLists.txt
+++ b/lib/lua/CMakeLists.txt
@@ -20,6 +20,12 @@ endif()
# Lua needs to be linked dynamically on Windows and statically on *nix, so that LuaRocks work
if (WIN32)
+
+ #for compiliers other than msvc we need to tell lua that its building as a dll
+ if (NOT MSVC)
+ add_flags_cxx(-DLUA_BUILD_AS_DLL=1)
+ endif()
+
add_library(lua SHARED ${SOURCE})
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer)
diff --git a/lib/luaexpat/CMakeLists.txt b/lib/luaexpat/CMakeLists.txt
index 7eef5c8ce..f6b21c1d7 100644
--- a/lib/luaexpat/CMakeLists.txt
+++ b/lib/luaexpat/CMakeLists.txt
@@ -7,6 +7,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.c"
+ "*.h"
)
add_library(luaexpat ${SOURCE})
diff --git a/lib/md5/CMakeLists.txt b/lib/md5/CMakeLists.txt
index 8ba09a0dd..cd9fe6320 100644
--- a/lib/md5/CMakeLists.txt
+++ b/lib/md5/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(md5 ${SOURCE})
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/polarssl b/lib/polarssl
-Subproject 2cb1a0c4009ecf368ecc74eb428394e10f9e6d0
+Subproject 1ed82759c68f92c4acc7e3f33b850cf9f01c8ab
diff --git a/lib/polarssl.cmake b/lib/polarssl.cmake
index d57cc9220..91f0fa145 100644
--- a/lib/polarssl.cmake
+++ b/lib/polarssl.cmake
@@ -1,5 +1,11 @@
if(NOT TARGET polarssl)
message("including polarssl")
- add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl EXCLUDE_FROM_ALL )
+ if (SELF_TEST)
+ set(ENABLE_TESTING OFF CACHE BOOL "Disable tests")
+ set(ENABLE_PROGRAMS OFF CACHE BOOL "Disable programs")
+ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl)
+ else()
+ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl EXCLUDE_FROM_ALL)
+ endif()
endif()
diff --git a/lib/sqlite/CMakeLists.txt b/lib/sqlite/CMakeLists.txt
index 0815127ef..9add2280b 100644
--- a/lib/sqlite/CMakeLists.txt
+++ b/lib/sqlite/CMakeLists.txt
@@ -17,6 +17,10 @@ if (WIN32)
source_group("Sources" FILES ${SOURCE})
endif()
+# FreeBSD requires us to define this to get POSIX 2001 standard
+if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+ add_flags_cxx(-D__POSIX_VISIBLE=200112)
+endif()
add_library(sqlite ${SOURCE})
diff --git a/lib/tolua++/CMakeLists.txt b/lib/tolua++/CMakeLists.txt
index e5c8ce3e8..e68a0e15b 100644
--- a/lib/tolua++/CMakeLists.txt
+++ b/lib/tolua++/CMakeLists.txt
@@ -26,7 +26,11 @@ if(NOT XXD_EXECUTABLE STREQUAL "XXD_EXECUTABLE-NOTFOUND")
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)
+ add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/container_lua.h
+ COMMAND ${XXD_EXECUTABLE} -i lua/container.lua | sed 's/unsigned char/static const unsigned char/g' >container_lua.h
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
+ DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/container.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 ${PROJECT_SOURCE_DIR}/src/bin/container_lua.h)
else()
message("xxd not found, changes to tolua scripts will be ignored")
endif()
diff --git a/lib/tolua++/src/bin/container_lua.h b/lib/tolua++/src/bin/container_lua.h
new file mode 100644
index 000000000..4c7cf6a67
--- /dev/null
+++ b/lib/tolua++/src/bin/container_lua.h
@@ -0,0 +1,1476 @@
+static const unsigned char lua_container_lua[] = {
+ 0x2d, 0x2d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x3a, 0x20, 0x63, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x61, 0x62, 0x73, 0x74,
+ 0x72, 0x61, 0x63, 0x74, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x62, 0x79,
+ 0x20, 0x57, 0x61, 0x6c, 0x64, 0x65, 0x6d, 0x61, 0x72, 0x20, 0x43, 0x65,
+ 0x6c, 0x65, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x65, 0x43, 0x47, 0x72,
+ 0x61, 0x66, 0x2f, 0x50, 0x55, 0x43, 0x2d, 0x52, 0x69, 0x6f, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x31, 0x39, 0x39, 0x38, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x24, 0x49, 0x64, 0x3a, 0x20, 0x24, 0x0a, 0x0a, 0x2d, 0x2d,
+ 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69,
+ 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77,
+ 0x61, 0x72, 0x65, 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6e,
+ 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+ 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72, 0x20,
+ 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x20, 0x69, 0x74, 0x2e, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61,
+ 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20,
+ 0x68, 0x65, 0x72, 0x65, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73,
+ 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x61, 0x73, 0x20, 0x69,
+ 0x73, 0x22, 0x20, 0x62, 0x61, 0x73, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x6e,
+ 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74,
+ 0x68, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x20, 0x6f,
+ 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f,
+ 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x69,
+ 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2c, 0x20, 0x73, 0x75,
+ 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x73, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, 0x65, 0x6e, 0x68, 0x61, 0x6e,
+ 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x6f, 0x72, 0x20,
+ 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x6e, 0x61,
+ 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70,
+ 0x65, 0x64, 0x65, 0x66, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x20,
+ 0x69, 0x6e, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x73, 0x63,
+ 0x6f, 0x70, 0x65, 0x0a, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74,
+ 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d,
+ 0x0a, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x75, 0x6d,
+ 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x43,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x52, 0x65, 0x70, 0x72, 0x65, 0x73,
+ 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x66, 0x65, 0x61, 0x74,
+ 0x75, 0x72, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x62,
+ 0x6f, 0x75, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x6f, 0x20, 0x6c,
+ 0x75, 0x61, 0x2e, 0x0a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e,
+ 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x3d, 0x0a, 0x7b, 0x0a, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x0a,
+ 0x7d, 0x0a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
+ 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74,
+ 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2c, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29, 0x0a,
+ 0x0a, 0x2d, 0x2d, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74,
+ 0x61, 0x67, 0x73, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x3a, 0x64, 0x65, 0x63, 0x6c, 0x74, 0x79, 0x70, 0x65,
+ 0x20, 0x28, 0x29, 0x0a, 0x20, 0x70, 0x75, 0x73, 0x68, 0x28, 0x73, 0x65,
+ 0x6c, 0x66, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69,
+ 0x3d, 0x31, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x65,
+ 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x73,
+ 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x3a, 0x64, 0x65, 0x63, 0x6c, 0x74,
+ 0x79, 0x70, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20,
+ 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x70, 0x6f,
+ 0x70, 0x28, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a, 0x2d, 0x2d,
+ 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f,
+ 0x72, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63,
+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x73, 0x75, 0x70, 0x63,
+ 0x6f, 0x64, 0x65, 0x20, 0x28, 0x29, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20,
+ 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x63, 0x68, 0x65,
+ 0x63, 0x6b, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63,
+ 0x63, 0x65, 0x73, 0x73, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a, 0x09, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x20, 0x70, 0x75, 0x73, 0x68, 0x28, 0x73, 0x65, 0x6c,
+ 0x66, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d,
+ 0x31, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x65, 0x6c,
+ 0x66, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x69, 0x66,
+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x3a, 0x63, 0x68, 0x65,
+ 0x63, 0x6b, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63,
+ 0x63, 0x65, 0x73, 0x73, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x20, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x3a, 0x73,
+ 0x75, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31,
+ 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x70, 0x6f, 0x70, 0x28, 0x29,
+ 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x68, 0x61, 0x73, 0x76, 0x61, 0x72,
+ 0x20, 0x28, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69,
+ 0x3d, 0x31, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x65,
+ 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x69,
+ 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x3a, 0x69, 0x73,
+ 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x29, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x31, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69,
+ 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+ 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
+ 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x43,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x28, 0x73, 0x65,
+ 0x6c, 0x66, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x20, 0x3d,
+ 0x20, 0x30, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x79, 0x70,
+ 0x65, 0x64, 0x65, 0x66, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x74, 0x6f, 0x6c,
+ 0x75, 0x61, 0x5f, 0x6e, 0x3d, 0x30, 0x7d, 0x0a, 0x20, 0x73, 0x65, 0x6c,
+ 0x66, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20,
+ 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x65,
+ 0x6e, 0x75, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x74, 0x6f, 0x6c, 0x75,
+ 0x61, 0x5f, 0x6e, 0x3d, 0x30, 0x7d, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66,
+ 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d,
+ 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c,
+ 0x66, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x70, 0x75,
+ 0x73, 0x68, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x75,
+ 0x73, 0x68, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x74, 0x2e, 0x70, 0x72,
+ 0x6f, 0x78, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72,
+ 0x0a, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20,
+ 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x70, 0x6f,
+ 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a,
+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x6f, 0x70,
+ 0x20, 0x28, 0x29, 0x0a, 0x2d, 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28,
+ 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2c, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75,
+ 0x72, 0x72, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x2d, 0x2d, 0x66,
+ 0x6f, 0x72, 0x65, 0x61, 0x63, 0x68, 0x28, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75,
+ 0x72, 0x72, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73,
+ 0x2c, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x29, 0x0a, 0x2d, 0x2d, 0x70, 0x72,
+ 0x69, 0x6e, 0x74, 0x28, 0x22, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x22, 0x29, 0x0a, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e,
+ 0x63, 0x75, 0x72, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x20, 0x63, 0x75,
+ 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x67, 0x65, 0x74, 0x63, 0x75, 0x72, 0x72, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x28, 0x29, 0x0a, 0x09, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72,
+ 0x72, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x61,
+ 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x75, 0x72,
+ 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x20,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75,
+ 0x72, 0x72, 0x3a, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x28, 0x74, 0x29,
+ 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x70, 0x70,
+ 0x65, 0x6e, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20,
+ 0x74, 0x6f, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x66, 0x75, 0x6e,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x28, 0x74, 0x29, 0x0a,
+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73,
+ 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63,
+ 0x75, 0x72, 0x72, 0x3a, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x28, 0x74, 0x29, 0x0a, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20,
+ 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x20, 0x74, 0x6f, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x75, 0x73, 0x65,
+ 0x72, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72,
+ 0x72, 0x3a, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x75, 0x73, 0x65, 0x72,
+ 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20, 0x65,
+ 0x6e, 0x75, 0x6d, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65,
+ 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70,
+ 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x28, 0x74, 0x29,
+ 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e,
+ 0x63, 0x75, 0x72, 0x72, 0x3a, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
+ 0x6e, 0x75, 0x6d, 0x28, 0x74, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
+ 0x2d, 0x2d, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74,
+ 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x0a, 0x66, 0x75,
+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x28, 0x6d, 0x6f, 0x64,
+ 0x2c, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x3a, 0x61,
+ 0x70, 0x70, 0x6c, 0x79, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x28,
+ 0x6d, 0x6f, 0x64, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20,
+ 0x69, 0x66, 0x20, 0x69, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x66,
+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69, 0x6e, 0x64,
+ 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a,
+ 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x3a, 0x66, 0x69, 0x6e, 0x64, 0x74,
+ 0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x09, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x69, 0x66,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x0a,
+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x74,
+ 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65,
+ 0x29, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x2e, 0x63, 0x75, 0x72, 0x72, 0x3a, 0x69, 0x73, 0x74, 0x79, 0x70, 0x65,
+ 0x64, 0x65, 0x66, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x20, 0x66, 0x75,
+ 0x6c, 0x6c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x77, 0x69, 0x74, 0x68,
+ 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x29, 0x0a,
+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x75, 0x6c,
+ 0x6c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20,
+ 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x0a, 0x09, 0x77, 0x68,
+ 0x69, 0x6c, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x20, 0x64, 0x6f, 0x0a,
+ 0x09, 0x20, 0x69, 0x66, 0x20, 0x63, 0x75, 0x72, 0x72, 0x20, 0x74, 0x68,
+ 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x20, 0x69, 0x66, 0x20, 0x63, 0x75, 0x72,
+ 0x72, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x20, 0x61,
+ 0x6e, 0x64, 0x20, 0x63, 0x75, 0x72, 0x72, 0x2e, 0x74, 0x79, 0x70, 0x65,
+ 0x64, 0x65, 0x66, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x0a, 0x09, 0x09, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66,
+ 0x73, 0x5b, 0x74, 0x5d, 0x0a, 0x09, 0x09, 0x20, 0x65, 0x6c, 0x73, 0x65,
+ 0x69, 0x66, 0x20, 0x63, 0x75, 0x72, 0x72, 0x2e, 0x75, 0x73, 0x65, 0x72,
+ 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x75,
+ 0x72, 0x72, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73,
+ 0x5b, 0x74, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x20,
+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x75, 0x72, 0x72,
+ 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5b, 0x74,
+ 0x5d, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65,
+ 0x6e, 0x64, 0x0a, 0x09, 0x20, 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x0a, 0x09, 0x65,
+ 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74,
+ 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x68, 0x65,
+ 0x63, 0x6b, 0x73, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x72, 0x65,
+ 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
+ 0x65, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x28, 0x74, 0x29, 0x0a, 0x20, 0x70, 0x75, 0x73, 0x68, 0x28, 0x73, 0x65,
+ 0x6c, 0x66, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69,
+ 0x3d, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x20,
+ 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x77, 0x68, 0x69,
+ 0x6c, 0x65, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x5b, 0x69, 0x5d, 0x20, 0x64,
+ 0x6f, 0x0a, 0x20, 0x20, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66,
+ 0x5b, 0x69, 0x5d, 0x3a, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x63,
+ 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29,
+ 0x20, 0x6f, 0x72, 0x20, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20,
+ 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x70, 0x6f,
+ 0x70, 0x28, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
+ 0x72, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x67,
+ 0x65, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x61, 0x70, 0x63, 0x65,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65,
+ 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x28,
+ 0x63, 0x75, 0x72, 0x72, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x3d,
+ 0x20, 0x27, 0x27, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x63,
+ 0x75, 0x72, 0x72, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x20, 0x69, 0x66, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x20,
+ 0x20, 0x20, 0x28, 0x20, 0x63, 0x75, 0x72, 0x72, 0x2e, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x27, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x75, 0x72,
+ 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20,
+ 0x3d, 0x3d, 0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
+ 0x65, 0x27, 0x29, 0x0a, 0x09, 0x09, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09,
+ 0x09, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
+ 0x3d, 0x20, 0x28, 0x63, 0x75, 0x72, 0x72, 0x2e, 0x6f, 0x72, 0x69, 0x67,
+ 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x72,
+ 0x20, 0x63, 0x75, 0x72, 0x72, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20,
+ 0x2e, 0x2e, 0x20, 0x27, 0x3a, 0x3a, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6e,
+ 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x09, 0x09, 0x20,
+ 0x2d, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
+ 0x3d, 0x20, 0x63, 0x75, 0x72, 0x72, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x20,
+ 0x2e, 0x2e, 0x20, 0x27, 0x3a, 0x3a, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6e,
+ 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x09, 0x09, 0x65,
+ 0x6e, 0x64, 0x0a, 0x09, 0x20, 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x0a, 0x09, 0x65,
+ 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e,
+ 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x20, 0x6e, 0x61, 0x6d,
+ 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x28, 0x6f, 0x6e, 0x6c, 0x79,
+ 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x29, 0x0a,
+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74,
+ 0x6f, 0x6e, 0x6c, 0x79, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
+ 0x65, 0x20, 0x28, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
+ 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75,
+ 0x72, 0x72, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x61,
+ 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x27,
+ 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72,
+ 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x75, 0x72,
+ 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20,
+ 0x3d, 0x3d, 0x20, 0x27, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x27, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a,
+ 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x63, 0x75, 0x72,
+ 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20,
+ 0x3d, 0x3d, 0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
+ 0x65, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x20, 0x6e,
+ 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x63,
+ 0x75, 0x72, 0x72, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x20,
+ 0x27, 0x3a, 0x3a, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+ 0x09, 0x20, 0x63, 0x75, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x63, 0x75, 0x72,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+ 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x69, 0x66, 0x20, 0x69,
+ 0x73, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x28,
+ 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x3a, 0x69, 0x73,
+ 0x65, 0x6e, 0x75, 0x6d, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x65,
+ 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e,
+ 0x64, 0x20, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x74, 0x6f,
+ 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x66,
+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73,
+ 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x61,
+ 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x73,
+ 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66,
+ 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66,
+ 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x74,
+ 0x0a, 0x20, 0x74, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x3d,
+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20, 0x74, 0x79, 0x70,
+ 0x65, 0x64, 0x65, 0x66, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x74,
+ 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x20,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6e, 0x61, 0x6d,
+ 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75,
+ 0x72, 0x72, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x6c, 0x75, 0x61,
+ 0x5f, 0x6e, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x6c, 0x75, 0x61,
+ 0x5f, 0x6e, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66,
+ 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x73, 0x65,
+ 0x6c, 0x66, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x2e,
+ 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x74,
+ 0x0a, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64,
+ 0x65, 0x66, 0x73, 0x5b, 0x74, 0x2e, 0x75, 0x74, 0x79, 0x70, 0x65, 0x5d,
+ 0x20, 0x3d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x20, 0x2e, 0x2e, 0x20, 0x74, 0x2e, 0x75, 0x74, 0x79, 0x70, 0x65, 0x0a,
+ 0x09, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x64, 0x65, 0x66, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x2e, 0x2e, 0x74, 0x2e, 0x75, 0x74, 0x79, 0x70, 0x65, 0x5d,
+ 0x20, 0x3d, 0x20, 0x74, 0x0a, 0x09, 0x74, 0x2e, 0x66, 0x74, 0x79, 0x70,
+ 0x65, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65,
+ 0x28, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x29, 0x20, 0x6f, 0x72, 0x20,
+ 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x09, 0x2d, 0x2d, 0x70, 0x72,
+ 0x69, 0x6e, 0x74, 0x28, 0x22, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x69,
+ 0x6e, 0x67, 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x22,
+ 0x2e, 0x2e, 0x74, 0x2e, 0x75, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x2e, 0x22,
+ 0x20, 0x61, 0x73, 0x20, 0x22, 0x2e, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x2e, 0x2e, 0x74, 0x2e, 0x75, 0x74, 0x79, 0x70,
+ 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x66, 0x74,
+ 0x79, 0x70, 0x65, 0x20, 0x22, 0x2e, 0x2e, 0x74, 0x2e, 0x66, 0x74, 0x79,
+ 0x70, 0x65, 0x29, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x5f,
+ 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28,
+ 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x2e, 0x74,
+ 0x2e, 0x75, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20,
+ 0x74, 0x2e, 0x66, 0x74, 0x79, 0x70, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
+ 0x69, 0x73, 0x65, 0x6e, 0x75, 0x6d, 0x28, 0x74, 0x2e, 0x66, 0x74, 0x79,
+ 0x70, 0x65, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x09, 0x09,
+ 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73,
+ 0x5b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x2e,
+ 0x74, 0x2e, 0x75, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x74,
+ 0x72, 0x75, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x20,
+ 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x74, 0x79,
+ 0x70, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x3a, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x75, 0x73, 0x65,
+ 0x72, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x74, 0x20, 0x3d, 0x3d, 0x20,
+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
+ 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x73,
+ 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x74, 0x68,
+ 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x72,
+ 0x6f, 0x78, 0x0a, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x63,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x73,
+ 0x65, 0x6c, 0x66, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x20, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74,
+ 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x29, 0x20, 0x2e, 0x2e, 0x20,
+ 0x74, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5b, 0x74,
+ 0x5d, 0x20, 0x3d, 0x20, 0x66, 0x74, 0x0a, 0x09, 0x5f, 0x75, 0x73, 0x65,
+ 0x72, 0x74, 0x79, 0x70, 0x65, 0x5b, 0x66, 0x74, 0x5d, 0x20, 0x3d, 0x20,
+ 0x66, 0x74, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66,
+ 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x70,
+ 0x70, 0x65, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x0a, 0x66, 0x75,
+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x61, 0x70,
+ 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x28, 0x74, 0x29,
+ 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6e,
+ 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e,
+ 0x63, 0x75, 0x72, 0x72, 0x29, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
+ 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f,
+ 0x6e, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x65, 0x6e, 0x75,
+ 0x6d, 0x73, 0x2e, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x6e, 0x20, 0x2b,
+ 0x20, 0x31, 0x0a, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x65, 0x6e, 0x75,
+ 0x6d, 0x73, 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x65, 0x6e, 0x75, 0x6d,
+ 0x73, 0x2e, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x6e, 0x5d, 0x20, 0x3d,
+ 0x20, 0x74, 0x0a, 0x09, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65,
+ 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x2e, 0x2e, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20,
+ 0x3d, 0x20, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20,
+ 0x64, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x75,
+ 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e,
+ 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x3a, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x6c,
+ 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x5b, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x6e, 0x61,
+ 0x6d, 0x65, 0x73, 0x5b, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d,
+ 0x20, 0x30, 0x0a, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x73,
+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x6c,
+ 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66,
+ 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x6c, 0x6e, 0x61, 0x6d,
+ 0x65, 0x5d, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x6d,
+ 0x61, 0x74, 0x28, 0x22, 0x25, 0x30, 0x32, 0x64, 0x22, 0x2c, 0x73, 0x65,
+ 0x6c, 0x66, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x6c, 0x6e,
+ 0x61, 0x6d, 0x65, 0x5d, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x3a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x74, 0x68, 0x65, 0x20,
+ 0x66, 0x61, 0x63, 0x74, 0x6f, 0x27, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66,
+ 0x69, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x3a, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65,
+ 0x66, 0x20, 0x28, 0x6d, 0x6f, 0x64, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x29,
+ 0x0a, 0x09, 0x69, 0x66, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x74, 0x79, 0x70,
+ 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x2d, 0x2d,
+ 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x22, 0x66, 0x6f, 0x75, 0x6e, 0x64,
+ 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x22, 0x2e, 0x2e,
+ 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x64,
+ 0x65, 0x66, 0x73, 0x5b, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x2e, 0x74, 0x79,
+ 0x70, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
+ 0x6d, 0x6f, 0x64, 0x31, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x31, 0x20,
+ 0x3d, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70,
+ 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x2e,
+ 0x6d, 0x6f, 0x64, 0x2c, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x74, 0x79, 0x70,
+ 0x65, 0x5d, 0x2e, 0x66, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x09, 0x09, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0x64, 0x32, 0x2c, 0x20, 0x74,
+ 0x79, 0x70, 0x65, 0x32, 0x20, 0x3d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x28, 0x6d, 0x6f, 0x64, 0x2e,
+ 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x6d, 0x6f, 0x64, 0x31, 0x2c, 0x20,
+ 0x74, 0x79, 0x70, 0x65, 0x31, 0x29, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x32, 0x20, 0x2e,
+ 0x2e, 0x20, 0x27, 0x20, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x6f, 0x64,
+ 0x31, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x32, 0x0a, 0x09, 0x09, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x32, 0x2c, 0x20,
+ 0x74, 0x79, 0x70, 0x65, 0x32, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09,
+ 0x64, 0x6f, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x6f,
+ 0x64, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65,
+ 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b,
+ 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x0a, 0x66, 0x75, 0x6e, 0x63,
+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x69, 0x73, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29,
+ 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x6e, 0x76, 0x20,
+ 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c,
+ 0x65, 0x20, 0x65, 0x6e, 0x76, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x69,
+ 0x66, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65,
+ 0x66, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20, 0x20, 0x20,
+ 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x6e, 0x76, 0x2e,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x69, 0x5d, 0x2e,
+ 0x75, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x74, 0x79, 0x70,
+ 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74,
+ 0x79, 0x70, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65,
+ 0x6e, 0x76, 0x20, 0x3d, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66,
+ 0x69, 0x6e, 0x64, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x76, 0x61, 0x72,
+ 0x28, 0x76, 0x61, 0x72, 0x29, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x74,
+ 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x76, 0x61, 0x72, 0x29,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
+ 0x20, 0x76, 0x61, 0x72, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e,
+ 0x63, 0x75, 0x72, 0x72, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20,
+ 0x63, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6e, 0x61, 0x6d,
+ 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x29, 0x0a, 0x09, 0x09,
+ 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x70,
+ 0x61, 0x69, 0x72, 0x73, 0x28, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+ 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x09,
+ 0x09, 0x09, 0x69, 0x66, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74,
+ 0x79, 0x70, 0x65, 0x28, 0x76, 0x61, 0x72, 0x2c, 0x20, 0x76, 0x2c, 0x20,
+ 0x6e, 0x73, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x0a, 0x09, 0x09,
+ 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09,
+ 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x61,
+ 0x6e, 0x64, 0x20, 0x63, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x7e, 0x3d,
+ 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
+ 0x63, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, 0x63, 0x3a, 0x66, 0x69,
+ 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65, 0x28, 0x63, 0x2e, 0x62, 0x61, 0x73,
+ 0x65, 0x29, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09,
+ 0x09, 0x09, 0x63, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x09, 0x09,
+ 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x72, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20,
+ 0x69, 0x66, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a,
+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6c, 0x6c,
+ 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x69, 0x6c,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x3a, 0x66, 0x69, 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x74,
+ 0x29, 0x0a, 0x0a, 0x09, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x74, 0x2c, 0x20, 0x22,
+ 0x3d, 0x2e, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09, 0x69,
+ 0x66, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5b, 0x74, 0x5d, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x74, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x5f, 0x2c, 0x65, 0x6d, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e,
+ 0x64, 0x28, 0x74, 0x2c, 0x20, 0x22, 0x28, 0x5b, 0x26, 0x25, 0x2a, 0x5d,
+ 0x29, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x29, 0x0a, 0x09, 0x74, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62,
+ 0x28, 0x74, 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x26, 0x25,
+ 0x2a, 0x5d, 0x29, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22,
+ 0x29, 0x0a, 0x09, 0x70, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x0a,
+ 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x70, 0x20, 0x61, 0x6e, 0x64,
+ 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x70, 0x29, 0x3d, 0x3d, 0x27, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x27, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x67, 0x65,
+ 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x70,
+ 0x29, 0x0a, 0x0a, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x5f,
+ 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73,
+ 0x2e, 0x6e, 0x2c, 0x31, 0x2c, 0x2d, 0x31, 0x20, 0x64, 0x6f, 0x20, 0x2d,
+ 0x2d, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65,
+ 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x69,
+ 0x66, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x28, 0x74, 0x2c, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x2c, 0x20, 0x73, 0x74,
+ 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61,
+ 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x2e, 0x2e,
+ 0x28, 0x65, 0x6d, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09,
+ 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+ 0x09, 0x09, 0x69, 0x66, 0x20, 0x70, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x70, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x7e,
+ 0x3d, 0x20, 0x27, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x2e, 0x62,
+ 0x61, 0x73, 0x65, 0x20, 0x7e, 0x3d, 0x20, 0x74, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x2d, 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74,
+ 0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x73, 0x20, 0x22, 0x2e,
+ 0x2e, 0x74, 0x2e, 0x2e, 0x22, 0x2c, 0x20, 0x70, 0x20, 0x69, 0x73, 0x20,
+ 0x22, 0x2e, 0x2e, 0x70, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x2e, 0x22,
+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69,
+ 0x73, 0x20, 0x22, 0x2e, 0x2e, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x79,
+ 0x70, 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e,
+ 0x61, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x22, 0x2e, 0x2e, 0x73, 0x65,
+ 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x09,
+ 0x70, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, 0x70, 0x3a, 0x66, 0x69,
+ 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65, 0x28, 0x70, 0x2e, 0x62, 0x61, 0x73,
+ 0x65, 0x29, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09,
+ 0x09, 0x09, 0x70, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x09, 0x09,
+ 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61,
+ 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x29, 0x0a, 0x09, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61,
+ 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x6e, 0x20, 0x3d, 0x20,
+ 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x73, 0x2e, 0x6e, 0x20, 0x2b, 0x31, 0x0a, 0x09, 0x5f, 0x67, 0x6c, 0x6f,
+ 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5b, 0x5f, 0x67,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
+ 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x0a, 0x09, 0x5f, 0x67, 0x6c, 0x6f,
+ 0x62, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x68, 0x61,
+ 0x73, 0x68, 0x5b, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x69,
+ 0x66, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x5f, 0x63, 0x6c, 0x61, 0x73,
+ 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
+ 0x70, 0x70, 0x65, 0x6e, 0x64, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x2c, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61,
+ 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, 0x74, 0x5d,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x63, 0x6c, 0x61, 0x73,
+ 0x73, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65,
+ 0x73, 0x5b, 0x74, 0x5d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x0a, 0x09,
+ 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, 0x74, 0x5d, 0x2e, 0x6c,
+ 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x5f,
+ 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x65, 0x73, 0x5b, 0x74, 0x5d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x61,
+ 0x6e, 0x64, 0x20, 0x28, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, 0x74, 0x5d, 0x2e, 0x62,
+ 0x61, 0x73, 0x65, 0x20, 0x7e, 0x3d, 0x20, 0x27, 0x27, 0x29, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f,
+ 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b,
+ 0x74, 0x5d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x0a, 0x09, 0x09,
+ 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x5f, 0x67,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65,
+ 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73,
+ 0x0a, 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x66, 0x6c, 0x61, 0x67,
+ 0x73, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x66, 0x6c,
+ 0x61, 0x67, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x7b, 0x7d, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x63,
+ 0x68, 0x69, 0x6c, 0x64, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x72, 0x65,
+ 0x67, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x29, 0x0a, 0x2d,
+ 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x22, 0x66, 0x69, 0x6e, 0x64,
+ 0x74, 0x79, 0x70, 0x65, 0x20, 0x22, 0x2e, 0x2e, 0x63, 0x68, 0x69, 0x6c,
+ 0x64, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x2e,
+ 0x2e, 0x72, 0x65, 0x67, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x2e, 0x22, 0x2c,
+ 0x20, 0x22, 0x2e, 0x2e, 0x73, 0x74, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63,
+ 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x72, 0x65, 0x67,
+ 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x74,
+ 0x79, 0x70, 0x65, 0x2c, 0x20, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x6c, 0x65, 0x6e, 0x28, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x74, 0x79,
+ 0x70, 0x65, 0x29, 0x2c, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a, 0x09,
+ 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x09,
+ 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x6c, 0x65, 0x6e, 0x28, 0x72, 0x65, 0x67, 0x74,
+ 0x79, 0x70, 0x65, 0x29, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x28, 0x62, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x6f, 0x72, 0x20,
+ 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28,
+ 0x72, 0x65, 0x67, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x62, 0x2d, 0x31,
+ 0x2c, 0x20, 0x62, 0x2d, 0x31, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x3a,
+ 0x27, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x73, 0x74,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x72, 0x65, 0x67,
+ 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x62, 0x2d, 0x31,
+ 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x73, 0x75, 0x62, 0x28, 0x73, 0x74, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x62,
+ 0x2d, 0x31, 0x29, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09,
+ 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75,
+ 0x65, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61,
+ 0x6c, 0x73, 0x65, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x74, 0x79,
+ 0x70, 0x65, 0x5f, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x73,
+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x29, 0x0a, 0x0a, 0x09,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x63, 0x68, 0x69, 0x6c, 0x64,
+ 0x0a, 0x09, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x27, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x65,
+ 0x6c, 0x66, 0x2e, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65,
+ 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x66,
+ 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70,
+ 0x61, 0x69, 0x72, 0x73, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x20, 0x64,
+ 0x6f, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x2e, 0x63, 0x6c,
+ 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x27, 0x20, 0x6f, 0x72, 0x20, 0x76, 0x2e,
+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d,
+ 0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x27,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66,
+ 0x20, 0x76, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x76, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65,
+ 0x66, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09,
+ 0x09, 0x09, 0x09, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76,
+ 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x73, 0x5b, 0x74, 0x5d,
+ 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20,
+ 0x76, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x76, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79,
+ 0x70, 0x65, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x09, 0x09, 0x09, 0x09, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
+ 0x76, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5b,
+ 0x74, 0x5d, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09,
+ 0x09, 0x09, 0x09, 0x74, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x3d, 0x20,
+ 0x66, 0x69, 0x6e, 0x64, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6f, 0x6e, 0x5f,
+ 0x63, 0x68, 0x69, 0x6c, 0x64, 0x73, 0x28, 0x76, 0x2c, 0x20, 0x74, 0x29,
+ 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x63, 0x68, 0x69,
+ 0x6c, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x74, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x65, 0x6e,
+ 0x64, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65,
+ 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74,
+ 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x3a, 0x69, 0x73, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x28, 0x74, 0x79,
+ 0x70, 0x65, 0x29, 0x0a, 0x20, 0x69, 0x66, 0x20, 0x67, 0x6c, 0x6f, 0x62,
+ 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x74, 0x79, 0x70,
+ 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x72, 0x65, 0x74,
+ 0x75, 0x72, 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x20, 0x65, 0x6c,
+ 0x73, 0x65, 0x0a, 0x20, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
+ 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
+ 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x73, 0x65, 0x74,
+ 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, 0x74,
+ 0x79, 0x70, 0x65, 0x2c, 0x22, 0x5e, 0x2e, 0x2a, 0x3a, 0x3a, 0x22, 0x2c,
+ 0x22, 0x22, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65,
+ 0x6e, 0x76, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x20, 0x77,
+ 0x68, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x20, 0x64, 0x6f, 0x0a,
+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x65, 0x6e, 0x75,
+ 0x6d, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20, 0x20, 0x20,
+ 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x65, 0x6e,
+ 0x75, 0x6d, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x65, 0x6e, 0x75,
+ 0x6d, 0x73, 0x5b, 0x69, 0x5d, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d,
+ 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x74, 0x79, 0x70, 0x65, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x3d,
+ 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x76, 0x20,
+ 0x3d, 0x20, 0x65, 0x6e, 0x76, 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
+ 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x69, 0x73, 0x76, 0x69, 0x72,
+ 0x74, 0x75, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65,
+ 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+ 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x63,
+ 0x68, 0x75, 0x6e, 0x6b, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x64, 0x6f, 0x70, 0x61, 0x72, 0x73, 0x65,
+ 0x20, 0x28, 0x73, 0x29, 0x0a, 0x2d, 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74,
+ 0x20, 0x28, 0x22, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x22, 0x2e, 0x2e,
+ 0x73, 0x29, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x20, 0x68,
+ 0x6f, 0x6f, 0x6b, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x62, 0x20, 0x3d, 0x20, 0x70, 0x61,
+ 0x72, 0x73, 0x65, 0x72, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x73, 0x29,
+ 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20, 0x73, 0x75, 0x62, 0x20, 0x74, 0x68,
+ 0x65, 0x6e, 0x0a, 0x20, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
+ 0x20, 0x73, 0x75, 0x62, 0x0a, 0x20, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x74,
+ 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x64, 0x6f, 0x0a,
+ 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c,
+ 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x3b, 0x22, 0x29, 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20,
+ 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x09, 0x09, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28,
+ 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x09, 0x65, 0x6e, 0x64,
+ 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74,
+ 0x72, 0x79, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x76, 0x65, 0x72,
+ 0x62, 0x61, 0x74, 0x69, 0x6d, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x20,
+ 0x64, 0x6f, 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62,
+ 0x2c, 0x65, 0x2c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c,
+ 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x24, 0x5c, 0x6e, 0x22, 0x29, 0x0a,
+ 0x20, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74,
+ 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a,
+ 0x20, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
+ 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x4c, 0x75, 0x61, 0x20,
+ 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x63, 0x6f, 0x64,
+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28,
+ 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x5c, 0x31,
+ 0x5c, 0x32, 0x29, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x43, 0x6f, 0x64,
+ 0x65, 0x28, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x63, 0x6f, 0x64,
+ 0x65, 0x2c, 0x32, 0x2c, 0x2d, 0x32, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d,
+ 0x20, 0x74, 0x72, 0x79, 0x20, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a,
+ 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
+ 0x62, 0x2c, 0x65, 0x2c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25,
+ 0x73, 0x2a, 0x28, 0x25, 0x62, 0x5c, 0x33, 0x5c, 0x34, 0x29, 0x22, 0x29,
+ 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x7b, 0x27,
+ 0x2e, 0x2e, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x63, 0x6f, 0x64,
+ 0x65, 0x2c, 0x32, 0x2c, 0x2d, 0x32, 0x29, 0x2e, 0x2e, 0x27, 0x5c, 0x6e,
+ 0x7d, 0x5c, 0x6e, 0x27, 0x0a, 0x09, 0x56, 0x65, 0x72, 0x62, 0x61, 0x74,
+ 0x69, 0x6d, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x76,
+ 0x65, 0x72, 0x62, 0x61, 0x74, 0x69, 0x6d, 0x20, 0x63, 0x6f, 0x64, 0x65,
+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x65, 0x67, 0x69, 0x73,
+ 0x74, 0x65, 0x72, 0x20, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74,
+ 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72,
+ 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20,
+ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20,
+ 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x43, 0x20, 0x63, 0x6f, 0x64,
+ 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, 0x65, 0x61, 0x6d, 0x62,
+ 0x6c, 0x65, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
+ 0x64, 0x6f, 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62,
+ 0x2c, 0x65, 0x2c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c,
+ 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x5c, 0x35, 0x5c,
+ 0x36, 0x29, 0x22, 0x29, 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x09, 0x09, 0x63, 0x6f, 0x64, 0x65,
+ 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75,
+ 0x62, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x2d,
+ 0x32, 0x29, 0x2e, 0x2e, 0x22, 0x5c, 0x6e, 0x22, 0x0a, 0x09, 0x09, 0x56,
+ 0x65, 0x72, 0x62, 0x61, 0x74, 0x69, 0x6d, 0x28, 0x63, 0x6f, 0x64, 0x65,
+ 0x2c, 0x20, 0x27, 0x27, 0x29, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x20, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x09,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d,
+ 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
+ 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x20, 0x64,
+ 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20, 0x64, 0x6f,
+ 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65,
+ 0x2c, 0x70, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73,
+ 0x2a, 0x54, 0x4f, 0x4c, 0x55, 0x41, 0x5f, 0x50, 0x52, 0x4f, 0x50, 0x45,
+ 0x52, 0x54, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x25, 0x73, 0x2a, 0x25,
+ 0x28, 0x2b, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x29, 0x25, 0x73,
+ 0x5d, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x25, 0x29, 0x2b, 0x25, 0x73, 0x2a,
+ 0x3b, 0x3f, 0x22, 0x29, 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x70, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x72, 0x20,
+ 0x70, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x09, 0x09, 0x09, 0x70, 0x74, 0x79,
+ 0x70, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
+ 0x74, 0x22, 0x0a, 0x20, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x09,
+ 0x09, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x72,
+ 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28,
+ 0x70, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x09, 0x20, 0x09, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28,
+ 0x73, 0x2c, 0x20, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x09, 0x65, 0x6e,
+ 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20,
+ 0x74, 0x72, 0x79, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65,
+ 0x64, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72,
+ 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20,
+ 0x64, 0x6f, 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62,
+ 0x2c, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73,
+ 0x2a, 0x54, 0x4f, 0x4c, 0x55, 0x41, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45,
+ 0x43, 0x54, 0x45, 0x44, 0x5f, 0x44, 0x45, 0x53, 0x54, 0x52, 0x55, 0x43,
+ 0x54, 0x4f, 0x52, 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x22, 0x29, 0x0a, 0x09,
+ 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09,
+ 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x5f,
+ 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x65,
+ 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x09, 0x20, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x73,
+ 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64,
+ 0x5f, 0x64, 0x65, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x28,
+ 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a, 0x09, 0x20, 0x09, 0x65, 0x6e, 0x64,
+ 0x0a, 0x20, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
+ 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x65, 0x2b, 0x31,
+ 0x29, 0x0a, 0x20, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64,
+ 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x27, 0x65,
+ 0x78, 0x74, 0x65, 0x72, 0x6e, 0x27, 0x20, 0x6b, 0x65, 0x79, 0x77, 0x6f,
+ 0x72, 0x64, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63,
+ 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20,
+ 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x25,
+ 0x73, 0x2b, 0x22, 0x29, 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x64, 0x6f,
+ 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x09, 0x09,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x20, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x09,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d,
+ 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x27, 0x76, 0x69, 0x72, 0x74, 0x75,
+ 0x61, 0x6c, 0x27, 0x20, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x6b, 0x64,
+ 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x62, 0x2c, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x25, 0x73,
+ 0x2b, 0x22, 0x29, 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x68, 0x6f,
+ 0x64, 0x69, 0x73, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x3d,
+ 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x20, 0x09, 0x09, 0x72, 0x65, 0x74,
+ 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73,
+ 0x2c, 0x20, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x09, 0x65, 0x6e, 0x64,
+ 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74,
+ 0x72, 0x79, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x20, 0x28, 0x70,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2c, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61,
+ 0x74, 0x65, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x29, 0x0a, 0x20, 0x64, 0x6f,
+ 0x0a, 0x20, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65,
+ 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69,
+ 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x25,
+ 0x77, 0x2a, 0x25, 0x73, 0x2a, 0x3a, 0x5b, 0x5e, 0x3a, 0x5d, 0x22, 0x29,
+ 0x0a, 0x20, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x0a, 0x20, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
+ 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x65, 0x29, 0x20,
+ 0x2d, 0x2d, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x5b, 0x5e, 0x3a, 0x5d, 0x0a, 0x20, 0x09, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d,
+ 0x20, 0x74, 0x72, 0x79, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x0a,
+ 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
+ 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f, 0x64,
+ 0x79, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28,
+ 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
+ 0x65, 0x25, 0x73, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d,
+ 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25,
+ 0x62, 0x7b, 0x7d, 0x29, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20,
+ 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
+ 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62,
+ 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
+ 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x29,
+ 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
+ 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29,
+ 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x6e, 0x61, 0x6d,
+ 0x65, 0x73, 0x61, 0x70, 0x63, 0x65, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20,
+ 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x6e,
+ 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25,
+ 0x73, 0x2a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x25,
+ 0x73, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f,
+ 0x25, 0x77, 0x5d, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x7b,
+ 0x7d, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x22, 0x29, 0x0a, 0x20, 0x20,
+ 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
+ 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62,
+ 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f,
+ 0x64, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65,
+ 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20,
+ 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20,
+ 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x6e,
+ 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e,
+ 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x23, 0x64, 0x65,
+ 0x66, 0x69, 0x6e, 0x65, 0x25, 0x73, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e,
+ 0x25, 0x73, 0x5d, 0x2a, 0x29, 0x5b, 0x5e, 0x5c, 0x6e, 0x5d, 0x2a, 0x5c,
+ 0x6e, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20,
+ 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63,
+ 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29,
+ 0x0a, 0x20, 0x20, 0x20, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x28, 0x6e,
+ 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c,
+ 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79,
+ 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x73, 0x0a,
+ 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f,
+ 0x64, 0x79, 0x2c, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22,
+ 0x5e, 0x25, 0x73, 0x2a, 0x65, 0x6e, 0x75, 0x6d, 0x25, 0x73, 0x2b, 0x28,
+ 0x25, 0x53, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x73, 0x3b, 0x5d, 0x2a,
+ 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a,
+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22,
+ 0x23, 0x53, 0x6f, 0x72, 0x72, 0x79, 0x2c, 0x20, 0x64, 0x65, 0x63, 0x6c,
+ 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x65,
+ 0x6e, 0x75, 0x6d, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x76, 0x61, 0x72,
+ 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20,
+ 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x5c, 0x6e,
+ 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x72,
+ 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x73, 0x65,
+ 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x20, 0x28, 0x65, 0x78,
+ 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x3a, 0x20, 0x27, 0x22, 0x2e, 0x2e, 0x6e,
+ 0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61,
+ 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x3b, 0x27, 0x29, 0x22,
+ 0x29, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63,
+ 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62,
+ 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x45,
+ 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x28, 0x6e, 0x61, 0x6d,
+ 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x76, 0x61, 0x72, 0x6e, 0x61,
+ 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65,
+ 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x64, 0x6f, 0x0a, 0x2d, 0x2d,
+ 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c,
+ 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x65, 0x6e, 0x75, 0x6d, 0x25, 0x73, 0x2b, 0x28, 0x25,
+ 0x53, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d, 0x29,
+ 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f,
+ 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a, 0x2d, 0x2d, 0x20,
+ 0x20, 0x20, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x28,
+ 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74,
+ 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a,
+ 0x2d, 0x2d, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x65,
+ 0x6e, 0x64, 0x20, 0x0a, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x62, 0x6f, 0x64,
+ 0x79, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a,
+ 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x25, 0x73, 0x2b, 0x65, 0x6e,
+ 0x75, 0x6d, 0x5b, 0x5e, 0x7b, 0x5d, 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x25, 0x77, 0x5f, 0x5d, 0x5b, 0x5e,
+ 0x25, 0x73, 0x5d, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a,
+ 0x22, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68,
+ 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f,
+ 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20,
+ 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x28, 0x6e, 0x61,
+ 0x6d, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x20,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d,
+ 0x20, 0x74, 0x72, 0x79, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f,
+ 0x72, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x6b,
+ 0x69, 0x6e, 0x64, 0x2c, 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73,
+ 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28,
+ 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77,
+ 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x25, 0x73, 0x25, 0x2a, 0x26, 0x3a, 0x3c,
+ 0x3e, 0x2c, 0x5d, 0x2d, 0x25, 0x73, 0x2b, 0x6f, 0x70, 0x65, 0x72, 0x61,
+ 0x74, 0x6f, 0x72, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x73,
+ 0x5d, 0x5b, 0x5e, 0x25, 0x73, 0x5d, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x28,
+ 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x63, 0x3f, 0x6f,
+ 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29, 0x25, 0x73, 0x2a, 0x3b,
+ 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09,
+ 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x6c, 0x69,
+ 0x6e, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65,
+ 0x63, 0x6c, 0x2c, 0x6b, 0x69, 0x6e, 0x64, 0x2c, 0x61, 0x72, 0x67, 0x2c,
+ 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66,
+ 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28,
+ 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x25, 0x73, 0x25,
+ 0x2a, 0x26, 0x3a, 0x3c, 0x3e, 0x2c, 0x5d, 0x2d, 0x25, 0x73, 0x2b, 0x6f,
+ 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x29, 0x25, 0x73, 0x2a, 0x28,
+ 0x5b, 0x5e, 0x25, 0x73, 0x5d, 0x5b, 0x5e, 0x25, 0x73, 0x5d, 0x2a, 0x29,
+ 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a,
+ 0x28, 0x63, 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29,
+ 0x5b, 0x25, 0x73, 0x5c, 0x6e, 0x5d, 0x2a, 0x25, 0x62, 0x7b, 0x7d, 0x25,
+ 0x73, 0x2a, 0x3b, 0x3f, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
+ 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x09, 0x2d,
+ 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x63, 0x61, 0x73, 0x74, 0x20, 0x6f,
+ 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x09, 0x62,
+ 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x6b, 0x69, 0x6e, 0x64,
+ 0x2c, 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x20,
+ 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x6f, 0x72, 0x29, 0x25, 0x73, 0x2b, 0x28, 0x5b, 0x25, 0x77, 0x5f, 0x3a,
+ 0x25, 0x64, 0x3c, 0x3e, 0x25, 0x2a, 0x25, 0x26, 0x25, 0x73, 0x5d, 0x2b,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73,
+ 0x2a, 0x28, 0x63, 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f,
+ 0x29, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x09, 0x69, 0x66, 0x20, 0x62,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x09, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x69, 0x65, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73,
+ 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x25, 0x62, 0x7b, 0x7d, 0x22,
+ 0x2c, 0x20, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x09, 0x09, 0x69,
+ 0x66, 0x20, 0x69, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
+ 0x09, 0x09, 0x09, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x65, 0x0a, 0x20, 0x20,
+ 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x09, 0x65, 0x6e, 0x64,
+ 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20,
+ 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63,
+ 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29,
+ 0x0a, 0x20, 0x20, 0x20, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72,
+ 0x28, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x6b, 0x69, 0x6e, 0x64, 0x2c, 0x61,
+ 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x29, 0x0a, 0x20, 0x20,
+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73,
+ 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d,
+ 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x2d, 0x2d, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63,
+ 0x6c, 0x2c, 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c,
+ 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x7e, 0x5f, 0x25, 0x77, 0x5d,
+ 0x5b, 0x5f, 0x40, 0x25, 0x77, 0x25, 0x73, 0x25, 0x2a, 0x26, 0x3a, 0x3c,
+ 0x3e, 0x5d, 0x2a, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x29, 0x25, 0x73, 0x2a,
+ 0x28, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x63, 0x3f,
+ 0x6f, 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29, 0x25, 0x73, 0x2a,
+ 0x3d, 0x3f, 0x25, 0x73, 0x2a, 0x30, 0x3f, 0x25, 0x73, 0x2a, 0x3b, 0x25,
+ 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x61, 0x72,
+ 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x2c, 0x76, 0x69, 0x72, 0x74,
+ 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73,
+ 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x28, 0x5c,
+ 0x6e, 0x5d, 0x2b, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x63, 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73,
+ 0x3f, 0x74, 0x3f, 0x29, 0x76, 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f,
+ 0x69, 0x3f, 0x64, 0x3f, 0x65, 0x3f, 0x25, 0x73, 0x2a, 0x6f, 0x3f, 0x76,
+ 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65,
+ 0x3f, 0x25, 0x73, 0x2a, 0x28, 0x3d, 0x3f, 0x25, 0x73, 0x2a, 0x30, 0x3f,
+ 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20,
+ 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68,
+ 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x09, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79,
+ 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x69,
+ 0x74, 0x68, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x0a,
+ 0x20, 0x20, 0x09, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c,
+ 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x7e, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f,
+ 0x40, 0x25, 0x77, 0x25, 0x73, 0x25, 0x2a, 0x26, 0x3a, 0x3c, 0x3e, 0x5d,
+ 0x2a, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x25, 0x62, 0x3c, 0x3e, 0x29, 0x25,
+ 0x73, 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28,
+ 0x63, 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29, 0x76,
+ 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65,
+ 0x3f, 0x25, 0x73, 0x2a, 0x6f, 0x3f, 0x76, 0x3f, 0x65, 0x3f, 0x72, 0x3f,
+ 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65, 0x3f, 0x25, 0x73, 0x2a, 0x3d,
+ 0x3f, 0x25, 0x73, 0x2a, 0x30, 0x3f, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73,
+ 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20,
+ 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x6c, 0x65, 0x74,
+ 0x74, 0x65, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x62, 0x2c, 0x65,
+ 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f,
+ 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e,
+ 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f,
+ 0x25, 0x77, 0x5d, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x63, 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73,
+ 0x3f, 0x74, 0x3f, 0x29, 0x76, 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f,
+ 0x69, 0x3f, 0x64, 0x3f, 0x65, 0x3f, 0x25, 0x73, 0x2a, 0x6f, 0x3f, 0x76,
+ 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65,
+ 0x3f, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20,
+ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
+ 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x0a,
+ 0x20, 0x20, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c,
+ 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x28, 0x3b, 0x5c, 0x6e, 0x5d,
+ 0x2b, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62,
+ 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29,
+ 0x0a, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62,
+ 0x28, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x20, 0x22, 0x25, 0x28, 0x25, 0x73,
+ 0x2a, 0x25, 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x29, 0x5d, 0x2a, 0x29, 0x25,
+ 0x73, 0x2a, 0x25, 0x29, 0x22, 0x2c, 0x20, 0x22, 0x20, 0x25, 0x31, 0x20,
+ 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x09, 0x69, 0x66, 0x20, 0x76, 0x69,
+ 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x76, 0x69, 0x72, 0x74, 0x2c,
+ 0x20, 0x22, 0x5b, 0x3d, 0x30, 0x5d, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x20, 0x20, 0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c,
+ 0x66, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x0a, 0x20, 0x20, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x66,
+ 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x70, 0x75, 0x72, 0x65, 0x5f, 0x76, 0x69,
+ 0x72, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65,
+ 0x0a, 0x20, 0x20, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x09,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72,
+ 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73,
+ 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20,
+ 0x20, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x3d,
+ 0x20, 0x27, 0x6f, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x27,
+ 0x27, 0x0a, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
+ 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x65, 0x63,
+ 0x6c, 0x2c, 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x29,
+ 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
+ 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29,
+ 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x6c,
+ 0x69, 0x6e, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c, 0x61, 0x72,
+ 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74,
+ 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73,
+ 0x2a, 0x28, 0x5b, 0x5e, 0x25, 0x28, 0x5c, 0x6e, 0x5d, 0x2b, 0x29, 0x25,
+ 0x73, 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28,
+ 0x63, 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29, 0x76,
+ 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65,
+ 0x3f, 0x25, 0x73, 0x2a, 0x6f, 0x3f, 0x76, 0x3f, 0x65, 0x3f, 0x72, 0x3f,
+ 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65, 0x3f, 0x5b, 0x5e, 0x3b, 0x7b,
+ 0x5d, 0x2a, 0x25, 0x62, 0x7b, 0x7d, 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x25,
+ 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x2d, 0x2d, 0x6c, 0x6f, 0x63,
+ 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c,
+ 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x7e, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f,
+ 0x40, 0x25, 0x77, 0x25, 0x73, 0x25, 0x2a, 0x26, 0x3a, 0x3c, 0x3e, 0x5d,
+ 0x2a, 0x5b, 0x5f, 0x25, 0x77, 0x3e, 0x5d, 0x29, 0x25, 0x73, 0x2a, 0x28,
+ 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x63, 0x3f, 0x6f,
+ 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29, 0x5b, 0x5e, 0x3b, 0x5d,
+ 0x2a, 0x25, 0x62, 0x7b, 0x7d, 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x25, 0x73,
+ 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
+ 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x2d,
+ 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67,
+ 0x6c, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x66, 0x75,
+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a,
+ 0x20, 0x20, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x2c,
+ 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x29, 0x25, 0x73,
+ 0x2a, 0x28, 0x25, 0x62, 0x28, 0x29, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x63,
+ 0x3f, 0x6f, 0x3f, 0x6e, 0x3f, 0x73, 0x3f, 0x74, 0x3f, 0x29, 0x76, 0x3f,
+ 0x65, 0x3f, 0x72, 0x3f, 0x72, 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65, 0x3f,
+ 0x25, 0x73, 0x2a, 0x6f, 0x3f, 0x76, 0x3f, 0x65, 0x3f, 0x72, 0x3f, 0x72,
+ 0x3f, 0x69, 0x3f, 0x64, 0x3f, 0x65, 0x3f, 0x2e, 0x2d, 0x25, 0x62, 0x7b,
+ 0x7d, 0x25, 0x73, 0x2a, 0x3b, 0x3f, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a,
+ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75,
+ 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74,
+ 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a,
+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20,
+ 0x3d, 0x3d, 0x20, 0x27, 0x6f, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d,
+ 0x20, 0x27, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
+ 0x20, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64,
+ 0x65, 0x63, 0x6c, 0x2c, 0x61, 0x72, 0x67, 0x2c, 0x63, 0x6f, 0x6e, 0x73,
+ 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
+ 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b,
+ 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d,
+ 0x65, 0x2c, 0x62, 0x61, 0x73, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x0a,
+ 0x09, 0x09, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x27, 0x20,
+ 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x27, 0x27, 0x0a, 0x09, 0x09,
+ 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25,
+ 0x73, 0x2a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x25, 0x73, 0x2a, 0x28, 0x5b,
+ 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x40, 0x5d, 0x2a, 0x29,
+ 0x25, 0x73, 0x2a, 0x3b, 0x22, 0x29, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x64,
+ 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0a, 0x09,
+ 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79,
+ 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x69,
+ 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e,
+ 0x0a, 0x09, 0x09, 0x09, 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65,
+ 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73,
+ 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
+ 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25,
+ 0x77, 0x40, 0x5d, 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x22, 0x29, 0x20,
+ 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20,
+ 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66,
+ 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x09, 0x09, 0x09, 0x09, 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65,
+ 0x2c, 0x62, 0x61, 0x73, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22,
+ 0x5e, 0x25, 0x73, 0x2a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x25, 0x73, 0x2a,
+ 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x40, 0x5d,
+ 0x2a, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x7b, 0x5d, 0x2d, 0x29,
+ 0x25, 0x73, 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d, 0x29, 0x25, 0x73, 0x2a,
+ 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x09, 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x62,
+ 0x61, 0x73, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25,
+ 0x73, 0x2a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x25, 0x73, 0x2b, 0x28,
+ 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x40, 0x5d, 0x2a,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x7b, 0x5d, 0x2d, 0x29, 0x25,
+ 0x73, 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d, 0x29, 0x25, 0x73, 0x2a, 0x22,
+ 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x09, 0x09, 0x62, 0x2c, 0x65, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
+ 0x62, 0x61, 0x73, 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x25, 0x73, 0x2a, 0x28,
+ 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x40, 0x5d, 0x2a,
+ 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5e, 0x7b, 0x5d, 0x2d, 0x29, 0x25,
+ 0x73, 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d, 0x29, 0x25, 0x73, 0x2a, 0x22,
+ 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09,
+ 0x09, 0x09, 0x09, 0x09, 0x09, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20,
+ 0x27, 0x27, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x62, 0x2c,
+ 0x65, 0x2c, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x6e, 0x61, 0x6d, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c,
+ 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66,
+ 0x25, 0x73, 0x25, 0x73, 0x2a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x25,
+ 0x73, 0x25, 0x73, 0x2a, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x2a, 0x25, 0x73,
+ 0x2a, 0x28, 0x25, 0x62, 0x7b, 0x7d, 0x29, 0x25, 0x73, 0x2a, 0x28, 0x5b,
+ 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f, 0x25, 0x77, 0x40, 0x5d, 0x2a, 0x29,
+ 0x25, 0x73, 0x2a, 0x3b, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e,
+ 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09,
+ 0x09, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20,
+ 0x3d, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6c,
+ 0x73, 0x65, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x31,
+ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x62, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x62,
+ 0x61, 0x73, 0x65, 0x20, 0x7e, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68,
+ 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x62, 0x61, 0x73, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75,
+ 0x62, 0x28, 0x62, 0x61, 0x73, 0x65, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73,
+ 0x2a, 0x3a, 0x25, 0x73, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a,
+ 0x09, 0x09, 0x09, 0x09, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x62,
+ 0x61, 0x73, 0x65, 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x70, 0x75, 0x62,
+ 0x6c, 0x69, 0x63, 0x25, 0x73, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29,
+ 0x0a, 0x09, 0x09, 0x09, 0x09, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20,
+ 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x62, 0x61, 0x73, 0x65, 0x2c, 0x20,
+ 0x22, 0x2c, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x2d, 0x2d, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x2d, 0x2d, 0x62, 0x2c, 0x65, 0x2c, 0x62, 0x61, 0x73, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x62, 0x61,
+ 0x73, 0x65, 0x2c, 0x22, 0x2e, 0x2d, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d,
+ 0x5b, 0x5f, 0x25, 0x77, 0x3c, 0x3e, 0x2c, 0x3a, 0x5d, 0x2a, 0x29, 0x24,
+ 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09,
+ 0x09, 0x09, 0x09, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x7b, 0x7d,
+ 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x5f,
+ 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c, 0x65,
+ 0x29, 0x0a, 0x09, 0x09, 0x09, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x28, 0x6e,
+ 0x61, 0x6d, 0x65, 0x2c, 0x62, 0x61, 0x73, 0x65, 0x2c, 0x62, 0x6f, 0x64,
+ 0x79, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
+ 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x09, 0x09, 0x09, 0x09, 0x76, 0x61, 0x72, 0x62, 0x2c, 0x76, 0x61, 0x72,
+ 0x65, 0x2c, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20,
+ 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28,
+ 0x73, 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25,
+ 0x77, 0x5d, 0x2b, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x22, 0x2c, 0x20, 0x65,
+ 0x2b, 0x31, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x76,
+ 0x61, 0x72, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x09, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x6e,
+ 0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61,
+ 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x65, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x72, 0x65, 0x0a, 0x09, 0x09, 0x09,
+ 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+ 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74,
+ 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a,
+ 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
+ 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x74, 0x79, 0x70, 0x65,
+ 0x64, 0x65, 0x66, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x74, 0x79, 0x70, 0x65,
+ 0x73, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28,
+ 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a, 0x74, 0x79, 0x70, 0x65, 0x64,
+ 0x65, 0x66, 0x25, 0x73, 0x25, 0x73, 0x2a, 0x28, 0x2e, 0x2d, 0x29, 0x25,
+ 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x69,
+ 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
+ 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62, 0x2c,
+ 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x54, 0x79, 0x70, 0x65, 0x64, 0x65,
+ 0x66, 0x28, 0x74, 0x79, 0x70, 0x65, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d,
+ 0x20, 0x74, 0x72, 0x79, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c,
+ 0x65, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22,
+ 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5f,
+ 0x40, 0x25, 0x73, 0x25, 0x77, 0x25, 0x64, 0x25, 0x2a, 0x26, 0x3a, 0x3c,
+ 0x3e, 0x2c, 0x5d, 0x2a, 0x5b, 0x5f, 0x25, 0x77, 0x25, 0x64, 0x5d, 0x29,
+ 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a, 0x20, 0x20,
+ 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
+ 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x62,
+ 0x2c, 0x65, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
+ 0x6c, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74,
+ 0x5f, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x28, 0x64, 0x65,
+ 0x63, 0x6c, 0x2c, 0x20, 0x22, 0x2c, 0x22, 0x29, 0x0a, 0x09, 0x56, 0x61,
+ 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x6c, 0x69, 0x73, 0x74, 0x5b,
+ 0x31, 0x5d, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x69, 0x73, 0x74,
+ 0x2e, 0x6e, 0x20, 0x3e, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x5f, 0x2c,
+ 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x66, 0x69,
+ 0x6e, 0x64, 0x28, 0x6c, 0x69, 0x73, 0x74, 0x5b, 0x31, 0x5d, 0x2c, 0x20,
+ 0x22, 0x28, 0x2e, 0x2d, 0x29, 0x25, 0x73, 0x2b, 0x28, 0x5b, 0x5e, 0x25,
+ 0x73, 0x5d, 0x2a, 0x29, 0x24, 0x22, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x09,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x20, 0x3d, 0x32, 0x3b, 0x0a,
+ 0x09, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x6c, 0x69, 0x73, 0x74,
+ 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x09, 0x56, 0x61,
+ 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x2e,
+ 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x5b, 0x69,
+ 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x3d, 0x69, 0x2b, 0x31, 0x0a,
+ 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x20,
+ 0x20, 0x20, 0x2d, 0x2d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65,
+ 0x28, 0x64, 0x65, 0x63, 0x6c, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28,
+ 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64,
+ 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x74,
+ 0x72, 0x79, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x64,
+ 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x2c,
+ 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22, 0x5e, 0x25, 0x73, 0x2a,
+ 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x3f, 0x5b, 0x5f, 0x25, 0x73, 0x25,
+ 0x77, 0x25, 0x64, 0x5d, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x25, 0x73, 0x2b,
+ 0x5b, 0x5f, 0x40, 0x25, 0x77, 0x25, 0x64, 0x5d, 0x2a, 0x25, 0x73, 0x2a,
+ 0x25, 0x5b, 0x25, 0x73, 0x2a, 0x25, 0x53, 0x2b, 0x25, 0x73, 0x2a, 0x25,
+ 0x5d, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a,
+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64,
+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73,
+ 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x56, 0x61, 0x72,
+ 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x64, 0x65, 0x63, 0x6c, 0x29, 0x0a,
+ 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74,
+ 0x72, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a,
+ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
+ 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x72, 0x72, 0x61,
+ 0x79, 0x0a, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x20, 0x62, 0x2c, 0x65, 0x2c, 0x64, 0x65, 0x63, 0x6c, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x73, 0x2c, 0x22,
+ 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x5f, 0x25, 0x77, 0x5d, 0x5b, 0x5d,
+ 0x5b, 0x5f, 0x40, 0x25, 0x73, 0x25, 0x77, 0x25, 0x64, 0x25, 0x2a, 0x26,
+ 0x3a, 0x3c, 0x3e, 0x5d, 0x2a, 0x5b, 0x5d, 0x5f, 0x25, 0x77, 0x25, 0x64,
+ 0x5d, 0x29, 0x25, 0x73, 0x2a, 0x3b, 0x25, 0x73, 0x2a, 0x22, 0x29, 0x0a,
+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x20, 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64,
+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x73,
+ 0x2c, 0x62, 0x2c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x41, 0x72, 0x72,
+ 0x61, 0x79, 0x28, 0x64, 0x65, 0x63, 0x6c, 0x29, 0x0a, 0x20, 0x20, 0x20,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x73, 0x75,
+ 0x62, 0x28, 0x73, 0x2c, 0x65, 0x2b, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x2d, 0x2d,
+ 0x20, 0x6e, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
+ 0x0a, 0x20, 0x69, 0x66, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c,
+ 0x22, 0x25, 0x73, 0x25, 0x73, 0x2a, 0x22, 0x2c, 0x22, 0x22, 0x29, 0x20,
+ 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
+ 0x20, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20,
+ 0x3d, 0x20, 0x73, 0x0a, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28,
+ 0x22, 0x23, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f,
+ 0x72, 0x22, 0x29, 0x0a, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20,
+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43,
+ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x70, 0x61, 0x72,
+ 0x73, 0x65, 0x20, 0x28, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x2d, 0x2d, 0x73,
+ 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x6d, 0x65, 0x6d,
+ 0x62, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x3d,
+ 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65,
+ 0x20, 0x73, 0x20, 0x7e, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x64, 0x6f, 0x0a,
+ 0x20, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x64,
+ 0x6f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20,
+ 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x69, 0x73, 0x76, 0x69, 0x72, 0x74,
+ 0x75, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,
+ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a, 0x2d,
+ 0x2d, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x20, 0x74,
+ 0x79, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65,
+ 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x29, 0x0a, 0x0a,
+ 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73,
+ 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63,
+ 0x75, 0x72, 0x72, 0x3a, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70,
+ 0x65, 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x29, 0x0a,
+ 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x65, 0x72, 0x3a, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f,
+ 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x70,
+ 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x09, 0x70, 0x74, 0x79, 0x70, 0x65,
+ 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73,
+ 0x75, 0x62, 0x28, 0x70, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x22, 0x5e,
+ 0x25, 0x73, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09, 0x70,
+ 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x70, 0x74, 0x79, 0x70, 0x65,
+ 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22,
+ 0x29, 0x0a, 0x0a, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x72, 0x6f,
+ 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d,
+ 0x20, 0x70, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x3a,
+ 0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79,
+ 0x5f, 0x74, 0x79, 0x70, 0x65, 0x28, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74,
+ 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x72, 0x6f,
+ 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f,
+ 0x72, 0x20, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x5f, 0x70,
+ 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x28, 0x29, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61,
+ 0x75, 0x6c, 0x74, 0x22, 0x0a, 0x65, 0x6e, 0x64, 0x0a
+};
+unsigned int lua_container_lua_len = 17673;
diff --git a/lib/tolua++/src/bin/function_lua.h b/lib/tolua++/src/bin/function_lua.h
index bcb0bfca2..b34f106d2 100644
--- a/lib/tolua++/src/bin/function_lua.h
+++ b/lib/tolua++/src/bin/function_lua.h
@@ -990,14 +990,15 @@ static const unsigned char lua_function_lua[] = {
0x5f, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x74,
0x29, 0x0a, 0x20, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61,
0x62, 0x6c, 0x65, 0x28, 0x74, 0x2c, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x46,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x0a, 0x0a, 0x20, 0x69,
- 0x66, 0x20, 0x74, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x7e, 0x3d,
- 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64,
+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x0a, 0x20, 0x69, 0x66,
0x20, 0x74, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x7e, 0x3d, 0x20,
- 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x72,
- 0x72, 0x6f, 0x72, 0x28, 0x22, 0x23, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69,
- 0x64, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x27, 0x20, 0x73, 0x70,
- 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
+ 0x27, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20,
+ 0x74, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x7e, 0x3d, 0x20, 0x27,
+ 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x72, 0x72,
+ 0x6f, 0x72, 0x28, 0x22, 0x23, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64,
+ 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x27, 0x20, 0x73, 0x70, 0x65,
+ 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20,
+ 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x74, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74,
0x29, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x61, 0x70, 0x70,
0x65, 0x6e, 0x64, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x69, 0x66, 0x20, 0x74,
0x3a, 0x69, 0x6e, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x28, 0x29, 0x20, 0x74,
@@ -1072,139 +1073,139 @@ static const unsigned char lua_function_lua[] = {
0x0a, 0x20, 0x2d, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20,
0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x28, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x61, 0x2c,
- 0x32, 0x2c, 0x2d, 0x32, 0x29, 0x29, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20,
- 0x6e, 0x6f, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5b, 0x27, 0x57,
- 0x27, 0x5d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
- 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x61, 0x2c, 0x20, 0x22, 0x25,
- 0x2e, 0x25, 0x2e, 0x25, 0x2e, 0x25, 0x73, 0x2a, 0x25, 0x29, 0x22, 0x29,
- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x09, 0x09, 0x77, 0x61, 0x72,
- 0x6e, 0x69, 0x6e, 0x67, 0x28, 0x22, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x76, 0x61, 0x72,
- 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65,
- 0x6e, 0x74, 0x73, 0x20, 0x28, 0x60, 0x2e, 0x2e, 0x2e, 0x27, 0x29, 0x20,
- 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70,
- 0x6f, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x49, 0x67, 0x6e, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x2e, 0x64, 0x2e, 0x2e, 0x61, 0x2e,
- 0x2e, 0x63, 0x29, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a,
- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x6e,
- 0x3d, 0x30, 0x7d, 0x0a, 0x0a, 0x20, 0x09, 0x61, 0x20, 0x3d, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x61,
- 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x25, 0x28, 0x25, 0x29,
- 0x5d, 0x29, 0x25, 0x73, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x22,
- 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x2c, 0x73,
- 0x74, 0x72, 0x69, 0x70, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20,
- 0x73, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x28, 0x73,
- 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x61, 0x2c, 0x32, 0x2c, 0x2d, 0x32,
- 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69,
- 0x70, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x73, 0x74, 0x72,
- 0x73, 0x75, 0x62, 0x28, 0x61, 0x2c, 0x31, 0x2c, 0x2d, 0x32, 0x29, 0x2c,
- 0x20, 0x31, 0x2c, 0x20, 0x2d, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x6c, 0x65, 0x6e, 0x28, 0x6c, 0x61, 0x73, 0x74, 0x29, 0x2b, 0x31,
- 0x29, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e,
- 0x73, 0x20, 0x3d, 0x20, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x74, 0x2c, 0x20,
- 0x22, 0x2c, 0x22, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x6c, 0x61, 0x73, 0x74,
- 0x2d, 0x31, 0x29, 0x0a, 0x0a, 0x09, 0x09, 0x6e, 0x73, 0x20, 0x3d, 0x20,
- 0x22, 0x28, 0x22, 0x2e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x67, 0x73, 0x75, 0x62, 0x28, 0x6e, 0x73, 0x2c, 0x20, 0x22, 0x25, 0x73,
- 0x2a, 0x2c, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29,
- 0x2e, 0x2e, 0x27, 0x29, 0x27, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x6e, 0x73,
- 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x64, 0x65, 0x66,
- 0x61, 0x75, 0x6c, 0x74, 0x73, 0x28, 0x6e, 0x73, 0x29, 0x0a, 0x0a, 0x09,
- 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x46,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x2c, 0x20, 0x6e,
- 0x73, 0x2c, 0x20, 0x63, 0x29, 0x0a, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20,
- 0x69, 0x3d, 0x31, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6f, 0x0a,
- 0x09, 0x09, 0x09, 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x74, 0x5b,
- 0x69, 0x5d, 0x2c, 0x20, 0x22, 0x3d, 0x2e, 0x2a, 0x24, 0x22, 0x2c, 0x20,
- 0x22, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65,
- 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74,
- 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x2e, 0x6e,
- 0x20, 0x3d, 0x20, 0x6c, 0x2e, 0x6e, 0x2b, 0x31, 0x0a, 0x20, 0x20, 0x6c,
- 0x5b, 0x6c, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x44, 0x65, 0x63, 0x6c,
- 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x5b, 0x69, 0x5d,
- 0x2c, 0x27, 0x76, 0x61, 0x72, 0x27, 0x2c, 0x74, 0x72, 0x75, 0x65, 0x29,
- 0x0a, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66,
- 0x20, 0x3d, 0x20, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x28, 0x64, 0x2c, 0x27, 0x66, 0x75, 0x6e, 0x63, 0x27, 0x29,
- 0x0a, 0x20, 0x66, 0x2e, 0x61, 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x6c,
- 0x0a, 0x20, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20,
- 0x63, 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x46,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x29, 0x0a, 0x65,
- 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x70,
- 0x2c, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2c, 0x20, 0x6c, 0x61, 0x73,
- 0x74, 0x29, 0x0a, 0x0a, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x3d,
- 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x0a,
- 0x09, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x61, 0x73, 0x74,
- 0x20, 0x6f, 0x72, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x67, 0x65,
- 0x74, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x6c, 0x73, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x22, 0x22, 0x0a, 0x09,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20,
- 0x22, 0x22, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f,
- 0x6f, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09,
- 0x66, 0x6f, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x72, 0x73,
- 0x74, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6f, 0x0a, 0x0a, 0x09,
- 0x09, 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x74, 0x2e, 0x2e,
- 0x6c, 0x73, 0x65, 0x70, 0x2e, 0x2e, 0x74, 0x5b, 0x69, 0x5d, 0x0a, 0x09,
- 0x09, 0x6c, 0x73, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x70, 0x0a,
- 0x09, 0x09, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75,
- 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e,
- 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x74, 0x68, 0x65, 0x6e,
- 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22,
- 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x72,
- 0x69, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x28, 0x73, 0x29, 0x0a, 0x0a,
- 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73,
- 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
- 0x73, 0x28, 0x73, 0x2c, 0x20, 0x27, 0x2c, 0x27, 0x29, 0x0a, 0x09, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x3d,
- 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72,
- 0x20, 0x69, 0x3d, 0x74, 0x2e, 0x6e, 0x2c, 0x31, 0x2c, 0x2d, 0x31, 0x20,
- 0x64, 0x6f, 0x0a, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
- 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70,
- 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x28,
- 0x74, 0x5b, 0x69, 0x5d, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09,
- 0x09, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x0a, 0x09,
- 0x09, 0x09, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x72,
- 0x75, 0x65, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x2d,
- 0x2d, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x74, 0x68,
- 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x09, 0x74, 0x5b, 0x69, 0x5d,
- 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73,
- 0x75, 0x62, 0x28, 0x74, 0x5b, 0x69, 0x5d, 0x2c, 0x20, 0x22, 0x3d, 0x2e,
- 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x2d,
- 0x2d, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x2c, 0x73, 0x74, 0x72,
- 0x69, 0x70, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x0a, 0x0a, 0x65, 0x6e, 0x64,
- 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x70, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
- 0x73, 0x28, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73,
- 0x2c, 0x20, 0x22, 0x5e, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29,
- 0x0a, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x25, 0x29,
- 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69,
- 0x74, 0x5f, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x28, 0x73,
- 0x2c, 0x20, 0x22, 0x2c, 0x22, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x73, 0x65, 0x70, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x20, 0x3d,
- 0x20, 0x22, 0x22, 0x2c, 0x22, 0x22, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20,
- 0x69, 0x3d, 0x31, 0x2c, 0x74, 0x2e, 0x6e, 0x20, 0x64, 0x6f, 0x0a, 0x09,
- 0x09, 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69,
- 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x74, 0x5b, 0x69, 0x5d,
- 0x2c, 0x20, 0x22, 0x3d, 0x2e, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22,
- 0x29, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65,
- 0x74, 0x2e, 0x2e, 0x73, 0x65, 0x70, 0x2e, 0x2e, 0x74, 0x5b, 0x69, 0x5d,
- 0x0a, 0x09, 0x09, 0x73, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x22, 0x2c, 0x22,
- 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x22, 0x28, 0x22, 0x2e, 0x2e, 0x72, 0x65, 0x74, 0x2e,
- 0x2e, 0x22, 0x29, 0x22, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a
+ 0x32, 0x2c, 0x2d, 0x32, 0x29, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5b, 0x27, 0x57, 0x27,
+ 0x5d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x61, 0x2c, 0x20, 0x22, 0x25, 0x2e,
+ 0x25, 0x2e, 0x25, 0x2e, 0x25, 0x73, 0x2a, 0x25, 0x29, 0x22, 0x29, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x09, 0x09, 0x77, 0x61, 0x72, 0x6e,
+ 0x69, 0x6e, 0x67, 0x28, 0x22, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x76, 0x61, 0x72, 0x69,
+ 0x61, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x20, 0x28, 0x60, 0x2e, 0x2e, 0x2e, 0x27, 0x29, 0x20, 0x61,
+ 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f,
+ 0x72, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x2e, 0x64, 0x2e, 0x2e, 0x61, 0x2e, 0x2e,
+ 0x63, 0x29, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
+ 0x6e, 0x69, 0x6c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a, 0x20,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x3d, 0x31, 0x0a, 0x20, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d,
+ 0x30, 0x7d, 0x0a, 0x0a, 0x20, 0x09, 0x61, 0x20, 0x3d, 0x20, 0x73, 0x74,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x61, 0x2c,
+ 0x20, 0x22, 0x25, 0x73, 0x2a, 0x28, 0x5b, 0x25, 0x28, 0x25, 0x29, 0x5d,
+ 0x29, 0x25, 0x73, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x22, 0x29,
+ 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x2c, 0x73, 0x74,
+ 0x72, 0x69, 0x70, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x73,
+ 0x74, 0x72, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x28, 0x73, 0x74,
+ 0x72, 0x73, 0x75, 0x62, 0x28, 0x61, 0x2c, 0x32, 0x2c, 0x2d, 0x32, 0x29,
+ 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x73, 0x74, 0x72, 0x73,
+ 0x75, 0x62, 0x28, 0x61, 0x2c, 0x31, 0x2c, 0x2d, 0x32, 0x29, 0x2c, 0x20,
+ 0x31, 0x2c, 0x20, 0x2d, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x6c, 0x65, 0x6e, 0x28, 0x6c, 0x61, 0x73, 0x74, 0x29, 0x2b, 0x31, 0x29,
+ 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x73,
+ 0x20, 0x3d, 0x20, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x74, 0x2c, 0x20, 0x22,
+ 0x2c, 0x22, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x2d,
+ 0x31, 0x29, 0x0a, 0x0a, 0x09, 0x09, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x22,
+ 0x28, 0x22, 0x2e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67,
+ 0x73, 0x75, 0x62, 0x28, 0x6e, 0x73, 0x2c, 0x20, 0x22, 0x25, 0x73, 0x2a,
+ 0x2c, 0x25, 0x73, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x2e,
+ 0x2e, 0x27, 0x29, 0x27, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x6e, 0x73, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x64, 0x65, 0x66, 0x61,
+ 0x75, 0x6c, 0x74, 0x73, 0x28, 0x6e, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x09,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x46, 0x75,
+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x2c, 0x20, 0x6e, 0x73,
+ 0x2c, 0x20, 0x63, 0x29, 0x0a, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69,
+ 0x3d, 0x31, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6f, 0x0a, 0x09,
+ 0x09, 0x09, 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x74, 0x5b, 0x69,
+ 0x5d, 0x2c, 0x20, 0x22, 0x3d, 0x2e, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22,
+ 0x22, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x5b,
+ 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x6c, 0x2e, 0x6e, 0x20,
+ 0x3d, 0x20, 0x6c, 0x2e, 0x6e, 0x2b, 0x31, 0x0a, 0x20, 0x20, 0x6c, 0x5b,
+ 0x6c, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x44, 0x65, 0x63, 0x6c, 0x61,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x5b, 0x69, 0x5d, 0x2c,
+ 0x27, 0x76, 0x61, 0x72, 0x27, 0x2c, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a,
+ 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x20, 0x65,
+ 0x6e, 0x64, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20,
+ 0x3d, 0x20, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x28, 0x64, 0x2c, 0x27, 0x66, 0x75, 0x6e, 0x63, 0x27, 0x29, 0x0a,
+ 0x20, 0x66, 0x2e, 0x61, 0x72, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x0a,
+ 0x20, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x63,
+ 0x0a, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x46, 0x75,
+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x29, 0x0a, 0x65, 0x6e,
+ 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x70, 0x2c,
+ 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2c, 0x20, 0x6c, 0x61, 0x73, 0x74,
+ 0x29, 0x0a, 0x0a, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x3d, 0x20,
+ 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x0a, 0x09,
+ 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20,
+ 0x6f, 0x72, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x67, 0x65, 0x74,
+ 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
+ 0x6c, 0x73, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x22, 0x22, 0x0a, 0x09, 0x6c,
+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x22,
+ 0x22, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x6f,
+ 0x70, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x66,
+ 0x6f, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74,
+ 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6f, 0x0a, 0x0a, 0x09, 0x09,
+ 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x74, 0x2e, 0x2e, 0x6c,
+ 0x73, 0x65, 0x70, 0x2e, 0x2e, 0x74, 0x5b, 0x69, 0x5d, 0x0a, 0x09, 0x09,
+ 0x6c, 0x73, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x70, 0x0a, 0x09,
+ 0x09, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65,
+ 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a,
+ 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x72, 0x65, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66,
+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69,
+ 0x70, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x28, 0x73, 0x29, 0x0a, 0x0a, 0x09,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70,
+ 0x6c, 0x69, 0x74, 0x5f, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73,
+ 0x28, 0x73, 0x2c, 0x20, 0x27, 0x2c, 0x27, 0x29, 0x0a, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x3d, 0x20,
+ 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x6c, 0x61, 0x73, 0x74, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20,
+ 0x69, 0x3d, 0x74, 0x2e, 0x6e, 0x2c, 0x31, 0x2c, 0x2d, 0x31, 0x20, 0x64,
+ 0x6f, 0x0a, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20,
+ 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x61,
+ 0x72, 0x61, 0x6d, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x74,
+ 0x5b, 0x69, 0x5d, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09,
+ 0x09, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x0a, 0x09, 0x09,
+ 0x09, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75,
+ 0x65, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x2d, 0x2d,
+ 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x74, 0x68, 0x65,
+ 0x6e, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x09, 0x74, 0x5b, 0x69, 0x5d, 0x20,
+ 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75,
+ 0x62, 0x28, 0x74, 0x5b, 0x69, 0x5d, 0x2c, 0x20, 0x22, 0x3d, 0x2e, 0x2a,
+ 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x2d, 0x2d,
+ 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72,
+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x2c, 0x73, 0x74, 0x72, 0x69,
+ 0x70, 0x2c, 0x6c, 0x61, 0x73, 0x74, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74,
+ 0x72, 0x69, 0x70, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73,
+ 0x28, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x74,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c,
+ 0x20, 0x22, 0x5e, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a,
+ 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x25, 0x29, 0x24,
+ 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f, 0x63,
+ 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74,
+ 0x5f, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x28, 0x73, 0x2c,
+ 0x20, 0x22, 0x2c, 0x22, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x73, 0x65, 0x70, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20,
+ 0x22, 0x22, 0x2c, 0x22, 0x22, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69,
+ 0x3d, 0x31, 0x2c, 0x74, 0x2e, 0x6e, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09,
+ 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x74, 0x5b, 0x69, 0x5d, 0x2c,
+ 0x20, 0x22, 0x3d, 0x2e, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29,
+ 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x74,
+ 0x2e, 0x2e, 0x73, 0x65, 0x70, 0x2e, 0x2e, 0x74, 0x5b, 0x69, 0x5d, 0x0a,
+ 0x09, 0x09, 0x73, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x22, 0x2c, 0x22, 0x0a,
+ 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x22, 0x28, 0x22, 0x2e, 0x2e, 0x72, 0x65, 0x74, 0x2e, 0x2e,
+ 0x22, 0x29, 0x22, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x0a
};
-unsigned int lua_function_lua_len = 14483;
+unsigned int lua_function_lua_len = 14494;
diff --git a/lib/tolua++/src/bin/lua/container.lua b/lib/tolua++/src/bin/lua/container.lua
index 2d11db7df..99488479e 100644
--- a/lib/tolua++/src/bin/lua/container.lua
+++ b/lib/tolua++/src/bin/lua/container.lua
@@ -58,7 +58,7 @@ function classContainer:hasvar ()
while self[i] do
if self[i]:isvariable() then
return 1
- end
+ end
i = i+1
end
return 0
@@ -568,7 +568,7 @@ function classContainer:doparse (s)
-- Enumerate(name,body)
-- return strsub(s,e+1)
-- end
--- end
+-- end
do
local b,e,body,name = strfind(s,"^%s*typedef%s+enum[^{]*(%b{})%s*([%w_][^%s]*)%s*;%s*")
@@ -606,14 +606,14 @@ function classContainer:doparse (s)
-- try function
do
--local b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w])%s*(%b())%s*(c?o?n?s?t?)%s*=?%s*0?%s*;%s*")
- local b,e,decl,arg,const,virt = strfind(s,"^%s*([^%(\n]+)%s*(%b())%s*(c?o?n?s?t?)%s*(=?%s*0?)%s*;%s*")
+ local b,e,decl,arg,const,virt = strfind(s,"^%s*([^%(\n]+)%s*(%b())%s*(c?o?n?s?t?)v?e?r?r?i?d?e?%s*o?v?e?r?r?i?d?e?%s*(=?%s*0?)%s*;%s*")
if not b then
-- try function with template
- b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w]%b<>)%s*(%b())%s*(c?o?n?s?t?)%s*=?%s*0?%s*;%s*")
+ b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w]%b<>)%s*(%b())%s*(c?o?n?s?t?)v?e?r?r?i?d?e?%s*o?v?e?r?r?i?d?e?%s*=?%s*0?%s*;%s*")
end
if not b then
-- try a single letter function name
- b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?)%s*;%s*")
+ b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?)v?e?r?r?i?d?e?%s*o?v?e?r?r?i?d?e?%s*;%s*")
end
if not b then
-- try function pointer
@@ -629,6 +629,9 @@ function classContainer:doparse (s)
end
end
_curr_code = strsub(s,b,e)
+ if const == 'o' then
+ const = ''
+ end
Function(decl,arg,const)
return strsub(s,e+1)
end
@@ -636,14 +639,17 @@ function classContainer:doparse (s)
-- try inline function
do
- local b,e,decl,arg,const = strfind(s,"^%s*([^%(\n]+)%s*(%b())%s*(c?o?n?s?t?)[^;{]*%b{}%s*;?%s*")
+ local b,e,decl,arg,const = strfind(s,"^%s*([^%(\n]+)%s*(%b())%s*(c?o?n?s?t?)v?e?r?r?i?d?e?%s*o?v?e?r?r?i?d?e?[^;{]*%b{}%s*;?%s*")
--local b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w>])%s*(%b())%s*(c?o?n?s?t?)[^;]*%b{}%s*;?%s*")
if not b then
-- try a single letter function name
- b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?).-%b{}%s*;?%s*")
+ b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?)v?e?r?r?i?d?e?%s*o?v?e?r?r?i?d?e?.-%b{}%s*;?%s*")
end
if b then
_curr_code = strsub(s,b,e)
+ if const == 'o' then
+ const = ''
+ end
Function(decl,arg,const)
return strsub(s,e+1)
end
diff --git a/lib/tolua++/src/bin/lua/function.lua b/lib/tolua++/src/bin/lua/function.lua
index 3b6b53c5e..9338e0fbc 100644
--- a/lib/tolua++/src/bin/lua/function.lua
+++ b/lib/tolua++/src/bin/lua/function.lua
@@ -458,9 +458,8 @@ end
-- Internal constructor
function _Function (t)
setmetatable(t,classFunction)
-
if t.const ~= 'const' and t.const ~= '' then
- error("#invalid 'const' specification")
+ error("#invalid 'const' specification: " .. t.const)
end
append(t)
@@ -489,7 +488,6 @@ end
function Function (d,a,c)
--local t = split(strsub(a,2,-2),',') -- eliminate braces
--local t = split_params(strsub(a,2,-2))
-
if not flags['W'] and string.find(a, "%.%.%.%s*%)") then
warning("Functions with variable arguments (`...') are not supported. Ignoring "..d..a..c)
diff --git a/lib/tolua++/src/bin/toluabind.c b/lib/tolua++/src/bin/toluabind.c
index 06b371f70..e72b4b13c 100644
--- a/lib/tolua++/src/bin/toluabind.c
+++ b/lib/tolua++/src/bin/toluabind.c
@@ -1013,1170 +1013,8 @@ TOLUA_API int tolua_tolua_open (lua_State* tolua_S)
{ /* begin embedded lua code */
int top = lua_gettop(tolua_S);
- static unsigned char B[] = {
- 45, 45, 32,116,111,108,117, 97, 58, 32, 99,111,110,116, 97,
- 105,110,101,114, 32, 97, 98,115,116,114, 97, 99,116, 32, 99,
- 108, 97,115,115, 10, 45, 45, 32, 87,114,105,116,116,101,110,
- 32, 98,121, 32, 87, 97,108,100,101,109, 97,114, 32, 67,101,
- 108,101,115, 10, 45, 45, 32, 84,101, 67, 71,114, 97,102, 47,
- 80, 85, 67, 45, 82,105,111, 10, 45, 45, 32, 74,117,108, 32,
- 49, 57, 57, 56, 10, 45, 45, 32, 36, 73,100, 58, 32, 36, 10,
- 10, 45, 45, 32, 84,104,105,115, 32, 99,111,100,101, 32,105,
- 115, 32,102,114,101,101, 32,115,111,102,116,119, 97,114,101,
- 59, 32,121,111,117, 32, 99, 97,110, 32,114,101,100,105,115,
- 116,114,105, 98,117,116,101, 32,105,116, 32, 97,110,100, 47,
- 111,114, 32,109,111,100,105,102,121, 32,105,116, 46, 10, 45,
- 45, 32, 84,104,101, 32,115,111,102,116,119, 97,114,101, 32,
- 112,114,111,118,105,100,101,100, 32,104,101,114,101,117,110,
- 100,101,114, 32,105,115, 32,111,110, 32, 97,110, 32, 34, 97,
- 115, 32,105,115, 34, 32, 98, 97,115,105,115, 44, 32, 97,110,
- 100, 10, 45, 45, 32,116,104,101, 32, 97,117,116,104,111,114,
- 32,104, 97,115, 32,110,111, 32,111, 98,108,105,103, 97,116,
- 105,111,110, 32,116,111, 32,112,114,111,118,105,100,101, 32,
- 109, 97,105,110,116,101,110, 97,110, 99,101, 44, 32,115,117,
- 112,112,111,114,116, 44, 32,117,112,100, 97,116,101,115, 44,
- 10, 45, 45, 32,101,110,104, 97,110, 99,101,109,101,110,116,
- 115, 44, 32,111,114, 32,109,111,100,105,102,105, 99, 97,116,
- 105,111,110,115, 46, 10, 10, 45, 45, 32,116, 97, 98,108,101,
- 32,116,111, 32,115,116,111,114,101, 32,110, 97,109,101,115,
- 112, 97, 99,101,100, 32,116,121,112,101,100,101,102,115, 47,
- 101,110,117,109,115, 32,105,110, 32,103,108,111, 98, 97,108,
- 32,115, 99,111,112,101, 10,103,108,111, 98, 97,108, 95,116,
- 121,112,101,100,101,102,115, 32, 61, 32,123,125, 10,103,108,
- 111, 98, 97,108, 95,101,110,117,109,115, 32, 61, 32,123,125,
- 10, 10, 45, 45, 32, 67,111,110,116, 97,105,110,101,114, 32,
- 99,108, 97,115,115, 10, 45, 45, 32, 82,101,112,114,101,115,
- 101,110,116,115, 32, 97, 32, 99,111,110,116, 97,105,110,101,
- 114, 32,111,102, 32,102,101, 97,116,117,114,101,115, 32,116,
- 111, 32, 98,101, 32, 98,111,117,110,100, 10, 45, 45, 32,116,
- 111, 32,108,117, 97, 46, 10, 99,108, 97,115,115, 67,111,110,
- 116, 97,105,110,101,114, 32, 61, 10,123, 10, 32, 99,117,114,
- 114, 32, 61, 32,110,105,108, 44, 10,125, 10, 99,108, 97,115,
- 115, 67,111,110,116, 97,105,110,101,114, 46, 95, 95,105,110,
- 100,101,120, 32, 61, 32, 99,108, 97,115,115, 67,111,110,116,
- 97,105,110,101,114, 10,115,101,116,109,101,116, 97,116, 97,
- 98,108,101, 40, 99,108, 97,115,115, 67,111,110,116, 97,105,
- 110,101,114, 44, 99,108, 97,115,115, 70,101, 97,116,117,114,
- 101, 41, 10, 10, 45, 45, 32,111,117,116,112,117,116, 32,116,
- 97,103,115, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
- 97,115,115, 67,111,110,116, 97,105,110,101,114, 58,100,101,
- 99,108,116,121,112,101, 32, 40, 41, 10, 32,112,117,115,104,
- 40,115,101,108,102, 41, 10, 32,108,111, 99, 97,108, 32,105,
- 61, 49, 10, 32,119,104,105,108,101, 32,115,101,108,102, 91,
- 105, 93, 32,100,111, 10, 32, 32,115,101,108,102, 91,105, 93,
- 58,100,101, 99,108,116,121,112,101, 40, 41, 10, 32, 32,105,
- 32, 61, 32,105, 43, 49, 10, 32,101,110,100, 10, 32,112,111,
- 112, 40, 41, 10,101,110,100, 10, 10, 10, 45, 45, 32,119,114,
- 105,116,101, 32,115,117,112,112,111,114,116, 32, 99,111,100,
- 101, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
- 115, 67,111,110,116, 97,105,110,101,114, 58,115,117,112, 99,
- 111,100,101, 32, 40, 41, 10, 10, 9,105,102, 32,110,111,116,
- 32,115,101,108,102, 58, 99,104,101, 99,107, 95,112,117, 98,
- 108,105, 99, 95, 97, 99, 99,101,115,115, 40, 41, 32,116,104,
- 101,110, 10, 9, 9,114,101,116,117,114,110, 10, 9,101,110,
- 100, 10, 10, 32,112,117,115,104, 40,115,101,108,102, 41, 10,
- 32,108,111, 99, 97,108, 32,105, 61, 49, 10, 32,119,104,105,
- 108,101, 32,115,101,108,102, 91,105, 93, 32,100,111, 10, 32,
- 32,105,102, 32,115,101,108,102, 91,105, 93, 58, 99,104,101,
- 99,107, 95,112,117, 98,108,105, 99, 95, 97, 99, 99,101,115,
- 115, 40, 41, 32,116,104,101,110, 10, 32, 32, 9,115,101,108,
- 102, 91,105, 93, 58,115,117,112, 99,111,100,101, 40, 41, 10,
- 32, 32,101,110,100, 10, 32, 32,105, 32, 61, 32,105, 43, 49,
- 10, 32,101,110,100, 10, 32,112,111,112, 40, 41, 10,101,110,
- 100, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,
- 115,115, 67,111,110,116, 97,105,110,101,114, 58,104, 97,115,
- 118, 97,114, 32, 40, 41, 10, 32,108,111, 99, 97,108, 32,105,
- 61, 49, 10, 32,119,104,105,108,101, 32,115,101,108,102, 91,
- 105, 93, 32,100,111, 10, 32, 32,105,102, 32,115,101,108,102,
- 91,105, 93, 58,105,115,118, 97,114,105, 97, 98,108,101, 40,
- 41, 32,116,104,101,110, 10, 9, 9, 32,114,101,116,117,114,
- 110, 32, 49, 10, 9, 9,101,110,100, 10, 32, 32,105, 32, 61,
- 32,105, 43, 49, 10, 32,101,110,100, 10, 9,114,101,116,117,
- 114,110, 32, 48, 10,101,110,100, 10, 10, 45, 45, 32, 73,110,
- 116,101,114,110, 97,108, 32, 99,111,110,116, 97,105,110,101,
- 114, 32, 99,111,110,115,116,114,117, 99,116,111,114, 10,102,
- 117,110, 99,116,105,111,110, 32, 95, 67,111,110,116, 97,105,
- 110,101,114, 32, 40,115,101,108,102, 41, 10, 32,115,101,116,
- 109,101,116, 97,116, 97, 98,108,101, 40,115,101,108,102, 44,
- 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 41,
- 10, 32,115,101,108,102, 46,110, 32, 61, 32, 48, 10, 32,115,
- 101,108,102, 46,116,121,112,101,100,101,102,115, 32, 61, 32,
- 123,116,111,108,117, 97, 95,110, 61, 48,125, 10, 32,115,101,
- 108,102, 46,117,115,101,114,116,121,112,101,115, 32, 61, 32,
- 123,125, 10, 32,115,101,108,102, 46,101,110,117,109,115, 32,
- 61, 32,123,116,111,108,117, 97, 95,110, 61, 48,125, 10, 32,
- 115,101,108,102, 46,108,110, 97,109,101,115, 32, 61, 32,123,
- 125, 10, 32,114,101,116,117,114,110, 32,115,101,108,102, 10,
- 101,110,100, 10, 10, 45, 45, 32,112,117,115,104, 32, 99,111,
- 110,116, 97,105,110,101,114, 10,102,117,110, 99,116,105,111,
- 110, 32,112,117,115,104, 32, 40,116, 41, 10, 9,116, 46,112,
- 114,111,120, 32, 61, 32, 99,108, 97,115,115, 67,111,110,116,
- 97,105,110,101,114, 46, 99,117,114,114, 10, 32, 99,108, 97,
- 115,115, 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,
- 114, 32, 61, 32,116, 10,101,110,100, 10, 10, 45, 45, 32,112,
- 111,112, 32, 99,111,110,116, 97,105,110,101,114, 10,102,117,
- 110, 99,116,105,111,110, 32,112,111,112, 32, 40, 41, 10, 45,
- 45,112,114,105,110,116, 40, 34,110, 97,109,101, 34, 44, 99,
- 108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 46, 99,
- 117,114,114, 46,110, 97,109,101, 41, 10, 45, 45,102,111,114,
- 101, 97, 99,104, 40, 99,108, 97,115,115, 67,111,110,116, 97,
- 105,110,101,114, 46, 99,117,114,114, 46,117,115,101,114,116,
- 121,112,101,115, 44,112,114,105,110,116, 41, 10, 45, 45,112,
- 114,105,110,116, 40, 34, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 34, 41, 10, 32, 99,108, 97,115,115, 67,
- 111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 32, 61,
- 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114,
- 46, 99,117,114,114, 46,112,114,111,120, 10,101,110,100, 10,
- 10, 45, 45, 32,103,101,116, 32, 99,117,114,114,101,110,116,
- 32,110, 97,109,101,115,112, 97, 99,101, 10,102,117,110, 99,
- 116,105,111,110, 32,103,101,116, 99,117,114,114,110, 97,109,
- 101,115,112, 97, 99,101, 32, 40, 41, 10, 9,114,101,116,117,
- 114,110, 32,103,101,116,110, 97,109,101,115,112, 97, 99,101,
- 40, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114,
- 46, 99,117,114,114, 41, 10,101,110,100, 10, 10, 45, 45, 32,
- 97,112,112,101,110,100, 32,116,111, 32, 99,117,114,114,101,
- 110,116, 32, 99,111,110,116, 97,105,110,101,114, 10,102,117,
- 110, 99,116,105,111,110, 32, 97,112,112,101,110,100, 32, 40,
- 116, 41, 10, 32,114,101,116,117,114,110, 32, 99,108, 97,115,
- 115, 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114,
- 58, 97,112,112,101,110,100, 40,116, 41, 10,101,110,100, 10,
- 10, 45, 45, 32, 97,112,112,101,110,100, 32,116,121,112,101,
- 100,101,102, 32,116,111, 32, 99,117,114,114,101,110,116, 32,
- 99,111,110,116, 97,105,110,101,114, 10,102,117,110, 99,116,
- 105,111,110, 32, 97,112,112,101,110,100,116,121,112,101,100,
- 101,102, 32, 40,116, 41, 10, 32,114,101,116,117,114,110, 32,
- 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 46,
- 99,117,114,114, 58, 97,112,112,101,110,100,116,121,112,101,
- 100,101,102, 40,116, 41, 10,101,110,100, 10, 10, 45, 45, 32,
- 97,112,112,101,110,100, 32,117,115,101,114,116,121,112,101,
- 32,116,111, 32, 99,117,114,114,101,110,116, 32, 99,111,110,
- 116, 97,105,110,101,114, 10,102,117,110, 99,116,105,111,110,
- 32, 97,112,112,101,110,100,117,115,101,114,116,121,112,101,
- 32, 40,116, 41, 10, 32,114,101,116,117,114,110, 32, 99,108,
- 97,115,115, 67,111,110,116, 97,105,110,101,114, 46, 99,117,
- 114,114, 58, 97,112,112,101,110,100,117,115,101,114,116,121,
- 112,101, 40,116, 41, 10,101,110,100, 10, 10, 45, 45, 32, 97,
- 112,112,101,110,100, 32,101,110,117,109, 32,116,111, 32, 99,
- 117,114,114,101,110,116, 32, 99,111,110,116, 97,105,110,101,
- 114, 10,102,117,110, 99,116,105,111,110, 32, 97,112,112,101,
- 110,100,101,110,117,109, 32, 40,116, 41, 10, 32,114,101,116,
- 117,114,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,
- 110,101,114, 46, 99,117,114,114, 58, 97,112,112,101,110,100,
- 101,110,117,109, 40,116, 41, 10,101,110,100, 10, 10, 45, 45,
- 32,115,117, 98,115,116,105,116,117,116,101, 32,116,121,112,
- 101,100,101,102, 10,102,117,110, 99,116,105,111,110, 32, 97,
- 112,112,108,121,116,121,112,101,100,101,102, 32, 40,109,111,
- 100, 44,116,121,112,101, 41, 10, 32,114,101,116,117,114,110,
- 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114,
- 46, 99,117,114,114, 58, 97,112,112,108,121,116,121,112,101,
- 100,101,102, 40,109,111,100, 44,116,121,112,101, 41, 10,101,
- 110,100, 10, 10, 45, 45, 32, 99,104,101, 99,107, 32,105,102,
- 32,105,115, 32,116,121,112,101, 10,102,117,110, 99,116,105,
- 111,110, 32,102,105,110,100,116,121,112,101, 32, 40,116,121,
- 112,101, 41, 10, 32,108,111, 99, 97,108, 32,116, 32, 61, 32,
- 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 46,
- 99,117,114,114, 58,102,105,110,100,116,121,112,101, 40,116,
- 121,112,101, 41, 10, 9,114,101,116,117,114,110, 32,116, 10,
- 101,110,100, 10, 10, 45, 45, 32, 99,104,101, 99,107, 32,105,
- 102, 32,105,115, 32,116,121,112,101,100,101,102, 10,102,117,
- 110, 99,116,105,111,110, 32,105,115,116,121,112,101,100,101,
- 102, 32, 40,116,121,112,101, 41, 10, 32,114,101,116,117,114,
- 110, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,
- 114, 46, 99,117,114,114, 58,105,115,116,121,112,101,100,101,
- 102, 40,116,121,112,101, 41, 10,101,110,100, 10, 10, 45, 45,
- 32,103,101,116, 32,102,117,108,108,116,121,112,101, 32, 40,
- 119,105,116,104, 32,110, 97,109,101,115,112, 97, 99,101, 41,
- 10,102,117,110, 99,116,105,111,110, 32,102,117,108,108,116,
- 121,112,101, 32, 40,116, 41, 10, 32,108,111, 99, 97,108, 32,
- 99,117,114,114, 32, 61, 32, 32, 99,108, 97,115,115, 67,111,
- 110,116, 97,105,110,101,114, 46, 99,117,114,114, 10, 9,119,
- 104,105,108,101, 32, 99,117,114,114, 32,100,111, 10, 9, 32,
- 105,102, 32, 99,117,114,114, 32,116,104,101,110, 10, 9, 9,
- 32,105,102, 32, 99,117,114,114, 46,116,121,112,101,100,101,
- 102,115, 32, 97,110,100, 32, 99,117,114,114, 46,116,121,112,
- 101,100,101,102,115, 91,116, 93, 32,116,104,101,110, 10, 9,
- 9, 32, 32,114,101,116,117,114,110, 32, 99,117,114,114, 46,
- 116,121,112,101,100,101,102,115, 91,116, 93, 10, 9, 9, 32,
- 101,108,115,101,105,102, 32, 99,117,114,114, 46,117,115,101,
- 114,116,121,112,101,115, 32, 97,110,100, 32, 99,117,114,114,
- 46,117,115,101,114,116,121,112,101,115, 91,116, 93, 32,116,
- 104,101,110, 10, 9, 9, 32, 32,114,101,116,117,114,110, 32,
- 99,117,114,114, 46,117,115,101,114,116,121,112,101,115, 91,
- 116, 93, 10, 9, 9, 9,101,110,100, 10, 9, 9,101,110,100,
- 10, 9, 32, 99,117,114,114, 32, 61, 32, 99,117,114,114, 46,
- 112,114,111,120, 10, 9,101,110,100, 10, 9,114,101,116,117,
- 114,110, 32,116, 10,101,110,100, 10, 10, 45, 45, 32, 99,104,
- 101, 99,107,115, 32,105,102, 32,105,116, 32,114,101,113,117,
- 105,114,101,115, 32, 99,111,108,108,101, 99,116,105,111,110,
- 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115,
- 67,111,110,116, 97,105,110,101,114, 58,114,101,113,117,105,
- 114,101, 99,111,108,108,101, 99,116,105,111,110, 32, 40,116,
- 41, 10, 32,112,117,115,104, 40,115,101,108,102, 41, 10, 32,
- 108,111, 99, 97,108, 32,105, 61, 49, 10, 9,108,111, 99, 97,
- 108, 32,114, 32, 61, 32,102, 97,108,115,101, 10, 32,119,104,
- 105,108,101, 32,115,101,108,102, 91,105, 93, 32,100,111, 10,
- 32, 32,114, 32, 61, 32,115,101,108,102, 91,105, 93, 58,114,
- 101,113,117,105,114,101, 99,111,108,108,101, 99,116,105,111,
- 110, 40,116, 41, 32,111,114, 32,114, 10, 32, 32,105, 32, 61,
- 32,105, 43, 49, 10, 32,101,110,100, 10, 9,112,111,112, 40,
- 41, 10, 9,114,101,116,117,114,110, 32,114, 10,101,110,100,
- 10, 10, 10, 45, 45, 32,103,101,116, 32,110, 97,109,101,115,
- 97,112, 99,101, 10,102,117,110, 99,116,105,111,110, 32,103,
- 101,116,110, 97,109,101,115,112, 97, 99,101, 32, 40, 99,117,
- 114,114, 41, 10, 9,108,111, 99, 97,108, 32,110, 97,109,101,
- 115,112, 97, 99,101, 32, 61, 32, 39, 39, 10, 9,119,104,105,
- 108,101, 32, 99,117,114,114, 32,100,111, 10, 9, 32,105,102,
- 32, 99,117,114,114, 32, 97,110,100, 10, 9, 9, 32, 32, 32,
- 40, 32, 99,117,114,114, 46, 99,108, 97,115,115,116,121,112,
- 101, 32, 61, 61, 32, 39, 99,108, 97,115,115, 39, 32,111,114,
- 32, 99,117,114,114, 46, 99,108, 97,115,115,116,121,112,101,
- 32, 61, 61, 32, 39,110, 97,109,101,115,112, 97, 99,101, 39,
- 41, 10, 9, 9,116,104,101,110, 10, 9, 9, 32,110, 97,109,
- 101,115,112, 97, 99,101, 32, 61, 32, 40, 99,117,114,114, 46,
- 111,114,105,103,105,110, 97,108, 95,110, 97,109,101, 32,111,
- 114, 32, 99,117,114,114, 46,110, 97,109,101, 41, 32, 46, 46,
- 32, 39, 58, 58, 39, 32, 46, 46, 32,110, 97,109,101,115,112,
- 97, 99,101, 10, 9, 9, 32, 45, 45,110, 97,109,101,115,112,
- 97, 99,101, 32, 61, 32, 99,117,114,114, 46,110, 97,109,101,
- 32, 46, 46, 32, 39, 58, 58, 39, 32, 46, 46, 32,110, 97,109,
- 101,115,112, 97, 99,101, 10, 9, 9,101,110,100, 10, 9, 32,
- 99,117,114,114, 32, 61, 32, 99,117,114,114, 46,112,114,111,
- 120, 10, 9,101,110,100, 10, 9,114,101,116,117,114,110, 32,
- 110, 97,109,101,115,112, 97, 99,101, 10,101,110,100, 10, 10,
- 45, 45, 32,103,101,116, 32,110, 97,109,101,115,112, 97, 99,
- 101, 32, 40,111,110,108,121, 32,110, 97,109,101,115,112, 97,
- 99,101, 41, 10,102,117,110, 99,116,105,111,110, 32,103,101,
- 116,111,110,108,121,110, 97,109,101,115,112, 97, 99,101, 32,
- 40, 41, 10, 32,108,111, 99, 97,108, 32, 99,117,114,114, 32,
- 61, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,
- 114, 46, 99,117,114,114, 10, 9,108,111, 99, 97,108, 32,110,
- 97,109,101,115,112, 97, 99,101, 32, 61, 32, 39, 39, 10, 9,
- 119,104,105,108,101, 32, 99,117,114,114, 32,100,111, 10, 9,
- 9,105,102, 32, 99,117,114,114, 46, 99,108, 97,115,115,116,
- 121,112,101, 32, 61, 61, 32, 39, 99,108, 97,115,115, 39, 32,
- 116,104,101,110, 10, 9, 9, 32,114,101,116,117,114,110, 32,
- 110, 97,109,101,115,112, 97, 99,101, 10, 9, 9,101,108,115,
- 101,105,102, 32, 99,117,114,114, 46, 99,108, 97,115,115,116,
- 121,112,101, 32, 61, 61, 32, 39,110, 97,109,101,115,112, 97,
- 99,101, 39, 32,116,104,101,110, 10, 9, 9, 32,110, 97,109,
- 101,115,112, 97, 99,101, 32, 61, 32, 99,117,114,114, 46,110,
- 97,109,101, 32, 46, 46, 32, 39, 58, 58, 39, 32, 46, 46, 32,
- 110, 97,109,101,115,112, 97, 99,101, 10, 9, 9,101,110,100,
- 10, 9, 32, 99,117,114,114, 32, 61, 32, 99,117,114,114, 46,
- 112,114,111,120, 10, 9,101,110,100, 10, 9,114,101,116,117,
- 114,110, 32,110, 97,109,101,115,112, 97, 99,101, 10,101,110,
- 100, 10, 10, 45, 45, 32, 99,104,101, 99,107, 32,105,102, 32,
- 105,115, 32,101,110,117,109, 10,102,117,110, 99,116,105,111,
- 110, 32,105,115,101,110,117,109, 32, 40,116,121,112,101, 41,
- 10, 32,114,101,116,117,114,110, 32, 99,108, 97,115,115, 67,
- 111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 58,105,
- 115,101,110,117,109, 40,116,121,112,101, 41, 10,101,110,100,
- 10, 10, 45, 45, 32, 97,112,112,101,110,100, 32,102,101, 97,
- 116,117,114,101, 32,116,111, 32, 99,111,110,116, 97,105,110,
- 101,114, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,
- 115,115, 67,111,110,116, 97,105,110,101,114, 58, 97,112,112,
- 101,110,100, 32, 40,116, 41, 10, 32,115,101,108,102, 46,110,
- 32, 61, 32,115,101,108,102, 46,110, 32, 43, 32, 49, 10, 32,
- 115,101,108,102, 91,115,101,108,102, 46,110, 93, 32, 61, 32,
- 116, 10, 32,116, 46,112, 97,114,101,110,116, 32, 61, 32,115,
- 101,108,102, 10,101,110,100, 10, 10, 45, 45, 32, 97,112,112,
- 101,110,100, 32,116,121,112,101,100,101,102, 10,102,117,110,
- 99,116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,116,
- 97,105,110,101,114, 58, 97,112,112,101,110,100,116,121,112,
- 101,100,101,102, 32, 40,116, 41, 10, 32,108,111, 99, 97,108,
- 32,110, 97,109,101,115,112, 97, 99,101, 32, 61, 32,103,101,
- 116,110, 97,109,101,115,112, 97, 99,101, 40, 99,108, 97,115,
- 115, 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114,
- 41, 10, 32,115,101,108,102, 46,116,121,112,101,100,101,102,
- 115, 46,116,111,108,117, 97, 95,110, 32, 61, 32,115,101,108,
- 102, 46,116,121,112,101,100,101,102,115, 46,116,111,108,117,
- 97, 95,110, 32, 43, 32, 49, 10, 32,115,101,108,102, 46,116,
- 121,112,101,100,101,102,115, 91,115,101,108,102, 46,116,121,
- 112,101,100,101,102,115, 46,116,111,108,117, 97, 95,110, 93,
- 32, 61, 32,116, 10, 9,115,101,108,102, 46,116,121,112,101,
- 100,101,102,115, 91,116, 46,117,116,121,112,101, 93, 32, 61,
- 32,110, 97,109,101,115,112, 97, 99,101, 32, 46, 46, 32,116,
- 46,117,116,121,112,101, 10, 9,103,108,111, 98, 97,108, 95,
- 116,121,112,101,100,101,102,115, 91,110, 97,109,101,115,112,
- 97, 99,101, 46, 46,116, 46,117,116,121,112,101, 93, 32, 61,
- 32,116, 10, 9,116, 46,102,116,121,112,101, 32, 61, 32,102,
- 105,110,100,116,121,112,101, 40,116, 46,116,121,112,101, 41,
- 32,111,114, 32,116, 46,116,121,112,101, 10, 9, 45, 45,112,
- 114,105,110,116, 40, 34, 97,112,112,101,110,100,105,110,103,
- 32,116,121,112,101,100,101,102, 32, 34, 46, 46,116, 46,117,
- 116,121,112,101, 46, 46, 34, 32, 97,115, 32, 34, 46, 46,110,
- 97,109,101,115,112, 97, 99,101, 46, 46,116, 46,117,116,121,
- 112,101, 46, 46, 34, 32,119,105,116,104, 32,102,116,121,112,
- 101, 32, 34, 46, 46,116, 46,102,116,121,112,101, 41, 10, 9,
- 97,112,112,101,110,100, 95,103,108,111, 98, 97,108, 95,116,
- 121,112,101, 40,110, 97,109,101,115,112, 97, 99,101, 46, 46,
- 116, 46,117,116,121,112,101, 41, 10, 9,105,102, 32,116, 46,
- 102,116,121,112,101, 32, 97,110,100, 32,105,115,101,110,117,
- 109, 40,116, 46,102,116,121,112,101, 41, 32,116,104,101,110,
- 10, 10, 9, 9,103,108,111, 98, 97,108, 95,101,110,117,109,
- 115, 91,110, 97,109,101,115,112, 97, 99,101, 46, 46,116, 46,
- 117,116,121,112,101, 93, 32, 61, 32,116,114,117,101, 10, 9,
- 101,110,100, 10,101,110,100, 10, 10, 45, 45, 32, 97,112,112,
- 101,110,100, 32,117,115,101,114,116,121,112,101, 58, 32,114,
- 101,116,117,114,110, 32,102,117,108,108, 32,116,121,112,101,
- 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115,
- 67,111,110,116, 97,105,110,101,114, 58, 97,112,112,101,110,
- 100,117,115,101,114,116,121,112,101, 32, 40,116, 41, 10, 9,
- 108,111, 99, 97,108, 32, 99,111,110,116, 97,105,110,101,114,
- 10, 9,105,102, 32,116, 32, 61, 61, 32, 40,115,101,108,102,
- 46,111,114,105,103,105,110, 97,108, 95,110, 97,109,101, 32,
- 111,114, 32,115,101,108,102, 46,110, 97,109,101, 41, 32,116,
- 104,101,110, 10, 9, 9, 99,111,110,116, 97,105,110,101,114,
- 32, 61, 32,115,101,108,102, 46,112,114,111,120, 10, 9,101,
- 108,115,101, 10, 9, 9, 99,111,110,116, 97,105,110,101,114,
- 32, 61, 32,115,101,108,102, 10, 9,101,110,100, 10, 9,108,
- 111, 99, 97,108, 32,102,116, 32, 61, 32,103,101,116,110, 97,
- 109,101,115,112, 97, 99,101, 40, 99,111,110,116, 97,105,110,
- 101,114, 41, 32, 46, 46, 32,116, 10, 9, 99,111,110,116, 97,
- 105,110,101,114, 46,117,115,101,114,116,121,112,101,115, 91,
- 116, 93, 32, 61, 32,102,116, 10, 9, 95,117,115,101,114,116,
- 121,112,101, 91,102,116, 93, 32, 61, 32,102,116, 10, 9,114,
- 101,116,117,114,110, 32,102,116, 10,101,110,100, 10, 10, 45,
- 45, 32, 97,112,112,101,110,100, 32,101,110,117,109, 10,102,
- 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 67,111,
- 110,116, 97,105,110,101,114, 58, 97,112,112,101,110,100,101,
- 110,117,109, 32, 40,116, 41, 10, 32,108,111, 99, 97,108, 32,
- 110, 97,109,101,115,112, 97, 99,101, 32, 61, 32,103,101,116,
- 110, 97,109,101,115,112, 97, 99,101, 40, 99,108, 97,115,115,
- 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 41,
- 10, 32,115,101,108,102, 46,101,110,117,109,115, 46,116,111,
- 108,117, 97, 95,110, 32, 61, 32,115,101,108,102, 46,101,110,
- 117,109,115, 46,116,111,108,117, 97, 95,110, 32, 43, 32, 49,
- 10, 32,115,101,108,102, 46,101,110,117,109,115, 91,115,101,
- 108,102, 46,101,110,117,109,115, 46,116,111,108,117, 97, 95,
- 110, 93, 32, 61, 32,116, 10, 9,103,108,111, 98, 97,108, 95,
- 101,110,117,109,115, 91,110, 97,109,101,115,112, 97, 99,101,
- 46, 46,116, 46,110, 97,109,101, 93, 32, 61, 32,116, 10,101,
- 110,100, 10, 10, 45, 45, 32,100,101,116,101,114,109,105,110,
- 101, 32,108,117, 97, 32,102,117,110, 99,116,105,111,110, 32,
- 110, 97,109,101, 32,111,118,101,114,108,111, 97,100, 10,102,
- 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 67,111,
- 110,116, 97,105,110,101,114, 58,111,118,101,114,108,111, 97,
- 100, 32, 40,108,110, 97,109,101, 41, 10, 32,105,102, 32,110,
- 111,116, 32,115,101,108,102, 46,108,110, 97,109,101,115, 91,
- 108,110, 97,109,101, 93, 32,116,104,101,110, 10, 32, 32,115,
- 101,108,102, 46,108,110, 97,109,101,115, 91,108,110, 97,109,
- 101, 93, 32, 61, 32, 48, 10, 32,101,108,115,101, 10, 32, 32,
- 115,101,108,102, 46,108,110, 97,109,101,115, 91,108,110, 97,
- 109,101, 93, 32, 61, 32,115,101,108,102, 46,108,110, 97,109,
- 101,115, 91,108,110, 97,109,101, 93, 32, 43, 32, 49, 10, 32,
- 101,110,100, 10, 32,114,101,116,117,114,110, 32,102,111,114,
- 109, 97,116, 40, 34, 37, 48, 50,100, 34, 44,115,101,108,102,
- 46,108,110, 97,109,101,115, 91,108,110, 97,109,101, 93, 41,
- 10,101,110,100, 10, 10, 45, 45, 32, 97,112,112,108,105,101,
- 115, 32,116,121,112,101,100,101,102, 58, 32,114,101,116,117,
- 114,110,115, 32,116,104,101, 32, 39,116,104,101, 32,102, 97,
- 99,116,111, 39, 32,109,111,100,105,102,105,101,114, 32, 97,
- 110,100, 32,116,121,112,101, 10,102,117,110, 99,116,105,111,
- 110, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,
- 114, 58, 97,112,112,108,121,116,121,112,101,100,101,102, 32,
- 40,109,111,100, 44,116,121,112,101, 41, 10, 9,105,102, 32,
- 103,108,111, 98, 97,108, 95,116,121,112,101,100,101,102,115,
- 91,116,121,112,101, 93, 32,116,104,101,110, 10, 9, 9, 45,
- 45,112,114,105,110,116, 40, 34,102,111,117,110,100, 32,116,
- 121,112,101,100,101,102, 32, 34, 46, 46,103,108,111, 98, 97,
- 108, 95,116,121,112,101,100,101,102,115, 91,116,121,112,101,
- 93, 46,116,121,112,101, 41, 10, 9, 9,108,111, 99, 97,108,
- 32,109,111,100, 49, 44, 32,116,121,112,101, 49, 32, 61, 32,
- 103,108,111, 98, 97,108, 95,116,121,112,101,100,101,102,115,
- 91,116,121,112,101, 93, 46,109,111,100, 44, 32,103,108,111,
- 98, 97,108, 95,116,121,112,101,100,101,102,115, 91,116,121,
- 112,101, 93, 46,102,116,121,112,101, 10, 9, 9,108,111, 99,
- 97,108, 32,109,111,100, 50, 44, 32,116,121,112,101, 50, 32,
- 61, 32, 97,112,112,108,121,116,121,112,101,100,101,102, 40,
- 109,111,100, 46, 46, 34, 32, 34, 46, 46,109,111,100, 49, 44,
- 32,116,121,112,101, 49, 41, 10, 9, 9, 45, 45,114,101,116,
- 117,114,110, 32,109,111,100, 50, 32, 46, 46, 32, 39, 32, 39,
- 32, 46, 46, 32,109,111,100, 49, 44, 32,116,121,112,101, 50,
- 10, 9, 9,114,101,116,117,114,110, 32,109,111,100, 50, 44,
- 32,116,121,112,101, 50, 10, 9,101,110,100, 10, 9,100,111,
- 32,114,101,116,117,114,110, 32,109,111,100, 44,116,121,112,
- 101, 32,101,110,100, 10,101,110,100, 10, 10, 45, 45, 32, 99,
- 104,101, 99,107, 32,105,102, 32,105,116, 32,105,115, 32, 97,
- 32,116,121,112,101,100,101,102, 10,102,117,110, 99,116,105,
- 111,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,
- 101,114, 58,105,115,116,121,112,101,100,101,102, 32, 40,116,
- 121,112,101, 41, 10, 32,108,111, 99, 97,108, 32,101,110,118,
- 32, 61, 32,115,101,108,102, 10, 32,119,104,105,108,101, 32,
- 101,110,118, 32,100,111, 10, 32, 32,105,102, 32,101,110,118,
- 46,116,121,112,101,100,101,102,115, 32,116,104,101,110, 10,
- 32, 32, 32,108,111, 99, 97,108, 32,105, 61, 49, 10, 32, 32,
- 32,119,104,105,108,101, 32,101,110,118, 46,116,121,112,101,
- 100,101,102,115, 91,105, 93, 32,100,111, 10, 32, 32, 32, 32,
- 105,102, 32,101,110,118, 46,116,121,112,101,100,101,102,115,
- 91,105, 93, 46,117,116,121,112,101, 32, 61, 61, 32,116,121,
- 112,101, 32,116,104,101,110, 10, 32, 32, 32, 32, 32, 32, 32,
- 32, 32,114,101,116,117,114,110, 32,116,121,112,101, 10, 32,
- 32, 32, 32, 32, 32, 32, 32,101,110,100, 10, 32, 32, 32, 32,
- 32, 32, 32, 32,105, 32, 61, 32,105, 43, 49, 10, 32, 32, 32,
- 101,110,100, 10, 32, 32,101,110,100, 10, 32, 32,101,110,118,
- 32, 61, 32,101,110,118, 46,112, 97,114,101,110,116, 10, 32,
- 101,110,100, 10, 32,114,101,116,117,114,110, 32,110,105,108,
- 10,101,110,100, 10, 10,102,117,110, 99,116,105,111,110, 32,
- 102,105,110,100, 95,101,110,117,109, 95,118, 97,114, 40,118,
- 97,114, 41, 10, 10, 9,105,102, 32,116,111,110,117,109, 98,
- 101,114, 40,118, 97,114, 41, 32,116,104,101,110, 32,114,101,
- 116,117,114,110, 32,118, 97,114, 32,101,110,100, 10, 10, 9,
- 108,111, 99, 97,108, 32, 99, 32, 61, 32, 99,108, 97,115,115,
- 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 10,
- 9,119,104,105,108,101, 32, 99, 32,100,111, 10, 9, 9,108,
- 111, 99, 97,108, 32,110,115, 32, 61, 32,103,101,116,110, 97,
- 109,101,115,112, 97, 99,101, 40, 99, 41, 10, 9, 9,102,111,
- 114, 32,107, 44,118, 32,105,110, 32,112, 97,105,114,115, 40,
- 95,103,108,111, 98, 97,108, 95,101,110,117,109,115, 41, 32,
- 100,111, 10, 9, 9, 9,105,102, 32,109, 97,116, 99,104, 95,
- 116,121,112,101, 40,118, 97,114, 44, 32,118, 44, 32,110,115,
- 41, 32,116,104,101,110, 10, 9, 9, 9, 9,114,101,116,117,
- 114,110, 32,118, 10, 9, 9, 9,101,110,100, 10, 9, 9,101,
- 110,100, 10, 9, 9,105,102, 32, 99, 46, 98, 97,115,101, 32,
- 97,110,100, 32, 99, 46, 98, 97,115,101, 32,126, 61, 32, 39,
- 39, 32,116,104,101,110, 10, 9, 9, 9, 99, 32, 61, 32, 95,
- 103,108,111, 98, 97,108, 95, 99,108, 97,115,115,101,115, 91,
- 99, 58,102,105,110,100,116,121,112,101, 40, 99, 46, 98, 97,
- 115,101, 41, 93, 10, 9, 9,101,108,115,101, 10, 9, 9, 9,
- 99, 32, 61, 32,110,105,108, 10, 9, 9,101,110,100, 10, 9,
- 101,110,100, 10, 10, 9,114,101,116,117,114,110, 32,118, 97,
- 114, 10,101,110,100, 10, 10, 45, 45, 32, 99,104,101, 99,107,
- 32,105,102, 32,105,115, 32, 97, 32,114,101,103,105,115,116,
- 101,114,101,100, 32,116,121,112,101, 58, 32,114,101,116,117,
- 114,110, 32,102,117,108,108, 32,116,121,112,101, 32,111,114,
- 32,110,105,108, 10,102,117,110, 99,116,105,111,110, 32, 99,
- 108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 58,102,
- 105,110,100,116,121,112,101, 32, 40,116, 41, 10, 10, 9,116,
- 32, 61, 32,115,116,114,105,110,103, 46,103,115,117, 98, 40,
- 116, 44, 32, 34, 61, 46, 42, 34, 44, 32, 34, 34, 41, 10, 9,
- 105,102, 32, 95, 98, 97,115,105, 99, 91,116, 93, 32,116,104,
- 101,110, 10, 9, 32,114,101,116,117,114,110, 32,116, 10, 9,
- 101,110,100, 10, 10, 9,108,111, 99, 97,108, 32, 95, 44, 95,
- 44,101,109, 32, 61, 32,115,116,114,105,110,103, 46,102,105,
- 110,100, 40,116, 44, 32, 34, 40, 91, 38, 37, 42, 93, 41, 37,
- 115, 42, 36, 34, 41, 10, 9,116, 32, 61, 32,115,116,114,105,
- 110,103, 46,103,115,117, 98, 40,116, 44, 32, 34, 37,115, 42,
- 40, 91, 38, 37, 42, 93, 41, 37,115, 42, 36, 34, 44, 32, 34,
- 34, 41, 10, 9,112, 32, 61, 32,115,101,108,102, 10, 9,119,
- 104,105,108,101, 32,112, 32, 97,110,100, 32,116,121,112,101,
- 40,112, 41, 61, 61, 39,116, 97, 98,108,101, 39, 32,100,111,
- 10, 9, 9,108,111, 99, 97,108, 32,115,116, 32, 61, 32,103,
- 101,116,110, 97,109,101,115,112, 97, 99,101, 40,112, 41, 10,
- 10, 9, 9,102,111,114, 32,105, 61, 95,103,108,111, 98, 97,
- 108, 95,116,121,112,101,115, 46,110, 44, 49, 44, 45, 49, 32,
- 100,111, 32, 45, 45, 32,105,110, 32,114,101,118,101,114,115,
- 101, 32,111,114,100,101,114, 10, 10, 9, 9, 9,105,102, 32,
- 109, 97,116, 99,104, 95,116,121,112,101, 40,116, 44, 32, 95,
- 103,108,111, 98, 97,108, 95,116,121,112,101,115, 91,105, 93,
- 44, 32,115,116, 41, 32,116,104,101,110, 10, 9, 9, 9, 9,
- 114,101,116,117,114,110, 32, 95,103,108,111, 98, 97,108, 95,
- 116,121,112,101,115, 91,105, 93, 46, 46, 40,101,109, 32,111,
- 114, 32, 34, 34, 41, 10, 9, 9, 9,101,110,100, 10, 9, 9,
- 101,110,100, 10, 9, 9,105,102, 32,112, 46, 98, 97,115,101,
- 32, 97,110,100, 32,112, 46, 98, 97,115,101, 32,126, 61, 32,
- 39, 39, 32, 97,110,100, 32,112, 46, 98, 97,115,101, 32,126,
- 61, 32,116, 32,116,104,101,110, 10, 9, 9, 9, 45, 45,112,
- 114,105,110,116, 40, 34,116,121,112,101, 32,105,115, 32, 34,
- 46, 46,116, 46, 46, 34, 44, 32,112, 32,105,115, 32, 34, 46,
- 46,112, 46, 98, 97,115,101, 46, 46, 34, 32,115,101,108,102,
- 46,116,121,112,101, 32,105,115, 32, 34, 46, 46,115,101,108,
- 102, 46,116,121,112,101, 46, 46, 34, 32,115,101,108,102, 46,
- 110, 97,109,101, 32,105,115, 32, 34, 46, 46,115,101,108,102,
- 46,110, 97,109,101, 41, 10, 9, 9, 9,112, 32, 61, 32, 95,
- 103,108,111, 98, 97,108, 95, 99,108, 97,115,115,101,115, 91,
- 112, 58,102,105,110,100,116,121,112,101, 40,112, 46, 98, 97,
- 115,101, 41, 93, 10, 9, 9,101,108,115,101, 10, 9, 9, 9,
- 112, 32, 61, 32,110,105,108, 10, 9, 9,101,110,100, 10, 9,
- 101,110,100, 10, 10, 9,114,101,116,117,114,110, 32,110,105,
- 108, 10,101,110,100, 10, 10,102,117,110, 99,116,105,111,110,
- 32, 97,112,112,101,110,100, 95,103,108,111, 98, 97,108, 95,
- 116,121,112,101, 40,116, 44, 32, 99,108, 97,115,115, 41, 10,
- 9, 95,103,108,111, 98, 97,108, 95,116,121,112,101,115, 46,
- 110, 32, 61, 32, 95,103,108,111, 98, 97,108, 95,116,121,112,
- 101,115, 46,110, 32, 43, 49, 10, 9, 95,103,108,111, 98, 97,
- 108, 95,116,121,112,101,115, 91, 95,103,108,111, 98, 97,108,
- 95,116,121,112,101,115, 46,110, 93, 32, 61, 32,116, 10, 9,
- 95,103,108,111, 98, 97,108, 95,116,121,112,101,115, 95,104,
- 97,115,104, 91,116, 93, 32, 61, 32, 49, 10, 9,105,102, 32,
- 99,108, 97,115,115, 32,116,104,101,110, 32, 97,112,112,101,
- 110,100, 95, 99,108, 97,115,115, 95,116,121,112,101, 40,116,
- 44, 32, 99,108, 97,115,115, 41, 32,101,110,100, 10,101,110,
- 100, 10, 10,102,117,110, 99,116,105,111,110, 32, 97,112,112,
- 101,110,100, 95, 99,108, 97,115,115, 95,116,121,112,101, 40,
- 116, 44, 99,108, 97,115,115, 41, 10, 9,105,102, 32, 95,103,
- 108,111, 98, 97,108, 95, 99,108, 97,115,115,101,115, 91,116,
- 93, 32,116,104,101,110, 10, 9, 9, 99,108, 97,115,115, 46,
- 102,108, 97,103,115, 32, 61, 32, 95,103,108,111, 98, 97,108,
- 95, 99,108, 97,115,115,101,115, 91,116, 93, 46,102,108, 97,
- 103,115, 10, 9, 9, 99,108, 97,115,115, 46,108,110, 97,109,
- 101,115, 32, 61, 32, 95,103,108,111, 98, 97,108, 95, 99,108,
- 97,115,115,101,115, 91,116, 93, 46,108,110, 97,109,101,115,
- 10, 9, 9,105,102, 32, 95,103,108,111, 98, 97,108, 95, 99,
- 108, 97,115,115,101,115, 91,116, 93, 46, 98, 97,115,101, 32,
- 97,110,100, 32, 40, 95,103,108,111, 98, 97,108, 95, 99,108,
- 97,115,115,101,115, 91,116, 93, 46, 98, 97,115,101, 32,126,
- 61, 32, 39, 39, 41, 32,116,104,101,110, 10, 9, 9, 9, 99,
- 108, 97,115,115, 46, 98, 97,115,101, 32, 61, 32, 95,103,108,
- 111, 98, 97,108, 95, 99,108, 97,115,115,101,115, 91,116, 93,
- 46, 98, 97,115,101, 32,111,114, 32, 99,108, 97,115,115, 46,
- 98, 97,115,101, 10, 9, 9,101,110,100, 10, 9,101,110,100,
- 10, 9, 95,103,108,111, 98, 97,108, 95, 99,108, 97,115,115,
- 101,115, 91,116, 93, 32, 61, 32, 99,108, 97,115,115, 10, 9,
- 99,108, 97,115,115, 46,102,108, 97,103,115, 32, 61, 32, 99,
- 108, 97,115,115, 46,102,108, 97,103,115, 32,111,114, 32,123,
- 125, 10,101,110,100, 10, 10,102,117,110, 99,116,105,111,110,
- 32,109, 97,116, 99,104, 95,116,121,112,101, 40, 99,104,105,
- 108,100,116,121,112,101, 44, 32,114,101,103,116,121,112,101,
- 44, 32,115,116, 41, 10, 45, 45,112,114,105,110,116, 40, 34,
- 102,105,110,100,116,121,112,101, 32, 34, 46, 46, 99,104,105,
- 108,100,116,121,112,101, 46, 46, 34, 44, 32, 34, 46, 46,114,
- 101,103,116,121,112,101, 46, 46, 34, 44, 32, 34, 46, 46,115,
- 116, 41, 10, 9,108,111, 99, 97,108, 32, 98, 44,101, 32, 61,
- 32,115,116,114,105,110,103, 46,102,105,110,100, 40,114,101,
- 103,116,121,112,101, 44, 32, 99,104,105,108,100,116,121,112,
- 101, 44, 32, 45,115,116,114,105,110,103, 46,108,101,110, 40,
- 99,104,105,108,100,116,121,112,101, 41, 44, 32,116,114,117,
- 101, 41, 10, 9,105,102, 32, 98, 32,116,104,101,110, 10, 10,
- 9, 9,105,102, 32,101, 32, 61, 61, 32,115,116,114,105,110,
- 103, 46,108,101,110, 40,114,101,103,116,121,112,101, 41, 32,
- 97,110,100, 10, 9, 9, 9, 9, 40, 98, 32, 61, 61, 32, 49,
- 32,111,114, 32, 40,115,116,114,105,110,103, 46,115,117, 98,
- 40,114,101,103,116,121,112,101, 44, 32, 98, 45, 49, 44, 32,
- 98, 45, 49, 41, 32, 61, 61, 32, 39, 58, 39, 32, 97,110,100,
- 10, 9, 9, 9, 9,115,116,114,105,110,103, 46,115,117, 98,
- 40,114,101,103,116,121,112,101, 44, 32, 49, 44, 32, 98, 45,
- 49, 41, 32, 61, 61, 32,115,116,114,105,110,103, 46,115,117,
- 98, 40,115,116, 44, 32, 49, 44, 32, 98, 45, 49, 41, 41, 41,
- 32,116,104,101,110, 10, 9, 9, 9,114,101,116,117,114,110,
- 32,116,114,117,101, 10, 9, 9,101,110,100, 10, 9,101,110,
- 100, 10, 10, 9,114,101,116,117,114,110, 32,102, 97,108,115,
- 101, 10,101,110,100, 10, 10,102,117,110, 99,116,105,111,110,
- 32,102,105,110,100,116,121,112,101, 95,111,110, 95, 99,104,
- 105,108,100,115, 40,115,101,108,102, 44, 32,116, 41, 10, 10,
- 9,108,111, 99, 97,108, 32,116, 99,104,105,108,100, 10, 9,
- 105,102, 32,115,101,108,102, 46, 99,108, 97,115,115,116,121,
- 112,101, 32, 61, 61, 32, 39, 99,108, 97,115,115, 39, 32,111,
- 114, 32,115,101,108,102, 46, 99,108, 97,115,115,116,121,112,
- 101, 32, 61, 61, 32, 39,110, 97,109,101,115,112, 97, 99,101,
- 39, 32,116,104,101,110, 10, 9, 9,102,111,114, 32,107, 44,
- 118, 32,105,110, 32,105,112, 97,105,114,115, 40,115,101,108,
- 102, 41, 32,100,111, 10, 9, 9, 9,105,102, 32,118, 46, 99,
- 108, 97,115,115,116,121,112,101, 32, 61, 61, 32, 39, 99,108,
- 97,115,115, 39, 32,111,114, 32,118, 46, 99,108, 97,115,115,
- 116,121,112,101, 32, 61, 61, 32, 39,110, 97,109,101,115,112,
- 97, 99,101, 39, 32,116,104,101,110, 10, 9, 9, 9, 9,105,
- 102, 32,118, 46,116,121,112,101,100,101,102,115, 32, 97,110,
- 100, 32,118, 46,116,121,112,101,100,101,102,115, 91,116, 93,
- 32,116,104,101,110, 10, 9, 9, 9, 9, 32,114,101,116,117,
- 114,110, 32,118, 46,116,121,112,101,100,101,102,115, 91,116,
- 93, 10, 9, 9, 9, 9,101,108,115,101,105,102, 32,118, 46,
- 117,115,101,114,116,121,112,101,115, 32, 97,110,100, 32,118,
- 46,117,115,101,114,116,121,112,101,115, 91,116, 93, 32,116,
- 104,101,110, 10, 9, 9, 9, 9, 32,114,101,116,117,114,110,
- 32,118, 46,117,115,101,114,116,121,112,101,115, 91,116, 93,
- 10, 9, 9, 9, 9,101,110,100, 10, 9, 9, 9, 9,116, 99,
- 104,105,108,100, 32, 61, 32,102,105,110,100,116,121,112,101,
- 95,111,110, 95, 99,104,105,108,100,115, 40,118, 44, 32,116,
- 41, 10, 9, 9, 9, 9,105,102, 32,116, 99,104,105,108,100,
- 32,116,104,101,110, 32,114,101,116,117,114,110, 32,116, 99,
- 104,105,108,100, 32,101,110,100, 10, 9, 9, 9,101,110,100,
- 10, 9, 9,101,110,100, 10, 9,101,110,100, 10, 9,114,101,
- 116,117,114,110, 32,110,105,108, 10, 10,101,110,100, 10, 10,
- 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 67,
- 111,110,116, 97,105,110,101,114, 58,105,115,101,110,117,109,
- 32, 40,116,121,112,101, 41, 10, 32,105,102, 32,103,108,111,
- 98, 97,108, 95,101,110,117,109,115, 91,116,121,112,101, 93,
- 32,116,104,101,110, 10, 9,114,101,116,117,114,110, 32,116,
- 121,112,101, 10, 32,101,108,115,101, 10, 32, 9,114,101,116,
- 117,114,110, 32,102, 97,108,115,101, 10, 32,101,110,100, 10,
- 10, 32,108,111, 99, 97,108, 32, 98, 97,115,101,116,121,112,
- 101, 32, 61, 32,103,115,117, 98, 40,116,121,112,101, 44, 34,
- 94, 46, 42, 58, 58, 34, 44, 34, 34, 41, 10, 32,108,111, 99,
- 97,108, 32,101,110,118, 32, 61, 32,115,101,108,102, 10, 32,
- 119,104,105,108,101, 32,101,110,118, 32,100,111, 10, 32, 32,
- 105,102, 32,101,110,118, 46,101,110,117,109,115, 32,116,104,
- 101,110, 10, 32, 32, 32,108,111, 99, 97,108, 32,105, 61, 49,
- 10, 32, 32, 32,119,104,105,108,101, 32,101,110,118, 46,101,
- 110,117,109,115, 91,105, 93, 32,100,111, 10, 32, 32, 32, 32,
- 105,102, 32,101,110,118, 46,101,110,117,109,115, 91,105, 93,
- 46,110, 97,109,101, 32, 61, 61, 32, 98, 97,115,101,116,121,
- 112,101, 32,116,104,101,110, 10, 32, 32, 32, 32, 32, 32, 32,
- 32, 32,114,101,116,117,114,110, 32,116,114,117,101, 10, 32,
- 32, 32, 32, 32, 32, 32, 32,101,110,100, 10, 32, 32, 32, 32,
- 32, 32, 32, 32,105, 32, 61, 32,105, 43, 49, 10, 32, 32, 32,
- 101,110,100, 10, 32, 32,101,110,100, 10, 32, 32,101,110,118,
- 32, 61, 32,101,110,118, 46,112, 97,114,101,110,116, 10, 32,
- 101,110,100, 10, 32,114,101,116,117,114,110, 32,102, 97,108,
- 115,101, 10,101,110,100, 10, 10,109,101,116,104,111,100,105,
- 115,118,105,114,116,117, 97,108, 32, 61, 32,102, 97,108,115,
- 101, 32, 45, 45, 32, 97, 32,103,108,111, 98, 97,108, 10, 10,
- 45, 45, 32,112, 97,114,115,101, 32, 99,104,117,110,107, 10,
- 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 67,
- 111,110,116, 97,105,110,101,114, 58,100,111,112, 97,114,115,
- 101, 32, 40,115, 41, 10, 45, 45,112,114,105,110,116, 32, 40,
- 34,112, 97,114,115,101, 32, 34, 46, 46,115, 41, 10, 10, 32,
- 45, 45, 32,116,114,121, 32,116,104,101, 32,112, 97,114,115,
- 101,114, 32,104,111,111,107, 10, 32,100,111, 10, 32, 9,108,
- 111, 99, 97,108, 32,115,117, 98, 32, 61, 32,112, 97,114,115,
- 101,114, 95,104,111,111,107, 40,115, 41, 10, 32, 9,105,102,
- 32,115,117, 98, 32,116,104,101,110, 10, 32, 9, 9,114,101,
- 116,117,114,110, 32,115,117, 98, 10, 32, 9,101,110,100, 10,
- 32,101,110,100, 10, 10, 32, 45, 45, 32,116,114,121, 32,116,
- 104,101, 32,110,117,108,108, 32,115,116, 97,116,101,109,101,
- 110,116, 10, 32,100,111, 10, 32, 9,108,111, 99, 97,108, 32,
- 98, 44,101, 44, 99,111,100,101, 32, 61, 32,115,116,114,105,
- 110,103, 46,102,105,110,100, 40,115, 44, 32, 34, 94, 37,115,
- 42, 59, 34, 41, 10, 32, 9,105,102, 32, 98, 32,116,104,101,
- 110, 10, 32, 9, 9,114,101,116,117,114,110, 32,115,116,114,
- 115,117, 98, 40,115, 44,101, 43, 49, 41, 10, 32, 9,101,110,
- 100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,116,114,121,
- 32,101,109,112,116,121, 32,118,101,114, 98, 97,116,105,109,
- 32,108,105,110,101, 10, 32,100,111, 10, 32, 9,108,111, 99,
- 97,108, 32, 98, 44,101, 44, 99,111,100,101, 32, 61, 32,115,
- 116,114,105,110,103, 46,102,105,110,100, 40,115, 44, 32, 34,
- 94, 37,115, 42, 36, 92,110, 34, 41, 10, 32, 9,105,102, 32,
- 98, 32,116,104,101,110, 10, 32, 9, 9,114,101,116,117,114,
- 110, 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41,
- 10, 32, 9,101,110,100, 10, 32,101,110,100, 10, 10, 32, 45,
- 45, 32,116,114,121, 32, 76,117, 97, 32, 99,111,100,101, 10,
- 32,100,111, 10, 32, 32,108,111, 99, 97,108, 32, 98, 44,101,
- 44, 99,111,100,101, 32, 61, 32,115,116,114,102,105,110,100,
- 40,115, 44, 34, 94, 37,115, 42, 40, 37, 98, 92, 49, 92, 50,
- 41, 34, 41, 10, 32, 32,105,102, 32, 98, 32,116,104,101,110,
- 10, 32, 32, 32, 67,111,100,101, 40,115,116,114,115,117, 98,
- 40, 99,111,100,101, 44, 50, 44, 45, 50, 41, 41, 10, 32, 32,
- 32,114,101,116,117,114,110, 32,115,116,114,115,117, 98, 40,
- 115, 44,101, 43, 49, 41, 10, 32, 32,101,110,100, 10, 32,101,
- 110,100, 10, 10, 32, 45, 45, 32,116,114,121, 32, 67, 32, 99,
- 111,100,101, 10, 32,100,111, 10, 32, 32,108,111, 99, 97,108,
- 32, 98, 44,101, 44, 99,111,100,101, 32, 61, 32,115,116,114,
- 102,105,110,100, 40,115, 44, 34, 94, 37,115, 42, 40, 37, 98,
- 92, 51, 92, 52, 41, 34, 41, 10, 32, 32,105,102, 32, 98, 32,
- 116,104,101,110, 10, 9, 99,111,100,101, 32, 61, 32, 39,123,
- 39, 46, 46,115,116,114,115,117, 98, 40, 99,111,100,101, 44,
- 50, 44, 45, 50, 41, 46, 46, 39, 92,110,125, 92,110, 39, 10,
- 9, 86,101,114, 98, 97,116,105,109, 40, 99,111,100,101, 44,
- 39,114, 39, 41, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32,
- 118,101,114, 98, 97,116,105,109, 32, 99,111,100,101, 32,102,
- 111,114, 32, 39,114, 39,101,103,105,115,116,101,114, 32,102,
- 114, 97,103,109,101,110,116, 10, 9,114,101,116,117,114,110,
- 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10,
- 32, 32,101,110,100, 10, 32,101,110,100, 10, 10, 32, 45, 45,
- 32,116,114,121, 32, 67, 32, 99,111,100,101, 32,102,111,114,
- 32,112,114,101, 97,109, 98,108,101, 32,115,101, 99,116,105,
- 111,110, 10, 32,100,111, 10, 32, 9,108,111, 99, 97,108, 32,
- 98, 44,101, 44, 99,111,100,101, 32, 61, 32,115,116,114,105,
- 110,103, 46,102,105,110,100, 40,115, 44, 32, 34, 94, 37,115,
- 42, 40, 37, 98, 92, 53, 92, 54, 41, 34, 41, 10, 32, 9,105,
- 102, 32, 98, 32,116,104,101,110, 10, 32, 9, 9, 99,111,100,
- 101, 32, 61, 32,115,116,114,105,110,103, 46,115,117, 98, 40,
- 99,111,100,101, 44, 32, 50, 44, 32, 45, 50, 41, 46, 46, 34,
- 92,110, 34, 10, 9, 9, 86,101,114, 98, 97,116,105,109, 40,
- 99,111,100,101, 44, 32, 39, 39, 41, 10, 9, 9,114,101,116,
- 117,114,110, 32,115,116,114,105,110,103, 46,115,117, 98, 40,
- 115, 44, 32,101, 43, 49, 41, 10, 32, 9,101,110,100, 10, 32,
- 101,110,100, 10, 10, 32, 45, 45, 32,116,114,121, 32,100,101,
- 102, 97,117,108,116, 95,112,114,111,112,101,114,116,121, 32,
- 100,105,114,101, 99,116,105,118,101, 10, 32,100,111, 10, 32,
- 9,108,111, 99, 97,108, 32, 98, 44,101, 44,112,116,121,112,
- 101, 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44, 32,
- 34, 94, 37,115, 42, 84, 79, 76, 85, 65, 95, 80, 82, 79, 80,
- 69, 82, 84, 89, 95, 84, 89, 80, 69, 37,115, 42, 37, 40, 43,
- 37,115, 42, 40, 91, 94, 37, 41, 37,115, 93, 42, 41, 37,115,
- 42, 37, 41, 43, 37,115, 42, 59, 63, 34, 41, 10, 32, 9,105,
- 102, 32, 98, 32,116,104,101,110, 10, 32, 9, 9,105,102, 32,
- 110,111,116, 32,112,116,121,112,101, 32,111,114, 32,112,116,
- 121,112,101, 32, 61, 61, 32, 34, 34, 32,116,104,101,110, 10,
- 32, 9, 9, 9,112,116,121,112,101, 32, 61, 32, 34,100,101,
- 102, 97,117,108,116, 34, 10, 32, 9, 9,101,110,100, 10, 32,
- 9, 9,115,101,108,102, 58,115,101,116, 95,112,114,111,112,
- 101,114,116,121, 95,116,121,112,101, 40,112,116,121,112,101,
- 41, 10, 9, 32, 9,114,101,116,117,114,110, 32,115,116,114,
- 115,117, 98, 40,115, 44, 32,101, 43, 49, 41, 10, 32, 9,101,
- 110,100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,116,114,
- 121, 32,112,114,111,116,101, 99,116,101,100, 95,100,101,115,
- 116,114,117, 99,116,111,114, 32,100,105,114,101, 99,116,105,
- 118,101, 10, 32,100,111, 10, 32, 9,108,111, 99, 97,108, 32,
- 98, 44,101, 32, 61, 32,115,116,114,105,110,103, 46,102,105,
- 110,100, 40,115, 44, 32, 34, 94, 37,115, 42, 84, 79, 76, 85,
- 65, 95, 80, 82, 79, 84, 69, 67, 84, 69, 68, 95, 68, 69, 83,
- 84, 82, 85, 67, 84, 79, 82, 37,115, 42, 59, 63, 34, 41, 10,
- 9,105,102, 32, 98, 32,116,104,101,110, 10, 9, 9,105,102,
- 32,115,101,108,102, 46,115,101,116, 95,112,114,111,116,101,
- 99,116,101,100, 95,100,101,115,116,114,117, 99,116,111,114,
- 32,116,104,101,110, 10, 9, 32, 9, 9,115,101,108,102, 58,
- 115,101,116, 95,112,114,111,116,101, 99,116,101,100, 95,100,
- 101,115,116,114,117, 99,116,111,114, 40,116,114,117,101, 41,
- 10, 9, 32, 9,101,110,100, 10, 32, 9, 9,114,101,116,117,
- 114,110, 32,115,116,114,115,117, 98, 40,115, 44, 32,101, 43,
- 49, 41, 10, 32, 9,101,110,100, 10, 32,101,110,100, 10, 10,
- 32, 45, 45, 32,116,114,121, 32, 39,101,120,116,101,114,110,
- 39, 32,107,101,121,119,111,114,100, 10, 32,100,111, 10, 32,
- 9,108,111, 99, 97,108, 32, 98, 44,101, 32, 61, 32,115,116,
- 114,105,110,103, 46,102,105,110,100, 40,115, 44, 32, 34, 94,
- 37,115, 42,101,120,116,101,114,110, 37,115, 43, 34, 41, 10,
- 32, 9,105,102, 32, 98, 32,116,104,101,110, 10, 9, 9, 45,
- 45, 32,100,111, 32,110,111,116,104,105,110,103, 10, 32, 9,
- 9,114,101,116,117,114,110, 32,115,116,114,115,117, 98, 40,
- 115, 44, 32,101, 43, 49, 41, 10, 32, 9,101,110,100, 10, 32,
- 101,110,100, 10, 10, 32, 45, 45, 32,116,114,121, 32, 39,118,
- 105,114,116,117, 97,108, 39, 32,107,101,121,119,111,114,107,
- 100, 10, 32,100,111, 10, 32, 9,108,111, 99, 97,108, 32, 98,
- 44,101, 32, 61, 32,115,116,114,105,110,103, 46,102,105,110,
- 100, 40,115, 44, 32, 34, 94, 37,115, 42,118,105,114,116,117,
- 97,108, 37,115, 43, 34, 41, 10, 32, 9,105,102, 32, 98, 32,
- 116,104,101,110, 10, 32, 9, 9,109,101,116,104,111,100,105,
- 115,118,105,114,116,117, 97,108, 32, 61, 32,116,114,117,101,
- 10, 32, 9, 9,114,101,116,117,114,110, 32,115,116,114,115,
- 117, 98, 40,115, 44, 32,101, 43, 49, 41, 10, 32, 9,101,110,
- 100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,116,114,121,
- 32,108, 97, 98,101,108,115, 32, 40,112,117, 98,108,105, 99,
- 44, 32,112,114,105,118, 97,116,101, 44, 32,101,116, 99, 41,
- 10, 32,100,111, 10, 32, 9,108,111, 99, 97,108, 32, 98, 44,
- 101, 32, 61, 32,115,116,114,105,110,103, 46,102,105,110,100,
- 40,115, 44, 32, 34, 94, 37,115, 42, 37,119, 42, 37,115, 42,
- 58, 91, 94, 58, 93, 34, 41, 10, 32, 9,105,102, 32, 98, 32,
- 116,104,101,110, 10, 32, 9, 9,114,101,116,117,114,110, 32,
- 115,116,114,115,117, 98, 40,115, 44, 32,101, 41, 32, 45, 45,
- 32,112,114,101,115,101,114,118,101, 32,116,104,101, 32, 91,
- 94, 58, 93, 10, 32, 9,101,110,100, 10, 32,101,110,100, 10,
- 10, 32, 45, 45, 32,116,114,121, 32,109,111,100,117,108,101,
- 10, 32,100,111, 10, 32, 32,108,111, 99, 97,108, 32, 98, 44,
- 101, 44,110, 97,109,101, 44, 98,111,100,121, 32, 61, 32,115,
- 116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,109,
- 111,100,117,108,101, 37,115, 37,115, 42, 40, 91, 95, 37,119,
- 93, 91, 95, 37,119, 93, 42, 41, 37,115, 42, 40, 37, 98,123,
- 125, 41, 37,115, 42, 34, 41, 10, 32, 32,105,102, 32, 98, 32,
- 116,104,101,110, 10, 32, 32, 32, 95, 99,117,114,114, 95, 99,
- 111,100,101, 32, 61, 32,115,116,114,115,117, 98, 40,115, 44,
- 98, 44,101, 41, 10, 32, 32, 32, 77,111,100,117,108,101, 40,
- 110, 97,109,101, 44, 98,111,100,121, 41, 10, 32, 32, 32,114,
- 101,116,117,114,110, 32,115,116,114,115,117, 98, 40,115, 44,
- 101, 43, 49, 41, 10, 32, 32,101,110,100, 10, 32,101,110,100,
- 10, 10, 32, 45, 45, 32,116,114,121, 32,110, 97,109,101,115,
- 97,112, 99,101, 10, 32,100,111, 10, 32, 32,108,111, 99, 97,
- 108, 32, 98, 44,101, 44,110, 97,109,101, 44, 98,111,100,121,
- 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94,
- 37,115, 42,110, 97,109,101,115,112, 97, 99,101, 37,115, 37,
- 115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 93, 42, 41,
- 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42, 59, 63, 34,
- 41, 10, 32, 32,105,102, 32, 98, 32,116,104,101,110, 10, 32,
- 32, 32, 95, 99,117,114,114, 95, 99,111,100,101, 32, 61, 32,
- 115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41, 10, 32,
- 32, 32, 78, 97,109,101,115,112, 97, 99,101, 40,110, 97,109,
- 101, 44, 98,111,100,121, 41, 10, 32, 32, 32,114,101,116,117,
- 114,110, 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49,
- 41, 10, 32, 32,101,110,100, 10, 32,101,110,100, 10, 10, 32,
- 45, 45, 32,116,114,121, 32,100,101,102,105,110,101, 10, 32,
- 100,111, 10, 32, 32,108,111, 99, 97,108, 32, 98, 44,101, 44,
- 110, 97,109,101, 32, 61, 32,115,116,114,102,105,110,100, 40,
- 115, 44, 34, 94, 37,115, 42, 35,100,101,102,105,110,101, 37,
- 115, 37,115, 42, 40, 91, 94, 37,115, 93, 42, 41, 91, 94, 92,
- 110, 93, 42, 92,110, 37,115, 42, 34, 41, 10, 32, 32,105,102,
- 32, 98, 32,116,104,101,110, 10, 32, 32, 32, 95, 99,117,114,
- 114, 95, 99,111,100,101, 32, 61, 32,115,116,114,115,117, 98,
- 40,115, 44, 98, 44,101, 41, 10, 32, 32, 32, 68,101,102,105,
- 110,101, 40,110, 97,109,101, 41, 10, 32, 32, 32,114,101,116,
- 117,114,110, 32,115,116,114,115,117, 98, 40,115, 44,101, 43,
- 49, 41, 10, 32, 32,101,110,100, 10, 32,101,110,100, 10, 10,
- 32, 45, 45, 32,116,114,121, 32,101,110,117,109,101,114, 97,
- 116,101,115, 10, 10, 32,100,111, 10, 32, 32,108,111, 99, 97,
- 108, 32, 98, 44,101, 44,110, 97,109,101, 44, 98,111,100,121,
- 44,118, 97,114,110, 97,109,101, 32, 61, 32,115,116,114,102,
- 105,110,100, 40,115, 44, 34, 94, 37,115, 42,101,110,117,109,
- 37,115, 43, 40, 37, 83, 42, 41, 37,115, 42, 40, 37, 98,123,
- 125, 41, 37,115, 42, 40, 91, 94, 37,115, 59, 93, 42, 41, 37,
- 115, 42, 59, 63, 37,115, 42, 34, 41, 10, 32, 32,105,102, 32,
- 98, 32,116,104,101,110, 10, 32, 32, 32, 45, 45,101,114,114,
- 111,114, 40, 34, 35, 83,111,114,114,121, 44, 32,100,101, 99,
- 108, 97,114, 97,116,105,111,110, 32,111,102, 32,101,110,117,
- 109,115, 32, 97,110,100, 32,118, 97,114,105, 97, 98,108,101,
- 115, 32,111,110, 32,116,104,101, 32,115, 97,109,101, 32,115,
- 116, 97,116,101,109,101,110,116, 32,105,115, 32,110,111,116,
- 32,115,117,112,112,111,114,116,101,100, 46, 92,110, 68,101,
- 99,108, 97,114,101, 32,121,111,117,114, 32,118, 97,114,105,
- 97, 98,108,101, 32,115,101,112, 97,114, 97,116,101,108,121,
- 32, 40,101,120, 97,109,112,108,101, 58, 32, 39, 34, 46, 46,
- 110, 97,109,101, 46, 46, 34, 32, 34, 46, 46,118, 97,114,110,
- 97,109,101, 46, 46, 34, 59, 39, 41, 34, 41, 10, 32, 32, 32,
- 95, 99,117,114,114, 95, 99,111,100,101, 32, 61, 32,115,116,
- 114,115,117, 98, 40,115, 44, 98, 44,101, 41, 10, 32, 32, 32,
- 69,110,117,109,101,114, 97,116,101, 40,110, 97,109,101, 44,
- 98,111,100,121, 44,118, 97,114,110, 97,109,101, 41, 10, 32,
- 32, 32,114,101,116,117,114,110, 32,115,116,114,115,117, 98,
- 40,115, 44,101, 43, 49, 41, 10, 32, 32,101,110,100, 10, 32,
- 101,110,100, 10, 10, 45, 45, 32,100,111, 10, 45, 45, 32, 32,
- 108,111, 99, 97,108, 32, 98, 44,101, 44,110, 97,109,101, 44,
- 98,111,100,121, 32, 61, 32,115,116,114,102,105,110,100, 40,
- 115, 44, 34, 94, 37,115, 42,101,110,117,109, 37,115, 43, 40,
- 37, 83, 42, 41, 37,115, 42, 40, 37, 98,123,125, 41, 37,115,
- 42, 59, 63, 37,115, 42, 34, 41, 10, 45, 45, 32, 32,105,102,
- 32, 98, 32,116,104,101,110, 10, 45, 45, 32, 32, 32, 95, 99,
- 117,114,114, 95, 99,111,100,101, 32, 61, 32,115,116,114,115,
- 117, 98, 40,115, 44, 98, 44,101, 41, 10, 45, 45, 32, 32, 32,
- 69,110,117,109,101,114, 97,116,101, 40,110, 97,109,101, 44,
- 98,111,100,121, 41, 10, 45, 45, 32, 32,114,101,116,117,114,
- 110, 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41,
- 10, 45, 45, 32, 32,101,110,100, 10, 45, 45, 32,101,110,100,
- 10, 10, 32,100,111, 10, 32, 32,108,111, 99, 97,108, 32, 98,
- 44,101, 44, 98,111,100,121, 44,110, 97,109,101, 32, 61, 32,
- 115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,
- 116,121,112,101,100,101,102, 37,115, 43,101,110,117,109, 91,
- 94,123, 93, 42, 40, 37, 98,123,125, 41, 37,115, 42, 40, 91,
- 37,119, 95, 93, 91, 94, 37,115, 93, 42, 41, 37,115, 42, 59,
- 37,115, 42, 34, 41, 10, 32, 32,105,102, 32, 98, 32,116,104,
- 101,110, 10, 32, 32, 32, 95, 99,117,114,114, 95, 99,111,100,
- 101, 32, 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,
- 101, 41, 10, 32, 32, 32, 69,110,117,109,101,114, 97,116,101,
- 40,110, 97,109,101, 44, 98,111,100,121, 41, 10, 32, 32, 32,
- 114,101,116,117,114,110, 32,115,116,114,115,117, 98, 40,115,
- 44,101, 43, 49, 41, 10, 32, 32,101,110,100, 10, 32,101,110,
- 100, 10, 10, 32, 45, 45, 32,116,114,121, 32,111,112,101,114,
- 97,116,111,114, 10, 32,100,111, 10, 32, 32,108,111, 99, 97,
- 108, 32, 98, 44,101, 44,100,101, 99,108, 44,107,105,110,100,
- 44, 97,114,103, 44, 99,111,110,115,116, 32, 61, 32,115,116,
- 114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42, 40, 91,
- 95, 37,119, 93, 91, 95, 37,119, 37,115, 37, 42, 38, 58, 60,
- 62, 44, 93, 45, 37,115, 43,111,112,101,114, 97,116,111,114,
- 41, 37,115, 42, 40, 91, 94, 37,115, 93, 91, 94, 37,115, 93,
- 42, 41, 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40,
- 99, 63,111, 63,110, 63,115, 63,116, 63, 41, 37,115, 42, 59,
- 37,115, 42, 34, 41, 10, 32, 32,105,102, 32,110,111,116, 32,
- 98, 32,116,104,101,110, 10, 9, 9, 32, 45, 45, 32,116,114,
- 121, 32,105,110,108,105,110,101, 10, 32, 32, 32, 98, 44,101,
- 44,100,101, 99,108, 44,107,105,110,100, 44, 97,114,103, 44,
- 99,111,110,115,116, 32, 61, 32,115,116,114,102,105,110,100,
- 40,115, 44, 34, 94, 37,115, 42, 40, 91, 95, 37,119, 93, 91,
- 95, 37,119, 37,115, 37, 42, 38, 58, 60, 62, 44, 93, 45, 37,
- 115, 43,111,112,101,114, 97,116,111,114, 41, 37,115, 42, 40,
- 91, 94, 37,115, 93, 91, 94, 37,115, 93, 42, 41, 37,115, 42,
- 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110,
- 63,115, 63,116, 63, 41, 91, 37,115, 92,110, 93, 42, 37, 98,
- 123,125, 37,115, 42, 59, 63, 37,115, 42, 34, 41, 10, 32, 32,
- 101,110,100, 10, 32, 32,105,102, 32,110,111,116, 32, 98, 32,
- 116,104,101,110, 10, 32, 32, 9, 45, 45, 32,116,114,121, 32,
- 99, 97,115,116, 32,111,112,101,114, 97,116,111,114, 10, 32,
- 32, 9, 98, 44,101, 44,100,101, 99,108, 44,107,105,110,100,
- 44, 97,114,103, 44, 99,111,110,115,116, 32, 61, 32,115,116,
- 114,102,105,110,100, 40,115, 44, 32, 34, 94, 37,115, 42, 40,
- 111,112,101,114, 97,116,111,114, 41, 37,115, 43, 40, 91, 37,
- 119, 95, 58, 37,100, 60, 62, 37, 42, 37, 38, 37,115, 93, 43,
- 41, 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99,
- 63,111, 63,110, 63,115, 63,116, 63, 41, 34, 41, 59, 10, 32,
- 32, 9,105,102, 32, 98, 32,116,104,101,110, 10, 32, 32, 9,
- 9,108,111, 99, 97,108, 32, 95, 44,105,101, 32, 61, 32,115,
- 116,114,105,110,103, 46,102,105,110,100, 40,115, 44, 32, 34,
- 94, 37,115, 42, 37, 98,123,125, 34, 44, 32,101, 43, 49, 41,
- 10, 32, 32, 9, 9,105,102, 32,105,101, 32,116,104,101,110,
- 10, 32, 32, 9, 9, 9,101, 32, 61, 32,105,101, 10, 32, 32,
- 9, 9,101,110,100, 10, 32, 32, 9,101,110,100, 10, 32, 32,
- 101,110,100, 10, 32, 32,105,102, 32, 98, 32,116,104,101,110,
- 10, 32, 32, 32, 95, 99,117,114,114, 95, 99,111,100,101, 32,
- 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41,
- 10, 32, 32, 32, 79,112,101,114, 97,116,111,114, 40,100,101,
- 99,108, 44,107,105,110,100, 44, 97,114,103, 44, 99,111,110,
- 115,116, 41, 10, 32, 32, 32,114,101,116,117,114,110, 32,115,
- 116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10, 32, 32,
- 101,110,100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,116,
- 114,121, 32,102,117,110, 99,116,105,111,110, 10, 32,100,111,
- 10, 32, 32, 45, 45,108,111, 99, 97,108, 32, 98, 44,101, 44,
- 100,101, 99,108, 44, 97,114,103, 44, 99,111,110,115,116, 32,
- 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,
- 115, 42, 40, 91,126, 95, 37,119, 93, 91, 95, 64, 37,119, 37,
- 115, 37, 42, 38, 58, 60, 62, 93, 42, 91, 95, 37,119, 93, 41,
- 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,
- 111, 63,110, 63,115, 63,116, 63, 41, 37,115, 42, 61, 63, 37,
- 115, 42, 48, 63, 37,115, 42, 59, 37,115, 42, 34, 41, 10, 32,
- 32,108,111, 99, 97,108, 32, 98, 44,101, 44,100,101, 99,108,
- 44, 97,114,103, 44, 99,111,110,115,116, 44,118,105,114,116,
- 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94,
- 37,115, 42, 40, 91, 94, 37, 40, 92,110, 93, 43, 41, 37,115,
- 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,
- 110, 63,115, 63,116, 63, 41, 37,115, 42, 40, 61, 63, 37,115,
- 42, 48, 63, 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10, 32,
- 32,105,102, 32,110,111,116, 32, 98, 32,116,104,101,110, 10,
- 32, 32, 9, 45, 45, 32,116,114,121, 32,102,117,110, 99,116,
- 105,111,110, 32,119,105,116,104, 32,116,101,109,112,108, 97,
- 116,101, 10, 32, 32, 9, 98, 44,101, 44,100,101, 99,108, 44,
- 97,114,103, 44, 99,111,110,115,116, 32, 61, 32,115,116,114,
- 102,105,110,100, 40,115, 44, 34, 94, 37,115, 42, 40, 91,126,
- 95, 37,119, 93, 91, 95, 64, 37,119, 37,115, 37, 42, 38, 58,
- 60, 62, 93, 42, 91, 95, 37,119, 93, 37, 98, 60, 62, 41, 37,
- 115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111,
- 63,110, 63,115, 63,116, 63, 41, 37,115, 42, 61, 63, 37,115,
- 42, 48, 63, 37,115, 42, 59, 37,115, 42, 34, 41, 10, 32, 32,
- 101,110,100, 10, 32, 32,105,102, 32,110,111,116, 32, 98, 32,
- 116,104,101,110, 10, 32, 32, 32, 45, 45, 32,116,114,121, 32,
- 97, 32,115,105,110,103,108,101, 32,108,101,116,116,101,114,
- 32,102,117,110, 99,116,105,111,110, 32,110, 97,109,101, 10,
- 32, 32, 32, 98, 44,101, 44,100,101, 99,108, 44, 97,114,103,
- 44, 99,111,110,115,116, 32, 61, 32,115,116,114,102,105,110,
- 100, 40,115, 44, 34, 94, 37,115, 42, 40, 91, 95, 37,119, 93,
- 41, 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99,
- 63,111, 63,110, 63,115, 63,116, 63, 41, 37,115, 42, 59, 37,
- 115, 42, 34, 41, 10, 32, 32,101,110,100, 10, 32, 32,105,102,
- 32,110,111,116, 32, 98, 32,116,104,101,110, 10, 32, 32, 32,
- 45, 45, 32,116,114,121, 32,102,117,110, 99,116,105,111,110,
- 32,112,111,105,110,116,101,114, 10, 32, 32, 32, 98, 44,101,
- 44,100,101, 99,108, 44, 97,114,103, 44, 99,111,110,115,116,
- 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94,
- 37,115, 42, 40, 91, 94, 37, 40, 59, 92,110, 93, 43, 37, 98,
- 40, 41, 41, 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42,
- 59, 37,115, 42, 34, 41, 10, 32, 32, 32,105,102, 32, 98, 32,
- 116,104,101,110, 10, 32, 32, 32, 32,100,101, 99,108, 32, 61,
- 32,115,116,114,105,110,103, 46,103,115,117, 98, 40,100,101,
- 99,108, 44, 32, 34, 37, 40, 37,115, 42, 37, 42, 40, 91, 94,
- 37, 41, 93, 42, 41, 37,115, 42, 37, 41, 34, 44, 32, 34, 32,
- 37, 49, 32, 34, 41, 10, 32, 32, 32,101,110,100, 10, 32, 32,
- 101,110,100, 10, 32, 32,105,102, 32, 98, 32,116,104,101,110,
- 10, 32, 32, 9,105,102, 32,118,105,114,116, 32, 97,110,100,
- 32,115,116,114,105,110,103, 46,102,105,110,100, 40,118,105,
- 114,116, 44, 32, 34, 91, 61, 48, 93, 34, 41, 32,116,104,101,
- 110, 10, 32, 32, 9, 9,105,102, 32,115,101,108,102, 46,102,
- 108, 97,103,115, 32,116,104,101,110, 10, 32, 32, 9, 9, 9,
- 115,101,108,102, 46,102,108, 97,103,115, 46,112,117,114,101,
- 95,118,105,114,116,117, 97,108, 32, 61, 32,116,114,117,101,
- 10, 32, 32, 9, 9,101,110,100, 10, 32, 32, 9,101,110,100,
- 10, 32, 32, 32, 95, 99,117,114,114, 95, 99,111,100,101, 32,
- 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41,
- 10, 32, 32, 32, 70,117,110, 99,116,105,111,110, 40,100,101,
- 99,108, 44, 97,114,103, 44, 99,111,110,115,116, 41, 10, 32,
- 32, 32,114,101,116,117,114,110, 32,115,116,114,115,117, 98,
- 40,115, 44,101, 43, 49, 41, 10, 32, 32,101,110,100, 10, 32,
- 101,110,100, 10, 10, 32, 45, 45, 32,116,114,121, 32,105,110,
- 108,105,110,101, 32,102,117,110, 99,116,105,111,110, 10, 32,
- 100,111, 10, 32, 32,108,111, 99, 97,108, 32, 98, 44,101, 44,
- 100,101, 99,108, 44, 97,114,103, 44, 99,111,110,115,116, 32,
- 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,
- 115, 42, 40, 91, 94, 37, 40, 92,110, 93, 43, 41, 37,115, 42,
- 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110,
- 63,115, 63,116, 63, 41, 91, 94, 59,123, 93, 42, 37, 98,123,
- 125, 37,115, 42, 59, 63, 37,115, 42, 34, 41, 10, 32, 32, 45,
- 45,108,111, 99, 97,108, 32, 98, 44,101, 44,100,101, 99,108,
- 44, 97,114,103, 44, 99,111,110,115,116, 32, 61, 32,115,116,
- 114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42, 40, 91,
- 126, 95, 37,119, 93, 91, 95, 64, 37,119, 37,115, 37, 42, 38,
- 58, 60, 62, 93, 42, 91, 95, 37,119, 62, 93, 41, 37,115, 42,
- 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110,
- 63,115, 63,116, 63, 41, 91, 94, 59, 93, 42, 37, 98,123,125,
- 37,115, 42, 59, 63, 37,115, 42, 34, 41, 10, 32, 32,105,102,
- 32,110,111,116, 32, 98, 32,116,104,101,110, 10, 32, 32, 32,
- 45, 45, 32,116,114,121, 32, 97, 32,115,105,110,103,108,101,
- 32,108,101,116,116,101,114, 32,102,117,110, 99,116,105,111,
- 110, 32,110, 97,109,101, 10, 32, 32, 32, 98, 44,101, 44,100,
- 101, 99,108, 44, 97,114,103, 44, 99,111,110,115,116, 32, 61,
- 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115,
- 42, 40, 91, 95, 37,119, 93, 41, 37,115, 42, 40, 37, 98, 40,
- 41, 41, 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116,
- 63, 41, 46, 45, 37, 98,123,125, 37,115, 42, 59, 63, 37,115,
- 42, 34, 41, 10, 32, 32,101,110,100, 10, 32, 32,105,102, 32,
- 98, 32,116,104,101,110, 10, 32, 32, 32, 95, 99,117,114,114,
- 95, 99,111,100,101, 32, 61, 32,115,116,114,115,117, 98, 40,
- 115, 44, 98, 44,101, 41, 10, 32, 32, 32, 70,117,110, 99,116,
- 105,111,110, 40,100,101, 99,108, 44, 97,114,103, 44, 99,111,
- 110,115,116, 41, 10, 32, 32, 32,114,101,116,117,114,110, 32,
- 115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10, 32,
- 32,101,110,100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,
- 116,114,121, 32, 99,108, 97,115,115, 10, 32,100,111, 10, 9,
- 32,108,111, 99, 97,108, 32, 98, 44,101, 44,110, 97,109,101,
- 44, 98, 97,115,101, 44, 98,111,100,121, 10, 9, 9, 98, 97,
- 115,101, 32, 61, 32, 39, 39, 32, 98,111,100,121, 32, 61, 32,
- 39, 39, 10, 9, 9, 98, 44,101, 44,110, 97,109,101, 32, 61,
- 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115,
- 42, 99,108, 97,115,115, 37,115, 42, 40, 91, 95, 37,119, 93,
- 91, 95, 37,119, 64, 93, 42, 41, 37,115, 42, 59, 34, 41, 32,
- 32, 45, 45, 32,100,117,109,109,121, 32, 99,108, 97,115,115,
- 10, 9, 9,108,111, 99, 97,108, 32,100,117,109,109,121, 32,
- 61, 32,102, 97,108,115,101, 10, 9, 9,105,102, 32,110,111,
- 116, 32, 98, 32,116,104,101,110, 10, 9, 9, 9, 98, 44,101,
- 44,110, 97,109,101, 32, 61, 32,115,116,114,102,105,110,100,
- 40,115, 44, 34, 94, 37,115, 42,115,116,114,117, 99,116, 37,
- 115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 64, 93, 42,
- 41, 37,115, 42, 59, 34, 41, 32, 32, 32, 32, 45, 45, 32,100,
- 117,109,109,121, 32,115,116,114,117, 99,116, 10, 9, 9, 9,
- 105,102, 32,110,111,116, 32, 98, 32,116,104,101,110, 10, 9,
- 9, 9, 9, 98, 44,101, 44,110, 97,109,101, 44, 98, 97,115,
- 101, 44, 98,111,100,121, 32, 61, 32,115,116,114,102,105,110,
- 100, 40,115, 44, 34, 94, 37,115, 42, 99,108, 97,115,115, 37,
- 115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 64, 93, 42,
- 41, 37,115, 42, 40, 91, 94,123, 93, 45, 41, 37,115, 42, 40,
- 37, 98,123,125, 41, 37,115, 42, 34, 41, 10, 9, 9, 9, 9,
- 105,102, 32,110,111,116, 32, 98, 32,116,104,101,110, 10, 9,
- 9, 9, 9, 9, 98, 44,101, 44,110, 97,109,101, 44, 98, 97,
- 115,101, 44, 98,111,100,121, 32, 61, 32,115,116,114,102,105,
- 110,100, 40,115, 44, 34, 94, 37,115, 42,115,116,114,117, 99,
- 116, 37,115, 43, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 64,
- 93, 42, 41, 37,115, 42, 40, 91, 94,123, 93, 45, 41, 37,115,
- 42, 40, 37, 98,123,125, 41, 37,115, 42, 34, 41, 10, 9, 9,
- 9, 9, 9,105,102, 32,110,111,116, 32, 98, 32,116,104,101,
- 110, 10, 9, 9, 9, 9, 9, 9, 98, 44,101, 44,110, 97,109,
- 101, 44, 98, 97,115,101, 44, 98,111,100,121, 32, 61, 32,115,
- 116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,117,
- 110,105,111,110, 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95,
- 37,119, 64, 93, 42, 41, 37,115, 42, 40, 91, 94,123, 93, 45,
- 41, 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42, 34, 41,
- 10, 9, 9, 9, 9, 9, 9,105,102, 32,110,111,116, 32, 98,
- 32,116,104,101,110, 10, 9, 9, 9, 9, 9, 9, 9, 98, 97,
- 115,101, 32, 61, 32, 39, 39, 10, 9, 9, 9, 9, 9, 9, 9,
- 98, 44,101, 44, 98,111,100,121, 44,110, 97,109,101, 32, 61,
- 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115,
- 42,116,121,112,101,100,101,102, 37,115, 37,115, 42,115,116,
- 114,117, 99,116, 37,115, 37,115, 42, 91, 95, 37,119, 93, 42,
- 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42, 40, 91, 95,
- 37,119, 93, 91, 95, 37,119, 64, 93, 42, 41, 37,115, 42, 59,
- 34, 41, 10, 9, 9, 9, 9, 9, 9,101,110,100, 10, 9, 9,
- 9, 9, 9,101,110,100, 10, 9, 9, 9, 9,101,110,100, 10,
- 9, 9, 9,101,108,115,101, 32,100,117,109,109,121, 32, 61,
- 32, 49, 32,101,110,100, 10, 9, 9,101,108,115,101, 32,100,
- 117,109,109,121, 32, 61, 32, 49, 32,101,110,100, 10, 9, 9,
- 105,102, 32, 98, 32,116,104,101,110, 10, 9, 9, 9,105,102,
- 32, 98, 97,115,101, 32,126, 61, 32, 39, 39, 32,116,104,101,
- 110, 10, 9, 9, 9, 9, 98, 97,115,101, 32, 61, 32,115,116,
- 114,105,110,103, 46,103,115,117, 98, 40, 98, 97,115,101, 44,
- 32, 34, 94, 37,115, 42, 58, 37,115, 42, 34, 44, 32, 34, 34,
- 41, 10, 9, 9, 9, 9, 98, 97,115,101, 32, 61, 32,115,116,
- 114,105,110,103, 46,103,115,117, 98, 40, 98, 97,115,101, 44,
- 32, 34, 37,115, 42,112,117, 98,108,105, 99, 37,115, 42, 34,
- 44, 32, 34, 34, 41, 10, 9, 9, 9, 9, 98, 97,115,101, 32,
- 61, 32,115,112,108,105,116, 40, 98, 97,115,101, 44, 32, 34,
- 44, 34, 41, 10, 9, 9, 9, 9, 45, 45,108,111, 99, 97,108,
- 32, 98, 44,101, 10, 9, 9, 9, 9, 45, 45, 98, 44,101, 44,
- 98, 97,115,101, 32, 61, 32,115,116,114,102,105,110,100, 40,
- 98, 97,115,101, 44, 34, 46, 45, 40, 91, 95, 37,119, 93, 91,
- 95, 37,119, 60, 62, 44, 58, 93, 42, 41, 36, 34, 41, 10, 9,
- 9, 9,101,108,115,101, 10, 9, 9, 9, 9, 98, 97,115,101,
- 32, 61, 32,123,125, 10, 9, 9, 9,101,110,100, 10, 9, 9,
- 9, 95, 99,117,114,114, 95, 99,111,100,101, 32, 61, 32,115,
- 116,114,115,117, 98, 40,115, 44, 98, 44,101, 41, 10, 9, 9,
- 9, 67,108, 97,115,115, 40,110, 97,109,101, 44, 98, 97,115,
- 101, 44, 98,111,100,121, 41, 10, 9, 9, 9,105,102, 32,110,
- 111,116, 32,100,117,109,109,121, 32,116,104,101,110, 10, 9,
- 9, 9, 9,118, 97,114, 98, 44,118, 97,114,101, 44,118, 97,
- 114,110, 97,109,101, 32, 61, 32,115,116,114,105,110,103, 46,
- 102,105,110,100, 40,115, 44, 32, 34, 94, 37,115, 42, 40, 91,
- 95, 37,119, 93, 43, 41, 37,115, 42, 59, 34, 44, 32,101, 43,
- 49, 41, 10, 9, 9, 9, 9,105,102, 32,118, 97,114, 98, 32,
- 116,104,101,110, 10, 9, 9, 9, 9, 9, 86, 97,114,105, 97,
- 98,108,101, 40,110, 97,109,101, 46, 46, 34, 32, 34, 46, 46,
- 118, 97,114,110, 97,109,101, 41, 10, 9, 9, 9, 9, 9,101,
- 32, 61, 32,118, 97,114,101, 10, 9, 9, 9, 9,101,110,100,
- 10, 9, 9, 9,101,110,100, 10, 9, 9, 9,114,101,116,117,
- 114,110, 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49,
- 41, 10, 9, 9,101,110,100, 10, 9,101,110,100, 10, 10, 32,
- 45, 45, 32,116,114,121, 32,116,121,112,101,100,101,102, 10,
- 32,100,111, 10, 32, 32,108,111, 99, 97,108, 32, 98, 44,101,
- 44,116,121,112,101,115, 32, 61, 32,115,116,114,102,105,110,
- 100, 40,115, 44, 34, 94, 37,115, 42,116,121,112,101,100,101,
- 102, 37,115, 37,115, 42, 40, 46, 45, 41, 37,115, 42, 59, 37,
- 115, 42, 34, 41, 10, 32, 32,105,102, 32, 98, 32,116,104,101,
- 110, 10, 32, 32, 32, 95, 99,117,114,114, 95, 99,111,100,101,
- 32, 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101,
- 41, 10, 32, 32, 32, 84,121,112,101,100,101,102, 40,116,121,
- 112,101,115, 41, 10, 32, 32, 32,114,101,116,117,114,110, 32,
- 115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10, 32,
- 32,101,110,100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,
- 116,114,121, 32,118, 97,114,105, 97, 98,108,101, 10, 32,100,
- 111, 10, 32, 32,108,111, 99, 97,108, 32, 98, 44,101, 44,100,
- 101, 99,108, 32, 61, 32,115,116,114,102,105,110,100, 40,115,
- 44, 34, 94, 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95, 64,
- 37,115, 37,119, 37,100, 37, 42, 38, 58, 60, 62, 44, 93, 42,
- 91, 95, 37,119, 37,100, 93, 41, 37,115, 42, 59, 37,115, 42,
- 34, 41, 10, 32, 32,105,102, 32, 98, 32,116,104,101,110, 10,
- 32, 32, 32, 95, 99,117,114,114, 95, 99,111,100,101, 32, 61,
- 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41, 10,
- 10, 9,108,111, 99, 97,108, 32,108,105,115,116, 32, 61, 32,
- 115,112,108,105,116, 95, 99, 95,116,111,107,101,110,115, 40,
- 100,101, 99,108, 44, 32, 34, 44, 34, 41, 10, 9, 86, 97,114,
- 105, 97, 98,108,101, 40,108,105,115,116, 91, 49, 93, 41, 10,
- 9,105,102, 32,108,105,115,116, 46,110, 32, 62, 32, 49, 32,
- 116,104,101,110, 10, 9, 9,108,111, 99, 97,108, 32, 95, 44,
- 95, 44,116,121,112,101, 32, 61, 32,115,116,114,102,105,110,
- 100, 40,108,105,115,116, 91, 49, 93, 44, 32, 34, 40, 46, 45,
- 41, 37,115, 43, 40, 91, 94, 37,115, 93, 42, 41, 36, 34, 41,
- 59, 10, 10, 9, 9,108,111, 99, 97,108, 32,105, 32, 61, 50,
- 59, 10, 9, 9,119,104,105,108,101, 32,108,105,115,116, 91,
- 105, 93, 32,100,111, 10, 9, 9, 9, 86, 97,114,105, 97, 98,
- 108,101, 40,116,121,112,101, 46, 46, 34, 32, 34, 46, 46,108,
- 105,115,116, 91,105, 93, 41, 10, 9, 9, 9,105, 61,105, 43,
- 49, 10, 9, 9,101,110,100, 10, 9,101,110,100, 10, 32, 32,
- 32, 45, 45, 86, 97,114,105, 97, 98,108,101, 40,100,101, 99,
- 108, 41, 10, 32, 32, 32,114,101,116,117,114,110, 32,115,116,
- 114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10, 32, 32,101,
- 110,100, 10, 32,101,110,100, 10, 10, 9, 45, 45, 32,116,114,
- 121, 32,115,116,114,105,110,103, 10, 32,100,111, 10, 32, 32,
- 108,111, 99, 97,108, 32, 98, 44,101, 44,100,101, 99,108, 32,
- 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,
- 115, 42, 40, 91, 95, 37,119, 93, 63, 91, 95, 37,115, 37,119,
- 37,100, 93, 45, 99,104, 97,114, 37,115, 43, 91, 95, 64, 37,
- 119, 37,100, 93, 42, 37,115, 42, 37, 91, 37,115, 42, 37, 83,
- 43, 37,115, 42, 37, 93, 41, 37,115, 42, 59, 37,115, 42, 34,
- 41, 10, 32, 32,105,102, 32, 98, 32,116,104,101,110, 10, 32,
- 32, 32, 95, 99,117,114,114, 95, 99,111,100,101, 32, 61, 32,
- 115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41, 10, 32,
- 32, 32, 86, 97,114,105, 97, 98,108,101, 40,100,101, 99,108,
- 41, 10, 32, 32, 32,114,101,116,117,114,110, 32,115,116,114,
- 115,117, 98, 40,115, 44,101, 43, 49, 41, 10, 32, 32,101,110,
- 100, 10, 32,101,110,100, 10, 10, 32, 45, 45, 32,116,114,121,
- 32, 97,114,114, 97,121, 10, 32,100,111, 10, 32, 32,108,111,
- 99, 97,108, 32, 98, 44,101, 44,100,101, 99,108, 32, 61, 32,
- 115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,
- 40, 91, 95, 37,119, 93, 91, 93, 91, 95, 64, 37,115, 37,119,
- 37,100, 37, 42, 38, 58, 60, 62, 93, 42, 91, 93, 95, 37,119,
- 37,100, 93, 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10, 32,
- 32,105,102, 32, 98, 32,116,104,101,110, 10, 32, 32, 32, 95,
- 99,117,114,114, 95, 99,111,100,101, 32, 61, 32,115,116,114,
- 115,117, 98, 40,115, 44, 98, 44,101, 41, 10, 32, 32, 32, 65,
- 114,114, 97,121, 40,100,101, 99,108, 41, 10, 32, 32, 32,114,
- 101,116,117,114,110, 32,115,116,114,115,117, 98, 40,115, 44,
- 101, 43, 49, 41, 10, 32, 32,101,110,100, 10, 32,101,110,100,
- 10, 10, 32, 45, 45, 32,110,111, 32,109, 97,116, 99,104,105,
- 110,103, 10, 32,105,102, 32,103,115,117, 98, 40,115, 44, 34,
- 37,115, 37,115, 42, 34, 44, 34, 34, 41, 32,126, 61, 32, 34,
- 34, 32,116,104,101,110, 10, 32, 32, 95, 99,117,114,114, 95,
- 99,111,100,101, 32, 61, 32,115, 10, 32, 32,101,114,114,111,
- 114, 40, 34, 35,112, 97,114,115,101, 32,101,114,114,111,114,
- 34, 41, 10, 32,101,108,115,101, 10, 32, 32,114,101,116,117,
- 114,110, 32, 34, 34, 10, 32,101,110,100, 10, 10,101,110,100,
- 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
- 115, 67,111,110,116, 97,105,110,101,114, 58,112, 97,114,115,
- 101, 32, 40,115, 41, 10, 10, 9, 45, 45,115,101,108,102, 46,
- 99,117,114,114, 95,109,101,109, 98,101,114, 95, 97, 99, 99,
- 101,115,115, 32, 61, 32,110,105,108, 10, 10, 32,119,104,105,
- 108,101, 32,115, 32,126, 61, 32, 39, 39, 32,100,111, 10, 32,
- 32,115, 32, 61, 32,115,101,108,102, 58,100,111,112, 97,114,
- 115,101, 40,115, 41, 10, 32, 32,109,101,116,104,111,100,105,
- 115,118,105,114,116,117, 97,108, 32, 61, 32,102, 97,108,115,
- 101, 10, 32,101,110,100, 10,101,110,100, 10, 10, 10, 45, 45,
- 32,112,114,111,112,101,114,116,121, 32,116,121,112,101,115,
- 10, 10,102,117,110, 99,116,105,111,110, 32,103,101,116, 95,
- 112,114,111,112,101,114,116,121, 95,116,121,112,101, 40, 41,
- 10, 10, 9,114,101,116,117,114,110, 32, 99,108, 97,115,115,
- 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 58,
- 103,101,116, 95,112,114,111,112,101,114,116,121, 95,116,121,
- 112,101, 40, 41, 10,101,110,100, 10, 10,102,117,110, 99,116,
- 105,111,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,
- 110,101,114, 58,115,101,116, 95,112,114,111,112,101,114,116,
- 121, 95,116,121,112,101, 40,112,116,121,112,101, 41, 10, 9,
- 112,116,121,112,101, 32, 61, 32,115,116,114,105,110,103, 46,
- 103,115,117, 98, 40,112,116,121,112,101, 44, 32, 34, 94, 37,
- 115, 42, 34, 44, 32, 34, 34, 41, 10, 9,112,116,121,112,101,
- 32, 61, 32,115,116,114,105,110,103, 46,103,115,117, 98, 40,
- 112,116,121,112,101, 44, 32, 34, 37,115, 42, 36, 34, 44, 32,
- 34, 34, 41, 10, 10, 9,115,101,108,102, 46,112,114,111,112,
- 101,114,116,121, 95,116,121,112,101, 32, 61, 32,112,116,121,
- 112,101, 10,101,110,100, 10, 10,102,117,110, 99,116,105,111,
- 110, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,
- 114, 58,103,101,116, 95,112,114,111,112,101,114,116,121, 95,
- 116,121,112,101, 40, 41, 10, 9,114,101,116,117,114,110, 32,
- 115,101,108,102, 46,112,114,111,112,101,114,116,121, 95,116,
- 121,112,101, 32,111,114, 32, 40,115,101,108,102, 46,112, 97,
- 114,101,110,116, 32, 97,110,100, 32,115,101,108,102, 46,112,
- 97,114,101,110,116, 58,103,101,116, 95,112,114,111,112,101,
- 114,116,121, 95,116,121,112,101, 40, 41, 41, 32,111,114, 32,
- 34,100,101,102, 97,117,108,116, 34, 10,101,110,100,32
- };
- tolua_dobuffer(tolua_S,(char*)B,sizeof(B),"tolua embedded: src/bin/lua/container.lua");
+ #include "container_lua.h"
+ tolua_dobuffer(tolua_S,(char*)lua_container_lua,sizeof(lua_container_lua),"tolua embedded: src/bin/lua/container.lua");
lua_settop(tolua_S, top);
} /* end of embedded lua code */
diff --git a/lib/zlib/CMakeLists.txt b/lib/zlib/CMakeLists.txt
index 6c52578ee..74cf94f8b 100644
--- a/lib/zlib/CMakeLists.txt
+++ b/lib/zlib/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
file(GLOB SOURCE
"*.c"
+ "*.h"
)
if(NOT TARGET zlib)
diff --git a/src/Authenticator.cpp b/src/Authenticator.cpp
deleted file mode 100644
index bd6db1c11..000000000
--- a/src/Authenticator.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Authenticator.h"
-#include "OSSupport/BlockingTCPLink.h"
-#include "Root.h"
-#include "Server.h"
-
-#include "inifile/iniFile.h"
-
-#include <sstream>
-
-
-
-
-
-#define DEFAULT_AUTH_SERVER "session.minecraft.net"
-#define DEFAULT_AUTH_ADDRESS "/game/checkserver.jsp?user=%USERNAME%&serverId=%SERVERID%"
-#define MAX_REDIRECTS 10
-
-
-
-
-
-cAuthenticator::cAuthenticator(void) :
- super("cAuthenticator"),
- m_Server(DEFAULT_AUTH_SERVER),
- m_Address(DEFAULT_AUTH_ADDRESS),
- m_ShouldAuthenticate(true)
-{
-}
-
-
-
-
-
-cAuthenticator::~cAuthenticator()
-{
- Stop();
-}
-
-
-
-
-
-void cAuthenticator::ReadINI(cIniFile & IniFile)
-{
- m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER);
- m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
- m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true);
-}
-
-
-
-
-
-void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash)
-{
- if (!m_ShouldAuthenticate)
- {
- cRoot::Get()->AuthenticateUser(a_ClientID);
- return;
- }
-
- cCSLock Lock(m_CS);
- m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash));
- m_QueueNonempty.Set();
-}
-
-
-
-
-
-void cAuthenticator::Start(cIniFile & IniFile)
-{
- ReadINI(IniFile);
- m_ShouldTerminate = false;
- super::Start();
-}
-
-
-
-
-
-void cAuthenticator::Stop(void)
-{
- m_ShouldTerminate = true;
- m_QueueNonempty.Set();
- Wait();
-}
-
-
-
-
-
-void cAuthenticator::Execute(void)
-{
- for (;;)
- {
- cCSLock Lock(m_CS);
- while (!m_ShouldTerminate && (m_Queue.size() == 0))
- {
- cCSUnlock Unlock(Lock);
- m_QueueNonempty.Wait();
- }
- if (m_ShouldTerminate)
- {
- return;
- }
- ASSERT(!m_Queue.empty());
-
- int ClientID = m_Queue.front().m_ClientID;
- AString UserName = m_Queue.front().m_Name;
- AString ActualAddress = m_Address;
- ReplaceString(ActualAddress, "%USERNAME%", UserName);
- ReplaceString(ActualAddress, "%SERVERID%", m_Queue.front().m_ServerID);
- m_Queue.pop_front();
- Lock.Unlock();
-
- if (!AuthFromAddress(m_Server, ActualAddress, UserName))
- {
- cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!");
- }
- else
- {
- cRoot::Get()->AuthenticateUser(ClientID);
- }
- } // for (-ever)
-}
-
-
-
-
-
-bool cAuthenticator::AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level /* = 1 */)
-{
- // Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep)
-
- cBlockingTCPLink Link;
- if (!Link.Connect(a_Server.c_str(), 80))
- {
- LOGWARNING("%s: cannot connect to auth server \"%s\", kicking user \"%s\"",
- __FUNCTION__, a_Server.c_str(), a_UserName.c_str()
- );
- return false;
- }
-
- Link.SendMessage( AString( "GET " + a_Address + " HTTP/1.1\r\n" ).c_str());
- Link.SendMessage( AString( "User-Agent: MCServer\r\n" ).c_str());
- Link.SendMessage( AString( "Host: " + a_Server + "\r\n" ).c_str());
- //Link.SendMessage( AString( "Host: session.minecraft.net\r\n" ).c_str());
- Link.SendMessage( AString( "Accept: */*\r\n" ).c_str());
- Link.SendMessage( AString( "Connection: close\r\n" ).c_str()); //Close so we don´t have to mess with the Content-Length :)
- Link.SendMessage( AString( "\r\n" ).c_str());
- AString DataRecvd;
- Link.ReceiveData(DataRecvd);
- Link.CloseSocket();
-
- std::stringstream ss(DataRecvd);
-
- // Parse the data received:
- std::string temp;
- ss >> temp;
- bool bRedirect = false;
- bool bOK = false;
- if ((temp.compare("HTTP/1.1") == 0) || (temp.compare("HTTP/1.0") == 0))
- {
- int code;
- ss >> code;
- if (code == 302)
- {
- // redirect blabla
- LOGD("%s: Need to redirect, current level %d!", __FUNCTION__, a_Level);
- if (a_Level > MAX_REDIRECTS)
- {
- LOGERROR("cAuthenticator: received too many levels of redirection from auth server \"%s\" for user \"%s\", bailing out and kicking the user", a_Server.c_str(), a_UserName.c_str());
- return false;
- }
- bRedirect = true;
- }
- else if (code == 200)
- {
- LOGD("cAuthenticator: Received status 200 OK! :D");
- bOK = true;
- }
- }
- else
- {
- LOGERROR("cAuthenticator: cannot parse auth reply from server \"%s\" for user \"%s\", kicking the user.", a_Server.c_str(), a_UserName.c_str());
- return false;
- }
-
- if( bRedirect )
- {
- AString Location;
- // Search for "Location:"
- bool bFoundLocation = false;
- while( !bFoundLocation && ss.good() )
- {
- char c = 0;
- while( c != '\n' )
- {
- ss.get( c );
- }
- AString Name;
- ss >> Name;
- if (Name.compare("Location:") == 0)
- {
- bFoundLocation = true;
- ss >> Location;
- }
- }
- if (!bFoundLocation)
- {
- LOGERROR("cAuthenticator: received invalid redirection from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
- return false;
- }
-
- Location = Location.substr(strlen("http://"), std::string::npos); // Strip http://
- std::string Server = Location.substr( 0, Location.find( "/" ) ); // Only leave server address
- Location = Location.substr( Server.length(), std::string::npos);
- return AuthFromAddress(Server, Location, a_UserName, a_Level + 1);
- }
-
- if (!bOK)
- {
- LOGERROR("cAuthenticator: received an error from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
- return false;
- }
-
- // Header says OK, so receive the rest.
- // Go past header, double \n means end of headers
- char c = 0;
- while (ss.good())
- {
- while (c != '\n')
- {
- ss.get(c);
- }
- ss.get(c);
- if( c == '\n' || c == '\r' || ss.peek() == '\r' || ss.peek() == '\n' )
- break;
- }
- if (!ss.good())
- {
- LOGERROR("cAuthenticator: error while parsing response body from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
- return false;
- }
-
- std::string Result;
- ss >> Result;
- LOGD("cAuthenticator: Authentication result was %s", Result.c_str());
-
- if (Result.compare("YES") == 0) //Works well
- {
- LOGINFO("Authentication result \"YES\", player authentication success!");
- return true;
- }
-
-
- LOGINFO("Authentication result was \"%s\", player authentication failure!", Result.c_str());
- return false;
-}
-
-
-
-
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 1cd7c74f8..4fe86e1c5 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -76,6 +76,7 @@ $cfile "../CompositeChat.h"
$cfile "../Map.h"
$cfile "../MapManager.h"
$cfile "../Scoreboard.h"
+$cfile "../Statistics.h"
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/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp
index db865cfa4..985a18a95 100644
--- a/src/Bindings/LuaChunkStay.cpp
+++ b/src/Bindings/LuaChunkStay.cpp
@@ -42,7 +42,7 @@ bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos)
// Add each set of coords:
int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos);
- m_Chunks.reserve(NumChunks);
+ m_Chunks.reserve((size_t)NumChunks);
for (int idx = 1; idx <= NumChunks; idx++)
{
// Push the idx-th element of the array onto stack top, check that it's a table:
diff --git a/src/Bindings/LuaFunctions.h b/src/Bindings/LuaFunctions.h
index 4f9eab86d..629e2d77d 100644
--- a/src/Bindings/LuaFunctions.h
+++ b/src/Bindings/LuaFunctions.h
@@ -4,12 +4,12 @@
#include <time.h>
// tolua_begin
-unsigned int GetTime()
+inline unsigned int GetTime()
{
return (unsigned int)time(0);
}
-std::string GetChar( std::string & a_Str, unsigned int a_Idx )
+inline std::string GetChar( std::string & a_Str, unsigned int a_Idx )
{
return std::string(1, a_Str[ a_Idx ]);
}
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 13eb17f7d..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"
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 20bbc48f2..14d9d16fc 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"
@@ -36,7 +37,7 @@
/****************************
* Better error reporting for Lua
**/
-int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError)
+static int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError)
{
// Retrieve current function name
lua_Debug entry;
@@ -56,7 +57,7 @@ int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaErro
-int lua_do_error(lua_State* L, const char * a_pFormat, ...)
+static int lua_do_error(lua_State* L, const char * a_pFormat, ...)
{
// Retrieve current function name
lua_Debug entry;
@@ -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,7 +191,51 @@ static int tolua_LOGERROR(lua_State* tolua_S)
-cPluginLua * GetLuaPlugin(lua_State * L)
+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;
+}
+
+
+
+
+
+static cPluginLua * GetLuaPlugin(lua_State * L)
{
// Get the plugin identification out of LuaState:
lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME);
@@ -1674,7 +1750,6 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
{
return 0;
}
- cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
// Read the params:
cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL);
@@ -1684,8 +1759,12 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
L.LogStackTrace();
return 0;
}
+
+ cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
+
if (!ChunkStay->AddChunks(2))
{
+ delete ChunkStay;
return 0;
}
@@ -1697,20 +1776,20 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
-static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
+static int tolua_cPlayer_GetGroups(lua_State * tolua_S)
{
- cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
+ cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL);
const cPlayer::GroupList & AllGroups = self->GetGroups();
- lua_createtable(tolua_S, AllGroups.size(), 0);
+ lua_createtable(tolua_S, (int)AllGroups.size(), 0);
int newTable = lua_gettop(tolua_S);
int index = 1;
cPlayer::GroupList::const_iterator iter = AllGroups.begin();
- while(iter != AllGroups.end())
+ while (iter != AllGroups.end())
{
- const cGroup* Group = *iter;
- tolua_pushusertype( tolua_S, (void*)Group, "const cGroup" );
+ const cGroup * Group = *iter;
+ tolua_pushusertype(tolua_S, (void *)Group, "const cGroup");
lua_rawseti(tolua_S, newTable, index);
++iter;
++index;
@@ -1722,20 +1801,20 @@ static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
-static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S)
+static int tolua_cPlayer_GetResolvedPermissions(lua_State * tolua_S)
{
- cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
+ cPlayer * self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
cPlayer::StringList AllPermissions = self->GetResolvedPermissions();
- lua_createtable(tolua_S, AllPermissions.size(), 0);
+ lua_createtable(tolua_S, (int)AllPermissions.size(), 0);
int newTable = lua_gettop(tolua_S);
int index = 1;
cPlayer::StringList::iterator iter = AllPermissions.begin();
- while(iter != AllPermissions.end())
+ while (iter != AllPermissions.end())
{
- std::string& Permission = *iter;
- tolua_pushstring( tolua_S, Permission.c_str() );
+ std::string & Permission = *iter;
+ lua_pushlstring(tolua_S, Permission.c_str(), Permission.length());
lua_rawseti(tolua_S, newTable, index);
++iter;
++index;
@@ -1997,18 +2076,18 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S)
static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
{
- cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S, 1, NULL);
+ cWebAdmin * self = (cWebAdmin *)tolua_tousertype(tolua_S, 1, NULL);
const cWebAdmin::PluginList & AllPlugins = self->GetPlugins();
- lua_createtable(tolua_S, AllPlugins.size(), 0);
+ lua_createtable(tolua_S, (int)AllPlugins.size(), 0);
int newTable = lua_gettop(tolua_S);
int index = 1;
cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin();
- while(iter != AllPlugins.end())
+ while (iter != AllPlugins.end())
{
- const cWebPlugin* Plugin = *iter;
- tolua_pushusertype( tolua_S, (void*)Plugin, "const cWebPlugin" );
+ const cWebPlugin * Plugin = *iter;
+ tolua_pushusertype(tolua_S, (void *)Plugin, "const cWebPlugin");
lua_rawseti(tolua_S, newTable, index);
++iter;
++index;
@@ -2785,8 +2864,8 @@ static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
}
// Set the type:
- int MessageType;
- L.GetStackValue(1, MessageType);
+ int MessageType = mtCustom;
+ L.GetStackValue(2, MessageType);
self->SetMessageType((eMessageType)MessageType);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
@@ -2838,6 +2917,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 837b1ae13..c6461c861 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -56,7 +56,7 @@ public:
virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0;
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) = 0;
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
- virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) = 0;
+ virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0;
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0;
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 46ee7da9e..625931931 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"
@@ -395,14 +400,14 @@ bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGri
-bool cPluginLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason)
+bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- m_LuaState.Call((int)(**itr), a_Player, a_Reason, cLuaState::Return, res);
+ m_LuaState.Call((int)(**itr), &a_Client, a_Reason, cLuaState::Return, res);
if (res)
{
return true;
@@ -1037,7 +1042,7 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message);
+ m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message, cLuaState::Return, res);
if (res)
{
return true;
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index ec74f07c6..598e031c0 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -79,7 +79,7 @@ public:
virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override;
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override;
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
- virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) override;
+ virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override;
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override;
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 4f528c2ae..acfc91bf8 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -143,13 +143,14 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni)
}
}
- if (GetNumPlugins() == 0)
+ size_t NumLoadedPlugins = GetNumPlugins();
+ if (NumLoadedPlugins == 0)
{
LOG("-- No Plugins Loaded --");
}
- else if (GetNumPlugins() > 1)
+ else if (NumLoadedPlugins > 1)
{
- LOG("-- Loaded %i Plugins --", GetNumPlugins());
+ LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins);
}
else
{
@@ -442,7 +443,7 @@ bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const cC
-bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Reason)
+bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_DISCONNECT);
if (Plugins == m_Hooks.end())
@@ -451,7 +452,7 @@ bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Re
}
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
- if ((*itr)->OnDisconnect(a_Player, a_Reason))
+ if ((*itr)->OnDisconnect(a_Client, a_Reason))
{
return true;
}
@@ -1869,7 +1870,7 @@ void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook)
-unsigned int cPluginManager::GetNumPlugins() const
+size_t cPluginManager::GetNumPlugins() const
{
return m_Plugins.size();
}
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index 6c4e8bae7..be40bd2f7 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -159,7 +159,7 @@ public: // tolua_export
/** Adds the plugin to the list of plugins called for the specified hook type. Handles multiple adds as a single add */
void AddHook(cPlugin * a_Plugin, int a_HookType);
- unsigned int GetNumPlugins() const; // tolua_export
+ size_t 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);
@@ -172,7 +172,7 @@ public: // tolua_export
bool CallHookChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup);
bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
- bool CallHookDisconnect (cPlayer * a_Player, const AString & a_Reason);
+ bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason);
bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd
bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
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 1e3cc7789..ba3a6b0c7 100644
--- a/src/Bindings/tolua++.exe
+++ b/src/Bindings/tolua++.exe
Binary files differ
diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp
index 3fba93e8a..9852b3dd9 100644
--- a/src/BiomeDef.cpp
+++ b/src/BiomeDef.cpp
@@ -7,6 +7,88 @@
#include "BiomeDef.h"
+
+
+// The "map" used for biome <-> string conversions:
+static struct {
+ EMCSBiome m_Biome;
+ const char * m_String;
+} g_BiomeMap[] =
+{
+ {biOcean, "Ocean"} ,
+ {biPlains, "Plains"},
+ {biDesert, "Desert"},
+ {biExtremeHills, "ExtremeHills"},
+ {biForest, "Forest"},
+ {biTaiga, "Taiga"},
+ {biSwampland, "Swampland"},
+ {biRiver, "River"},
+ {biNether, "Hell"},
+ {biNether, "Nether"},
+ {biEnd, "Sky"},
+ {biEnd, "End"},
+ {biFrozenOcean, "FrozenOcean"},
+ {biFrozenRiver, "FrozenRiver"},
+ {biIcePlains, "IcePlains"},
+ {biIcePlains, "Tundra"},
+ {biIceMountains, "IceMountains"},
+ {biMushroomIsland, "MushroomIsland"},
+ {biMushroomShore, "MushroomShore"},
+ {biBeach, "Beach"},
+ {biDesertHills, "DesertHills"},
+ {biForestHills, "ForestHills"},
+ {biTaigaHills, "TaigaHills"},
+ {biExtremeHillsEdge, "ExtremeHillsEdge"},
+ {biJungle, "Jungle"},
+ {biJungleHills, "JungleHills"},
+
+ // Release 1.7 biomes:
+ {biJungleEdge, "JungleEdge"},
+ {biDeepOcean, "DeepOcean"},
+ {biStoneBeach, "StoneBeach"},
+ {biColdBeach, "ColdBeach"},
+ {biBirchForest, "BirchForest"},
+ {biBirchForestHills, "BirchForestHills"},
+ {biRoofedForest, "RoofedForest"},
+ {biColdTaiga, "ColdTaiga"},
+ {biColdTaigaHills, "ColdTaigaHills"},
+ {biMegaTaiga, "MegaTaiga"},
+ {biMegaTaigaHills, "MegaTaigaHills"},
+ {biExtremeHillsPlus, "ExtremeHillsPlus"},
+ {biSavanna, "Savanna"},
+ {biSavannaPlateau, "SavannaPlateau"},
+ {biMesa, "Mesa"},
+ {biMesaPlateauF, "MesaPlateauF"},
+ {biMesaPlateau, "MesaPlateau"},
+
+ // Release 1.7 variants:
+ {biSunflowerPlains, "SunflowerPlains"},
+ {biDesertM, "DesertM"},
+ {biExtremeHillsM, "ExtremeHillsM"},
+ {biFlowerForest, "FlowerForest"},
+ {biTaigaM, "TaigaM"},
+ {biSwamplandM, "SwamplandM"},
+ {biIcePlainsSpikes, "IcePlainsSpikes"},
+ {biJungleM, "JungleM"},
+ {biJungleEdgeM, "JungleEdgeM"},
+ {biBirchForestM, "BirchForestM"},
+ {biBirchForestHillsM, "BirchForestHillsM"},
+ {biRoofedForestM, "RoofedForestM"},
+ {biColdTaigaM, "ColdTaigaM"},
+ {biMegaSpruceTaiga, "MegaSpruceTaiga"},
+ {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"},
+ {biExtremeHillsPlusM, "ExtremeHillsPlusM"},
+ {biSavannaM, "SavannaM"},
+ {biSavannaPlateauM, "SavannaPlateauM"},
+ {biMesaBryce, "MesaBryce"},
+ {biMesaPlateauFM, "MesaPlateauFM"},
+ {biMesaPlateauM, "MesaPlateauM"},
+} ;
+
+
+
+
+
EMCSBiome StringToBiome(const AString & a_BiomeString)
{
// If it is a number, return it:
@@ -25,87 +107,11 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
return biInvalidBiome;
}
- // Convert using the built-in map:
- static struct {
- EMCSBiome m_Biome;
- const char * m_String;
- } BiomeMap[] =
- {
- {biOcean, "Ocean"} ,
- {biPlains, "Plains"},
- {biDesert, "Desert"},
- {biExtremeHills, "ExtremeHills"},
- {biForest, "Forest"},
- {biTaiga, "Taiga"},
- {biSwampland, "Swampland"},
- {biRiver, "River"},
- {biNether, "Hell"},
- {biNether, "Nether"},
- {biEnd, "Sky"},
- {biEnd, "End"},
- {biFrozenOcean, "FrozenOcean"},
- {biFrozenRiver, "FrozenRiver"},
- {biIcePlains, "IcePlains"},
- {biIcePlains, "Tundra"},
- {biIceMountains, "IceMountains"},
- {biMushroomIsland, "MushroomIsland"},
- {biMushroomShore, "MushroomShore"},
- {biBeach, "Beach"},
- {biDesertHills, "DesertHills"},
- {biForestHills, "ForestHills"},
- {biTaigaHills, "TaigaHills"},
- {biExtremeHillsEdge, "ExtremeHillsEdge"},
- {biJungle, "Jungle"},
- {biJungleHills, "JungleHills"},
-
- // Release 1.7 biomes:
- {biJungleEdge, "JungleEdge"},
- {biDeepOcean, "DeepOcean"},
- {biStoneBeach, "StoneBeach"},
- {biColdBeach, "ColdBeach"},
- {biBirchForest, "BirchForest"},
- {biBirchForestHills, "BirchForestHills"},
- {biRoofedForest, "RoofedForest"},
- {biColdTaiga, "ColdTaiga"},
- {biColdTaigaHills, "ColdTaigaHills"},
- {biMegaTaiga, "MegaTaiga"},
- {biMegaTaigaHills, "MegaTaigaHills"},
- {biExtremeHillsPlus, "ExtremeHillsPlus"},
- {biSavanna, "Savanna"},
- {biSavannaPlateau, "SavannaPlateau"},
- {biMesa, "Mesa"},
- {biMesaPlateauF, "MesaPlateauF"},
- {biMesaPlateau, "MesaPlateau"},
-
- // Release 1.7 variants:
- {biSunflowerPlains, "SunflowerPlains"},
- {biDesertM, "DesertM"},
- {biExtremeHillsM, "ExtremeHillsM"},
- {biFlowerForest, "FlowerForest"},
- {biTaigaM, "TaigaM"},
- {biSwamplandM, "SwamplandM"},
- {biIcePlainsSpikes, "IcePlainsSpikes"},
- {biJungleM, "JungleM"},
- {biJungleEdgeM, "JungleEdgeM"},
- {biBirchForestM, "BirchForestM"},
- {biBirchForestHillsM, "BirchForestHillsM"},
- {biRoofedForestM, "RoofedForestM"},
- {biColdTaigaM, "ColdTaigaM"},
- {biMegaSpruceTaiga, "MegaSpruceTaiga"},
- {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"},
- {biExtremeHillsPlusM, "ExtremeHillsPlusM"},
- {biSavannaM, "SavannaM"},
- {biSavannaPlateauM, "SavannaPlateauM"},
- {biMesaBryce, "MesaBryce"},
- {biMesaPlateauFM, "MesaPlateauFM"},
- {biMesaPlateauM, "MesaPlateauM"},
- } ;
-
- for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++)
+ for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++)
{
- if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0)
+ if (NoCaseCompare(g_BiomeMap[i].m_String, a_BiomeString) == 0)
{
- return BiomeMap[i].m_Biome;
+ return g_BiomeMap[i].m_Biome;
}
} // for i - BiomeMap[]
return biInvalidBiome;
@@ -115,6 +121,22 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
+AString BiomeToString(int a_Biome)
+{
+ for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++)
+ {
+ if (g_BiomeMap[i].m_Biome == a_Biome)
+ {
+ return g_BiomeMap[i].m_String;
+ }
+ }
+ return AString();
+}
+
+
+
+
+
bool IsBiomeNoDownfall(EMCSBiome a_Biome)
{
switch (a_Biome)
diff --git a/src/BiomeDef.h b/src/BiomeDef.h
index 474d4df76..f929596e9 100644
--- a/src/BiomeDef.h
+++ b/src/BiomeDef.h
@@ -10,7 +10,7 @@
#pragma once
-
+#include "StringUtils.h"
// tolua_begin
@@ -104,10 +104,13 @@ enum EMCSBiome
biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value
} ;
-/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure.
+/** Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. */
extern EMCSBiome StringToBiome(const AString & a_BiomeString);
-/// Returns true if the biome has no downfall - deserts and savannas
+/** Translates biome enum into biome string. Returns empty string on failure (unknown biome). */
+extern AString BiomeToString(int a_Biome);
+
+/** Returns true if the biome has no downfall - deserts and savannas */
extern bool IsBiomeNoDownfall(EMCSBiome a_Biome);
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index f6d54e41c..40fdd68c0 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -9,22 +9,34 @@
#include "OSSupport/GZipFile.h"
#include "Blocks/BlockHandler.h"
#include "Cuboid.h"
+#include "ChunkData.h"
+// Disable MSVC warnings: "conditional expression is constant"
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable:4127)
+#endif
+
+
+
+
+
+typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta);
// This wild construct allows us to pass a function argument and still have it inlined by the compiler :)
/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function
-template<typename Combinator> void InternalMergeBlocks(
+template<bool MetasValid, CombinatorFunc Combinator>
+void InternalMergeBlocks(
BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes,
NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
int a_SizeX, int a_SizeY, int a_SizeZ,
int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
int a_DstOffX, int a_DstOffY, int a_DstOffZ,
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
- int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ,
- Combinator a_Combinator
+ int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ
)
{
UNUSED(a_SrcSizeY);
@@ -41,7 +53,15 @@ template<typename Combinator> void InternalMergeBlocks(
int DstIdx = DstBaseZ + a_DstOffX;
for (int x = 0; x < a_SizeX; x++)
{
- a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
+ if (MetasValid)
+ {
+ Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
+ }
+ else
+ {
+ BLOCKTYPE FakeDestMeta = 0;
+ Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0);
+ }
++DstIdx;
++SrcIdx;
} // for x
@@ -54,10 +74,14 @@ 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)
+template<bool MetaValid>
+void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
a_DstType = a_SrcType;
- a_DstMeta = a_SrcMeta;
+ if (MetaValid)
+ {
+ a_DstMeta = a_SrcMeta;
+ }
}
@@ -65,12 +89,16 @@ 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)
+template<bool MetaValid>
+void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_DstType == E_BLOCK_AIR)
{
a_DstType = a_SrcType;
- a_DstMeta = a_SrcMeta;
+ if (MetaValid)
+ {
+ a_DstMeta = a_SrcMeta;
+ }
}
// "else" is the default, already in place
}
@@ -80,12 +108,16 @@ 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)
+template<bool MetaValid>
+void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_SrcType != E_BLOCK_AIR)
{
a_DstType = a_SrcType;
- a_DstMeta = a_SrcMeta;
+ if (MetaValid)
+ {
+ a_DstMeta = a_SrcMeta;
+ }
}
// "else" is the default, already in place
}
@@ -95,7 +127,8 @@ 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)
+template<bool MetaValid>
+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)
@@ -107,7 +140,10 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
if (a_SrcType == E_BLOCK_AIR)
{
a_DstType = E_BLOCK_AIR;
- a_DstMeta = 0;
+ if (MetaValid)
+ {
+ a_DstMeta = 0;
+ }
return;
}
@@ -132,7 +168,10 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
case E_BLOCK_STATIONARY_LAVA:
{
a_DstType = a_SrcType;
- a_DstMeta = a_SrcMeta;
+ if (MetaValid)
+ {
+ a_DstMeta = a_SrcMeta;
+ }
return;
}
}
@@ -146,7 +185,10 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
case E_BLOCK_MYCELIUM:
{
a_DstType = E_BLOCK_STONE;
- a_DstMeta = 0;
+ if (MetaValid)
+ {
+ a_DstMeta = 0;
+ }
return;
}
}
@@ -158,6 +200,75 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
+/** Combinator used for cBlockArea::msSpongePrint merging */
+template<bool MetaValid>
+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;
+ if (MetaValid)
+ {
+ a_DstMeta = a_SrcMeta;
+ }
+ }
+}
+
+
+
+
+
+/** Combinator used for cBlockArea::msDifference merging */
+template<bool MetaValid>
+void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+{
+ if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta)))
+ {
+ a_DstType = E_BLOCK_AIR;
+ if (MetaValid)
+ {
+ a_DstMeta = 0;
+ }
+ }
+ else
+ {
+ a_DstType = a_SrcType;
+ if (MetaValid)
+ {
+ a_DstMeta = a_SrcMeta;
+ }
+ }
+}
+
+
+
+
+
+/** Combinator used for cBlockArea::msMask merging */
+template<bool MetaValid>
+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) || !MetaValid || (a_SrcMeta != a_DstMeta))
+ {
+ a_DstType = E_BLOCK_AIR;
+ if (MetaValid)
+ {
+ a_DstMeta = 0;
+ }
+ }
+}
+
+// Re-enable previously disabled MSVC warnings
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBlockArea:
@@ -435,7 +546,7 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
a_Into.Clear();
a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
a_Into.m_Origin = m_Origin;
- int BlockCount = GetBlockCount();
+ size_t BlockCount = GetBlockCount();
if (HasBlockTypes())
{
memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE));
@@ -481,9 +592,9 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
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();
+ size_t NumBlocks = GetBlockCount();
if (HasBlockTypes())
{
f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE));
@@ -588,110 +699,19 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
{
- // Block types are compulsory, block metas are voluntary
- if (!HasBlockTypes() || !a_Src.HasBlockTypes())
- {
- LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
- return;
- }
-
- // Dst is *this, Src is a_Src
- int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
- int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
- int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
-
- int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
- int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
- int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
-
- int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
- int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
- int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
NIBBLETYPE * DstMetas = m_BlockMetas;
+
bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
if (IsDummyMetas)
{
- SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()];
- DstMetas = new NIBBLETYPE[GetBlockCount()];
+ MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
}
-
- switch (a_Strategy)
- {
- case msOverwrite:
- {
- 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,
- MergeCombinatorOverwrite
- );
- break;
- } // case msOverwrite
-
- case msFillAir:
- {
- 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,
- MergeCombinatorFillAir
- );
- break;
- } // case msFillAir
-
- case msImprint:
- {
- 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,
- MergeCombinatorImprint
- );
- break;
- } // case msImprint
-
- case msLake:
- {
- 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,
- MergeCombinatorLake
- );
- break;
- } // case msLake
-
- default:
- {
- LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
- ASSERT(!"Unknown block area merge strategy");
- break;
- }
- } // switch (a_Strategy)
-
- if (IsDummyMetas)
+ else
{
- delete[] SrcMetas;
- delete[] DstMetas;
+ MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
}
}
@@ -718,31 +738,31 @@ void cBlockArea::Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_Block
a_DataTypes = a_DataTypes & GetDataTypes();
}
- int BlockCount = GetBlockCount();
+ size_t BlockCount = GetBlockCount();
if ((a_DataTypes & baTypes) != 0)
{
- for (int i = 0; i < BlockCount; i++)
+ for (size_t i = 0; i < BlockCount; i++)
{
m_BlockTypes[i] = a_BlockType;
}
}
if ((a_DataTypes & baMetas) != 0)
{
- for (int i = 0; i < BlockCount; i++)
+ for (size_t i = 0; i < BlockCount; i++)
{
m_BlockMetas[i] = a_BlockMeta;
}
}
if ((a_DataTypes & baLight) != 0)
{
- for (int i = 0; i < BlockCount; i++)
+ for (size_t i = 0; i < BlockCount; i++)
{
m_BlockLight[i] = a_BlockLight;
}
}
if ((a_DataTypes & baSkyLight) != 0)
{
- for (int i = 0; i < BlockCount; i++)
+ for (size_t i = 0; i < BlockCount; i++)
{
m_BlockSkyLight[i] = a_BlockSkyLight;
}
@@ -1815,116 +1835,88 @@ bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ)
-void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
+void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer)
{
- if (m_Area.m_BlockTypes == NULL)
- {
- // Don't want BlockTypes
- return;
- }
-
- 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
- // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
- int SizeX = cChunkDef::Width;
- int SizeZ = cChunkDef::Width;
- int OffX, OffZ;
- int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
- if (OffX < 0)
- {
- BaseX = -OffX;
- SizeX += OffX; // SizeX is decreased, OffX is negative
- OffX = 0;
- }
- else
- {
- BaseX = 0;
- }
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
- if (OffZ < 0)
- {
- BaseZ = -OffZ;
- SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
- OffZ = 0;
- }
- else
- {
- 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_Origin.x + m_Area.m_Size.x)
- {
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
- }
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
- }
-
- for (int y = 0; y < SizeY; y++)
- {
- int ChunkY = MinY + y;
- int AreaY = y;
- for (int z = 0; z < SizeZ; z++)
+ if (m_Area.m_BlockTypes != NULL)
{
- int ChunkZ = BaseZ + z;
- int AreaZ = OffZ + z;
- for (int x = 0; x < SizeX; x++)
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
+
+ // SizeX, SizeZ are the dimensions 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
+ // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
+ int SizeX = cChunkDef::Width;
+ int SizeZ = cChunkDef::Width;
+ int OffX, OffZ;
+ int BaseX, BaseZ;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
+ if (OffX < 0)
{
- int ChunkX = BaseX + x;
- int AreaX = OffX + x;
- m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ);
- } // for x
- } // for z
- } // for y
-}
-
-
-
+ BaseX = -OffX;
+ SizeX += OffX; // SizeX is decreased, OffX is negative
+ OffX = 0;
+ }
+ else
+ {
+ BaseX = 0;
+ }
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
+ if (OffZ < 0)
+ {
+ BaseZ = -OffZ;
+ SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
+ OffZ = 0;
+ }
+ else
+ {
+ 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_Origin.x + m_Area.m_Size.x)
+ {
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
+ }
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
+ {
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
+ }
+ for (int y = 0; y < SizeY; y++)
+ {
+ int ChunkY = MinY + y;
+ int AreaY = y;
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int ChunkZ = BaseZ + z;
+ int AreaZ = OffZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int ChunkX = BaseX + x;
+ int AreaX = OffX + x;
+ m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockBuffer.GetBlock(ChunkX, ChunkY, ChunkZ);
+ } // for x
+ } // for z
+ } // for y
+ }
+ }
-void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas)
-{
- if (m_Area.m_BlockMetas == NULL)
+ if (m_Area.m_BlockMetas != NULL)
{
- // Don't want metas
- return;
+ a_BlockBuffer.CopyMetas(m_Area.m_BlockMetas);
}
- CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas);
-}
-
-
-
-
-void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight)
-{
- if (m_Area.m_BlockLight == NULL)
+ if (m_Area.m_BlockLight != NULL)
{
- // Don't want light
- return;
+ a_BlockBuffer.CopyBlockLight(m_Area.m_BlockLight);
}
- CopyNibbles(m_Area.m_BlockLight, a_BlockLight);
-}
-
-
-
-
-void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight)
-{
- if (m_Area.m_BlockSkyLight == NULL)
+ if (m_Area.m_BlockSkyLight != NULL)
{
- // Don't want skylight
- return;
+ a_BlockBuffer.CopySkyLight(m_Area.m_BlockSkyLight);
}
- CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight);
-}
+}
@@ -1985,7 +1977,7 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
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;
+ size_t BlockCount = (size_t)(NewSizeX * NewSizeY * NewSizeZ);
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
int OldIndex = 0;
@@ -2015,7 +2007,7 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
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;
+ size_t BlockCount = (size_t)(NewSizeX * NewSizeY * NewSizeZ);
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
int OldIndex = 0;
@@ -2067,4 +2059,134 @@ void cBlockArea::RelSetData(
+template<bool MetasValid>
+void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas)
+{
+ // Block types are compulsory, block metas are voluntary
+ if (!HasBlockTypes() || !a_Src.HasBlockTypes())
+ {
+ LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
+ return;
+ }
+
+ // Dst is *this, Src is a_Src
+ int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
+ int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
+ int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
+
+ int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
+ int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
+ int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
+
+ int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
+ int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
+ int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
+
+ switch (a_Strategy)
+ {
+ case cBlockArea::msOverwrite:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msOverwrite
+
+ case cBlockArea::msFillAir:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msFillAir
+
+ case cBlockArea::msImprint:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msImprint
+
+ case cBlockArea::msLake:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msLake
+
+ case cBlockArea::msSpongePrint:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msSpongePrint
+
+ case cBlockArea::msDifference:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msDifference
+
+ case cBlockArea::msMask:
+ {
+ InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >(
+ 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
+ );
+ return;
+ } // case msMask
+ } // switch (a_Strategy)
+
+ LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
+ ASSERT(!"Unknown block area merge strategy");
+ return;
+}
+
+
diff --git a/src/BlockArea.h b/src/BlockArea.h
index d28325d7d..2bd26facd 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -14,6 +14,7 @@
#include "ForEachChunkProvider.h"
#include "Vector3.h"
+#include "ChunkDataCallback.h"
@@ -51,6 +52,9 @@ public:
msFillAir,
msImprint,
msLake,
+ msSpongePrint,
+ msDifference,
+ msMask,
} ;
cBlockArea(void);
@@ -127,8 +131,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 |
+----------+--------+--------+
@@ -143,6 +147,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);
@@ -275,7 +295,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_Size.x * m_Size.y * m_Size.z; }
+ size_t GetBlockCount(void) const { return (size_t)(m_Size.x * m_Size.y * m_Size.z); }
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
protected:
@@ -297,11 +317,8 @@ protected:
void CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc);
// cChunkDataCallback overrides:
- virtual bool Coords (int a_ChunkX, int a_ChunkZ) override;
- virtual void BlockTypes (const BLOCKTYPE * a_BlockTypes) override;
- virtual void BlockMeta (const NIBBLETYPE * a_BlockMetas) override;
- virtual void BlockLight (const NIBBLETYPE * a_BlockLight) override;
- virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override;
+ virtual bool Coords(int a_ChunkX, int a_ChunkZ) override;
+ virtual void ChunkData(const cChunkData & a_BlockTypes) override;
} ;
typedef NIBBLETYPE * NIBBLEARRAY;
@@ -344,6 +361,9 @@ protected:
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
);
+
+ template<bool MetasValid>
+ void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas);
// tolua_begin
} ;
// tolua_end
diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp
new file mode 100644
index 000000000..0914353eb
--- /dev/null
+++ b/src/BlockEntities/BeaconEntity.cpp
@@ -0,0 +1,116 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "BeaconEntity.h"
+#include "../BlockArea.h"
+
+
+
+
+
+cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
+ super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World)
+{
+}
+
+
+
+
+
+int cBeaconEntity::GetPyramidLevel(void)
+{
+ cBlockArea Area;
+ int MinY = GetPosY() - 4;
+ if (MinY < 0)
+ {
+ MinY = 0;
+ }
+ int MaxY = GetPosY() - 1;
+ if (MaxY < 0)
+ {
+ MaxY = 0;
+ }
+
+ Area.Read(
+ m_World,
+ GetPosX() - 4, GetPosX() + 4,
+ MinY, MaxY,
+ GetPosZ() - 4, GetPosZ() + 4,
+ cBlockArea::baTypes
+ );
+
+ int Layer = 1;
+ int MiddleXZ = 4;
+
+ for (int Y = Area.GetSizeY() - 1; Y > 0; Y--)
+ {
+ for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++)
+ {
+ for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++)
+ {
+ if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z)))
+ {
+ return Layer - 1;
+ }
+ }
+ }
+ Layer++;
+ }
+
+ return Layer - 1;
+}
+
+
+
+
+
+bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
+{
+ switch(a_BlockType)
+ {
+ case E_BLOCK_DIAMOND_BLOCK:
+ case E_BLOCK_GOLD_BLOCK:
+ case E_BLOCK_IRON_BLOCK:
+ case E_BLOCK_EMERALD_BLOCK:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ return false;
+}
+
+
+
+
+
+void cBeaconEntity::SaveToJson(Json::Value& a_Value)
+{
+}
+
+
+
+
+void cBeaconEntity::SendTo(cClientHandle & a_Client)
+{
+}
+
+
+
+
+
+void cBeaconEntity::UsedBy(cPlayer * a_Player)
+{
+}
+
+
+
+
diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h
new file mode 100644
index 000000000..b1df68bc4
--- /dev/null
+++ b/src/BlockEntities/BeaconEntity.h
@@ -0,0 +1,44 @@
+
+#pragma once
+
+#include "BlockEntity.h"
+
+
+
+
+
+namespace Json
+{
+ class Value;
+}
+
+
+
+
+
+class cBeaconEntity :
+ public cBlockEntity
+{
+ typedef cBlockEntity super;
+
+public:
+
+ /** The initial constructor */
+ cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+ /** Returns the amount of layers the pyramid below the beacon has. */
+ int GetPyramidLevel(void);
+
+ /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */
+ static bool IsMineralBlock(BLOCKTYPE a_BlockType);
+
+ // cBlockEntity overrides:
+ virtual void SaveToJson(Json::Value& a_Value ) override;
+ virtual void SendTo(cClientHandle & a_Client) override;
+ virtual void UsedBy(cPlayer * a_Player) override;
+ virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override;
+} ;
+
+
+
+
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index b42318c2f..430f04551 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -4,6 +4,7 @@
// Implements the cBlockEntity class that is the common ancestor for all block entities
#include "Globals.h"
+#include "BeaconEntity.h"
#include "BlockEntity.h"
#include "ChestEntity.h"
#include "CommandBlockEntity.h"
@@ -26,6 +27,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
{
switch (a_BlockType)
{
+ case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt
index 920767f5c..3e3d17f86 100644
--- a/src/BlockEntities/CMakeLists.txt
+++ b/src/BlockEntities/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(BlockEntities ${SOURCE})
diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp
index d395997a6..146ad915b 100644
--- a/src/BlockEntities/CommandBlockEntity.cpp
+++ b/src/BlockEntities/CommandBlockEntity.cpp
@@ -21,7 +21,8 @@
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
m_ShouldExecute(false),
- m_IsPowered(false)
+ m_IsPowered(false),
+ m_Result(0)
{}
@@ -160,7 +161,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/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index e03bf776d..2a32f69d9 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -128,10 +128,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR)
{
DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0);
- m_Contents.SetSlot(a_SlotNum, m_Contents.GetSlot(a_SlotNum).m_ItemType, m_Contents.GetSlot(a_SlotNum).m_ItemCount, m_Contents.GetSlot(a_SlotNum).m_ItemDamage + 1);
- // If the durability has run out destroy the item.
- if (m_Contents.GetSlot(a_SlotNum).m_ItemDamage > 64)
- {
+
+ bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1);
+
+ if (ItemBroke)
+ {
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
}
diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp
index 7d6d1f89e..1b1741713 100644
--- a/src/BlockEntities/FurnaceEntity.cpp
+++ b/src/BlockEntities/FurnaceEntity.cpp
@@ -413,19 +413,20 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
return false;
}
- if (m_Contents.GetSlot(fsOutput).IsEmpty())
+ const cItem & Slot = m_Contents.GetSlot(fsOutput);
+ if (Slot.IsEmpty())
{
// The output is empty, can cook
return true;
}
- if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out))
+ if (!Slot.IsEqual(*m_CurrentRecipe->Out))
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false;
}
- if (m_Contents.GetSlot(fsOutput).IsFullStack())
+ if (Slot.IsFullStack())
{
// Cannot add any more items to the output slot
return false;
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index 41fb9f811..7f001c739 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -234,24 +234,27 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool TrySuckPickupIn(cPickup * a_Pickup)
{
+ cItem & Item = a_Pickup->GetItem();
+
for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{
if (m_Contents.IsSlotEmpty(i))
{
m_bFoundPickupsAbove = true;
- m_Contents.SetSlot(i, a_Pickup->GetItem());
+ m_Contents.SetSlot(i, Item);
a_Pickup->Destroy(); // Kill pickup
return true;
}
- else if (m_Contents.GetSlot(i).IsEqual(a_Pickup->GetItem()) && !m_Contents.GetSlot(i).IsFullStack())
+ else if (m_Contents.GetSlot(i).IsEqual(Item) && !m_Contents.GetSlot(i).IsFullStack())
{
m_bFoundPickupsAbove = true;
int PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
- a_Pickup->GetItem().m_ItemCount -= m_Contents.ChangeSlotCount(i, a_Pickup->GetItem().m_ItemCount) - PreviousCount; // Set count to however many items were added
- if (a_Pickup->GetItem().IsEmpty())
+ Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added
+
+ if (Item.IsEmpty())
{
a_Pickup->Destroy(); // Kill pickup if all items were added
}
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
index c0a1781f6..dc9c18d58 100644
--- a/src/BlockEntities/MobHeadEntity.cpp
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -14,6 +14,8 @@
cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
+ m_Type(SKULL_TYPE_SKELETON),
+ m_Rotation(SKULL_ROTATION_NORTH),
m_Owner("")
{
}
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index 79e122032..bfe826f40 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -102,7 +102,7 @@ public:
return true;
}
- a_Item.m_ItemDamage = atoi(Split[1].c_str());
+ a_Item.m_ItemDamage = (short)atoi(Split[1].c_str());
if ((a_Item.m_ItemDamage == 0) && (Split[1] != "0"))
{
// Parsing the number failed
@@ -324,7 +324,7 @@ eDimension StringToDimension(const AString & a_DimensionString)
{ dimOverworld, "Normal"},
{ dimOverworld, "World"},
{ dimNether, "Nether"},
- { dimNether, "Hell"}, // Alternate name for End
+ { dimNether, "Hell"}, // Alternate name for Nether
{ dimEnd, "End"},
{ dimEnd, "Sky"}, // Old name for End
} ;
@@ -337,7 +337,8 @@ eDimension StringToDimension(const AString & a_DimensionString)
} // for i - DimensionMap[]
// Not found
- return (eDimension)-1000;
+ LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", a_DimensionString.c_str());
+ return dimOverworld;
}
diff --git a/src/BlockID.h b/src/BlockID.h
index 2fec512e2..a227245aa 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -503,6 +503,10 @@ enum
E_META_PLANKS_CONIFER = 1,
E_META_PLANKS_BIRCH = 2,
E_META_PLANKS_JUNGLE = 3,
+
+ // E_BLOCK_(XXX_WEIGHTED)_PRESSURE_PLATE metas:
+ E_META_PRESSURE_PLATE_RAISED = 0,
+ E_META_PRESSURE_PLATE_DEPRESSED = 1,
// E_BLOCK_QUARTZ_BLOCK metas:
E_META_QUARTZ_NORMAL = 0,
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 7d438ba3e..e8d9a7ec4 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -110,10 +110,13 @@ void cBlockInfo::Initialize(void)
// Transparent blocks
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_AIR ].m_Transparent = true;
+ ms_Info[E_BLOCK_ANVIL ].m_Transparent = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_Transparent = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_Transparent = true;
+ ms_Info[E_BLOCK_CAKE ].m_Transparent = true;
ms_Info[E_BLOCK_CARROTS ].m_Transparent = true;
ms_Info[E_BLOCK_CHEST ].m_Transparent = true;
+ ms_Info[E_BLOCK_COBBLESTONE_WALL ].m_Transparent = true;
ms_Info[E_BLOCK_COBWEB ].m_Transparent = true;
ms_Info[E_BLOCK_CROPS ].m_Transparent = true;
ms_Info[E_BLOCK_DANDELION ].m_Transparent = true;
@@ -126,9 +129,11 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_FLOWER_POT ].m_Transparent = true;
ms_Info[E_BLOCK_GLASS ].m_Transparent = true;
ms_Info[E_BLOCK_GLASS_PANE ].m_Transparent = true;
+ ms_Info[E_BLOCK_HEAD ].m_Transparent = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_ICE ].m_Transparent = true;
ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
+ ms_Info[E_BLOCK_LADDER ].m_Transparent = true;
ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
@@ -195,12 +200,14 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_BED ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_CAKE ].m_PistonBreakable = true;
ms_Info[E_BLOCK_COBWEB ].m_PistonBreakable = true;
ms_Info[E_BLOCK_CROPS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_DANDELION ].m_PistonBreakable = true;
ms_Info[E_BLOCK_DEAD_BUSH ].m_PistonBreakable = true;
ms_Info[E_BLOCK_FIRE ].m_PistonBreakable = true;
ms_Info[E_BLOCK_FLOWER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_HEAD ].m_PistonBreakable = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true;
@@ -242,6 +249,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_CACTUS ].m_IsSnowable = false;
ms_Info[E_BLOCK_CHEST ].m_IsSnowable = false;
ms_Info[E_BLOCK_CROPS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_COBBLESTONE_WALL ].m_IsSnowable = false;
ms_Info[E_BLOCK_DANDELION ].m_IsSnowable = false;
ms_Info[E_BLOCK_FIRE ].m_IsSnowable = false;
ms_Info[E_BLOCK_FLOWER ].m_IsSnowable = false;
@@ -275,6 +283,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_COBWEB ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_HEAD ].m_IsSnowable = false;
// Blocks that don't drop without a special tool:
@@ -282,6 +291,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_CAULDRON ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COAL_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBBLESTONE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_COBBLESTONE_WALL ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBBLESTONE_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBWEB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_RequiresSpecialTool = true;
@@ -324,6 +334,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_AIR ].m_IsSolid = false;
ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false;
+ ms_Info[E_BLOCK_CAKE ].m_IsSolid = false;
ms_Info[E_BLOCK_CARROTS ].m_IsSolid = false;
ms_Info[E_BLOCK_COBWEB ].m_IsSolid = false;
ms_Info[E_BLOCK_CROPS ].m_IsSolid = false;
@@ -365,7 +376,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 +408,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..35a356678 100644
--- a/src/Blocks/BlockAnvil.h
+++ b/src/Blocks/BlockAnvil.h
@@ -18,10 +18,19 @@ public:
{
}
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
}
+
+
+ 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
+ {
+ cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ);
+ a_Player->OpenWindow(Window);
+ }
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
@@ -31,27 +40,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..51e79b888 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)
{
}
@@ -39,6 +39,13 @@ public:
}
+ virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
+ {
+ return true;
+ }
+
+
+
// Bed specific helper functions
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h
new file mode 100644
index 000000000..39fd3cac8
--- /dev/null
+++ b/src/Blocks/BlockBigFlower.h
@@ -0,0 +1,131 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockBigFlowerHandler :
+ public cBlockHandler
+{
+public:
+ typedef cBlockHandler super;
+
+ cBlockBigFlowerHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ if (Meta & 0x8)
+ {
+ super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY - 1, a_BlockZ);
+ }
+ else
+ {
+ super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ);
+ }
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ NIBBLETYPE Meta = a_BlockMeta & 0x7;
+
+ if ((Meta == 2) || (Meta == 3))
+ {
+ return;
+ }
+
+ a_Pickups.push_back(cItem(E_BLOCK_BIG_FLOWER, 1, Meta));
+ }
+
+
+ virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ if (Meta & 0x8)
+ {
+ Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ);
+ }
+
+ NIBBLETYPE FlowerMeta = Meta & 0x7;
+ if (!a_Player->IsGameModeCreative())
+ {
+ if (((FlowerMeta == 2) || (FlowerMeta == 3)) && (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SHEARS))
+ {
+ MTRand r1;
+ if (r1.randInt(10) == 5)
+ {
+ cItems Pickups;
+ if (FlowerMeta == 2)
+ {
+ Pickups.Add(E_BLOCK_TALL_GRASS, 2, 1);
+ }
+ else if (FlowerMeta == 3)
+ {
+ Pickups.Add(E_BLOCK_TALL_GRASS, 2, 2);
+ }
+ a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ);
+ }
+ a_Player->UseEquippedItem();
+ }
+ }
+ }
+
+
+ virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
+ {
+ return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR) && (a_RelY < cChunkDef::Height) && ((a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR) || (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_BIG_FLOWER)));
+ }
+
+
+ virtual void OnPlacedByPlayer(
+ 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,
+ BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
+ ) override
+ {
+ int Meta = (((int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3) + 2) % 4;
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, 0x8 | Meta);
+ }
+
+
+ virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (OldMeta & 0x8)
+ {
+ // Was upper part of flower
+ if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) == m_BlockType)
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ }
+ else
+ {
+ // Was lower part
+ if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ) == m_BlockType)
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ }
+ }
+
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.grass";
+ }
+} ;
+
+
+
+
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..c9a769c75 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)
{
}
@@ -56,6 +56,7 @@ public:
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
+ // FIXME: This is unreachable, as the condition is the same as the above one
a_BlockMeta = (yaw < 0) ? 4 : 5;
return true;
}
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 a1ab74257..2d4fccbac 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"
@@ -35,8 +35,10 @@ public:
// Grass becomes dirt if there is something on top of it:
if (a_RelY < cChunkDef::Height - 1)
{
- BLOCKTYPE Above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ);
- if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above)) || IsBlockWater(Above))
+ BLOCKTYPE Above;
+ NIBBLETYPE AboveMeta;
+ a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY + 1, a_RelZ, Above, AboveMeta);
+ if (!cBlockInfo::GetHandler(Above)->CanDirtGrowGrass(AboveMeta))
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL);
return;
@@ -44,12 +46,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;
@@ -77,7 +79,7 @@ public:
BLOCKTYPE AboveDest;
NIBBLETYPE AboveMeta;
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
- if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !IsBlockWater(AboveDest))
+ if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta))
{
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread))
{
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/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h
new file mode 100644
index 000000000..81d2cb9a0
--- /dev/null
+++ b/src/Blocks/BlockEnchantmentTable.h
@@ -0,0 +1,37 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../UI/Window.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBlockEnchantmentTableHandler :
+ public cBlockHandler
+{
+public:
+ cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
+ {
+ cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ);
+ a_Player->OpenWindow(Window);
+ }
+
+
+ virtual bool IsUseable(void) override
+ {
+ return true;
+ }
+};
+
+
+
+
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/BlockFarmland.h b/src/Blocks/BlockFarmland.h
index b720ccd14..3dd5bcd1d 100644
--- a/src/Blocks/BlockFarmland.h
+++ b/src/Blocks/BlockFarmland.h
@@ -52,9 +52,9 @@ public:
return;
}
- int NumBlocks = Area.GetBlockCount();
+ size_t NumBlocks = Area.GetBlockCount();
BLOCKTYPE * BlockTypes = Area.GetBlockTypes();
- for (int i = 0; i < NumBlocks; i++)
+ for (size_t i = 0; i < NumBlocks; i++)
{
if (
(BlockTypes[i] == E_BLOCK_WATER) ||
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..f9f32eb50 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
@@ -66,7 +68,6 @@ public:
{
return 0;
}
-
for (int newY = Y + 1; newY < cChunkDef::Height; newY++)
{
@@ -82,7 +83,7 @@ public:
// This is because the frame is a solid obsidian pillar
if ((MaxY != 0) && (newY == Y + 1))
{
- return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface);
+ return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0;
}
else
{
@@ -97,18 +98,18 @@ public:
}
/// Evaluates if coords have a valid border on top, based on MaxY
- int EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
+ bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
{
for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners
{
if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN)
{
// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
- return 0;
+ return false;
}
}
// Everything was obsidian, found a border!
- return -1; // Return -1 for a frame border
+ return true;
}
/// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE)
@@ -167,7 +168,7 @@ public:
{
return false; // Not valid slice, no portal can be formed
}
- } XZP = X1 - 1; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there
+ } XZP = X1 - 1; // Set boundary of frame interior
for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM)
{
int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY);
@@ -197,13 +198,13 @@ public:
if ((Value == -1) || (ValueTwo == -1))
{
FoundFrameZP = true;
- continue;
+ break;
}
else if ((Value != MaxY) && (ValueTwo != MaxY))
{
return false;
}
- } XZP = Z1 - 2;
+ } XZP = Z1 - 1;
for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--)
{
int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY);
@@ -211,13 +212,13 @@ public:
if ((Value == -1) || (ValueTwo == -1))
{
FoundFrameZM = true;
- continue;
+ break;
}
else if ((Value != MaxY) && (ValueTwo != MaxY))
{
return false;
}
- } XZM = Z2 + 2;
+ } XZM = Z2 + 1;
return (FoundFrameZP && FoundFrameZM);
}
};
diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h
index 37885e4de..d0c4ea55b 100644
--- a/src/Blocks/BlockFluid.h
+++ b/src/Blocks/BlockFluid.h
@@ -49,6 +49,12 @@ public:
}
super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk);
}
+
+
+ virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
+ {
+ return false;
+ }
} ;
@@ -93,6 +99,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 +126,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..304e35e84 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -8,6 +8,7 @@
#include "../Chunk.h"
#include "BlockAnvil.h"
#include "BlockBed.h"
+#include "BlockBigFlower.h"
#include "BlockBrewingStand.h"
#include "BlockButton.h"
#include "BlockCactus.h"
@@ -24,6 +25,7 @@
#include "BlockDirt.h"
#include "BlockDoor.h"
#include "BlockDropSpenser.h"
+#include "BlockEnchantmentTable.h"
#include "BlockEnderchest.h"
#include "BlockEntity.h"
#include "BlockFarmland.h"
@@ -41,6 +43,7 @@
#include "BlockIce.h"
#include "BlockLadder.h"
#include "BlockLeaves.h"
+#include "BlockLilypad.h"
#include "BlockNewLeaves.h"
#include "BlockLever.h"
#include "BlockMelon.h"
@@ -89,6 +92,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
+ case E_BLOCK_BIG_FLOWER: return new cBlockBigFlowerHandler (a_BlockType);
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType);
case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
@@ -116,6 +120,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_DOUBLE_WOODEN_SLAB: return new cBlockDoubleSlabHandler (a_BlockType);
case E_BLOCK_DROPPER: return new cBlockDropSpenserHandler (a_BlockType);
case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType);
+ case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType);
case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType);
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( );
case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
@@ -142,6 +147,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);
@@ -394,6 +400,15 @@ bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, in
+bool cBlockHandler::CanDirtGrowGrass(NIBBLETYPE a_Meta)
+{
+ return ((cBlockInfo::IsTransparent(m_BlockType)) || (cBlockInfo::IsOneHitDig(m_BlockType)));
+}
+
+
+
+
+
bool cBlockHandler::IsUseable()
{
return false;
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index 3a3efb3cc..fb6cae729 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -85,6 +85,9 @@ public:
/// Checks if the block can stay at the specified relative coords in the chunk
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk);
+
+ /** Can the dirt under this block grow to grass? */
+ virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta);
/** Checks if the block can be placed at this point.
Default: CanBeAt(...)
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..495e849fa 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"
@@ -16,6 +16,7 @@
{ \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \
+ case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_NEW_LOG: return true; \
}
@@ -37,16 +38,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 +61,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));
@@ -136,14 +138,14 @@ bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ)
{
// Filter the blocks into a {leaves, log, other (air)} set:
BLOCKTYPE * Types = a_Area.GetBlockTypes();
- for (int i = a_Area.GetBlockCount() - 1; i > 0; i--)
+ for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--)
{
switch (Types[i])
{
- case E_BLOCK_NEW_LEAVES:
- case E_BLOCK_NEW_LOG:
case E_BLOCK_LEAVES:
case E_BLOCK_LOG:
+ case E_BLOCK_NEW_LEAVES:
+ case E_BLOCK_NEW_LOG:
{
break;
}
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 6aa01f986..b7629b07c 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -22,14 +22,127 @@ public:
a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
}
- bool TrySpawnWither(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
+ 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;
+
+ class cPlayerCallback : public cPlayerListCallback
+ {
+ Vector3f m_Pos;
+
+ virtual bool Item(cPlayer * a_Player)
+ {
+ // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
+ double Dist = (a_Player->GetPosition() - m_Pos).Length();
+ if (Dist < 50.0)
+ {
+ // If player is close, award achievement
+ a_Player->AwardAchievement(achSpawnWither);
+ }
+ return false;
+ }
+
+ public:
+ cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
+
+ } PlayerCallback(Vector3f(a_BlockX, a_BlockY, a_BlockZ));
+
+ 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);
+
+ // Award Achievement
+ a_World->ForEachPlayer(PlayerCallback);
+
+ return true;
+ }
+
+ CallbackA.Reset();
+ CallbackB.Reset();
- // TODO 2014-03-24 xdot
+ 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);
+
+ // Award Achievement
+ a_World->ForEachPlayer(PlayerCallback);
+
+ return true;
+ }
return false;
}
@@ -62,20 +175,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);
- TrySpawnWither(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ 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/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/BlockPortal.h b/src/Blocks/BlockPortal.h
index 21bcbdeea..3b8030028 100644
--- a/src/Blocks/BlockPortal.h
+++ b/src/Blocks/BlockPortal.h
@@ -2,6 +2,7 @@
#pragma once
#include "BlockHandler.h"
+#include "../Mobs/Monster.h"
@@ -38,6 +39,19 @@ public:
return; // No pickups
}
+ virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
+ {
+ cFastRandom Random;
+ if (Random.NextInt(2000) != 0)
+ {
+ return;
+ }
+
+ int PosX = a_Chunk.GetPosX() * 16 + a_RelX;
+ int PosZ = a_Chunk.GetPosZ() * 16 + a_RelZ;
+
+ a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, cMonster::mtZombiePigman);
+ }
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
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..358b5ca11 100644
--- a/src/Blocks/BlockRail.h
+++ b/src/Blocks/BlockRail.h
@@ -141,7 +141,7 @@ public:
NIBBLETYPE Meta = 0;
char RailsCnt = 0;
bool Neighbors[8]; // 0 - EAST, 1 - WEST, 2 - NORTH, 3 - SOUTH, 4 - EAST UP, 5 - WEST UP, 6 - NORTH UP, 7 - SOUTH UP
- memset(Neighbors, false, sizeof(Neighbors));
+ memset(Neighbors, 0, sizeof(Neighbors));
Neighbors[0] = (IsUnstable(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN));
Neighbors[1] = (IsUnstable(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN));
Neighbors[2] = (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN));
@@ -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/BlockSign.h b/src/Blocks/BlockSign.h
index cd0c02a40..9d6fede21 100644
--- a/src/Blocks/BlockSign.h
+++ b/src/Blocks/BlockSign.h
@@ -31,7 +31,7 @@ public:
}
- static char RotationToMetaData(double a_Rotation)
+ static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 180 + (180 / 16); // So it's not aligned with axis
if (a_Rotation > 360)
@@ -45,7 +45,7 @@ public:
}
- static char DirectionToMetaData(eBlockFace a_Direction)
+ static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
{
switch (a_Direction)
{
@@ -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..80841b094 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;
}
@@ -121,6 +97,12 @@ public:
return "";
}
+
+ virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
+ {
+ return ((a_Meta & 0x8) != 0);
+ }
+
/// Returns true if the specified blocktype is one of the slabs handled by this handler
static bool IsAnySlabType(BLOCKTYPE a_BlockType)
@@ -184,6 +166,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..a49fda5ae 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 (
@@ -77,6 +77,11 @@ public:
// Reset meta to 0
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
+
+ virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
+ {
+ return true;
+ }
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
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/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h
index b8af1f1da..ba1f2e0f6 100644
--- a/src/Blocks/BlockTallGrass.h
+++ b/src/Blocks/BlockTallGrass.h
@@ -15,14 +15,14 @@ public:
: cBlockHandler(a_BlockType)
{
}
-
-
+
+
virtual bool DoesIgnoreBuildCollision(void) override
{
return true;
}
-
-
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Drop seeds, sometimes
@@ -34,11 +34,25 @@ public:
}
+ virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if ((!a_Player->IsGameModeCreative()) && (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SHEARS))
+ {
+ cItems Pickups;
+ Pickups.Add(E_BLOCK_TALL_GRASS, 1, Meta);
+ a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ);
+ }
+ a_Player->UseEquippedItem();
+ }
+
+
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR));
}
-
+
virtual const char * GetStepSound(void) override
{
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 d096c81a8..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;
@@ -197,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/CMakeLists.txt b/src/Blocks/CMakeLists.txt
index 082ff41ac..4b8c745ad 100644
--- a/src/Blocks/CMakeLists.txt
+++ b/src/Blocks/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Blocks ${SOURCE})
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/BoundingBox.cpp b/src/BoundingBox.cpp
index 482f9923f..ce831c200 100644
--- a/src/BoundingBox.cpp
+++ b/src/BoundingBox.cpp
@@ -288,7 +288,7 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d &
Coeff = c;
}
c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Max.y);
- if ((c >= 0) && (c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
+ if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
{
Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM;
Coeff = c;
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index 1893d89a8..4de89f7c1 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -143,7 +143,7 @@ protected:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cByteBuffer:
-cByteBuffer::cByteBuffer(int a_BufferSize) :
+cByteBuffer::cByteBuffer(size_t a_BufferSize) :
m_Buffer(new char[a_BufferSize + 1]),
m_BufferSize(a_BufferSize + 1),
#ifdef _DEBUG
@@ -171,7 +171,7 @@ cByteBuffer::~cByteBuffer()
-bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
+bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
@@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
}
ASSERT(m_BufferSize >= m_WritePos);
size_t TillEnd = m_BufferSize - m_WritePos;
+ const char * Bytes = (const char *)a_Bytes;
if (TillEnd <= a_Count)
{
// Need to wrap around the ringbuffer end
if (TillEnd > 0)
{
- memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd);
- a_Bytes += TillEnd;
+ memcpy(m_Buffer + m_WritePos, Bytes, TillEnd);
+ Bytes += TillEnd;
a_Count -= TillEnd;
WrittenBytes = TillEnd;
}
@@ -203,7 +204,7 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
// We're guaranteed that we'll fit in a single write op
if (a_Count > 0)
{
- memcpy(m_Buffer + m_WritePos, a_Bytes, a_Count);
+ memcpy(m_Buffer + m_WritePos, Bytes, a_Count);
m_WritePos += a_Count;
WrittenBytes += a_Count;
}
@@ -326,7 +327,7 @@ bool cByteBuffer::ReadBEShort(short & a_Value)
CheckValid();
NEEDBYTES(2);
ReadBuf(&a_Value, 2);
- a_Value = ntohs(a_Value);
+ a_Value = (short)ntohs((u_short)a_Value);
return true;
}
@@ -340,7 +341,7 @@ bool cByteBuffer::ReadBEInt(int & a_Value)
CheckValid();
NEEDBYTES(4);
ReadBuf(&a_Value, 4);
- a_Value = ntohl(a_Value);
+ a_Value = (int)ntohl((u_long)a_Value);
return true;
}
@@ -419,7 +420,7 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value)
ASSERT(!"Negative string length? Are you sure?");
return true;
}
- return ReadUTF16String(a_Value, Length);
+ return ReadUTF16String(a_Value, (size_t)Length);
}
@@ -437,7 +438,7 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value)
{
NEEDBYTES(1);
ReadBuf(&b, 1);
- Value = Value | (((Int64)(b & 0x7f)) << Shift);
+ Value = Value | (((UInt32)(b & 0x7f)) << Shift);
Shift += 7;
} while ((b & 0x80) != 0);
a_Value = Value;
@@ -461,7 +462,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
{
LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
}
- return ReadString(a_Value, (int)Size);
+ return ReadString(a_Value, (size_t)Size);
}
@@ -516,7 +517,7 @@ bool cByteBuffer::WriteBEShort(short a_Value)
CHECK_THREAD;
CheckValid();
PUTBYTES(2);
- short Converted = htons(a_Value);
+ u_short Converted = htons((u_short)a_Value);
return WriteBuf(&Converted, 2);
}
@@ -529,7 +530,7 @@ bool cByteBuffer::WriteBEInt(int a_Value)
CHECK_THREAD;
CheckValid();
PUTBYTES(4);
- int Converted = HostToNetwork4(&a_Value);
+ UInt32 Converted = HostToNetwork4(&a_Value);
return WriteBuf(&Converted, 4);
}
@@ -542,7 +543,7 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value)
CHECK_THREAD;
CheckValid();
PUTBYTES(8);
- Int64 Converted = HostToNetwork8(&a_Value);
+ UInt64 Converted = HostToNetwork8(&a_Value);
return WriteBuf(&Converted, 8);
}
@@ -555,7 +556,7 @@ bool cByteBuffer::WriteBEFloat(float a_Value)
CHECK_THREAD;
CheckValid();
PUTBYTES(4);
- int Converted = HostToNetwork4(&a_Value);
+ UInt32 Converted = HostToNetwork4(&a_Value);
return WriteBuf(&Converted, 4);
}
@@ -568,7 +569,7 @@ bool cByteBuffer::WriteBEDouble(double a_Value)
CHECK_THREAD;
CheckValid();
PUTBYTES(8);
- Int64 Converted = HostToNetwork8(&a_Value);
+ UInt64 Converted = HostToNetwork8(&a_Value);
return WriteBuf(&Converted, 8);
}
@@ -612,7 +613,7 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value)
// A 32-bit integer can be encoded by at most 5 bytes:
unsigned char b[5];
- int idx = 0;
+ size_t idx = 0;
do
{
b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
@@ -631,7 +632,7 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
CHECK_THREAD;
CheckValid();
PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early.
- bool res = WriteVarInt(a_Value.size());
+ bool res = WriteVarInt((UInt32)(a_Value.size()));
if (!res)
{
return false;
@@ -756,7 +757,7 @@ bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
-bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
+bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars)
{
// Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String
CHECK_THREAD;
@@ -887,9 +888,7 @@ void cByteBuffer::AdvanceReadPos(size_t a_Count)
void cByteBuffer::CheckValid(void) const
{
- ASSERT(m_ReadPos >= 0);
ASSERT(m_ReadPos < m_BufferSize);
- ASSERT(m_WritePos >= 0);
ASSERT(m_WritePos < m_BufferSize);
}
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 1915467f3..adaa00330 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -27,28 +27,28 @@ their own synchronization.
class cByteBuffer
{
public:
- cByteBuffer(int a_BufferSize);
+ cByteBuffer(size_t a_BufferSize);
~cByteBuffer();
- /// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
- bool Write(const char * a_Bytes, size_t a_Count);
+ /** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */
+ bool Write(const void * a_Bytes, size_t a_Count);
- /// Returns the number of bytes that can be successfully written to the ringbuffer
+ /** Returns the number of bytes that can be successfully written to the ringbuffer */
size_t GetFreeSpace(void) const;
- /// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
+ /** Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() */
size_t GetUsedSpace(void) const;
- /// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
+ /** Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) */
size_t GetReadableSpace(void) const;
- /// Returns the current data start index. For debugging purposes.
+ /** Returns the current data start index. For debugging purposes. */
size_t GetDataStart(void) const { return m_DataStart; }
- /// Returns true if the specified amount of bytes are available for reading
+ /** Returns true if the specified amount of bytes are available for reading */
bool CanReadBytes(size_t a_Count) const;
- /// Returns true if the specified amount of bytes are available for writing
+ /** Returns true if the specified amount of bytes are available for writing */
bool CanWriteBytes(size_t a_Count) const;
// Read the specified datatype and advance the read pointer; return true if successfully read:
@@ -65,7 +65,7 @@ public:
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
bool ReadLEInt (int & a_Value);
- /// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...)
+ /** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */
template <typename T> bool ReadVarInt(T & a_Value)
{
UInt32 v;
@@ -91,37 +91,37 @@ public:
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
bool WriteLEInt (int a_Value);
- /// Reads a_Count bytes into a_Buffer; returns true if successful
+ /** Reads a_Count bytes into a_Buffer; returns true if successful */
bool ReadBuf(void * a_Buffer, size_t a_Count);
- /// Writes a_Count bytes into a_Buffer; returns true if successful
+ /** Writes a_Count bytes into a_Buffer; returns true if successful */
bool WriteBuf(const void * a_Buffer, size_t a_Count);
- /// Reads a_Count bytes into a_String; returns true if successful
+ /** Reads a_Count bytes into a_String; returns true if successful */
bool ReadString(AString & a_String, size_t a_Count);
- /// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
- bool ReadUTF16String(AString & a_String, int a_NumChars);
+ /** Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String */
+ bool ReadUTF16String(AString & a_String, size_t a_NumChars);
- /// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
+ /** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */
bool SkipRead(size_t a_Count);
- /// Reads all available data into a_Data
+ /** Reads all available data into a_Data */
void ReadAll(AString & a_Data);
- /// Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success.
+ /** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
- /// Removes the bytes that have been read from the ringbuffer
+ /** Removes the bytes that have been read from the ringbuffer */
void CommitRead(void);
- /// Restarts next reading operation at the start of the ringbuffer
+ /** Restarts next reading operation at the start of the ringbuffer */
void ResetRead(void);
- /// Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication
+ /** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */
void ReadAgain(AString & a_Out);
- /// Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs
+ /** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */
void CheckValid(void) const;
protected:
@@ -136,7 +136,7 @@ protected:
size_t m_WritePos; // Where the data ends in the ringbuffer
size_t m_ReadPos; // Where the next read will start in the ringbuffer
- /// Advances the m_ReadPos by a_Count bytes
+ /** Advances the m_ReadPos by a_Count bytes */
void AdvanceReadPos(size_t a_Count);
} ;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 448dc4b70..900577526 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,15 +5,15 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
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 OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++)
+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
@@ -57,6 +57,14 @@ if (NOT MSVC)
Entities/Pickup.h
Entities/Player.h
Entities/ProjectileEntity.h
+ Entities/ArrowEntity.h
+ Entities/ThrownEggEntity.h
+ Entities/ThrownEnderPearlEntity.h
+ Entities/ExpBottleEntity.h
+ Entities/ThrownSnowballEntity.h
+ Entities/FireChargeEntity.h
+ Entities/FireworkEntity.h
+ Entities/GhastFireballEntity.h
Entities/TNTEntity.h
Entities/ExpOrb.h
Entities/HangingEntity.h
@@ -104,7 +112,6 @@ if (NOT MSVC)
Bindings/PluginLua
Bindings/PluginManager
Bindings/WebPlugin
- Bindings/WebPlugin
)
target_link_libraries(Bindings lua sqlite tolualib)
@@ -124,6 +131,7 @@ if (NOT MSVC)
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp")
@@ -138,6 +146,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 +158,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 +176,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,8 +241,8 @@ endif ()
if (NOT MSVC)
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
- target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage)
- target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
+ target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
+ target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities PolarSSL++)
endif ()
if (WIN32)
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index bd4cb9937..23412a4c3 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -238,13 +238,12 @@ void cChunk::MarkLoadFailed(void)
void cChunk::GetAllData(cChunkDataCallback & a_Callback)
{
- a_Callback.HeightMap (&m_HeightMap);
- a_Callback.BiomeData (&m_BiomeMap);
- a_Callback.BlockTypes (m_BlockTypes);
- a_Callback.BlockMeta (m_BlockMeta);
- a_Callback.LightIsValid (m_IsLightValid);
- a_Callback.BlockLight (m_BlockLight);
- a_Callback.BlockSkyLight(m_BlockSkyLight);
+ a_Callback.HeightMap(&m_HeightMap);
+ a_Callback.BiomeData(&m_BiomeMap);
+
+ a_Callback.LightIsValid(m_IsLightValid);
+
+ a_Callback.ChunkData(m_ChunkData);
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{
@@ -262,7 +261,7 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback)
void cChunk::SetAllData(
- const BLOCKTYPE * a_BlockTypes,
+ const BLOCKTYPE * a_BlockTypes,
const NIBBLETYPE * a_BlockMeta,
const NIBBLETYPE * a_BlockLight,
const NIBBLETYPE * a_BlockSkyLight,
@@ -272,29 +271,23 @@ void cChunk::SetAllData(
)
{
memcpy(m_BiomeMap, a_BiomeMap, sizeof(m_BiomeMap));
-
+
if (a_HeightMap != NULL)
{
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
}
-
- memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
- memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta));
- if (a_BlockLight != NULL)
- {
- memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
- }
- if (a_BlockSkyLight != NULL)
+
+ if (a_HeightMap == NULL)
{
- memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
+ CalculateHeightmap(a_BlockTypes);
}
+
+ m_ChunkData.SetBlockTypes(a_BlockTypes);
+ m_ChunkData.SetMetas(a_BlockMeta);
+ m_ChunkData.SetBlockLight(a_BlockLight);
+ m_ChunkData.SetSkyLight(a_BlockSkyLight);
m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL);
-
- if (a_HeightMap == NULL)
- {
- CalculateHeightmap();
- }
// Clear the block entities present - either the loader / saver has better, or we'll create empty ones:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
@@ -332,8 +325,11 @@ void cChunk::SetLight(
{
// TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation.
// Postponing until we see how bad it is :)
- memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
- memcpy(m_BlockSkyLight, a_SkyLight, sizeof(m_BlockSkyLight));
+
+ m_ChunkData.SetBlockLight(a_BlockLight);
+
+ m_ChunkData.SetSkyLight(a_SkyLight);
+
m_IsLightValid = true;
}
@@ -343,7 +339,7 @@ void cChunk::SetLight(
void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes)
{
- memcpy(a_BlockTypes, m_BlockTypes, NumBlocks);
+ m_ChunkData.CopyBlockTypes(a_BlockTypes);
}
@@ -452,7 +448,7 @@ void cChunk::CollectMobCensus(cMobCensus& toFill)
{
cMonster& Monster = (cMonster&)(**itr);
currentPosition = Monster.GetPosition();
- for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++)
+ for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); ++itr2)
{
toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength());
}
@@ -600,7 +596,7 @@ void cChunk::Tick(float a_Dt)
delete ToDelete;
continue;
}
- itr++;
+ ++itr;
} // for itr - m_Entitites[]
// If any entity moved out of the chunk, move it to the neighbor:
@@ -629,8 +625,7 @@ void cChunk::Tick(float a_Dt)
void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ)
{
- unsigned Index = MakeIndex(a_RelX, a_RelY, a_RelZ);
- cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]);
+ cBlockHandler * Handler = BlockHandler(GetBlock(a_RelX, a_RelY, a_RelZ));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243
cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*this->GetWorld());
@@ -694,7 +689,7 @@ void cChunk::ProcessQueuedSetBlocks(void)
{
if (itr->m_Tick <= CurrTick)
{
- if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to -1 if not specified
+ if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to 0 if not specified
{
if (GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == itr->m_PreviousType)
{
@@ -751,23 +746,22 @@ void cChunk::BroadcastPendingBlockChanges(void)
void cChunk::CheckBlocks()
{
- if (m_ToTickBlocks.size() == 0)
+ if (m_ToTickBlocks.empty())
{
return;
}
- std::vector<unsigned int> ToTickBlocks;
+ std::vector<Vector3i> ToTickBlocks;
std::swap(m_ToTickBlocks, ToTickBlocks);
cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World);
- for (std::vector<unsigned int>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
+ for (std::vector<Vector3i>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
{
- unsigned int index = (*itr);
- Vector3i BlockPos = IndexToCoordinate(index);
+ Vector3i Pos = (*itr);
- cBlockHandler * Handler = BlockHandler(GetBlock(index));
- Handler->Check(ChunkInterface, PluginInterface, BlockPos.x, BlockPos.y, BlockPos.z, *this);
+ cBlockHandler * Handler = BlockHandler(GetBlock(Pos));
+ Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this);
} // for itr - ToTickBlocks[]
}
@@ -810,8 +804,7 @@ void cChunk::TickBlocks(void)
continue; // It's all air up here
}
- unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ);
- cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]);
+ cBlockHandler * Handler = BlockHandler(GetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243
Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ);
} // for i - tickblocks
@@ -884,7 +877,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);
}
@@ -1203,9 +1196,8 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB
// The chunk is not available, bail out
return false;
}
- int idx = Chunk->MakeIndex(a_RelX, a_RelY, a_RelZ);
- a_BlockLight = Chunk->GetBlockLight(idx);
- a_SkyLight = Chunk->GetSkyLight(idx);
+ a_BlockLight = Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
+ a_SkyLight = Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
return true;
}
@@ -1296,9 +1288,10 @@ void cChunk::CreateBlockEntities(void)
{
for (int y = 0; y < Height; y++)
{
- BLOCKTYPE BlockType = cChunkDef::GetBlock(m_BlockTypes, x, y, z);
+ BLOCKTYPE BlockType = GetBlock(x, y, z);
switch (BlockType)
{
+ case E_BLOCK_BEACON:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
@@ -1348,7 +1341,7 @@ void cChunk::WakeUpSimulators(void)
int BlockZ = z + BaseZ;
for (int y = GetHeight(x, z); y >= 0; y--)
{
- BLOCKTYPE Block = cChunkDef::GetBlock(m_BlockTypes, x, y, z);
+ BLOCKTYPE Block = GetBlock(x, y, z);
// The redstone sim takes multiple blocks, use the inbuilt checker
if (RedstoneSimulator->IsAllowedBlock(Block))
@@ -1383,7 +1376,7 @@ void cChunk::WakeUpSimulators(void)
-void cChunk::CalculateHeightmap()
+void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes)
{
for (int x = 0; x < Width; x++)
{
@@ -1392,7 +1385,7 @@ void cChunk::CalculateHeightmap()
for (int y = Height - 1; y > -1; y--)
{
int index = MakeIndex( x, y, z );
- if (m_BlockTypes[index] != E_BLOCK_AIR)
+ if (a_BlockTypes[index] != E_BLOCK_AIR)
{
m_HeightMap[x + z * Width] = (unsigned char)y;
break;
@@ -1409,11 +1402,9 @@ void cChunk::CalculateHeightmap()
void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta);
-
- const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
// Tick this block and its neighbors:
- m_ToTickBlocks.push_back(index);
+ m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ);
// If there was a block entity, remove it:
@@ -1429,6 +1420,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
// If the new block is a block entity, create the entity object:
switch (a_BlockType)
{
+ case E_BLOCK_BEACON:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
@@ -1476,7 +1468,7 @@ void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
return;
}
- m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ));
+ m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
}
@@ -1514,17 +1506,16 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
ASSERT(IsValid());
- const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- const BLOCKTYPE OldBlockType = cChunkDef::GetBlock(m_BlockTypes, index);
- const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index);
+ const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ const BLOCKTYPE OldBlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta))
{
return;
}
MarkDirty();
-
- m_BlockTypes[index] = a_BlockType;
+
+ m_ChunkData.SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType);
// The client doesn't need to distinguish between stationary and nonstationary fluids:
if (
@@ -1540,7 +1531,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta));
}
- SetNibble(m_BlockMeta, index, a_BlockMeta);
+ m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta);
// ONLY recalculate lighting if it's necessary!
if (
@@ -1563,7 +1554,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
{
for (int y = a_RelY - 1; y > 0; --y)
{
- if (m_BlockTypes[MakeIndexNoCheck(a_RelX, y, a_RelZ)] != E_BLOCK_AIR)
+ if (GetBlock(a_RelX, y, a_RelZ) != E_BLOCK_AIR)
{
m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y;
break;
@@ -1579,19 +1570,16 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client)
{
- // The coords must be valid, because the upper level already does chunk lookup. No need to check them again.
- // There's an debug-time assert in MakeIndexNoCheck anyway
- unsigned int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
if (a_Client == NULL)
{
// Queue the block for all clients in the chunk (will be sent in Tick())
- m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(index), GetMeta(index)));
+ m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)));
return;
}
Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ);
- a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(index), GetMeta(index));
+ a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ));
// FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr)
@@ -2450,22 +2438,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
return 0; // Clip
}
- return m_BlockTypes[MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)];
-}
-
-
-
-
-
-BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
-{
- if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks))
- {
- ASSERT(!"GetBlock(idx) out of bounds!");
- return 0;
- }
-
- return m_BlockTypes[ a_BlockIdx ];
+ return m_ChunkData.GetBlock(a_RelX, a_RelY, a_RelZ);
}
@@ -2474,9 +2447,8 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{
- int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx);
- a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx);
+ a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ a_BlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
}
@@ -2485,11 +2457,10 @@ void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_
void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight)
{
- int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx);
- a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx);
- a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx);
- a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx);
+ a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ a_Meta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
+ a_SkyLight = m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ);
+ a_BlockLight = m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ);
}
@@ -2511,7 +2482,7 @@ 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))
+ 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;
diff --git a/src/Chunk.h b/src/Chunk.h
index b3fa563cc..d95537acf 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -3,6 +3,7 @@
#include "Entities/Entity.h"
#include "ChunkDef.h"
+#include "ChunkData.h"
#include "Simulator/FireSimulator.h"
#include "Simulator/SandSimulator.h"
@@ -66,6 +67,7 @@ public:
cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks
);
+ cChunk(cChunk & other);
~cChunk();
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated)
@@ -154,7 +156,7 @@ public:
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const;
- BLOCKTYPE GetBlock(int a_BlockIdx) const;
+ BLOCKTYPE GetBlock(Vector3i a_cords) const { return GetBlock(a_cords.x, a_cords.y, a_cords.z);}
void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
@@ -267,7 +269,7 @@ public:
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords
void CalculateLighting(); // Recalculate right now
- void CalculateHeightmap();
+ void CalculateHeightmap(const BLOCKTYPE * a_BlockTypes);
// Broadcast various packets to all clients of this chunk:
// (Please keep these alpha-sorted)
@@ -320,15 +322,23 @@ public:
m_BlockTickZ = a_RelZ;
}
- inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
- inline NIBBLETYPE GetMeta(int a_BlockIdx) const {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
- inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
- inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); }
+ inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
+ {
+ return m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
+ }
+ inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
+ {
+ bool hasChanged = m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_Meta);
+ if (hasChanged)
+ {
+ MarkDirty();
+
+ m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), a_Meta));
+ }
+ }
- inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
- inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
- inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); }
- inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx); }
+ inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ); }
+ inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ); }
/** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
@@ -382,14 +392,14 @@ private:
struct sSetBlockQueueItem
{
+ Int64 m_Tick;
int m_RelX, m_RelY, m_RelZ;
BLOCKTYPE m_BlockType;
NIBBLETYPE m_BlockMeta;
- Int64 m_Tick;
BLOCKTYPE m_PreviousType;
sSetBlockQueueItem(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) :
- m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_Tick(a_Tick), m_PreviousType(a_PreviousBlockType)
+ m_Tick(a_Tick), m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_PreviousType(a_PreviousBlockType)
{
}
} ;
@@ -403,8 +413,8 @@ private:
bool m_IsSaving; // True if the chunk is being saved
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
- std::vector<unsigned int> m_ToTickBlocks;
- sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
+ std::vector<Vector3i> m_ToTickBlocks;
+ sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick
@@ -420,11 +430,7 @@ private:
cWorld * m_World;
cChunkMap * m_ChunkMap;
- // TODO: Make these pointers and don't allocate what isn't needed
- BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks];
- NIBBLETYPE m_BlockMeta [cChunkDef::NumBlocks / 2];
- NIBBLETYPE m_BlockLight [cChunkDef::NumBlocks / 2];
- NIBBLETYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2];
+ cChunkData m_ChunkData;
cChunkDef::HeightMap m_HeightMap;
cChunkDef::BiomeMap m_BiomeMap;
diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp
new file mode 100644
index 000000000..142c141c4
--- /dev/null
+++ b/src/ChunkData.cpp
@@ -0,0 +1,592 @@
+
+// ChunkData.cpp
+
+// Implements the cChunkData class that represents the block's type, meta, blocklight and skylight storage for a chunk
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+
+
+
+
+/** Returns true if all a_Array's elements between [0] and [a_NumElements - 1] are equal to a_Value. */
+template <typename T> inline bool IsAllValue(const T * a_Array, size_t a_NumElements, T a_Value)
+{
+ for (size_t i = 0; i < a_NumElements; i++)
+ {
+ if (a_Array[i] != a_Value)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+cChunkData::cChunkData(void)
+#if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ : m_IsOwner(true)
+#endif
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = NULL;
+ }
+}
+
+
+
+
+
+cChunkData::~cChunkData()
+{
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ if (!m_IsOwner)
+ {
+ return;
+ }
+ #endif
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = NULL;
+ }
+}
+
+
+
+
+
+#if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ cChunkData::cChunkData(const cChunkData & a_Other) :
+ m_IsOwner(true)
+ {
+ // Move contents and ownership from a_Other to this, pointer-wise:
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = a_Other.m_Sections[i];
+ }
+ a_Other.m_IsOwner = false;
+ }
+
+
+
+
+
+ cChunkData & cChunkData::operator =(const cChunkData & a_Other)
+ {
+ // If assigning to self, no-op
+ if (&a_Other == this)
+ {
+ return *this;
+ }
+
+ // Free any currently held contents:
+ if (m_IsOwner)
+ {
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = NULL;
+ }
+ }
+
+ // Move contents and ownership from a_Other to this, pointer-wise:
+ m_IsOwner = true;
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = a_Other.m_Sections[i];
+ }
+ a_Other.m_IsOwner = false;
+ return *this;
+ }
+
+#else
+
+ // unique_ptr style interface for memory management
+ cChunkData::cChunkData(cChunkData && other)
+ {
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ m_Sections[i] = other.m_Sections[i];
+ other.m_Sections[i] = NULL;
+ }
+ }
+
+
+
+
+
+ cChunkData & cChunkData::operator =(cChunkData && other)
+ {
+ if (&other != this)
+ {
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = other.m_Sections[i];
+ other.m_Sections[i] = NULL;
+ }
+ }
+ return *this;
+ }
+#endif
+
+
+
+
+
+BLOCKTYPE cChunkData::GetBlock(int a_X, int a_Y, int a_Z) const
+{
+ ASSERT((a_X >= 0) && (a_X < cChunkDef::Width));
+ ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height));
+ ASSERT((a_Z >= 0) && (a_Z < cChunkDef::Width));
+ int Section = a_Y / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * SectionHeight), a_Z);
+ return m_Sections[Section]->m_BlockTypes[Index];
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+
+
+
+void cChunkData::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block)
+{
+ if (
+ (a_RelX >= cChunkDef::Width) || (a_RelX < 0) ||
+ (a_RelY >= cChunkDef::Height) || (a_RelY < 0) ||
+ (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0)
+ )
+ {
+ ASSERT(!"cChunkData::SetMeta(): index out of range!");
+ return;
+ }
+
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] == NULL)
+ {
+ if (a_Block == 0x00)
+ {
+ return;
+ }
+ m_Sections[Section] = Allocate();
+ if (m_Sections[Section] == NULL)
+ {
+ ASSERT(!"Failed to allocate a new section in Chunkbuffer");
+ return;
+ }
+ ZeroSection(m_Sections[Section]);
+ }
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ m_Sections[Section]->m_BlockTypes[Index] = a_Block;
+}
+
+
+
+
+
+NIBBLETYPE cChunkData::GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
+{
+ if (
+ (a_RelX < cChunkDef::Width) && (a_RelX > -1) &&
+ (a_RelY < cChunkDef::Height) && (a_RelY > -1) &&
+ (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
+ {
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ return (m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!");
+ return 0;
+}
+
+
+
+
+
+bool cChunkData::SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble)
+{
+ if (
+ (a_RelX >= cChunkDef::Width) || (a_RelX < 0) ||
+ (a_RelY >= cChunkDef::Height) || (a_RelY < 0) ||
+ (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0)
+ )
+ {
+ ASSERT(!"cChunkData::SetMeta(): index out of range!");
+ return false;
+ }
+
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] == NULL)
+ {
+ if ((a_Nibble & 0xf) == 0x00)
+ {
+ return false;
+ }
+ m_Sections[Section] = Allocate();
+ if (m_Sections[Section] == NULL)
+ {
+ ASSERT(!"Failed to allocate a new section in Chunkbuffer");
+ return false;
+ }
+ ZeroSection(m_Sections[Section]);
+ }
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ NIBBLETYPE oldval = m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4) & 0xf;
+ m_Sections[Section]->m_BlockMetas[Index / 2] = static_cast<NIBBLETYPE>(
+ (m_Sections[Section]->m_BlockMetas[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
+ ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
+ );
+ return oldval == a_Nibble;
+}
+
+
+
+
+
+NIBBLETYPE cChunkData::GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const
+{
+ if (
+ (a_RelX < cChunkDef::Width) && (a_RelX > -1) &&
+ (a_RelY < cChunkDef::Height) && (a_RelY > -1) &&
+ (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)
+ )
+ {
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!");
+ return 0;
+}
+
+
+
+
+
+NIBBLETYPE cChunkData::GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const
+{
+ if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
+ {
+ int Section = a_RelY / SectionHeight;
+ if (m_Sections[Section] != NULL)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ);
+ return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0xF;
+ }
+ }
+ ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!");
+ return 0;
+}
+
+
+
+
+
+cChunkData cChunkData::Copy(void) const
+{
+ cChunkData copy;
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ copy.m_Sections[i] = Allocate();
+ *copy.m_Sections[i] = *m_Sections[i];
+ }
+ }
+ return copy;
+}
+
+
+
+
+
+void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Length) const
+{
+ size_t ToSkip = a_Idx;
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ size_t StartPos = 0;
+ if (ToSkip > 0)
+ {
+ StartPos = std::min(ToSkip, +SectionBlockCount);
+ ToSkip -= StartPos;
+ }
+ if (StartPos < SectionBlockCount)
+ {
+ size_t ToCopy = std::min(+SectionBlockCount - StartPos, a_Length);
+ a_Length -= ToCopy;
+ if (m_Sections[i] != NULL)
+ {
+ BLOCKTYPE * blockbuffer = m_Sections[i]->m_BlockTypes;
+ memcpy(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], blockbuffer + StartPos, sizeof(BLOCKTYPE) * ToCopy);
+ }
+ else
+ {
+ memset(&a_Dest[(i * SectionBlockCount) - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::CopyMetas(NIBBLETYPE * a_Dest) const
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockMetas, sizeof(m_Sections[i]->m_BlockMetas));
+ }
+ else
+ {
+ memset(&a_Dest[i * SectionBlockCount / 2], 0, sizeof(m_Sections[i]->m_BlockMetas));
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::CopyBlockLight(NIBBLETYPE * a_Dest) const
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockLight, sizeof(m_Sections[i]->m_BlockLight));
+ }
+ else
+ {
+ memset(&a_Dest[i * SectionBlockCount / 2], 0, sizeof(m_Sections[i]->m_BlockLight));
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::CopySkyLight(NIBBLETYPE * a_Dest) const
+{
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockSkyLight, sizeof(m_Sections[i]->m_BlockSkyLight));
+ }
+ else
+ {
+ memset(&a_Dest[i * SectionBlockCount / 2], 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ }
+ }
+}
+
+
+
+
+
+void cChunkData::SetBlockTypes(const BLOCKTYPE * a_Src)
+{
+ ASSERT(a_Src != NULL);
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount, SectionBlockCount, (const BLOCKTYPE)0))
+ {
+ // No need for the section, the data is all-air
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight));
+ memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+void cChunkData::SetMetas(const NIBBLETYPE * a_Src)
+{
+ ASSERT(a_Src != NULL);
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0))
+ {
+ // No need for the section, the data is all zeroes
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight));
+ memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+
+void cChunkData::SetBlockLight(const NIBBLETYPE * a_Src)
+{
+ if (a_Src == NULL)
+ {
+ return;
+ }
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0))
+ {
+ // No need for the section, the data is all zeroes
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight));
+ memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+void cChunkData::SetSkyLight(const NIBBLETYPE * a_Src)
+{
+ if (a_Src == NULL)
+ {
+ return;
+ }
+
+ for (size_t i = 0; i < NumSections; i++)
+ {
+ // If the section is already allocated, copy the data into it:
+ if (m_Sections[i] != NULL)
+ {
+ memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight));
+ continue;
+ }
+
+ // The section doesn't exist, find out if it is needed:
+ if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0xff))
+ {
+ // No need for the section, the data is all zeroes
+ continue;
+ }
+
+ // Allocate the section and copy the data into it:
+ m_Sections[i] = Allocate();
+ memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight));
+ memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes));
+ memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas));
+ memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight));
+ } // for i - m_Sections[]
+}
+
+
+
+
+
+cChunkData::sChunkSection * cChunkData::Allocate(void)
+{
+ // TODO: Use an allocation pool
+ return new cChunkData::sChunkSection;
+}
+
+
+
+
+
+void cChunkData::Free(cChunkData::sChunkSection * a_Section)
+{
+ // TODO: Use an allocation pool
+ delete a_Section;
+}
+
+
+
+
+
+void cChunkData::ZeroSection(cChunkData::sChunkSection * a_Section) const
+{
+ memset(a_Section->m_BlockTypes, 0x00, sizeof(a_Section->m_BlockTypes));
+ memset(a_Section->m_BlockMetas, 0x00, sizeof(a_Section->m_BlockMetas));
+ memset(a_Section->m_BlockLight, 0x00, sizeof(a_Section->m_BlockLight));
+ memset(a_Section->m_BlockSkyLight, 0xff, sizeof(a_Section->m_BlockSkyLight));
+}
+
+
+
+
diff --git a/src/ChunkData.h b/src/ChunkData.h
new file mode 100644
index 000000000..fef31b5ad
--- /dev/null
+++ b/src/ChunkData.h
@@ -0,0 +1,125 @@
+
+// ChunkData.h
+
+// Declares the cChunkData class that represents the block's type, meta, blocklight and skylight storage for a chunk
+
+
+
+
+
+#pragma once
+
+
+#include <cstring>
+
+
+#include "ChunkDef.h"
+
+
+
+
+#if __cplusplus < 201103L
+// auto_ptr style interface for memory management
+#else
+// unique_ptr style interface for memory management
+#endif
+
+class cChunkData
+{
+public:
+
+ cChunkData(void);
+ ~cChunkData();
+
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ cChunkData(const cChunkData & a_Other);
+ cChunkData & operator =(const cChunkData & a_Other);
+ #else
+ // unique_ptr style interface for memory management
+ cChunkData(cChunkData && a_Other);
+ cChunkData & operator =(cChunkData && a_ther);
+ #endif
+
+ BLOCKTYPE GetBlock(int a_X, int a_Y, int a_Z) const;
+ void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block);
+
+ NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const;
+ bool SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble);
+
+ NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const;
+
+ NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const;
+
+ /** Creates a (deep) copy of self. */
+ cChunkData Copy(void) const;
+
+ /** Copies the blocktype data into the specified flat array.
+ Optionally, only a part of the data is copied, as specified by the a_Idx and a_Length parameters. */
+ void CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx = 0, size_t a_Length = cChunkDef::NumBlocks) const;
+
+ /** Copies the metadata into the specified flat array. */
+ void CopyMetas(NIBBLETYPE * a_Dest) const;
+
+ /** Copies the block light data into the specified flat array. */
+ void CopyBlockLight(NIBBLETYPE * a_Dest) const;
+
+ /** Copies the skylight data into the specified flat array. */
+ void CopySkyLight (NIBBLETYPE * a_Dest) const;
+
+ /** Copies the blocktype data from the specified flat array into the internal representation.
+ Allocates sections that are needed for the operation.
+ Requires that a_Src is a valid pointer. */
+ void SetBlockTypes(const BLOCKTYPE * a_Src);
+
+ /** Copies the metadata from the specified flat array into the internal representation.
+ Allocates sectios that are needed for the operation.
+ Requires that a_Src is a valid pointer. */
+ void SetMetas(const NIBBLETYPE * a_Src);
+
+ /** Copies the blocklight data from the specified flat array into the internal representation.
+ Allocates sectios that are needed for the operation.
+ Allows a_Src to be NULL, in which case it doesn't do anything. */
+ void SetBlockLight(const NIBBLETYPE * a_Src);
+
+ /** Copies the skylight data from the specified flat array into the internal representation.
+ Allocates sectios that are needed for the operation.
+ Allows a_Src to be NULL, in which case it doesn't do anything. */
+ void SetSkyLight(const NIBBLETYPE * a_Src);
+
+private:
+
+ static const size_t SectionHeight = 16;
+ static const size_t NumSections = (cChunkDef::Height / SectionHeight);
+ static const size_t SectionBlockCount = SectionHeight * cChunkDef::Width * cChunkDef::Width;
+
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ mutable bool m_IsOwner;
+ #endif
+
+ struct sChunkSection {
+ BLOCKTYPE m_BlockTypes [SectionBlockCount];
+ NIBBLETYPE m_BlockMetas [SectionBlockCount / 2];
+ NIBBLETYPE m_BlockLight [SectionBlockCount / 2];
+ NIBBLETYPE m_BlockSkyLight[SectionBlockCount / 2];
+ };
+
+ sChunkSection * m_Sections[NumSections];
+
+ /** Allocates a new section. Entry-point to custom allocators. */
+ static sChunkSection * Allocate(void);
+
+ /** Frees the specified section, previously allocated using Allocate().
+ Note that a_Section may be NULL. */
+ static void Free(sChunkSection * a_Section);
+
+ /** Sets the data in the specified section to their default values. */
+ void ZeroSection(sChunkSection * a_Section) const;
+};
+
+
+
+
+
+
diff --git a/src/ChunkDataCallback.h b/src/ChunkDataCallback.h
new file mode 100644
index 000000000..0c8b1098f
--- /dev/null
+++ b/src/ChunkDataCallback.h
@@ -0,0 +1,127 @@
+
+// ChunkDataCallback.h
+
+// Declares the cChunkDataCallback interface and several trivial descendants, for reading chunk data
+
+
+
+
+
+#pragma once
+
+#include "ChunkData.h"
+
+
+
+
+
+/** Interface class used for getting data out of a chunk using the GetAllData() function.
+Implementation must use the pointers immediately and NOT store any of them for later use
+The virtual methods are called in the same order as they're declared here.
+*/
+class cChunkDataCallback abstract
+{
+public:
+
+ virtual ~cChunkDataCallback() {}
+
+ /** Called before any other callbacks to inform of the current coords
+ (only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
+ If false is returned, the chunk is skipped.
+ */
+ virtual bool Coords(int a_ChunkX, int a_ChunkZ) { UNUSED(a_ChunkX); UNUSED(a_ChunkZ); return true; };
+
+ /// Called once to provide heightmap data
+ virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {UNUSED(a_HeightMap); };
+
+ /// Called once to provide biome data
+ virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); };
+
+ /// Called once to let know if the chunk lighting is valid. Return value is ignored
+ virtual void LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); };
+
+ /// Called once to export block info
+ virtual void ChunkData(const cChunkData & a_Buffer) {UNUSED(a_Buffer); };
+
+ /// Called for each entity in the chunk
+ virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); };
+
+ /// Called for each blockentity in the chunk
+ virtual void BlockEntity(cBlockEntity * a_Entity) {UNUSED(a_Entity); };
+} ;
+
+
+
+
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into a buffer
+*/
+class cChunkDataCollector :
+ public cChunkDataCallback
+{
+public:
+
+ cChunkData m_BlockData;
+
+protected:
+
+ virtual void ChunkData(const cChunkData & a_BlockData) override
+ {
+ m_BlockData = a_BlockData.Copy();
+ }
+};
+
+
+
+
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer
+*/
+class cChunkDataArrayCollector :
+ public cChunkDataCallback
+{
+public:
+
+ // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
+ unsigned char m_BlockData[cChunkDef::BlockDataSize];
+
+protected:
+
+ virtual void ChunkData(const cChunkData & a_ChunkBuffer) override
+ {
+ a_ChunkBuffer.CopyBlockTypes(m_BlockData);
+ a_ChunkBuffer.CopyMetas(m_BlockData + cChunkDef::NumBlocks);
+ a_ChunkBuffer.CopyBlockLight(m_BlockData + 3 * cChunkDef::NumBlocks / 2);
+ a_ChunkBuffer.CopySkyLight(m_BlockData + 2 * cChunkDef::NumBlocks);
+ }
+};
+
+
+
+
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into separate buffers */
+class cChunkDataSeparateCollector :
+ public cChunkDataCallback
+{
+public:
+
+ cChunkDef::BlockTypes m_BlockTypes;
+ cChunkDef::BlockNibbles m_BlockMetas;
+ cChunkDef::BlockNibbles m_BlockLight;
+ cChunkDef::BlockNibbles m_BlockSkyLight;
+
+protected:
+
+ virtual void ChunkData(const cChunkData & a_ChunkBuffer) override
+ {
+ a_ChunkBuffer.CopyBlockTypes(m_BlockTypes);
+ a_ChunkBuffer.CopyMetas(m_BlockMetas);
+ a_ChunkBuffer.CopyBlockLight(m_BlockLight);
+ a_ChunkBuffer.CopySkyLight(m_BlockSkyLight);
+ }
+} ;
+
+
+
+
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 9c7753820..f89e16ed1 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -77,13 +77,19 @@ public:
idx = x + Width * z // Need to verify this with the protocol spec, currently unknown!
*/
typedef EMCSBiome BiomeMap[Width * Width];
-
+
/// The type used for block type operations and storage, AXIS_ORDER ordering
typedef BLOCKTYPE BlockTypes[NumBlocks];
-
+
/// The type used for block data in nibble format, AXIS_ORDER ordering
typedef NIBBLETYPE BlockNibbles[NumBlocks / 2];
+ /** The storage wrapper used for compressed blockdata residing in RAMz */
+ typedef std::vector<BLOCKTYPE> COMPRESSED_BLOCKTYPE;
+
+ /** The storage wrapper used for compressed nibbledata residing in RAMz */
+ typedef std::vector<NIBBLETYPE> COMPRESSED_NIBBLETYPE;
+
/// Converts absolute block coords into relative (chunk + block) coords:
inline static void AbsoluteToRelative(/* in-out */ int & a_X, int & a_Y, int & a_Z, /* out */ int & a_ChunkX, int & a_ChunkZ )
@@ -219,46 +225,67 @@ public:
ASSERT((a_Z >= 0) && (a_Z <= Width));
a_BiomeMap[a_X + Width * a_Z] = a_Biome;
}
-
-
- static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int a_BlockIdx)
+
+
+ static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, bool a_IsSkyLightNibble = false)
{
if ((a_BlockIdx > -1) && (a_BlockIdx < NumBlocks))
{
- return (a_Buffer[a_BlockIdx / 2] >> ((a_BlockIdx & 1) * 4)) & 0x0f;
+ if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size())
+ {
+ return (a_IsSkyLightNibble ? 0xff : 0);
+ }
+ return (a_Buffer[(size_t)(a_BlockIdx / 2)] >> ((a_BlockIdx & 1) * 4)) & 0x0f;
}
ASSERT(!"cChunkDef::GetNibble(): index out of chunk range!");
return 0;
}
-
-
+
+
+ static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, bool a_IsSkyLightNibble = false)
+ {
+ if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
+ {
+ size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
+ if ((Index / 2) >= a_Buffer.size())
+ {
+ return (a_IsSkyLightNibble ? 0xff : 0);
+ }
+ return ExpandNibble(a_Buffer, Index);
+ }
+ ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!");
+ return 0;
+ }
+
+
static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int x, int y, int z)
{
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
{
int Index = MakeIndexNoCheck(x, y, z);
- return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ return (a_Buffer[(size_t)(Index / 2)] >> ((Index & 1) * 4)) & 0x0f;
}
ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!");
return 0;
}
- static void SetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble)
+ static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble)
{
if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks))
{
ASSERT(!"cChunkDef::SetNibble(): index out of range!");
return;
}
- a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>(
- (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble
- ((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set
- );
+ if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size())
+ {
+ a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1));
+ }
+ a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, (size_t)a_BlockIdx, a_Nibble);
}
-
-
- static void SetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble)
+
+
+ static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble)
{
if (
(x >= Width) || (x < 0) ||
@@ -270,155 +297,33 @@ public:
return;
}
- int Index = MakeIndexNoCheck(x, y, z);
- a_Buffer[Index / 2] = static_cast<NIBBLETYPE>(
- (a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
- ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
- );
- }
-
-
- inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
- {
- return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
- }
-
-
- inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value )
- {
- SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
- }
-
-} ;
-
-
-
-
-
-/** Interface class used for getting data out of a chunk using the GetAllData() function.
-Implementation must use the pointers immediately and NOT store any of them for later use
-The virtual methods are called in the same order as they're declared here.
-*/
-class cChunkDataCallback abstract
-{
-public:
-
- virtual ~cChunkDataCallback() {}
-
- /** Called before any other callbacks to inform of the current coords
- (only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
- If false is returned, the chunk is skipped.
- */
- virtual bool Coords(int a_ChunkX, int a_ChunkZ) { UNUSED(a_ChunkX); UNUSED(a_ChunkZ); return true; };
-
- /// Called once to provide heightmap data
- virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {UNUSED(a_HeightMap); };
-
- /// Called once to provide biome data
- virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); };
-
- /// Called once to export block types
- virtual void BlockTypes (const BLOCKTYPE * a_Type) {UNUSED(a_Type); };
-
- /// Called once to export block meta
- virtual void BlockMeta (const NIBBLETYPE * a_Meta) {UNUSED(a_Meta); };
-
- /// Called once to let know if the chunk lighting is valid. Return value is used to control if BlockLight() and BlockSkyLight() are called next (if true)
- virtual bool LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); return true; };
-
- /// Called once to export block light
- virtual void BlockLight (const NIBBLETYPE * a_BlockLight) {UNUSED(a_BlockLight); };
-
- /// Called once to export sky light
- virtual void BlockSkyLight(const NIBBLETYPE * a_SkyLight) {UNUSED(a_SkyLight); };
-
- /// Called for each entity in the chunk
- virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); };
-
- /// Called for each blockentity in the chunk
- virtual void BlockEntity(cBlockEntity * a_Entity) {UNUSED(a_Entity); };
-} ;
-
-
-
-
-
-/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer
-*/
-class cChunkDataCollector :
- public cChunkDataCallback
-{
-public:
-
- // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
- unsigned char m_BlockData[cChunkDef::BlockDataSize];
-
-protected:
-
- virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
- {
- memcpy(m_BlockData, a_BlockTypes, sizeof(cChunkDef::BlockTypes));
- }
-
-
- virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
- {
- memcpy(m_BlockData + cChunkDef::NumBlocks, a_BlockMeta, cChunkDef::NumBlocks / 2);
- }
-
-
- virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
- {
- memcpy(m_BlockData + 3 * cChunkDef::NumBlocks / 2, a_BlockLight, cChunkDef::NumBlocks / 2);
- }
-
-
- virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
- {
- memcpy(m_BlockData + 2 * cChunkDef::NumBlocks, a_BlockSkyLight, cChunkDef::NumBlocks / 2);
+ size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
+ if ((Index / 2) >= a_Buffer.size())
+ {
+ a_Buffer.resize(((Index / 2) + 1));
+ }
+ a_Buffer[(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble);
}
-} ;
-
+private:
-/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers
-*/
-class cChunkDataSeparateCollector :
- public cChunkDataCallback
-{
-public:
-
- cChunkDef::BlockTypes m_BlockTypes;
- cChunkDef::BlockNibbles m_BlockMetas;
- cChunkDef::BlockNibbles m_BlockLight;
- cChunkDef::BlockNibbles m_BlockSkyLight;
-
-protected:
-
- virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
+ inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index, NIBBLETYPE a_Nibble)
{
- memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
- }
-
-
- virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
- {
- memcpy(m_BlockMetas, a_BlockMeta, sizeof(m_BlockMetas));
+ return static_cast<NIBBLETYPE>(
+ (a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble
+ ((a_Nibble & 0x0f) << ((a_Index & 1) * 4)) // The nibble being set
+ );
}
- virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
+ inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index)
{
- memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
+ return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f;
}
- virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
- {
- memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
- }
} ;
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index e695f0ab2..d3f44bef8 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -219,9 +219,8 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockType = Chunk->GetBlock(Index);
- a_BlockMeta = Chunk->GetMeta(Index);
+ a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -242,8 +241,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockType = Chunk->GetBlock(Index);
+ a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -264,8 +262,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockMeta = Chunk->GetMeta(Index);
+ a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -346,9 +343,8 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity *
void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSLayers);
- int x, y, z, ChunkX, ChunkZ;
+ int x, z, ChunkX, ChunkZ;
x = a_BlockX;
- y = a_BlockY;
z = a_BlockZ;
cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
@@ -916,19 +912,21 @@ void cChunkMap::SetChunkData(
}
// Notify relevant ChunkStays:
- for (cChunkStays::iterator itr = m_ChunkStays.begin(); itr != m_ChunkStays.end(); )
+ cChunkStays ToBeDisabled;
+ for (cChunkStays::iterator itr = m_ChunkStays.begin(), end = m_ChunkStays.end(); itr != end; ++itr)
{
if ((*itr)->ChunkAvailable(a_ChunkX, a_ChunkZ))
{
- cChunkStays::iterator cur = itr;
- ++itr;
- m_ChunkStays.erase(cur);
- }
- else
- {
- ++itr;
+ // The chunkstay wants to be disabled, add it to a list of to-be-disabled chunkstays for later processing:
+ ToBeDisabled.push_back(*itr);
}
} // for itr - m_ChunkStays[]
+
+ // Disable (and possibly remove) the chunkstays that chose to get disabled:
+ for (cChunkStays::iterator itr = ToBeDisabled.begin(), end = ToBeDisabled.end(); itr != end; ++itr)
+ {
+ (*itr)->Disable();
+ }
}
// Notify plugins of the chunk becoming available
@@ -1144,9 +1142,8 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
// First check if it isn't queued in the m_FastSetBlockQueue:
{
int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
- int ChunkX, ChunkY, ChunkZ;
+ int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
- ChunkY = 0;
cCSLock Lock(m_CSFastSetBlock);
for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr)
{
@@ -1248,8 +1245,6 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
if ((Chunk != NULL) && Chunk->IsValid())
{
Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
- Chunk->MarkDirty();
- Chunk->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, NULL);
}
}
@@ -1486,9 +1481,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
res = false;
continue;
}
- int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
- itr->BlockType = Chunk->GetBlock(idx);
- itr->BlockMeta = Chunk->GetMeta(idx);
+ itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z);
+ itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z);
}
return res;
}
@@ -1654,7 +1648,10 @@ void cChunkMap::AddEntity(cEntity * a_Entity)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if (
+ (Chunk == NULL) || // Chunk not present at all
+ (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953)
+ )
{
LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.",
a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID()
@@ -1689,7 +1686,7 @@ void cChunkMap::RemoveEntity(cEntity * a_Entity)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return;
}
@@ -1721,7 +1718,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -1971,7 +1968,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -1986,7 +1983,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback &
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2001,7 +1998,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2016,7 +2013,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2031,7 +2028,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2046,7 +2043,7 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallba
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2064,7 +2061,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2082,7 +2079,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2100,7 +2097,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2118,7 +2115,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2136,7 +2133,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2154,7 +2151,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2171,7 +2168,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2188,7 +2185,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2206,7 +2203,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2224,7 +2221,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2242,7 +2239,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString &
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
- if ((Chunk == NULL) && !Chunk->IsValid())
+ if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@@ -2974,7 +2971,12 @@ void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay)
Chunk->Stay(true);
if (Chunk->IsValid())
{
- a_ChunkStay.ChunkAvailable(itr->m_ChunkX, itr->m_ChunkZ);
+ if (a_ChunkStay.ChunkAvailable(itr->m_ChunkX, itr->m_ChunkZ))
+ {
+ // The chunkstay wants to be deactivated, disable it and bail out:
+ a_ChunkStay.Disable();
+ return;
+ }
}
} // for itr - WantedChunks[]
}
@@ -3017,6 +3019,7 @@ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay)
}
Chunk->Stay(false);
} // for itr - Chunks[]
+ a_ChunkStay.OnDisabled();
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 9d973f2a9..c3deda088 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -5,7 +5,8 @@
#pragma once
-#include "ChunkDef.h"
+
+#include "ChunkDataCallback.h"
diff --git a/src/ChunkSender.h b/src/ChunkSender.h
index a26f764a7..00565d7c3 100644
--- a/src/ChunkSender.h
+++ b/src/ChunkSender.h
@@ -27,6 +27,7 @@ Note that it may be called by world's BroadcastToChunk() if the client is still
#include "OSSupport/IsThread.h"
#include "ChunkDef.h"
+#include "ChunkDataCallback.h"
diff --git a/src/ChunkStay.cpp b/src/ChunkStay.cpp
index 6b1d5ee34..b5002a63d 100644
--- a/src/ChunkStay.cpp
+++ b/src/ChunkStay.cpp
@@ -31,10 +31,7 @@ cChunkStay::~cChunkStay()
void cChunkStay::Clear(void)
{
- if (m_ChunkMap != NULL)
- {
- Disable();
- }
+ ASSERT(m_ChunkMap == NULL);
m_Chunks.clear();
}
@@ -97,8 +94,9 @@ void cChunkStay::Disable(void)
{
ASSERT(m_ChunkMap != NULL);
- m_ChunkMap->DelChunkStay(*this);
+ cChunkMap * ChunkMap = m_ChunkMap;
m_ChunkMap = NULL;
+ ChunkMap->DelChunkStay(*this);
}
diff --git a/src/ChunkStay.h b/src/ChunkStay.h
index 2510cb490..29893befc 100644
--- a/src/ChunkStay.h
+++ b/src/ChunkStay.h
@@ -36,8 +36,12 @@ class cChunkStay
{
public:
cChunkStay(void);
+
+ /** Deletes the object. Note that this calls Clear(), which means that the ChunkStay needs to be disabled. */
virtual ~cChunkStay();
+ /** Clears all the chunks that have been added.
+ To be used only while the ChunkStay object is not enabled. */
void Clear(void);
/** Adds a chunk to be locked from unloading.
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 46c10ae82..9b03bead9 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -24,13 +24,15 @@
#include "Root.h"
-#include "Authenticator.h"
+#include "Protocol/Authenticator.h"
#include "MersenneTwister.h"
#include "Protocol/ProtocolRecognizer.h"
#include "CompositeChat.h"
#include "Items/ItemSword.h"
+#include "md5/md5.h"
+
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
@@ -175,6 +177,84 @@ void cClientHandle::Destroy(void)
+void cClientHandle::GenerateOfflineUUID(void)
+{
+ m_UUID = GenerateOfflineUUID(m_Username);
+}
+
+
+
+
+
+AString cClientHandle::FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2)
+{
+ if (ShouldAppendChatPrefixes)
+ return Printf("%s[%s] %s", m_Color1.c_str(), a_ChatPrefixS.c_str(), m_Color2.c_str());
+ else
+ return Printf("%s", m_Color1.c_str());
+}
+
+
+
+
+
+AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString &a_AdditionalData)
+{
+ switch (a_ChatPrefix)
+ {
+ case mtCustom: return "";
+ case mtFailure: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Rose, cChatColor::White);
+ case mtInformation: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Yellow, cChatColor::White);
+ case mtSuccess: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Green, cChatColor::White);
+ case mtWarning: return FormatChatPrefix(ShouldAppendChatPrefixes, "WARN", cChatColor::Rose, cChatColor::White);
+ case mtFatal: return FormatChatPrefix(ShouldAppendChatPrefixes, "FATAL", cChatColor::Red, cChatColor::White);
+ case mtDeath: return FormatChatPrefix(ShouldAppendChatPrefixes, "DEATH", cChatColor::Gray, cChatColor::White);
+ case mtJoin: return FormatChatPrefix(ShouldAppendChatPrefixes, "JOIN", cChatColor::Yellow, cChatColor::White);
+ case mtLeave: return FormatChatPrefix(ShouldAppendChatPrefixes, "LEAVE", cChatColor::Yellow, cChatColor::White);
+ case mtPrivateMessage:
+ {
+ if (ShouldAppendChatPrefixes)
+ {
+ return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
+ }
+ else
+ {
+ return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
+ }
+ }
+ }
+ ASSERT(!"Unhandled chat prefix type!");
+ return "";
+}
+
+
+
+
+
+AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
+{
+ // Proper format for a version 3 UUID is:
+ // xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B
+
+ // Generate an md5 checksum, and use it as base for the ID:
+ MD5 Checksum(a_Username);
+ AString UUID = Checksum.hexdigest();
+ UUID[12] = '3'; // Version 3 UUID
+ UUID[16] = '8'; // Variant 1 UUID
+
+ // Now the digest doesn't have the UUID slashes, but the client requires them, so add them into the appropriate positions:
+ UUID.insert(8, "-");
+ UUID.insert(13, "-");
+ UUID.insert(18, "-");
+ UUID.insert(23, "-");
+
+ return UUID;
+}
+
+
+
+
+
void cClientHandle::Kick(const AString & a_Reason)
{
if (m_State >= csAuthenticating) // Don't log pings
@@ -188,7 +268,7 @@ void cClientHandle::Kick(const AString & a_Reason)
-void cClientHandle::Authenticate(void)
+void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID)
{
if (m_State != csAuthenticating)
{
@@ -197,6 +277,12 @@ void cClientHandle::Authenticate(void)
ASSERT( m_Player == NULL );
+ m_Username = a_Name;
+ m_UUID = a_UUID;
+
+ // Send login success (if the protocol supports it):
+ m_Protocol->SendLoginSuccess();
+
// Spawn player (only serversided, so data is loaded)
m_Player = new cPlayer(this, GetUsername());
@@ -251,6 +337,11 @@ void cClientHandle::Authenticate(void)
// Send scoreboard data
World->GetScoreBoard().SendTo(*this);
+ // Delay the first ping until the client "settles down"
+ // This should fix #889, "BadCast exception, cannot convert bit to fm" error in client
+ cTimer t1;
+ m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds
+
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
}
@@ -412,14 +503,16 @@ void cClientHandle::HandlePing(void)
{
// Somebody tries to retrieve information about the server
AString Reply;
+ const cServer & Server = *cRoot::Get()->GetServer();
+
Printf(Reply, "%s%s%i%s%i",
- cRoot::Get()->GetServer()->GetDescription().c_str(),
+ Server.GetDescription().c_str(),
cChatColor::Delimiter.c_str(),
- cRoot::Get()->GetServer()->GetNumPlayers(),
+ Server.GetNumPlayers(),
cChatColor::Delimiter.c_str(),
- cRoot::Get()->GetServer()->GetMaxPlayers()
+ Server.GetMaxPlayers()
);
- Kick(Reply.c_str());
+ Kick(Reply);
}
@@ -540,6 +633,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
// Client <-> Server branding exchange
SendPluginMessage("MC|Brand", "MCServer");
}
+ else if (a_Channel == "MC|ItemName")
+ {
+ HandleAnvilItemName(a_Message.c_str(), a_Message.size());
+ }
else if (a_Channel == "REGISTER")
{
if (HasPluginChannel(a_Channel))
@@ -623,7 +720,7 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList
-void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length)
+void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length)
{
if (a_Length < 14)
{
@@ -681,6 +778,29 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int
+void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length)
+{
+ if (a_Length < 1)
+ {
+ return;
+ }
+
+ if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil))
+ {
+ return;
+ }
+
+ AString Name(a_Data, a_Length);
+ if (Name.length() <= 30)
+ {
+ ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player);
+ }
+}
+
+
+
+
+
void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status)
{
LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i",
@@ -695,6 +815,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
return;
}
+ if (
+ ((a_Status == DIG_STATUS_STARTED) || (a_Status == DIG_STATUS_FINISHED)) && // Only do a radius check for block destruction - things like pickup tossing send coordinates that are to be ignored
+ ((Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) ||
+ (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
+ (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6))
+ )
+ {
+ m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ return;
+ }
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
{
@@ -758,6 +889,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
case DIG_STATUS_CANCELLED:
{
// Block breaking cancelled by player
+ FinishDigAnimation();
return;
}
@@ -796,7 +928,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
// It is a duplicate packet, drop it right away
return;
}
-
+
if (
m_Player->IsGameModeCreative() &&
ItemCategory::IsSword(m_Player->GetInventory().GetEquippedItem().m_ItemType)
@@ -805,14 +937,17 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
// Players can't destroy blocks with a Sword in the hand.
return;
}
-
- if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta))
+
+ if (
+ (Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) ||
+ (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
+ (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)
+ )
{
- // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows:
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
return;
}
-
+
// Set the last digging coords to the block being dug, so that they can be checked in DIG_FINISHED to avoid dig/aim bug in the client:
m_HasStartedDigging = true;
m_LastDigBlockX = a_BlockX;
@@ -884,24 +1019,24 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
return;
}
- m_HasStartedDigging = false;
- if (m_BlockDigAnimStage != -1)
+ FinishDigAnimation();
+
+ cWorld * World = m_Player->GetWorld();
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
+
+ if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta))
{
- // End dig animation
- m_BlockDigAnimStage = -1;
- // It seems that 10 ends block animation
- m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, 10, this);
+ // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows:
+ m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ return;
}
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
-
if (a_OldBlock == E_BLOCK_AIR)
{
LOGD("Dug air - what the function?");
return;
}
-
- cWorld * World = m_Player->GetWorld();
+
ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ);
// The ItemHandler is also responsible for spawning the pickups
cChunkInterface ChunkInterface(World->GetChunkMap());
@@ -916,6 +1051,36 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
+void cClientHandle::FinishDigAnimation()
+{
+ if (
+ !m_HasStartedDigging || // Hasn't received the DIG_STARTED packet
+ (m_LastDigBlockX == -1) ||
+ (m_LastDigBlockY == -1) ||
+ (m_LastDigBlockZ == -1)
+ )
+ {
+ return;
+ }
+
+ m_HasStartedDigging = false;
+ if (m_BlockDigAnimStage != -1)
+ {
+ // End dig animation
+ m_BlockDigAnimStage = -1;
+ // It seems that 10 ends block animation
+ m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ, 10, this);
+ }
+
+ m_BlockDigAnimX = -1;
+ m_BlockDigAnimY = -1;
+ m_BlockDigAnimZ = -1;
+}
+
+
+
+
+
void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem)
{
LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
@@ -923,7 +1088,23 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
);
cWorld * World = m_Player->GetWorld();
-
+
+ if (
+ (Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) ||
+ (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
+ (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)
+ )
+ {
+ 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);
+ World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
+ m_Player->GetInventory().SendEquippedSlot();
+ }
+ return;
+ }
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
@@ -937,10 +1118,13 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
- World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things
+ World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
+ m_Player->GetInventory().SendEquippedSlot();
}
return;
}
+
+ m_NumBlockChangeInteractionsThisTick++;
if (!CheckBlockInteractionsRate())
{
@@ -960,7 +1144,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,11 +1172,11 @@ 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);
}
- else if (ItemHandler->IsFood())
+ else if (ItemHandler->IsFood() && !m_Player->IsGameModeCreative())
{
if (m_Player->IsSatiated())
{
@@ -1026,6 +1210,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 +1221,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 +1237,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 +1246,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;
}
@@ -1124,6 +1308,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
{
// Handler refused the placement, send that information back to the client:
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockY, m_Player);
+ m_Player->GetInventory().SendEquippedSlot();
return;
}
@@ -1133,12 +1318,13 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
{
// A plugin doesn't agree with placing the block, revert the block on the client:
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ m_Player->GetInventory().SendEquippedSlot();
return;
}
// 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();
}
@@ -1173,8 +1359,8 @@ void cClientHandle::HandleChat(const AString & a_Message)
Color = AString("@") + Color[2];
}
else
- {
- Color.empty();
+ {
+ Color.clear();
}
Msg.AddTextPart(AString("<") + m_Player->GetName() + "> ", Color);
Msg.ParseText(a_Message);
@@ -1205,28 +1391,8 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO
void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround)
{
- if ((m_Player == NULL) || (m_State != csPlaying))
- {
- // The client hasn't been spawned yet and sends nonsense, we know better
- return;
- }
-
- /*
- // TODO: Invalid stance check
- if ((a_PosY >= a_Stance) || (a_Stance > a_PosY + 1.65))
- {
- LOGD("Invalid stance");
- SendPlayerMoveLook();
- return;
- }
- */
-
- m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ));
- m_Player->SetStance (a_Stance);
- m_Player->SetTouchGround(a_IsOnGround);
- m_Player->SetHeadYaw (a_Rotation);
- m_Player->SetYaw (a_Rotation);
- m_Player->SetPitch (a_Pitch);
+ HandlePlayerLook(a_Rotation, a_Pitch, a_IsOnGround);
+ HandlePlayerPos(a_PosX, a_PosY, a_PosZ, a_Stance, a_IsOnGround);
}
@@ -1415,7 +1581,7 @@ void cClientHandle::HandleDisconnect(const AString & a_Reason)
{
LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str());
- cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason);
+ cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason);
m_HasSentDC = true;
Destroy();
@@ -1530,7 +1696,7 @@ void cClientHandle::HandleTabCompletion(const AString & a_Text)
-void cClientHandle::SendData(const char * a_Data, int a_Size)
+void cClientHandle::SendData(const char * a_Data, size_t a_Size)
{
if (m_HasSentDC)
{
@@ -1545,7 +1711,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size)
if (m_OutgoingDataOverflow.empty())
{
// No queued overflow data; if this packet fits into the ringbuffer, put it in, otherwise put it in the overflow buffer:
- int CanFit = m_OutgoingData.GetFreeSpace();
+ size_t CanFit = m_OutgoingData.GetFreeSpace();
if (CanFit > a_Size)
{
CanFit = a_Size;
@@ -1563,7 +1729,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size)
{
// There is a queued overflow. Append to it, then send as much from its front as possible
m_OutgoingDataOverflow.append(a_Data, a_Size);
- int CanFit = m_OutgoingData.GetFreeSpace();
+ size_t CanFit = m_OutgoingData.GetFreeSpace();
if (CanFit > 128)
{
// No point in moving the data over if it's not large enough - too much effort for too little an effect
@@ -1606,10 +1772,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;
@@ -1677,13 +1841,16 @@ void cClientHandle::Tick(float a_Dt)
}
// Send a ping packet:
- cTimer t1;
- if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()))
+ if (m_State == csPlaying)
{
- m_PingID++;
- m_PingStartTime = t1.GetNowTime();
- m_Protocol->SendKeepAlive(m_PingID);
- m_LastPingTime = m_PingStartTime;
+ cTimer t1;
+ if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()))
+ {
+ m_PingID++;
+ m_PingStartTime = t1.GetNowTime();
+ m_Protocol->SendKeepAlive(m_PingID);
+ m_LastPingTime = m_PingStartTime;
+ }
}
// Handle block break animation:
@@ -1803,7 +1970,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock
void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData)
{
bool ShouldAppendChatPrefixes = true;
-
+
if (GetPlayer()->GetWorld() == NULL)
{
cWorld * World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName());
@@ -1822,89 +1989,9 @@ void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefi
ShouldAppendChatPrefixes = false;
}
- AString Message;
+ AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData);
- switch (a_ChatPrefix)
- {
- case mtCustom: break;
- case mtFailure:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[INFO] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Rose.c_str());
- break;
- }
- case mtInformation:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[INFO] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Yellow.c_str());
- break;
- }
- case mtSuccess:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[INFO] %s", cChatColor::Green.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Green.c_str());
- break;
- }
- case mtWarning:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[WARN] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Rose.c_str());
- break;
- }
- case mtFatal:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[FATAL] %s", cChatColor::Red.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Red.c_str());
- break;
- }
- case mtDeath:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[DEATH] %s", cChatColor::Gray.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Gray.c_str());
- break;
- }
- case mtPrivateMessage:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
- else
- Message = Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
- break;
- }
- case mtJoin:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[JOIN] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Yellow.c_str());
- break;
- }
- case mtLeave:
- {
- if (ShouldAppendChatPrefixes)
- Message = Printf("%s[LEAVE] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
- else
- Message = Printf("%s", cChatColor::Yellow.c_str());
- break;
- }
- default: ASSERT(!"Unhandled chat prefix type!"); return;
- }
-
- Message.append(a_Message);
-
- m_Protocol->SendChat(Message);
+ m_Protocol->SendChat(Message.append(a_Message));
}
@@ -2101,7 +2188,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo
}
// Update the statistics:
- m_NumExplosionsThisTick += 1;
+ m_NumExplosionsThisTick++;
m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
}
@@ -2394,6 +2481,15 @@ void cClientHandle::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTy
+void cClientHandle::SendStatistics(const cStatManager & a_Manager)
+{
+ m_Protocol->SendStatistics(a_Manager);
+}
+
+
+
+
+
void cClientHandle::SendTabCompletionResults(const AStringVector & a_Results)
{
m_Protocol->SendTabCompletionResults(a_Results);
@@ -2633,12 +2729,13 @@ void cClientHandle::PacketError(unsigned char a_PacketType)
-void cClientHandle::DataReceived(const char * a_Data, int a_Size)
+bool cClientHandle::DataReceived(const char * a_Data, size_t a_Size)
{
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
m_TimeSinceLastPacket = 0;
cCSLock Lock(m_CSIncomingData);
m_IncomingData.append(a_Data, a_Size);
+ return false;
}
@@ -2673,9 +2770,9 @@ void cClientHandle::SocketClosed(void)
LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str());
- if (m_Username != "") // Ignore client pings
+ if (!m_Username.empty()) // Ignore client pings
{
- cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected");
+ cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, "Player disconnected");
}
Destroy();
@@ -2685,4 +2782,27 @@ void cClientHandle::SocketClosed(void)
+void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment)
+{
+ cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow();
+ cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player);
+ int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment);
+
+ if (Item.EnchantByXPLevels(BaseEnchantmentLevel))
+ {
+ if (m_Player->IsGameModeCreative() || m_Player->DeltaExperience(-m_Player->XpForLevel(BaseEnchantmentLevel)) >= 0)
+ {
+ Window->m_SlotArea->SetSlot(0, *m_Player, Item);
+ Window->SendSlot(*m_Player, Window->m_SlotArea, 0);
+ Window->BroadcastWholeWindow();
+
+ Window->SetProperty(0, 0, *m_Player);
+ Window->SetProperty(1, 0, *m_Player);
+ Window->SetProperty(2, 0, *m_Player);
+ }
+ }
+}
+
+
+
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 8366caa16..659c67658 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -18,6 +18,8 @@
#include "ByteBuffer.h"
#include "Scoreboard.h"
#include "Map.h"
+#include "Enchantments.h"
+#include "UI/SlotArea.h"
@@ -37,6 +39,7 @@ class cFallingBlock;
class cItemHandler;
class cWorld;
class cCompositeChat;
+class cStatManager;
@@ -62,8 +65,27 @@ public:
cPlayer* GetPlayer() { return m_Player; } // tolua_export
+ const AString & GetUUID(void) const { return m_UUID; } // tolua_export
+ void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
+
+ /** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
+ This is used for the offline (non-auth) mode, when there's no UUID source.
+ Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
+ Internally calls the GenerateOfflineUUID static function. */
+ void GenerateOfflineUUID(void);
+
+ /** Generates an UUID based on the player name provided.
+ This is used for the offline (non-auth) mode, when there's no UUID source.
+ Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
+ static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export
+
+ /** Formats the type of message with the proper color and prefix for sending to the client. **/
+ static AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData);
+
+ static AString FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2);
+
void Kick(const AString & a_Reason); // tolua_export
- void Authenticate(void); // Called by cAuthenticator when the user passes authentication
+ void Authenticate(const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator when the user passes authentication
void StreamChunks(void);
@@ -139,6 +161,7 @@ public:
void SendSpawnMob (const cMonster & a_Mob);
void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch);
void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType = 0);
+ void SendStatistics (const cStatManager & a_Manager);
void SendTabCompletionResults(const AStringVector & a_Results);
void SendTeleportEntity (const cEntity & a_Entity);
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
@@ -225,16 +248,19 @@ public:
*/
bool HandleLogin(int a_ProtocolVersion, const AString & a_Username);
- void SendData(const char * a_Data, int a_Size);
+ void SendData(const char * a_Data, size_t a_Size);
/** Called when the player moves into a different world; queues sreaming the new chunks */
void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket);
- /** 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);
+ /** Called when the player will enchant a Item */
+ void HandleEnchantItem(Byte & WindowID, Byte & Enchantment);
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);
+
/** The type used for storing the names of registered plugin channels. */
typedef std::set<AString> cChannels;
@@ -326,6 +352,7 @@ private:
static int s_ClientCount;
int m_UniqueID;
+ AString m_UUID;
/** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */
bool m_HasSentPlayerChunk;
@@ -349,6 +376,9 @@ private:
/** Handles the DIG_FINISHED dig packet: */
void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta);
+ /** The clients will receive a finished dig animation */
+ void FinishDigAnimation();
+
/** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */
AStringVector BreakApartPluginChannels(const AString & a_PluginChannels);
@@ -359,10 +389,13 @@ private:
void UnregisterPluginChannels(const AStringVector & a_ChannelList);
/** Handles the "MC|AdvCdm" plugin message */
- void HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length);
+ void HandleCommandBlockMessage(const char * a_Data, size_t a_Length);
+
+ /** Handles the "MC|ItemName" plugin message */
+ void HandleAnvilItemName(const char * a_Data, size_t a_Length);
// cSocketThreads::cCallback overrides:
- virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
+ virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
virtual void SocketClosed (void) override; // The socket has been closed for any reason
}; // tolua_export
diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp
index a917ee70f..a3612983a 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);
}
@@ -189,6 +189,15 @@ void cCompositeChat::AddSuggestCommandPart(const AString & a_Text, const AString
+void cCompositeChat::AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style)
+{
+ m_Parts.push_back(new cShowAchievementPart(a_PlayerName, a_Achievement, a_Style));
+}
+
+
+
+
+
void cCompositeChat::ParseText(const AString & a_ParseText)
{
size_t len = a_ParseText.length();
@@ -290,9 +299,10 @@ void cCompositeChat::ParseText(const AString & a_ParseText)
-void cCompositeChat::SetMessageType(eMessageType a_MessageType)
+void cCompositeChat::SetMessageType(eMessageType a_MessageType, const AString & a_AdditionalMessageTypeData)
{
m_MessageType = a_MessageType;
+ m_AdditionalMessageTypeData = a_AdditionalMessageTypeData;
}
@@ -314,6 +324,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())
@@ -424,3 +486,16 @@ cCompositeChat::cSuggestCommandPart::cSuggestCommandPart(const AString & a_Text,
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cCompositeChat::cShowAchievementPart:
+
+cCompositeChat::cShowAchievementPart::cShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style) :
+ super(ptShowAchievement, a_Achievement, a_Style),
+ m_PlayerName(a_PlayerName)
+{
+}
+
+
+
+
diff --git a/src/CompositeChat.h b/src/CompositeChat.h
index 27319490d..1ad196f1d 100644
--- a/src/CompositeChat.h
+++ b/src/CompositeChat.h
@@ -38,6 +38,7 @@ public:
ptUrl,
ptRunCommand,
ptSuggestCommand,
+ ptShowAchievement,
} ;
class cBasePart
@@ -46,6 +47,7 @@ public:
ePartType m_PartType;
AString m_Text;
AString m_Style;
+ AString m_AdditionalStyleData;
cBasePart(ePartType a_PartType, const AString & a_Text, const AString & a_Style = "");
@@ -106,6 +108,15 @@ public:
public:
cSuggestCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "");
} ;
+
+ class cShowAchievementPart :
+ public cBasePart
+ {
+ typedef cBasePart super;
+ public:
+ AString m_PlayerName;
+ cShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = "");
+ } ;
typedef std::vector<cBasePart *> cParts;
@@ -117,7 +128,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();
@@ -148,13 +159,20 @@ public:
/** Adds a part that suggests a command (enters it into the chat message area, but doesn't send) when clicked.
The default style is underlined yellow text. */
void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "u@b");
+
+ /** Adds a part that fully formats a specified achievement using client translatable strings
+ Takes achievement name and player awarded to. Displays as {player} has earned the achievement {achievement_name}.
+ */
+ void AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = "");
/** Parses text into various parts, adds those.
Recognizes "http:" and "https:" URLs and @color-codes. */
void ParseText(const AString & a_ParseText);
- /** Sets the message type, which is indicated by prefixes added to the message when serializing. */
- void SetMessageType(eMessageType a_MessageType);
+ /** Sets the message type, which is indicated by prefixes added to the message when serializing
+ Takes optional AdditionalMessageTypeData to set m_AdditionalMessageTypeData. See said variable for more documentation.
+ */
+ void SetMessageType(eMessageType a_MessageType, const AString & a_AdditionalMessageTypeData = "");
/** Adds the "underline" style to each part that is an URL. */
void UnderlineUrls(void);
@@ -163,11 +181,23 @@ public:
/** Returns the message type set previously by SetMessageType(). */
eMessageType GetMessageType(void) const { return m_MessageType; }
+
+ /** Returns additional data pertaining to message type, for example, the name of a mtPrivateMsg sender */
+ AString GetAdditionalMessageTypeData(void) const { return m_AdditionalMessageTypeData; }
+
+ /** 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;
@@ -175,6 +205,9 @@ protected:
/** The message type, as indicated by prefixes. */
eMessageType m_MessageType;
+ /** Additional data pertaining to message type, for example, the name of a mtPrivateMsg sender */
+ AString m_AdditionalMessageTypeData;
+
/** Adds a_AddStyle to a_Style; overwrites the existing style if appropriate.
If the style already contains something that a_AddStyle overrides, it is erased first. */
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index 30e7a8733..53a638ee5 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -661,14 +661,16 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
ASSERT(itrS->x + a_OffsetX < a_GridWidth);
ASSERT(itrS->y + a_OffsetY < a_GridHeight);
int GridID = (itrS->x + a_OffsetX) + a_GridStride * (itrS->y + a_OffsetY);
+
+ const cItem & Item = itrS->m_Item;
if (
(itrS->x >= a_GridWidth) ||
(itrS->y >= a_GridHeight) ||
- (itrS->m_Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) || // same item type?
- (itrS->m_Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items
+ (Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) || // same item type?
+ (Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items
(
- (itrS->m_Item.m_ItemDamage > 0) && // should compare damage values?
- (itrS->m_Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage)
+ (Item.m_ItemDamage > 0) && // should compare damage values?
+ (Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage)
)
)
{
@@ -800,7 +802,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe
break;
}
case E_ITEM_PAPER: break;
- default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break;
+ default: LOG("Unexpected item in firework rocket recipe, was the crafting file's fireworks section changed?"); break;
}
}
}
@@ -824,7 +826,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe
case E_ITEM_DYE:
{
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
- DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
+ DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye((NIBBLETYPE)(a_CraftingGrid[GridID].m_ItemDamage & 0x0f)));
break;
}
case E_ITEM_GUNPOWDER: break;
@@ -835,7 +837,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe
case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break;
case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break;
case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break;
- default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins
+ default: LOG("Unexpected item in firework star recipe, was the crafting file's fireworks section changed?"); break; // ermahgerd BARD ardmins
}
}
diff --git a/src/Crypto.cpp b/src/Crypto.cpp
deleted file mode 100644
index 26500f263..000000000
--- a/src/Crypto.cpp
+++ /dev/null
@@ -1,509 +0,0 @@
-
-// Crypto.cpp
-
-// Implements classes that wrap the cryptographic code library
-
-#include "Globals.h"
-#include "Crypto.h"
-
-#include "polarssl/pk.h"
-
-
-
-
-
-/*
-// Self-test the hash formatting for known values:
-// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
-// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
-// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
-
-class Test
-{
-public:
- Test(void)
- {
- AString DigestNotch, DigestJeb, DigestSimon;
- Byte Digest[20];
- cSHA1Checksum Checksum;
- Checksum.Update((const Byte *)"Notch", 5);
- Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, DigestNotch);
- Checksum.Restart();
- Checksum.Update((const Byte *)"jeb_", 4);
- Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, DigestJeb);
- Checksum.Restart();
- Checksum.Update((const Byte *)"simon", 5);
- Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, DigestSimon);
- printf("Notch: \"%s\"\n", DigestNotch.c_str());
- printf("jeb_: \"%s\"\n", DigestJeb.c_str());
- printf("simon: \"%s\"\n", DigestSimon.c_str());
- assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
- assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
- assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
- }
-} test;
-*/
-
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cRSAPrivateKey:
-
-cRSAPrivateKey::cRSAPrivateKey(void)
-{
- rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
- InitRnd();
-}
-
-
-
-
-
-cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other)
-{
- rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
- rsa_copy(&m_Rsa, &a_Other.m_Rsa);
- InitRnd();
-}
-
-
-
-
-
-cRSAPrivateKey::~cRSAPrivateKey()
-{
- entropy_free(&m_Entropy);
- rsa_free(&m_Rsa);
-}
-
-
-
-
-
-void cRSAPrivateKey::InitRnd(void)
-{
- entropy_init(&m_Entropy);
- const unsigned char pers[] = "rsa_genkey";
- ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
-}
-
-
-
-
-
-bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits)
-{
- if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0)
- {
- // Key generation failed
- return false;
- }
-
- return true;
-}
-
-
-
-
-
-AString cRSAPrivateKey::GetPubKeyDER(void)
-{
- class cPubKey
- {
- public:
- cPubKey(rsa_context * a_Rsa) :
- m_IsValid(false)
- {
- pk_init(&m_Key);
- if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
- {
- ASSERT(!"Cannot init PrivKey context");
- return;
- }
- if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
- {
- ASSERT(!"Cannot copy PrivKey to PK context");
- return;
- }
- m_IsValid = true;
- }
-
- ~cPubKey()
- {
- if (m_IsValid)
- {
- pk_free(&m_Key);
- }
- }
-
- operator pk_context * (void) { return &m_Key; }
-
- protected:
- bool m_IsValid;
- pk_context m_Key;
- } PkCtx(&m_Rsa);
-
- unsigned char buf[3000];
- int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
- if (res < 0)
- {
- return AString();
- }
- return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
-}
-
-
-
-
-
-int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
-{
- if (a_EncryptedLength < m_Rsa.len)
- {
- LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
- __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
- );
- ASSERT(!"Invalid a_DecryptedMaxLength!");
- return -1;
- }
- if (a_DecryptedMaxLength < m_Rsa.len)
- {
- LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
- __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
- );
- ASSERT(!"Invalid a_DecryptedMaxLength!");
- return -1;
- }
- size_t DecryptedLength;
- int res = rsa_pkcs1_decrypt(
- &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength,
- a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
- );
- if (res != 0)
- {
- return -1;
- }
- return (int)DecryptedLength;
-}
-
-
-
-
-
-int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
-{
- if (a_EncryptedMaxLength < m_Rsa.len)
- {
- LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
- __FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
- );
- ASSERT(!"Invalid a_DecryptedMaxLength!");
- return -1;
- }
- if (a_EncryptedMaxLength < m_Rsa.len)
- {
- LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
- __FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
- );
- ASSERT(!"Invalid a_PlainLength!");
- return -1;
- }
- int res = rsa_pkcs1_encrypt(
- &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE,
- a_PlainLength, a_PlainData, a_EncryptedData
- );
- if (res != 0)
- {
- return -1;
- }
- return (int)m_Rsa.len;
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cPublicKey:
-
-cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
-{
- pk_init(&m_Pk);
- if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
- {
- ASSERT(!"Cannot parse PubKey");
- return;
- }
- InitRnd();
-}
-
-
-
-
-
-cPublicKey::~cPublicKey()
-{
- pk_free(&m_Pk);
-}
-
-
-
-
-
-int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
-{
- size_t DecryptedLen = a_DecryptedMaxLength;
- int res = pk_decrypt(&m_Pk,
- a_EncryptedData, a_EncryptedLength,
- a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
- ctr_drbg_random, &m_Ctr_drbg
- );
- if (res != 0)
- {
- return res;
- }
- return (int)DecryptedLen;
-}
-
-
-
-
-
-int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
-{
- size_t EncryptedLength = a_EncryptedMaxLength;
- int res = pk_encrypt(&m_Pk,
- a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
- ctr_drbg_random, &m_Ctr_drbg
- );
- if (res != 0)
- {
- return res;
- }
- return (int)EncryptedLength;
-}
-
-
-
-
-
-void cPublicKey::InitRnd(void)
-{
- entropy_init(&m_Entropy);
- const unsigned char pers[] = "rsa_genkey";
- ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cAESCFBDecryptor:
-
-cAESCFBDecryptor::cAESCFBDecryptor(void) :
- m_IVOffset(0),
- m_IsValid(false)
-{
-}
-
-
-
-
-
-cAESCFBDecryptor::~cAESCFBDecryptor()
-{
- // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
- memset(&m_Aes, 0, sizeof(m_Aes));
-}
-
-
-
-
-
-void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
-{
- ASSERT(!IsValid()); // Cannot Init twice
-
- memcpy(m_IV, a_IV, 16);
- aes_setkey_enc(&m_Aes, a_Key, 128);
- m_IsValid = true;
-}
-
-
-
-
-
-void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
-{
- ASSERT(IsValid()); // Must Init() first
-
- // PolarSSL doesn't support AES-CFB8, need to implement it manually:
- for (size_t i = 0; i < a_Length; i++)
- {
- Byte Buffer[sizeof(m_IV)];
- aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
- for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
- {
- m_IV[idx] = m_IV[idx + 1];
- }
- m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
- a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cAESCFBEncryptor:
-
-cAESCFBEncryptor::cAESCFBEncryptor(void) :
- m_IVOffset(0),
- m_IsValid(false)
-{
-}
-
-
-
-
-
-cAESCFBEncryptor::~cAESCFBEncryptor()
-{
- // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
- memset(&m_Aes, 0, sizeof(m_Aes));
-}
-
-
-
-
-
-void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
-{
- ASSERT(!IsValid()); // Cannot Init twice
- ASSERT(m_IVOffset == 0);
-
- memcpy(m_IV, a_IV, 16);
- aes_setkey_enc(&m_Aes, a_Key, 128);
- m_IsValid = true;
-}
-
-
-
-
-
-void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
-{
- ASSERT(IsValid()); // Must Init() first
-
- // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
- for (size_t i = 0; i < a_Length; i++)
- {
- Byte Buffer[sizeof(m_IV)];
- aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
- for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
- {
- m_IV[idx] = m_IV[idx + 1];
- }
- a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
- m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cSHA1Checksum:
-
-cSHA1Checksum::cSHA1Checksum(void) :
- m_DoesAcceptInput(true)
-{
- sha1_starts(&m_Sha1);
-}
-
-
-
-
-
-void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length)
-{
- ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
-
- sha1_update(&m_Sha1, a_Data, a_Length);
-}
-
-
-
-
-
-void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output)
-{
- ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
-
- sha1_finish(&m_Sha1, a_Output);
- m_DoesAcceptInput = false;
-}
-
-
-
-
-
-void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
-{
- Checksum Digest;
- memcpy(Digest, a_Digest, sizeof(Digest));
-
- bool IsNegative = (Digest[0] >= 0x80);
- if (IsNegative)
- {
- // Two's complement:
- bool carry = true; // Add one to the whole number
- for (int i = 19; i >= 0; i--)
- {
- Digest[i] = ~Digest[i];
- if (carry)
- {
- carry = (Digest[i] == 0xff);
- Digest[i]++;
- }
- }
- }
- a_Out.clear();
- a_Out.reserve(40);
- for (int i = 0; i < 20; i++)
- {
- AppendPrintf(a_Out, "%02x", Digest[i]);
- }
- while ((a_Out.length() > 0) && (a_Out[0] == '0'))
- {
- a_Out.erase(0, 1);
- }
- if (IsNegative)
- {
- a_Out.insert(0, "-");
- }
-}
-
-
-
-
-
-
-void cSHA1Checksum::Restart(void)
-{
- sha1_starts(&m_Sha1);
- m_DoesAcceptInput = true;
-}
-
-
-
-
diff --git a/src/Crypto.h b/src/Crypto.h
deleted file mode 100644
index a9ec2c6d4..000000000
--- a/src/Crypto.h
+++ /dev/null
@@ -1,198 +0,0 @@
-
-// Crypto.h
-
-// Declares classes that wrap the cryptographic code library
-
-
-
-
-
-#pragma once
-
-#include "polarssl/rsa.h"
-#include "polarssl/aes.h"
-#include "polarssl/entropy.h"
-#include "polarssl/ctr_drbg.h"
-#include "polarssl/sha1.h"
-#include "polarssl/pk.h"
-
-
-
-
-
-/** Encapsulates an RSA private key used in PKI cryptography */
-class cRSAPrivateKey
-{
-public:
- /** Creates a new empty object, the key is not assigned */
- cRSAPrivateKey(void);
-
- /** Deep-copies the key from a_Other */
- cRSAPrivateKey(const cRSAPrivateKey & a_Other);
-
- ~cRSAPrivateKey();
-
- /** Generates a new key within this object, with the specified size in bits.
- Returns true on success, false on failure. */
- bool Generate(unsigned a_KeySizeBits = 1024);
-
- /** Returns the public key part encoded in ASN1 DER encoding */
- AString GetPubKeyDER(void);
-
- /** Decrypts the data using RSAES-PKCS#1 algorithm.
- Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
- Returns the number of bytes decrypted, or negative number for error. */
- int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
-
- /** Encrypts the data using RSAES-PKCS#1 algorithm.
- Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
- Returns the number of bytes decrypted, or negative number for error. */
- int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
-
-protected:
- rsa_context m_Rsa;
- entropy_context m_Entropy;
- ctr_drbg_context m_Ctr_drbg;
-
- /** Initializes the m_Entropy and m_Ctr_drbg contexts
- Common part of this object's construction, called from all constructors. */
- void InitRnd(void);
-} ;
-
-
-
-
-
-class cPublicKey
-{
-public:
- cPublicKey(const AString & a_PublicKeyDER);
- ~cPublicKey();
-
- /** Decrypts the data using the stored public key
- Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
- Returns the number of bytes decrypted, or negative number for error. */
- int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
-
- /** Encrypts the data using the stored public key
- Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
- Returns the number of bytes decrypted, or negative number for error. */
- int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
-
-protected:
- pk_context m_Pk;
- entropy_context m_Entropy;
- ctr_drbg_context m_Ctr_drbg;
-
- /** Initializes the m_Entropy and m_Ctr_drbg contexts
- Common part of this object's construction, called from all constructors. */
- void InitRnd(void);
-} ;
-
-
-
-
-
-/** Decrypts data using the AES / CFB (128) algorithm */
-class cAESCFBDecryptor
-{
-public:
- Byte test;
-
- cAESCFBDecryptor(void);
- ~cAESCFBDecryptor();
-
- /** Initializes the decryptor with the specified Key / IV */
- void Init(const Byte a_Key[16], const Byte a_IV[16]);
-
- /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
- void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
-
- /** Returns true if the object has been initialized with the Key / IV */
- bool IsValid(void) const { return m_IsValid; }
-
-protected:
- aes_context m_Aes;
-
- /** The InitialVector, used by the CFB mode decryption */
- Byte m_IV[16];
-
- /** Current offset in the m_IV, used by the CFB mode decryption */
- size_t m_IVOffset;
-
- /** Indicates whether the object has been initialized with the Key / IV */
- bool m_IsValid;
-} ;
-
-
-
-
-
-/** Encrypts data using the AES / CFB (128) algorithm */
-class cAESCFBEncryptor
-{
-public:
- cAESCFBEncryptor(void);
- ~cAESCFBEncryptor();
-
- /** Initializes the decryptor with the specified Key / IV */
- void Init(const Byte a_Key[16], const Byte a_IV[16]);
-
- /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
- void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
-
- /** Returns true if the object has been initialized with the Key / IV */
- bool IsValid(void) const { return m_IsValid; }
-
-protected:
- aes_context m_Aes;
-
- /** The InitialVector, used by the CFB mode encryption */
- Byte m_IV[16];
-
- /** Current offset in the m_IV, used by the CFB mode encryption */
- size_t m_IVOffset;
-
- /** Indicates whether the object has been initialized with the Key / IV */
- bool m_IsValid;
-} ;
-
-
-
-
-
-/** Calculates a SHA1 checksum for data stream */
-class cSHA1Checksum
-{
-public:
- typedef Byte Checksum[20]; // The type used for storing the checksum
-
- cSHA1Checksum(void);
-
- /** Adds the specified data to the checksum */
- void Update(const Byte * a_Data, size_t a_Length);
-
- /** Calculates and returns the final checksum */
- void Finalize(Checksum & a_Output);
-
- /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
- bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
-
- /** Converts a raw 160-bit SHA1 digest into a Java Hex representation
- According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
- */
- static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
-
- /** Clears the current context and start a new checksum calculation */
- void Restart(void);
-
-protected:
- /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
- bool m_DoesAcceptInput;
-
- sha1_context m_Sha1;
-} ;
-
-
-
-
diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp
index 322084dc4..f73a45555 100644
--- a/src/DeadlockDetect.cpp
+++ b/src/DeadlockDetect.cpp
@@ -109,21 +109,24 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
WorldAges::iterator itr = m_WorldAges.find(a_WorldName);
if (itr == m_WorldAges.end())
{
- ASSERT(!"Unknown world in cDeadlockDetect");
+ SetWorldAge(a_WorldName, a_Age);
return;
}
- if (itr->second.m_Age == a_Age)
+
+ cDeadlockDetect::sWorldAge & WorldAge = itr->second;
+
+ if (WorldAge.m_Age == a_Age)
{
- itr->second.m_NumCyclesSame += 1;
- if (itr->second.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS)
+ WorldAge.m_NumCyclesSame += 1;
+ if (WorldAge.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS)
{
DeadlockDetected();
}
}
else
{
- itr->second.m_Age = a_Age;
- itr->second.m_NumCyclesSame = 0;
+ WorldAge.m_Age = a_Age;
+ WorldAge.m_NumCyclesSame = 0;
}
}
diff --git a/src/Defines.h b/src/Defines.h
index 1a8b3fa4a..563fc308c 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -3,6 +3,7 @@
#include "ChatColor.h"
#include <limits>
+#include <cmath>
@@ -493,15 +494,17 @@ inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a
inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch)
{
- if (fabs(a_X) < std::numeric_limits<double>::epsilon())
+ double r = sqrt((a_X * a_X) + (a_Z * a_Z));
+ if (r < std::numeric_limits<double>::epsilon())
{
- a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
+ a_Pan = 0;
}
else
{
- a_Pan = 0;
+ a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
}
- a_Pitch = atan2(a_Y, sqrt((a_X * a_X) + (a_Z * a_Z))) * 180 / PI;
+
+ a_Pitch = atan2(a_Y, r) * 180 / PI;
}
@@ -526,6 +529,15 @@ inline float GetSpecialSignf( float a_Val )
+template<class T> inline T Diff(T a_Val1, T a_Val2)
+{
+ return std::abs(a_Val1 - a_Val2);
+}
+
+
+
+
+
// tolua_begin
enum eMessageType
diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp
index 1d8188e96..264878c22 100644
--- a/src/Enchantments.cpp
+++ b/src/Enchantments.cpp
@@ -5,6 +5,7 @@
#include "Globals.h"
#include "Enchantments.h"
#include "WorldStorage/FastNBT.h"
+#include "FastRandom.h"
@@ -28,6 +29,18 @@ cEnchantments::cEnchantments(const AString & a_StringSpec)
+void cEnchantments::Add(const cEnchantments & a_Other)
+{
+ for (cEnchantments::cMap::const_iterator itr = a_Other.m_Enchantments.begin(), end = a_Other.m_Enchantments.end(); itr != end; ++itr)
+ {
+ SetLevel(itr->first, itr->second);
+ } // for itr - a_Other.m_Enchantments[]
+}
+
+
+
+
+
void cEnchantments::AddFromString(const AString & a_StringSpec)
{
// Add enchantments in the stringspec; if a specified enchantment already exists, overwrites it
@@ -49,21 +62,17 @@ void cEnchantments::AddFromString(const AString & a_StringSpec)
LOG("%s: Malformed enchantment decl: \"%s\", skipping.", __FUNCTION__, itr->c_str());
continue;
}
- int id = atoi(Split[0].c_str());
- if ((id == 0) && (Split[0] != "0"))
+ int id = StringToEnchantmentID(Split[0]);
+ if (id < 0)
{
- id = StringToEnchantmentID(Split[0]);
+ LOG("%s: Failed to parse enchantment \"%s\", skipping.", __FUNCTION__, Split[0].c_str());
+ continue;
}
int lvl = atoi(Split[1].c_str());
- if (
- ((id <= 0) && (Split[0] != "0")) ||
- ((lvl == 0) && (Split[1] != "0"))
- )
- {
- // Numbers failed to parse
- LOG("%s: Failed to parse enchantment declaration for numbers: \"%s\" and \"%s\", skipping.",
- __FUNCTION__, Split[0].c_str(), Split[1].c_str()
- );
+ if ((lvl == 0) && (Split[1] != "0"))
+ {
+ // Level failed to parse
+ LOG("%s: Failed to parse enchantment level \"%s\", skipping.", __FUNCTION__, Split[1].c_str());
continue;
}
SetLevel(id, lvl);
@@ -74,6 +83,15 @@ void cEnchantments::AddFromString(const AString & a_StringSpec)
+size_t cEnchantments::Count(void)
+{
+ return m_Enchantments.size();
+}
+
+
+
+
+
AString cEnchantments::ToString(void) const
{
// Serialize all the enchantments into a string
@@ -150,7 +168,7 @@ bool cEnchantments::IsEmpty(void) const
int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName)
{
- struct
+ static const struct
{
int m_Value;
const char * m_Name;
@@ -181,6 +199,15 @@ int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName)
{ enchLuckOfTheSea, "LuckOfTheSea"},
{ enchLure, "Lure"},
} ;
+
+ // First try to parse as a number:
+ int id = atoi(a_EnchantmentName.c_str());
+ if ((id != 0) || (a_EnchantmentName == "0"))
+ {
+ return id;
+ }
+
+ // It wasn't a number, do a lookup:
for (size_t i = 0; i < ARRAYCOUNT(EnchantmentNames); i++)
{
if (NoCaseCompare(EnchantmentNames[i].m_Name, a_EnchantmentName) == 0)
@@ -213,7 +240,781 @@ bool cEnchantments::operator !=(const cEnchantments & a_Other) const
+void cEnchantments::AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantments, short a_ItemType, int a_EnchantmentLevel)
+{
+ if (ItemCategory::IsSword(a_ItemType))
+ {
+ // Sharpness
+ if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 4);
+ }
+ else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 3);
+ }
+ else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 1);
+ }
+
+ // Smite
+ if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 1);
+ }
+
+ // Bane of Arthropods
+ if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 1);
+ }
+
+ // Knockback
+ if ((a_EnchantmentLevel >= 25) && (a_EnchantmentLevel <= 75))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 1);
+ }
+
+ // Fire Aspect
+ if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 1);
+ }
+
+ // Looting
+ if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 3);
+ }
+ else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 2);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 1);
+ }
+ }
+
+ else if (ItemCategory::IsTool(a_ItemType))
+ {
+ // Efficiency
+ if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 81))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 3);
+ }
+ else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 61))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 51))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 1);
+ }
+
+ // Silk Touch
+ if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchSilkTouch, 1);
+ }
+
+ // Fortune
+ if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 3);
+ }
+ else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 2);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 1);
+ }
+ }
+
+ else if (ItemCategory::IsArmor(a_ItemType))
+ {
+ // Protection
+ if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 1);
+ }
+ // Fire Protection
+ if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 46))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 26) && (a_EnchantmentLevel <= 38))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 18) && (a_EnchantmentLevel <= 30))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 22))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 1);
+ }
+
+ // Blast Protection
+ if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 25))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 17))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 1);
+ }
+
+ // Projectile Protection
+ if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 30))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 9) && (a_EnchantmentLevel <= 24))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 3) && (a_EnchantmentLevel <= 18))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 1);
+ }
+
+ // Thorns
+ if ((a_EnchantmentLevel >= 50) && (a_EnchantmentLevel <= 100))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 3);
+ }
+ else if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 1);
+ }
+
+
+ if (ItemCategory::IsHelmet(a_ItemType))
+ {
+ // Respiration
+ if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 60))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 3);
+ }
+ else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 40))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 1);
+ }
+
+ // Aqua Affinity
+ if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchAquaAffinity, 1);
+ }
+ }
+
+ else if (ItemCategory::IsBoots(a_ItemType))
+ {
+ // Feather Fall
+ if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 4);
+ }
+ else if ((a_EnchantmentLevel >= 17) && (a_EnchantmentLevel <= 27))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 3);
+ }
+ else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 21))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 15))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1);
+ }
+ }
+ }
+
+ else if (a_ItemType == E_ITEM_BOW)
+ {
+ // Power
+ if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 46))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 3);
+ }
+ else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 26))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 16))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 1);
+ }
+
+ // Punch
+ if ((a_EnchantmentLevel >= 32) && (a_EnchantmentLevel <= 57))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 2);
+ }
+ else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 37))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 1);
+ }
+
+ // Flame and Infinity
+ if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFlame, 1);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchInfinity, 1);
+ }
+ }
+
+ else if (a_ItemType == E_ITEM_FISHING_ROD)
+ {
+ // Luck of the Sea and Lure
+ if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 3);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 3);
+ }
+ else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 2);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 2);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 1);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 1);
+ }
+ }
+
+ else if (a_ItemType == E_ITEM_BOOK)
+ {
+ // All Enchantments
+
+ // Sharpness
+ if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 4);
+ }
+ else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 3);
+ }
+ else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 1);
+ }
+
+ // Smite
+ if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 1);
+ }
+
+ // Bane of Arthropods
+ if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 1);
+ }
+
+ // Knockback
+ if ((a_EnchantmentLevel >= 25) && (a_EnchantmentLevel <= 75))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 1);
+ }
+
+ // Fire Aspect
+ if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 1);
+ }
+
+ // Looting
+ if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 3);
+ }
+ else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 2);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 1);
+ }
+
+ // Efficiency
+ if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 81))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 3);
+ }
+ else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 61))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 51))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 1);
+ }
+
+ // Silk Touch
+ if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchSilkTouch, 1);
+ }
+
+ // Fortune
+ if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 3);
+ }
+ else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 2);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 1);
+ }
+
+ // Protection
+ if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 1);
+ }
+
+ // Fire Protection
+ if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 46))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 26) && (a_EnchantmentLevel <= 38))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 18) && (a_EnchantmentLevel <= 30))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 22))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 1);
+ }
+
+ // Blast Protection
+ if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 25))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 17))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 1);
+ }
+
+ // Projectile Protection
+ if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 4);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 30))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 3);
+ }
+ else if ((a_EnchantmentLevel >= 9) && (a_EnchantmentLevel <= 24))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 2);
+ }
+ else if ((a_EnchantmentLevel >= 3) && (a_EnchantmentLevel <= 18))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 1);
+ }
+
+ // Thorns
+ if ((a_EnchantmentLevel >= 50) && (a_EnchantmentLevel <= 100))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 3);
+ }
+ else if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 1);
+ }
+
+ // Respiration
+ if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 60))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 3);
+ }
+ else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 2);
+ }
+ else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 40))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 1);
+ }
+
+ // Aqua Affinity
+ if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 41))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchAquaAffinity, 1);
+ }
+
+ // Feather Fall
+ if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 33))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 4);
+ }
+ else if ((a_EnchantmentLevel >= 17) && (a_EnchantmentLevel <= 27))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 3);
+ }
+ else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 21))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 15))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1);
+ }
+
+ // Power
+ if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 46))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 4);
+ }
+ else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 3);
+ }
+ else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 26))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 2);
+ }
+ else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 16))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 1);
+ }
+
+ // Punch
+ if ((a_EnchantmentLevel >= 32) && (a_EnchantmentLevel <= 57))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 2);
+ }
+ else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 37))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 1);
+ }
+
+ // Flame and Infinity
+ if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 2, enchFlame, 1);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchInfinity, 1);
+ }
+
+ // Luck of the Sea and Lure
+ if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 3);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 3);
+ }
+ else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 2);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 2);
+ }
+ else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 1);
+ AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 1);
+ }
+ }
+
+ // Unbreaking
+ if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 3);
+ }
+ else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 63))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 2);
+ }
+ else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55))
+ {
+ AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 1);
+ }
+}
+
+
+
+
+
+void cEnchantments::AddEnchantmentWeightToVector(cWeightedEnchantments & a_Enchantments, int a_Weight, int a_EnchantmentID, int a_EnchantmentLevel)
+{
+ cWeightedEnchantment weightedenchantment;
+ weightedenchantment.m_Weight = a_Weight;
+ cEnchantments enchantment;
+ enchantment.SetLevel(a_EnchantmentID, a_EnchantmentLevel);
+ weightedenchantment.m_Enchantments = enchantment;
+ a_Enchantments.push_back(weightedenchantment);
+}
+
+
+
+
+
+void cEnchantments::RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, int a_EnchantmentID)
+{
+ for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
+ {
+ if ((*it).m_Enchantments.GetLevel(a_EnchantmentID) > 0)
+ {
+ a_Enchantments.erase(it);
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cEnchantments::RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, const cEnchantments & a_Enchantment)
+{
+ for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
+ {
+ if ((*it).m_Enchantments == a_Enchantment)
+ {
+ a_Enchantments.erase(it);
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cEnchantments::CheckEnchantmentConflictsFromVector(cWeightedEnchantments & a_Enchantments, cEnchantments a_FirstEnchantment)
+{
+ if (a_FirstEnchantment.GetLevel(cEnchantments::enchProtection) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchFireProtection) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchBlastProtection) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchProjectileProtection) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection);
+ }
+
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSharpness) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSmite);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBaneOfArthropods);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSmite) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSharpness);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBaneOfArthropods);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchBaneOfArthropods) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSharpness);
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSmite);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSilkTouch) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFortune);
+ }
+ else if (a_FirstEnchantment.GetLevel(cEnchantments::enchFortune) > 0)
+ {
+ RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSilkTouch);
+ }
+}
+
+
+
+
+
+cEnchantments cEnchantments::GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments)
+{
+ cFastRandom Random;
+
+ int AllWeights = 0;
+ for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
+ {
+ AllWeights += (*it).m_Weight;
+ }
+ int RandomNumber = Random.GenerateRandomInteger(0, AllWeights - 1);
+ for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
+ {
+ RandomNumber -= (*it).m_Weight;
+ if (RandomNumber < 0)
+ {
+ return (*it).m_Enchantments;
+ }
+ }
+
+ return cEnchantments();
+}
diff --git a/src/Enchantments.h b/src/Enchantments.h
index f77b535d8..85a316414 100644
--- a/src/Enchantments.h
+++ b/src/Enchantments.h
@@ -8,6 +8,7 @@
#pragma once
+#include "Defines.h"
#include "WorldStorage/EnchantmentSerializer.h"
@@ -18,6 +19,11 @@ class cFastNBTWriter;
class cParsedNBT;
+// fwd:
+struct cWeightedEnchantment;
+
+typedef std::vector<cWeightedEnchantment> cWeightedEnchantments;
+
@@ -28,11 +34,14 @@ mapping each enchantment's id onto its level. ID may be either a number or the e
Level value of 0 means no such enchantment, and it will not be stored in the m_Enchantments.
Serialization will never put zero-level enchantments into the stringspec and will always use numeric IDs.
*/
+
+
// tolua_begin
class cEnchantments
{
public:
- /// Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs )
+ /** Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs )
+ */
enum
{
@@ -61,56 +70,90 @@ public:
enchLuckOfTheSea = 61,
enchLure = 62,
} ;
-
- /// Creates an empty enchantments container
+
+ /** Creates an empty enchantments container */
cEnchantments(void);
- /// Creates an enchantments container filled with enchantments parsed from stringspec
+ /** Creates an enchantments container filled with enchantments parsed from stringspec */
cEnchantments(const AString & a_StringSpec);
- /// Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it
+ /** Adds the enchantments contained in a_Other into this object.
+ Existing enchantments are preserved, unless a_Other specifies a different level, in which case the level is changed. */
+ void Add(const cEnchantments & a_Other);
+
+ /** Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it */
void AddFromString(const AString & a_StringSpec);
- /// Serializes all the enchantments into a string
+ /** Get the count of enchantments */
+ size_t Count(void);
+
+ /** Serializes all the enchantments into a string */
AString ToString(void) const;
- /// Returns the level for the specified enchantment; 0 if not stored
+ /** Returns the level for the specified enchantment; 0 if not stored */
int GetLevel(int a_EnchantmentID) const;
- /// Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0
+ /** Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0 */
void SetLevel(int a_EnchantmentID, int a_Level);
- /// Removes all enchantments
+ /** Removes all enchantments */
void Clear(void);
- /// Returns true if there are no enchantments
+ /** Returns true if there are no enchantments */
bool IsEmpty(void) const;
- /// Converts enchantment name to the numeric representation; returns -1 if enchantment name not found; case insensitive
+ /** Converts enchantment name or ID (number in string) to the numeric representation; returns -1 if enchantment name not found; case insensitive */
static int StringToEnchantmentID(const AString & a_EnchantmentName);
- /// Returns true if a_Other contains exactly the same enchantments and levels
+ /** Returns true if a_Other contains exactly the same enchantments and levels */
bool operator ==(const cEnchantments & a_Other) const;
-
+
// tolua_end
+
+ /** Add enchantment weights from item to the vector */
+ static void AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantments, short a_ItemType, int a_EnchantmentLevel);
+
+ /** Add a enchantment with weight to the vector */
+ static void AddEnchantmentWeightToVector(cWeightedEnchantments & a_Enchantments, int a_Weight, int a_EnchantmentID, int a_EnchantmentLevel);
+
+ /** Remove the entire enchantment (with weight) from the vector */
+ static void RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, int a_EnchantmentID);
- /// Returns true if a_Other doesn't contain exactly the same enchantments and levels
+ /** Remove the entire enchantment (with weight) from the vector */
+ static void RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, const cEnchantments & a_Enchantment);
+
+ /** Check enchantment conflicts from enchantments from the vector */
+ static void CheckEnchantmentConflictsFromVector(cWeightedEnchantments & a_Enchantments, cEnchantments a_FirstEnchantment);
+
+ /** Gets random enchantment from Vector and returns it */
+ static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments);
+
+ /** Returns true if a_Other doesn't contain exactly the same enchantments and levels */
bool operator !=(const cEnchantments & a_Other) const;
- /// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments")
+ /** Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") */
friend void EnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName);
- /// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments)
+ /** Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) */
friend void EnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx);
-
+
protected:
- /// Maps enchantment ID -> enchantment level
+ /** Maps enchantment ID -> enchantment level */
typedef std::map<int, int> cMap;
- /// Currently stored enchantments
+ /** Currently stored enchantments */
cMap m_Enchantments;
} ; // tolua_export
+// Define the cWeightedEnchantment struct for the Enchanting System to store the EnchantmentWeights:
+struct cWeightedEnchantment
+{
+ int m_Weight;
+ cEnchantments m_Enchantments;
+};
+
+
+
diff --git a/src/Endianness.h b/src/Endianness.h
index 86eb369f5..78f9a5d99 100644
--- a/src/Endianness.h
+++ b/src/Endianness.h
@@ -1,12 +1,14 @@
#pragma once
+#define ntohll(x) ((((UInt64)ntohl((u_long)x)) << 32) + ntohl(x >> 32))
+
// Changes endianness
-inline unsigned long long HostToNetwork8(const void* a_Value )
+inline UInt64 HostToNetwork8(const void * a_Value)
{
unsigned long long __HostToNetwork8;
memcpy( &__HostToNetwork8, a_Value, sizeof( __HostToNetwork8 ) );
@@ -18,7 +20,7 @@ inline unsigned long long HostToNetwork8(const void* a_Value )
-inline unsigned int HostToNetwork4(const void* a_Value )
+inline UInt32 HostToNetwork4(const void* a_Value )
{
unsigned int __HostToNetwork4;
memcpy( &__HostToNetwork4, a_Value, sizeof( __HostToNetwork4 ) );
@@ -30,11 +32,10 @@ inline unsigned int HostToNetwork4(const void* a_Value )
-inline double NetworkToHostDouble8(const void* a_Value )
+inline double NetworkToHostDouble8(const void * a_Value)
{
-#define ntohll(x) ((((unsigned long long)ntohl((u_long)x)) << 32) + ntohl(x >> 32))
- unsigned long long buf = 0;//(*(unsigned long long*)a_Value);
- memcpy( &buf, a_Value, 8 );
+ UInt64 buf = 0;
+ memcpy(&buf, a_Value, 8);
buf = ntohll(buf);
double x;
memcpy(&x, &buf, sizeof(double));
@@ -45,23 +46,25 @@ inline double NetworkToHostDouble8(const void* a_Value )
-inline long long NetworkToHostLong8(const void * a_Value )
+inline Int64 NetworkToHostLong8(const void * a_Value)
{
- unsigned long long buf = *(unsigned long long*)a_Value;
+ UInt64 buf;
+ memcpy(&buf, a_Value, 8);
buf = ntohll(buf);
- return *reinterpret_cast<long long *>(&buf);
+ return *reinterpret_cast<Int64 *>(&buf);
}
-inline float NetworkToHostFloat4(const void* a_Value )
+inline float NetworkToHostFloat4(const void * a_Value)
{
- u_long buf = *(u_long*)a_Value;
- buf = ntohl( buf );
- float x = 0;
- memcpy( &x, &buf, sizeof(float) );
+ UInt32 buf;
+ float x;
+ memcpy(&buf, a_Value, 4);
+ buf = ntohl(buf);
+ memcpy(&x, &buf, sizeof(float));
return x;
}
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp
new file mode 100644
index 000000000..8d2569125
--- /dev/null
+++ b/src/Entities/ArrowEntity.cpp
@@ -0,0 +1,194 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Player.h"
+#include "ArrowEntity.h"
+#include "../Chunk.h"
+
+
+
+
+
+cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
+ m_PickupState(psNoPickup),
+ m_DamageCoeff(2),
+ m_IsCritical(false),
+ m_Timer(0),
+ m_HitGroundTimer(0),
+ m_HasTeleported(false),
+ m_bIsCollected(false),
+ m_HitBlockPos(Vector3i(0, 0, 0))
+{
+ SetSpeed(a_Speed);
+ SetMass(0.1);
+ SetYawFromSpeed();
+ SetPitchFromSpeed();
+ LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
+ m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
+ GetYaw(), GetPitch()
+ );
+}
+
+
+
+
+
+cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
+ super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
+ m_PickupState(psInSurvivalOrCreative),
+ m_DamageCoeff(2),
+ m_IsCritical((a_Force >= 1)),
+ m_Timer(0),
+ m_HitGroundTimer(0),
+ m_HasTeleported(false),
+ m_bIsCollected(false),
+ m_HitBlockPos(0, 0, 0)
+{
+}
+
+
+
+
+
+bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
+{
+ switch (m_PickupState)
+ {
+ case psNoPickup: return false;
+ case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
+ case psInCreative: return a_Player.IsGameModeCreative();
+ }
+ ASSERT(!"Unhandled pickup state");
+ return false;
+}
+
+
+
+
+
+void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ if (a_HitFace == BLOCK_FACE_NONE) { return; }
+
+ super::OnHitSolidBlock(a_HitPos, a_HitFace);
+ int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
+
+ switch (a_HitFace)
+ {
+ case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
+ case BLOCK_FACE_YM:
+ {
+ break;
+ }
+ default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
+ }
+
+ m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
+
+ // Broadcast arrow hit sound
+ m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+}
+
+
+
+
+
+void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
+ {
+ // Not an entity that interacts with an arrow
+ return;
+ }
+
+ int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
+ if (m_IsCritical)
+ {
+ Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
+ }
+ a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
+
+ // Broadcast successful hit sound
+ m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+
+ Destroy();
+}
+
+
+
+
+
+void cArrowEntity::CollectedBy(cPlayer * a_Dest)
+{
+ if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
+ {
+ int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
+ if (NumAdded > 0) // Only play effects if there was space in inventory
+ {
+ m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
+ // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
+ m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_bIsCollected = true;
+ }
+ }
+}
+
+
+
+
+
+void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ m_Timer += a_Dt;
+
+ if (m_bIsCollected)
+ {
+ if (m_Timer > 500.f) // 0.5 seconds
+ {
+ Destroy();
+ return;
+ }
+ }
+ else if (m_Timer > 1000 * 60 * 5) // 5 minutes
+ {
+ Destroy();
+ return;
+ }
+
+ if (m_IsInGround)
+ {
+ // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
+ // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
+ // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
+ // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
+
+ if (!m_HasTeleported) // Sent a teleport already, don't do again
+ {
+ if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
+ {
+ m_World->BroadcastTeleportEntity(*this);
+ m_HasTeleported = true;
+ }
+ else
+ {
+ m_HitGroundTimer += a_Dt;
+ }
+ }
+
+ int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
+ cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
+
+ if (Chunk == NULL)
+ {
+ // Inside an unloaded chunk, abort
+ return;
+ }
+
+ if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
+ {
+ m_IsInGround = false; // Yes, begin simulating physics again
+ }
+ }
+}
diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h
new file mode 100644
index 000000000..1fe3032ee
--- /dev/null
+++ b/src/Entities/ArrowEntity.h
@@ -0,0 +1,96 @@
+//
+// ArrowEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cArrowEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+ /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
+ enum ePickupState
+ {
+ psNoPickup = 0,
+ psInSurvivalOrCreative = 1,
+ psInCreative = 2,
+ } ;
+
+ // tolua_end
+
+ CLASS_PROTODEF(cArrowEntity);
+
+ /// Creates a new arrow with psNoPickup state and default damage modifier coeff
+ cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+ /// Creates a new arrow as shot by a player, initializes it from the player object
+ cArrowEntity(cPlayer & a_Player, double a_Force);
+
+ // tolua_begin
+
+ /// Returns whether the arrow can be picked up by players
+ ePickupState GetPickupState(void) const { return m_PickupState; }
+
+ /// Sets a new pickup state
+ void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
+
+ /// Returns the damage modifier coeff.
+ double GetDamageCoeff(void) const { return m_DamageCoeff; }
+
+ /// Sets the damage modifier coeff
+ void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
+
+ /// Returns true if the specified player can pick the arrow up
+ bool CanPickup(const cPlayer & a_Player) const;
+
+ /// Returns true if the arrow is set as critical
+ bool IsCritical(void) const { return m_IsCritical; }
+
+ /// Sets the IsCritical flag
+ void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
+
+ // tolua_end
+
+protected:
+
+ /// Determines when the arrow can be picked up by players
+ ePickupState m_PickupState;
+
+ /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
+ double m_DamageCoeff;
+
+ /// If true, the arrow deals more damage
+ bool m_IsCritical;
+
+ /// Timer for pickup collection animation or five minute timeout
+ float m_Timer;
+
+ /// Timer for client arrow position confirmation via TeleportEntity
+ float m_HitGroundTimer;
+
+ // Whether the arrow has already been teleported into the proper position in the ground.
+ bool m_HasTeleported;
+
+ /// If true, the arrow is in the process of being collected - don't go to anyone else
+ bool m_bIsCollected;
+
+ /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
+ Vector3i m_HitBlockPos;
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+ virtual void CollectedBy(cPlayer * a_Player) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+}; // tolua_export
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 94b24c5af..31bfe3dc3 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -33,9 +33,12 @@ void cBoat::SpawnOn(cClientHandle & a_ClientHandle)
-void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
+bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
{
- super::DoTakeDamage(TDI);
+ if (!super::DoTakeDamage(TDI))
+ {
+ return false;
+ }
if (GetHealth() == 0)
{
@@ -50,6 +53,7 @@ void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
}
Destroy(true);
}
+ return true;
}
@@ -122,5 +126,3 @@ void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways)
AddSpeed(ToAddSpeed);
}
-
- \ No newline at end of file
diff --git a/src/Entities/Boat.h b/src/Entities/Boat.h
index c4c9afe7a..0fcfbd602 100644
--- a/src/Entities/Boat.h
+++ b/src/Entities/Boat.h
@@ -26,7 +26,7 @@ public:
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
- virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt
index 85cc45494..205cb2cca 100644
--- a/src/Entities/CMakeLists.txt
+++ b/src/Entities/CMakeLists.txt
@@ -6,6 +6,9 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Entities ${SOURCE})
+
+target_link_libraries(Entities WorldStorage)
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/Entity.cpp b/src/Entities/Entity.cpp
index 221cbbea7..1226a2319 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -1,3 +1,4 @@
+
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Entity.h"
@@ -10,7 +11,6 @@
#include "../Simulator/FluidSimulator.h"
#include "../Bindings/PluginManager.h"
#include "../Tracer.h"
-#include "Minecart.h"
#include "Player.h"
@@ -32,19 +32,14 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_Attachee(NULL)
, m_bDirtyHead(true)
, m_bDirtyOrientation(true)
- , m_bDirtyPosition(true)
- , m_bDirtySpeed(true)
- , m_bOnGround( false )
- , m_Gravity( -9.81f )
- , m_LastPosX( 0.0 )
- , m_LastPosY( 0.0 )
- , m_LastPosZ( 0.0 )
- , m_TimeLastTeleportPacket(0)
- , m_TimeLastMoveReltPacket(0)
- , m_TimeLastSpeedPacket(0)
+ , m_bHasSentNoSpeed(true)
+ , m_bOnGround(false)
+ , m_Gravity(-9.81f)
+ , m_LastPos(a_X, a_Y, a_Z)
, m_IsInitialized(false)
, m_EntityType(a_EntityType)
, m_World(NULL)
+ , m_IsFireproof(false)
, m_TicksSinceLastBurnDamage(0)
, m_TicksSinceLastLavaDamage(0)
, m_TicksSinceLastFireDamage(0)
@@ -52,13 +47,16 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_TicksSinceLastVoidDamage(0)
, m_IsSwimming(false)
, m_IsSubmerged(false)
- , m_HeadYaw( 0.0 )
+ , m_AirLevel(0)
+ , m_AirTickTimer(0)
+ , m_HeadYaw(0.0)
, m_Rot(0.0, 0.0, 0.0)
, m_Pos(a_X, a_Y, a_Z)
, m_WaterSpeed(0, 0, 0)
, m_Mass (0.001) // Default 1g
, m_Width(a_Width)
, m_Height(a_Height)
+ , m_InvulnerableTicks(0)
{
cCSLock Lock(m_CSCount);
m_EntityCount++;
@@ -293,27 +291,37 @@ void cEntity::SetPitchFromSpeed(void)
-void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
{
- return;
+ return false;
}
if (m_Health <= 0)
{
// Can't take damage if already dead
- return;
+ return false;
+ }
+
+ if (m_InvulnerableTicks > 0)
+ {
+ // Entity is invulnerable
+ return false;
}
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
{
+ cPlayer * Player = (cPlayer *)a_TDI.Attacker;
+
// IsOnGround() only is false if the player is moving downwards
- if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
+ if (!Player->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
{
a_TDI.FinalDamage += 2;
m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
}
+
+ Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
}
m_Health -= (short)a_TDI.FinalDamage;
@@ -325,17 +333,54 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
m_Health = 0;
}
- if (IsMob() || IsPlayer()) // Knockback for only players and mobs
+ if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs
{
- AddSpeed(a_TDI.Knockback * 2);
+ int KnockbackLevel = 0;
+ if (a_TDI.Attacker->GetEquippedWeapon().m_ItemType == E_ITEM_BOW)
+ {
+ KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch);
+ }
+ else
+ {
+ KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback);
+ }
+
+ Vector3d additionalSpeed(0, 0, 0);
+ switch (KnockbackLevel)
+ {
+ case 1:
+ {
+ additionalSpeed.Set(5, .3, 5);
+ break;
+ }
+ case 2:
+ {
+ additionalSpeed.Set(8, .3, 8);
+ break;
+ }
+ default:
+ {
+ additionalSpeed.Set(2, .3, 2);
+ break;
+ }
+ }
+ AddSpeed(a_TDI.Knockback * additionalSpeed);
}
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
+ m_World->BroadcastEntityStatus(*this, esGenericHurt);
+
+ m_InvulnerableTicks = 10;
if (m_Health <= 0)
{
KilledBy(a_TDI.Attacker);
+
+ if (a_TDI.Attacker != NULL)
+ {
+ a_TDI.Attacker->Killed(this);
+ }
}
+ return true;
}
@@ -380,11 +425,8 @@ int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver)
-int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
+bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
{
- // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
-
- // Filter out damage types that are not protected by armor:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20
switch (a_DamageType)
{
@@ -399,9 +441,34 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
case dtLightning:
case dtPlugin:
{
- return 0;
+ return false;
+ }
+
+ case dtAttack:
+ case dtArrowAttack:
+ case dtCactusContact:
+ case dtLavaContact:
+ case dtFireContact:
+ case dtEnderPearl:
+ case dtExplosion:
+ {
+ return true;
}
}
+ ASSERT(!"Invalid damage type!");
+ return false;
+}
+
+
+
+
+
+int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
+{
+ // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
+
+ // Filter out damage types that are not protected by armor:
+ if (!ArmorCoversAgainst(a_DamageType)) return 0;
// Add up all armor points:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
@@ -479,7 +546,7 @@ void cEntity::KilledBy(cEntity * a_Killer)
GetDrops(Drops, a_Killer);
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD);
+ m_World->BroadcastEntityStatus(*this, esGenericDead);
}
@@ -510,46 +577,61 @@ void cEntity::SetHealth(int a_Health)
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
+ if (m_InvulnerableTicks > 0)
+ {
+ m_InvulnerableTicks--;
+ }
+
if (m_AttachedTo != NULL)
{
- if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
+ Vector3d DeltaPos = m_Pos - m_AttachedTo->GetPosition();
+ if (DeltaPos.Length() > 0.5)
{
SetPosition(m_AttachedTo->GetPosition());
+
+ if (IsPlayer())
+ {
+ cPlayer * Player = (cPlayer *)this;
+ Player->UpdateMovementStats(DeltaPos);
+ }
}
}
else
{
- if (a_Chunk.IsValid())
+ if (!a_Chunk.IsValid())
{
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT);
-
- if ((NextChunk == NULL) || !NextChunk->IsValid())
- {
- return;
- }
+ return;
+ }
- TickBurning(*NextChunk);
+ // Position changed -> super::Tick() called
+ GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, POSX_TOINT, POSZ_TOINT)
- if (GetPosY() < VOID_BOUNDARY)
- {
- TickInVoid(*NextChunk);
- }
- else
- {
- m_TicksSinceLastVoidDamage = 0;
- }
+ TickBurning(*NextChunk);
- if (IsMob() || IsPlayer())
- {
- // Set swimming state
- SetSwimState(*NextChunk);
+ if (GetPosY() < VOID_BOUNDARY)
+ {
+ TickInVoid(*NextChunk);
+ }
+ else
+ {
+ m_TicksSinceLastVoidDamage = 0;
+ }
- // Handle drowning
- HandleAir();
- }
+ if (IsMob() || IsPlayer() || IsPickup() || IsExpOrb())
+ {
+ DetectCacti();
+ }
+ if (IsMob() || IsPlayer())
+ {
+ // Set swimming state
+ SetSwimState(*NextChunk);
- HandlePhysics(a_Dt, *NextChunk);
+ // Handle drowning
+ HandleAir();
}
+
+ // None of the above functions change position, we remain in the chunk of NextChunk
+ HandlePhysics(a_Dt, *NextChunk);
}
}
@@ -559,34 +641,30 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
+ int BlockX = POSX_TOINT;
+ int BlockY = POSY_TOINT;
+ int BlockZ = POSZ_TOINT;
+
+ // Position changed -> super::HandlePhysics() called
+ GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ)
+
// TODO Add collision detection with entities.
a_Dt /= 1000; // Convert from msec to sec
- Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ());
- Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ());
- int BlockX = (int) floor(NextPos.x);
- int BlockY = (int) floor(NextPos.y);
- int BlockZ = (int) floor(NextPos.z);
+ Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ());
+ Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ());
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{
- // Outside of the world
-
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
- // See if we can commit our changes. If not, we will discard them.
- if (NextChunk != NULL)
- {
- SetSpeed(NextSpeed);
- NextPos += (NextSpeed * a_Dt);
- SetPosition(NextPos);
- }
-
+ // Outside of the world
+ AddSpeedY(m_Gravity * a_Dt);
+ AddPosition(GetSpeed() * a_Dt);
return;
}
- int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width);
- int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ );
- BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
+ int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
+ int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
+ BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
+ BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{
if (m_bOnGround) // check if it's still on the ground
@@ -616,7 +694,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
bool IsNoAirSurrounding = true;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{
- if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
+ if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
{
// The pickup is too close to an unloaded chunk, bail out of any physics handling
return;
@@ -730,30 +808,43 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NextSpeed += m_WaterSpeed;
- if( NextSpeed.SqrLength() > 0.f )
+ if (NextSpeed.SqrLength() > 0.f)
{
- cTracer Tracer( GetWorld() );
- bool HasHit = Tracer.Trace( NextPos, NextSpeed, 2 );
- if (HasHit) // Oh noez! we hit something
+ cTracer Tracer(GetWorld());
+ // Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse
+ int DistanceToTrace = (int)(ceil((NextSpeed * a_Dt).SqrLength()) * 2);
+ bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace);
+
+ if (HasHit)
{
- // Set to hit position
+ // Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current)
+ // This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement
if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength())
{
+ // Block hit was within our projected path
+ // Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1.
+ // For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP
if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f;
if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f;
if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f;
- if (Tracer.HitNormal.y > 0) // means on ground
+ if (Tracer.HitNormal.y == 1) // Hit BLOCK_FACE_YP, we are on the ground
{
m_bOnGround = true;
}
- NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z);
- NextPos.x += Tracer.HitNormal.x * 0.3f;
- NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot
- NextPos.z += Tracer.HitNormal.z * 0.3f;
+
+ // Now, set our position to the hit block (i.e. move part way along our intended trajectory)
+ NextPos.Set(Tracer.RealHit.x, Tracer.RealHit.y, Tracer.RealHit.z);
+ NextPos.x += Tracer.HitNormal.x * 0.1;
+ NextPos.y += Tracer.HitNormal.y * 0.05;
+ NextPos.z += Tracer.HitNormal.z * 0.1;
}
else
{
+ // We have hit a block but overshot our intended trajectory, move normally, safe in the warm cocoon of knowledge that we won't appear to teleport forwards on clients,
+ // and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never
+ // be henceforth seen again in the time of programmers and man alike
+ // </&sensationalist>
NextPos += (NextSpeed * a_Dt);
}
}
@@ -764,20 +855,8 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
}
- BlockX = (int) floor(NextPos.x);
- BlockZ = (int) floor(NextPos.z);
-
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
- // See if we can commit our changes. If not, we will discard them.
- if (NextChunk != NULL)
- {
- if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
- if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
- if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
- if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
- if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
- if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
- }
+ SetPosition(NextPos);
+ SetSpeed(NextSpeed);
}
@@ -788,6 +867,14 @@ void cEntity::TickBurning(cChunk & a_Chunk)
{
// Remember the current burning state:
bool HasBeenBurning = (m_TicksLeftBurning > 0);
+
+ if (m_World->IsWeatherWet())
+ {
+ if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT))
+ {
+ m_TicksLeftBurning = 0;
+ }
+ }
// Do the burning damage:
if (m_TicksLeftBurning > 0)
@@ -795,7 +882,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastBurnDamage++;
if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
{
- TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
+ if (!m_IsFireproof)
+ {
+ TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
+ }
m_TicksSinceLastBurnDamage = 0;
}
m_TicksLeftBurning--;
@@ -806,7 +896,7 @@ void cEntity::TickBurning(cChunk & a_Chunk)
int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
int MinRelZ = (int)floor(GetPosZ() - m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
int MaxRelZ = (int)floor(GetPosZ() + m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
- int MinY = std::max(0, std::min(cChunkDef::Height - 1, (int)floor(GetPosY())));
+ int MinY = std::max(0, std::min(cChunkDef::Height - 1, POSY_TOINT));
int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height)));
bool HasWater = false;
bool HasLava = false;
@@ -863,7 +953,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastLavaDamage++;
if (m_TicksSinceLastLavaDamage >= LAVA_TICKS_PER_DAMAGE)
{
- TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
+ if (!m_IsFireproof)
+ {
+ TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
+ }
m_TicksSinceLastLavaDamage = 0;
}
}
@@ -881,7 +974,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastFireDamage++;
if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE)
{
- TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
+ if (!m_IsFireproof)
+ {
+ TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
+ }
m_TicksSinceLastFireDamage = 0;
}
}
@@ -922,6 +1018,27 @@ void cEntity::TickInVoid(cChunk & a_Chunk)
+void cEntity::DetectCacti(void)
+{
+ int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT;
+ double w = m_Width / 2;
+ if (
+ ((Y > 0) && (Y < cChunkDef::Height)) &&
+ ((((X + 1) - GetPosX() < w) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) ||
+ ((GetPosX() - X < w) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) ||
+ (((Z + 1) - GetPosZ() < w) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS)) ||
+ ((GetPosZ() - Z < w) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS)) ||
+ (((GetPosY() - Y < 1) && (GetWorld()->GetBlock(X, Y, Z) == E_BLOCK_CACTUS))))
+ )
+ {
+ TakeDamage(dtCactusContact, NULL, 1, 0);
+ }
+}
+
+
+
+
+
void cEntity::SetSwimState(cChunk & a_Chunk)
{
int RelY = (int)floor(GetPosY() + 0.1);
@@ -941,9 +1058,9 @@ void cEntity::SetSwimState(cChunk & a_Chunk)
{
// This sometimes happens on Linux machines
// Ref.: http://forum.mc-server.org/showthread.php?tid=1244
- LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}",
- RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ()
- );
+ LOGD("SetSwimState failure: RelX = %d, RelZ = %d, Pos = %.02f, %.02f}",
+ RelX, RelY, GetPosX(), GetPosZ()
+ );
m_IsSwimming = false;
m_IsSubmerged = false;
return;
@@ -981,13 +1098,13 @@ void cEntity::HandleAir(void)
}
else
{
- m_AirTickTimer -= 1;
+ m_AirTickTimer--;
}
}
else
{
// Reduce air supply
- m_AirLevel -= 1;
+ m_AirLevel--;
}
}
else
@@ -1040,6 +1157,16 @@ void cEntity::SetMaxHealth(int a_MaxHealth)
+/// Sets whether the entity is fireproof
+void cEntity::SetIsFireproof(bool a_IsFireproof)
+{
+ m_IsFireproof = a_IsFireproof;
+}
+
+
+
+
+
/// Puts the entity on fire for the specified amount of ticks
void cEntity::StartBurning(int a_TicksLeftBurning)
{
@@ -1099,72 +1226,70 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
- //We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks
- if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2))
- {
- m_World->BroadcastEntityVelocity(*this,a_Exclude);
- m_bDirtySpeed = false;
- m_TimeLastSpeedPacket = m_World->GetWorldAge();
- }
-
- //Have to process position related packets this every two ticks
- if (m_World->GetWorldAge() % 2 == 0)
+ // Process packet sending every two ticks
+ if (GetWorld()->GetWorldAge() % 2 == 0)
{
- int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0));
- int DiffY = (int) (floor(GetPosY() * 32.0) - floor(m_LastPosY * 32.0));
- int DiffZ = (int) (floor(GetPosZ() * 32.0) - floor(m_LastPosZ * 32.0));
- Int64 DiffTeleportPacket = m_World->GetWorldAge() - m_TimeLastTeleportPacket;
- // 4 blocks is max Relative So if the Diff is greater than 127 or. Send an absolute position every 20 seconds
- if (DiffTeleportPacket >= 400 ||
- ((DiffX > 127) || (DiffX < -128) ||
- (DiffY > 127) || (DiffY < -128) ||
- (DiffZ > 127) || (DiffZ < -128)))
+ double SpeedSqr = GetSpeed().SqrLength();
+ if (SpeedSqr == 0.0)
{
- //
- m_World->BroadcastTeleportEntity(*this,a_Exclude);
- m_TimeLastTeleportPacket = m_World->GetWorldAge();
- m_TimeLastMoveReltPacket = m_TimeLastTeleportPacket; //Must synchronize.
- m_LastPosX = GetPosX();
- m_LastPosY = GetPosY();
- m_LastPosZ = GetPosZ();
- m_bDirtyPosition = false;
- m_bDirtyOrientation = false;
+ // Speed is zero, send this to clients once only as well as an absolute position
+ if (!m_bHasSentNoSpeed)
+ {
+ m_World->BroadcastEntityVelocity(*this, a_Exclude);
+ m_World->BroadcastTeleportEntity(*this, a_Exclude);
+ m_bHasSentNoSpeed = true;
+ }
}
else
{
- Int64 DiffMoveRelPacket = m_World->GetWorldAge() - m_TimeLastMoveReltPacket;
- //if the change is big enough.
- if ((abs(DiffX) >= 4 || abs(DiffY) >= 4 || abs(DiffZ) >= 4 || DiffMoveRelPacket >= 60) && m_bDirtyPosition)
+ // Movin'
+ m_World->BroadcastEntityVelocity(*this, a_Exclude);
+ m_bHasSentNoSpeed = false;
+ }
+
+ // TODO: Pickups move disgracefully if relative move packets are sent as opposed to just velocity. Have a system to send relmove only when SetPosXXX() is called with a large difference in position
+ int DiffX = (int)(floor(GetPosX() * 32.0) - floor(m_LastPos.x * 32.0));
+ int DiffY = (int)(floor(GetPosY() * 32.0) - floor(m_LastPos.y * 32.0));
+ int DiffZ = (int)(floor(GetPosZ() * 32.0) - floor(m_LastPos.z * 32.0));
+
+ if ((DiffX != 0) || (DiffY != 0) || (DiffZ != 0)) // Have we moved?
+ {
+ if ((abs(DiffX) <= 127) && (abs(DiffY) <= 127) && (abs(DiffZ) <= 127)) // Limitations of a Byte
{
+ // Difference within Byte limitations, use a relative move packet
if (m_bDirtyOrientation)
{
- m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude);
+ m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude);
m_bDirtyOrientation = false;
}
else
{
- m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude);
+ m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude);
}
- m_LastPosX = GetPosX();
- m_LastPosY = GetPosY();
- m_LastPosZ = GetPosZ();
- m_bDirtyPosition = false;
- m_TimeLastMoveReltPacket = m_World->GetWorldAge();
+ // Clients seem to store two positions, one for the velocity packet and one for the teleport/relmove packet
+ // The latter is only changed with a relmove/teleport, and m_LastPos stores this position
+ m_LastPos = GetPosition();
}
else
{
- if (m_bDirtyOrientation)
- {
- m_World->BroadcastEntityLook(*this,a_Exclude);
- m_bDirtyOrientation = false;
- }
- }
+ // Too big a movement, do a teleport
+ m_World->BroadcastTeleportEntity(*this, a_Exclude);
+ m_LastPos = GetPosition(); // See above
+ m_bDirtyOrientation = false;
+ }
}
+
if (m_bDirtyHead)
{
- m_World->BroadcastEntityHeadLook(*this,a_Exclude);
+ m_World->BroadcastEntityHeadLook(*this, a_Exclude);
m_bDirtyHead = false;
}
+ if (m_bDirtyOrientation)
+ {
+ // Send individual update in case above (sending with rel-move packet) wasn't done
+ GetWorld()->BroadcastEntityLook(*this, a_Exclude);
+ m_bDirtyOrientation = false;
+ }
}
}
@@ -1304,7 +1429,7 @@ void cEntity::SetRoll(double a_Roll)
void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
{
m_Speed.Set(a_SpeedX, a_SpeedY, a_SpeedZ);
- m_bDirtySpeed = true;
+
WrapSpeed();
}
@@ -1314,7 +1439,7 @@ void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
void cEntity::SetSpeedX(double a_SpeedX)
{
m_Speed.x = a_SpeedX;
- m_bDirtySpeed = true;
+
WrapSpeed();
}
@@ -1324,7 +1449,7 @@ void cEntity::SetSpeedX(double a_SpeedX)
void cEntity::SetSpeedY(double a_SpeedY)
{
m_Speed.y = a_SpeedY;
- m_bDirtySpeed = true;
+
WrapSpeed();
}
@@ -1334,7 +1459,7 @@ void cEntity::SetSpeedY(double a_SpeedY)
void cEntity::SetSpeedZ(double a_SpeedZ)
{
m_Speed.z = a_SpeedZ;
- m_bDirtySpeed = true;
+
WrapSpeed();
}
@@ -1354,7 +1479,7 @@ void cEntity::SetWidth(double a_Width)
void cEntity::AddPosX(double a_AddPosX)
{
m_Pos.x += a_AddPosX;
- m_bDirtyPosition = true;
+
}
@@ -1363,7 +1488,7 @@ void cEntity::AddPosX(double a_AddPosX)
void cEntity::AddPosY(double a_AddPosY)
{
m_Pos.y += a_AddPosY;
- m_bDirtyPosition = true;
+
}
@@ -1372,7 +1497,7 @@ void cEntity::AddPosY(double a_AddPosY)
void cEntity::AddPosZ(double a_AddPosZ)
{
m_Pos.z += a_AddPosZ;
- m_bDirtyPosition = true;
+
}
@@ -1383,7 +1508,7 @@ void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ)
m_Pos.x += a_AddPosX;
m_Pos.y += a_AddPosY;
m_Pos.z += a_AddPosZ;
- m_bDirtyPosition = true;
+
}
@@ -1393,8 +1518,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed
{
m_Speed.x += a_AddSpeedX;
m_Speed.y += a_AddSpeedY;
- m_Speed.z += a_AddSpeedZ;
- m_bDirtySpeed = true;
+ m_Speed.z += a_AddSpeedZ;
WrapSpeed();
}
@@ -1404,8 +1528,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed
void cEntity::AddSpeedX(double a_AddSpeedX)
{
- m_Speed.x += a_AddSpeedX;
- m_bDirtySpeed = true;
+ m_Speed.x += a_AddSpeedX;
WrapSpeed();
}
@@ -1415,8 +1538,7 @@ void cEntity::AddSpeedX(double a_AddSpeedX)
void cEntity::AddSpeedY(double a_AddSpeedY)
{
- m_Speed.y += a_AddSpeedY;
- m_bDirtySpeed = true;
+ m_Speed.y += a_AddSpeedY;
WrapSpeed();
}
@@ -1426,8 +1548,7 @@ void cEntity::AddSpeedY(double a_AddSpeedY)
void cEntity::AddSpeedZ(double a_AddSpeedZ)
{
- m_Speed.z += a_AddSpeedZ;
- m_bDirtySpeed = true;
+ m_Speed.z += a_AddSpeedZ;
WrapSpeed();
}
@@ -1469,7 +1590,7 @@ void cEntity::SteerVehicle(float a_Forward, float a_Sideways)
Vector3d cEntity::GetLookVector(void) const
{
Matrix4d m;
- m.Init(Vector3f(), 0, m_Rot.x, -m_Rot.y);
+ m.Init(Vector3d(), 0, m_Rot.x, -m_Rot.y);
Vector3d Look = m.Transform(Vector3d(0, 0, 1));
return Look;
}
@@ -1482,8 +1603,7 @@ Vector3d cEntity::GetLookVector(void) const
// Set position
void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ)
{
- m_Pos.Set(a_PosX, a_PosY, a_PosZ);
- m_bDirtyPosition = true;
+ m_Pos.Set(a_PosX, a_PosY, a_PosZ);
}
@@ -1492,8 +1612,7 @@ void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ)
void cEntity::SetPosX(double a_PosX)
{
- m_Pos.x = a_PosX;
- m_bDirtyPosition = true;
+ m_Pos.x = a_PosX;
}
@@ -1502,8 +1621,7 @@ void cEntity::SetPosX(double a_PosX)
void cEntity::SetPosY(double a_PosY)
{
- m_Pos.y = a_PosY;
- m_bDirtyPosition = true;
+ m_Pos.y = a_PosY;
}
@@ -1513,7 +1631,6 @@ void cEntity::SetPosY(double a_PosY)
void cEntity::SetPosZ(double a_PosZ)
{
m_Pos.z = a_PosZ;
- m_bDirtyPosition = true;
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index e41f74b09..0c393c0f5 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -32,6 +32,8 @@
#define POSZ_TOINT (int)floor(GetPosZ())
#define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT)
+#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); if ((ChunkVarName == NULL) || !ChunkVarName->IsValid()) { return; }
+
@@ -88,23 +90,42 @@ public:
} ;
// tolua_end
-
- enum
+
+ enum eEntityStatus
{
- ENTITY_STATUS_HURT = 2,
- ENTITY_STATUS_DEAD = 3,
- ENTITY_STATUS_WOLF_TAMING = 6,
- ENTITY_STATUS_WOLF_TAMED = 7,
- ENTITY_STATUS_WOLF_SHAKING = 8,
- ENTITY_STATUS_EATING_ACCEPTED = 9,
- ENTITY_STATUS_SHEEP_EATING = 10,
- ENTITY_STATUS_GOLEM_ROSING = 11,
- ENTITY_STATUS_VILLAGER_HEARTS = 12,
- ENTITY_STATUS_VILLAGER_ANGRY = 13,
- ENTITY_STATUS_VILLAGER_HAPPY = 14,
- ENTITY_STATUS_WITCH_MAGICKING = 15,
+ // TODO: Investiagate 0, 1, and 5 as Wiki.vg is not certain
+
+ // Entity becomes coloured red
+ esGenericHurt = 2,
+ // Entity plays death animation (entity falls to ground)
+ esGenericDead = 3,
+ // Iron Golem plays attack animation (arms lift and fall)
+ esIronGolemAttacking = 4,
+ // Wolf taming particles spawn (smoke)
+ esWolfTaming = 6,
+ // Wolf tamed particles spawn (hearts)
+ esWolfTamed = 7,
+ // Wolf plays water removal animation (shaking and water particles)
+ esWolfDryingWater = 8,
+ // Informs client that eating was accepted
+ esPlayerEatingAccepted = 9,
+ // Sheep plays eating animation (head lowers to ground)
+ esSheepEating = 10,
+ // Iron Golem holds gift to villager children
+ esIronGolemGivingPlant = 11,
+ // Villager spawns heart particles
+ esVillagerBreeding = 12,
+ // Villager spawns thunderclound particles
+ esVillagerAngry = 13,
+ // Villager spawns green crosses
+ esVillagerHappy = 14,
+ // Witch spawns magic particle (TODO: investigation into what this is)
+ esWitchMagicking = 15,
+
// It seems 16 (zombie conversion) is now done with metadata
- ENTITY_STATUS_FIREWORK_EXPLODE= 17,
+
+ // Informs client to explode a firework based on its metadata
+ esFireworkExploding = 17,
} ;
enum
@@ -118,7 +139,8 @@ public:
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
DROWNING_TICKS = 20, ///< Number of ticks per heart of damage
- VOID_BOUNDARY = -46 ///< At what position Y to begin applying void damage
+ VOID_BOUNDARY = -46, ///< At what position Y to begin applying void damage
+ FALL_DAMAGE_HEIGHT = 4 ///< At what position Y fall damage is applied
} ;
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
@@ -159,7 +181,7 @@ public:
cWorld * GetWorld(void) const { return m_World; }
- double GetHeadYaw (void) const { return m_HeadYaw; }
+ double GetHeadYaw (void) const { return m_HeadYaw; } // In degrees
double GetHeight (void) const { return m_Height; }
double GetMass (void) const { return m_Mass; }
const Vector3d & GetPosition (void) const { return m_Pos; }
@@ -167,9 +189,9 @@ public:
double GetPosY (void) const { return m_Pos.y; }
double GetPosZ (void) const { return m_Pos.z; }
const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components
- double GetYaw (void) const { return m_Rot.x; }
- double GetPitch (void) const { return m_Rot.y; }
- double GetRoll (void) const { return m_Rot.z; }
+ double GetYaw (void) const { return m_Rot.x; } // In degrees, [-180, +180)
+ double GetPitch (void) const { return m_Rot.y; } // In degrees, [-180, +180), but normal client clips to [-90, +90]
+ double GetRoll (void) const { return m_Rot.z; } // In degrees, unused in current client
Vector3d GetLookVector(void) const;
const Vector3d & GetSpeed (void) const { return m_Speed; }
double GetSpeedX (void) const { return m_Speed.x; }
@@ -189,9 +211,9 @@ public:
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components
- void SetYaw (double a_Yaw);
- void SetPitch (double a_Pitch);
- void SetRoll (double a_Roll);
+ void SetYaw (double a_Yaw); // In degrees, normalizes to [-180, +180)
+ void SetPitch (double a_Pitch); // In degrees, normalizes to [-180, +180)
+ void SetRoll (double a_Roll); // In degrees, normalizes to [-180, +180)
void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ);
void SetSpeed (const Vector3d & a_Speed) { SetSpeed(a_Speed.x, a_Speed.y, a_Speed.z); }
void SetSpeedX (double a_SpeedX);
@@ -240,14 +262,19 @@ public:
// tolua_end
- /// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
+ /** Makes this entity take damage specified in the a_TDI.
+ The TDI is sent through plugins first, then applied.
+ If it returns false, the entity hasn't receive any damage. */
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI);
// tolua_begin
/// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
virtual int GetRawDamageAgainst(const cEntity & a_Receiver);
+ /** Returns whether armor will protect against the passed damage type **/
+ virtual bool ArmorCoversAgainst(eDamageType a_DamageType);
+
/// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
@@ -272,6 +299,9 @@ public:
/// Called when the health drops below zero. a_Killer may be NULL (environmental damage)
virtual void KilledBy(cEntity * a_Killer);
+ /// Called when the entity kills another entity
+ virtual void Killed(cEntity * a_Victim) {}
+
/// Heals the specified amount of HPs
void Heal(int a_HitPoints);
@@ -290,6 +320,9 @@ public:
/// Updates the state related to this entity being on fire
virtual void TickBurning(cChunk & a_Chunk);
+
+ /** Detects the time for application of cacti damage */
+ virtual void DetectCacti(void);
/// Handles when the entity is in the void
virtual void TickInVoid(cChunk & a_Chunk);
@@ -307,6 +340,11 @@ public:
int GetMaxHealth(void) const { return m_MaxHealth; }
+ /// Sets whether the entity is fireproof
+ void SetIsFireproof(bool a_IsFireproof);
+
+ bool IsFireproof(void) const { return m_IsFireproof; }
+
/// Puts the entity on fire for the specified amount of ticks
void StartBurning(int a_TicksLeftBurning);
@@ -364,6 +402,12 @@ public:
virtual bool IsSubmerged(void) const{ return m_IsSubmerged; }
/** Gets remaining air of a monster */
int GetAirLevel(void) const { return m_AirLevel; }
+
+ /** Gets the invulnerable ticks from the entity */
+ int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; }
+
+ /** Set the invulnerable ticks from the entity */
+ void SetInvulnerableTicks(int a_InvulnerableTicks) { m_InvulnerableTicks = a_InvulnerableTicks; }
// tolua_end
@@ -392,27 +436,37 @@ protected:
/// The entity which is attached to this entity (rider), NULL if none
cEntity * m_Attachee;
- // Flags that signal that we haven't updated the clients with the latest.
- bool m_bDirtyHead;
- bool m_bDirtyOrientation;
- bool m_bDirtyPosition;
- bool m_bDirtySpeed;
-
- bool m_bOnGround;
- float m_Gravity;
+ /** Stores whether head yaw has been set manually */
+ bool m_bDirtyHead;
+
+ /** Stores whether our yaw/pitch/roll (body orientation) has been set manually */
+ bool m_bDirtyOrientation;
- // Last Position.
- double m_LastPosX, m_LastPosY, m_LastPosZ;
+ /** Stores whether we have sent a Velocity packet with a speed of zero (no speed) to the client
+ Ensures that said packet is sent only once */
+ bool m_bHasSentNoSpeed;
- // This variables keep track of the last time a packet was sent
- Int64 m_TimeLastTeleportPacket, m_TimeLastMoveReltPacket, m_TimeLastSpeedPacket; // In ticks
+ /** Stores if the entity is on the ground */
+ bool m_bOnGround;
+
+ /** Stores gravity that is applied to an entity every tick
+ For realistic effects, this should be negative. For spaaaaaaace, this can be zero or even positive */
+ float m_Gravity;
+
+ /** Last position sent to client via the Relative Move or Teleport packets (not Velocity)
+ Only updated if cEntity::BroadcastMovementUpdate() is called! */
+ Vector3d m_LastPos;
- bool m_IsInitialized; // Is set to true when it's initialized, until it's destroyed (Initialize() till Destroy() )
+ /** True when entity is initialised (Initialize()) and false when destroyed pending deletion (Destroy()) */
+ bool m_IsInitialized;
eEntityType m_EntityType;
cWorld * m_World;
+ /// Whether the entity is capable of taking fire or lava damage.
+ bool m_IsFireproof;
+
/// Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire())
int m_TicksSinceLastBurnDamage;
@@ -428,12 +482,14 @@ protected:
/// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void.
int m_TicksSinceLastVoidDamage;
+
virtual void Destroyed(void) {} // Called after the entity has been destroyed
void SetWorld(cWorld * a_World) { m_World = a_World; }
/** Called in each tick to handle air-related processing i.e. drowning */
virtual void HandleAir();
+
/** Called once per tick to set IsSwimming and IsSubmerged */
virtual void SetSwimState(cChunk & a_Chunk);
@@ -445,29 +501,33 @@ protected:
int m_AirTickTimer;
private:
- // Measured in degrees, [-180, +180)
+ /** Measured in degrees, [-180, +180) */
double m_HeadYaw;
- // Measured in meter/second (m/s)
+ /** Measured in meter/second (m/s) */
Vector3d m_Speed;
- // Measured in degrees, [-180, +180)
+ /** Measured in degrees, [-180, +180) */
Vector3d m_Rot;
- /// Position of the entity's XZ center and Y bottom
+ /** Position of the entity's XZ center and Y bottom */
Vector3d m_Pos;
- // Measured in meter / second
+ /** Measured in meter / second */
Vector3d m_WaterSpeed;
- // Measured in Kilograms (Kg)
+ /** Measured in Kilograms (Kg) */
double m_Mass;
- /// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter.
+ /** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
double m_Width;
- /// Height of the entity (Y axis)
+ /** Height of the entity (Y axis) */
double m_Height;
+
+ /** If a player hit a entity, the entity receive a invulnerable of 10 ticks.
+ While this ticks, a player can't hit this entity. */
+ int m_InvulnerableTicks;
} ; // tolua_export
typedef std::list<cEntity *> cEntityList;
diff --git a/src/Entities/ExpBottleEntity.cpp b/src/Entities/ExpBottleEntity.cpp
new file mode 100644
index 000000000..202dde942
--- /dev/null
+++ b/src/Entities/ExpBottleEntity.cpp
@@ -0,0 +1,27 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ExpBottleEntity.h"
+#include "../World.h"
+
+
+
+
+
+cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ // Spawn an experience orb with a reward between 3 and 11.
+ m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
+ m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
+
+ Destroy();
+}
diff --git a/src/Entities/ExpBottleEntity.h b/src/Entities/ExpBottleEntity.h
new file mode 100644
index 000000000..b2043d8f1
--- /dev/null
+++ b/src/Entities/ExpBottleEntity.h
@@ -0,0 +1,33 @@
+//
+// ExpBottleEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cExpBottleEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cExpBottleEntity);
+
+ cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+
+}; // tolua_export
diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp
index 3623c869a..10f79aedc 100644
--- a/src/Entities/ExpOrb.cpp
+++ b/src/Entities/ExpOrb.cpp
@@ -34,8 +34,6 @@ cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
void cExpOrb::SpawnOn(cClientHandle & a_Client)
{
a_Client.SendExperienceOrb(*this);
- m_bDirtyPosition = false;
- m_bDirtySpeed = false;
m_bDirtyOrientation = false;
m_bDirtyHead = false;
}
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/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index a66c7e4ae..111c5fa84 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -55,9 +55,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
- int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx);
- NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx);
+ BLOCKTYPE BlockBelow = a_Chunk.GetBlock(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
+ NIBBLETYPE BelowMeta = a_Chunk.GetMeta(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta))
{
// Fallen onto a block that breaks this into pickups (e. g. half-slab)
@@ -87,7 +86,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
AddSpeedY(MilliDt * -9.8f);
AddPosition(GetSpeed() * MilliDt);
- if ((GetSpeedX() != 0) || (GetSpeedZ() != 0))
+ // If not static (one billionth precision) broadcast movement
+ if ((fabs(GetSpeedX()) > std::numeric_limits<double>::epsilon()) || (fabs(GetSpeedZ()) > std::numeric_limits<double>::epsilon()))
{
BroadcastMovementUpdate();
}
diff --git a/src/Entities/FireChargeEntity.cpp b/src/Entities/FireChargeEntity.cpp
new file mode 100644
index 000000000..aba32602f
--- /dev/null
+++ b/src/Entities/FireChargeEntity.cpp
@@ -0,0 +1,50 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "FireChargeEntity.h"
+#include "../World.h"
+
+
+
+
+
+cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
+{
+ SetSpeed(a_Speed);
+ SetGravity(0);
+}
+
+
+
+
+
+void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
+ {
+ m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
+ }
+}
+
+
+
+
+
+void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ Destroy();
+ Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
+}
+
+
+
+
+
+void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ Destroy();
+ Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
+
+ // TODO: Some entities are immune to hits
+ a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
+}
diff --git a/src/Entities/FireChargeEntity.h b/src/Entities/FireChargeEntity.h
new file mode 100644
index 000000000..3924c337c
--- /dev/null
+++ b/src/Entities/FireChargeEntity.h
@@ -0,0 +1,36 @@
+//
+// FireChargeEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cFireChargeEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cFireChargeEntity);
+
+ cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+
+} ; // tolua_export
diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp
new file mode 100644
index 000000000..403a53c84
--- /dev/null
+++ b/src/Entities/FireworkEntity.cpp
@@ -0,0 +1,73 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "FireworkEntity.h"
+#include "../World.h"
+#include "../Chunk.h"
+
+
+
+
+
+cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
+ super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
+ m_ExplodeTimer(0),
+ m_FireworkItem(a_Item)
+{
+}
+
+
+
+
+
+void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
+{
+ int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
+ int PosY = POSY_TOINT;
+
+ if ((PosY < 0) || (PosY >= cChunkDef::Height))
+ {
+ goto setspeed;
+ }
+
+ if (m_IsInGround)
+ {
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
+ {
+ m_IsInGround = false;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
+ {
+ OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
+ return;
+ }
+ }
+
+setspeed:
+ AddSpeedY(1);
+ AddPosition(GetSpeed() * (a_Dt / 1000));
+}
+
+
+
+
+
+void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
+ {
+ m_World->BroadcastEntityStatus(*this, esFireworkExploding);
+ Destroy();
+ }
+
+ m_ExplodeTimer++;
+}
diff --git a/src/Entities/FireworkEntity.h b/src/Entities/FireworkEntity.h
new file mode 100644
index 000000000..c62ca9402
--- /dev/null
+++ b/src/Entities/FireworkEntity.h
@@ -0,0 +1,40 @@
+//
+// FireworkEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cFireworkEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cFireworkEntity);
+
+ cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
+ const cItem & GetItem(void) const { return m_FireworkItem; }
+
+protected:
+
+ // cProjectileEntity overrides:
+ virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ int m_ExplodeTimer;
+ cItem m_FireworkItem;
+
+}; // 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/GhastFireballEntity.cpp b/src/Entities/GhastFireballEntity.cpp
new file mode 100644
index 000000000..9e4cb387e
--- /dev/null
+++ b/src/Entities/GhastFireballEntity.cpp
@@ -0,0 +1,44 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "GhastFireballEntity.h"
+#include "../World.h"
+
+
+
+
+
+cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
+{
+ SetSpeed(a_Speed);
+ SetGravity(0);
+}
+
+
+
+
+
+void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
+}
+
+
+
+
+
+void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ Destroy();
+ Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
+}
+
+
+
+
+
+void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ Destroy();
+ Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
+}
diff --git a/src/Entities/GhastFireballEntity.h b/src/Entities/GhastFireballEntity.h
new file mode 100644
index 000000000..9e4572c78
--- /dev/null
+++ b/src/Entities/GhastFireballEntity.h
@@ -0,0 +1,38 @@
+//
+// GhastFireballEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cGhastFireballEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cGhastFireballEntity);
+
+ cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+
+ // TODO: Deflecting the fireballs by arrow- or sword- hits
+
+} ; // tolua_export
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 7f38aa35a..7bd440d6d 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -132,7 +132,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return;
}
- int PosY = (int)floor(GetPosY());
+ int PosY = POSY_TOINT;
if ((PosY <= 0) || (PosY >= cChunkDef::Height))
{
// Outside the world, just process normal falling physics
@@ -141,8 +141,8 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return;
}
- int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width;
+ int RelPosX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelPosZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
if (Chunk == NULL)
{
@@ -195,7 +195,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
super::HandlePhysics(a_Dt, *Chunk);
}
- if (m_bIsOnDetectorRail && !Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())).Equals(m_DetectorRailPosition))
+ if (m_bIsOnDetectorRail && !Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT).Equals(m_DetectorRailPosition))
{
m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
m_bIsOnDetectorRail = false;
@@ -203,7 +203,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
else if (WasDetectorRail)
{
m_bIsOnDetectorRail = true;
- m_DetectorRailPosition = Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ m_DetectorRailPosition = Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT);
}
// Broadcast positioning changes to client
@@ -719,11 +719,11 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{
if (GetSpeedZ() > 0)
{
- BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ()));
+ BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ()));
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
// We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
- cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1);
+ cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
@@ -736,10 +736,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
}
else if (GetSpeedZ() < 0)
{
- BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
+ BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
- cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1);
+ cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
@@ -756,10 +756,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{
if (GetSpeedX() > 0)
{
- BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT);
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
- cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
+ cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
@@ -772,10 +772,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
}
else if (GetSpeedX() < 0)
{
- BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
- cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
+ cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
@@ -793,10 +793,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
case E_META_RAIL_CURVED_ZP_XM:
case E_META_RAIL_CURVED_ZP_XP:
{
- BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
- BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
- BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
- BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
+ BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
+ BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT);
+ BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
+ BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1);
if (
(!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||
(!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) ||
@@ -805,7 +805,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
)
{
SetSpeed(0, 0, 0);
- SetPosition((int)floor(GetPosX()) + 0.5, GetPosY(), (int)floor(GetPosZ()) + 0.5);
+ SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
return true;
}
break;
@@ -822,7 +822,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
{
cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID()));
int ChunkX, ChunkZ;
- cChunkDef::BlockToChunk((int)floor(GetPosX()), (int)floor(GetPosZ()), ChunkX, ChunkZ);
+ cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);
m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback);
if (!MinecartCollisionCallback.FoundIntersection())
@@ -902,18 +902,21 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
-void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
+bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
{
Destroy();
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
- super::DoTakeDamage(TDI);
- return; // No drops for creative
+ SetInvulnerableTicks(0);
+ return super::DoTakeDamage(TDI); // No drops for creative
}
m_LastDamage = TDI.FinalDamage;
- super::DoTakeDamage(TDI);
+ if (!super::DoTakeDamage(TDI))
+ {
+ return false;
+ }
m_World->BroadcastEntityMetadata(*this);
@@ -952,12 +955,13 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
default:
{
ASSERT(!"Unhandled minecart type when spawning pickup!");
- return;
+ return true;
}
}
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
}
+ return true;
}
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index ebdb576e0..1e60f091c 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -36,7 +36,7 @@ public:
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
- virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual void Destroyed() override;
int LastDamage(void) const { return m_LastDamage; }
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index 7fc89b62b..0fd006485 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -98,45 +98,44 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
if (!m_bCollected)
{
- int BlockY = (int) floor(GetPosY());
+ int BlockY = POSY_TOINT;
+ int BlockX = POSX_TOINT;
+ int BlockZ = POSZ_TOINT;
+
if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world
{
- int BlockX = (int) floor(GetPosX());
- int BlockZ = (int) floor(GetPosZ());
// Position might have changed due to physics. So we have to make sure we have the correct chunk.
- cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
- if (CurrentChunk != NULL) // Make sure the chunk is loaded
- {
- int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
- int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
+ GET_AND_VERIFY_CURRENT_CHUNK(CurrentChunk, BlockX, BlockZ)
+
+ int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
+ int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
- // If the pickup is on the bottommost block position, make it think the void is made of air: (#131)
- BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
- BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
-
- if (
- IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) ||
- IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE)
- )
+ // If the pickup is on the bottommost block position, make it think the void is made of air: (#131)
+ BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
+ BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
+
+ if (
+ IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) ||
+ IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE)
+ )
+ {
+ m_bCollected = true;
+ m_Timer = 0; // We have to reset the timer.
+ m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
+ if (m_Timer > 500.f)
{
- m_bCollected = true;
- m_Timer = 0; // We have to reset the timer.
- m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
- if (m_Timer > 500.f)
- {
- Destroy(true);
- return;
- }
+ Destroy(true);
+ return;
}
+ }
- if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me
+ if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me
+ {
+ cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
+ m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
+ if (PickupCombiningCallback.FoundMatchingPickup())
{
- cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
- m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
- if (PickupCombiningCallback.FoundMatchingPickup())
- {
- m_World->BroadcastEntityMetadata(*this);
- }
+ m_World->BroadcastEntityMetadata(*this);
}
}
}
@@ -156,7 +155,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
- if (GetPosY() < -8) // Out of this world and no more visible!
+ if (GetPosY() < VOID_BOUNDARY) // Out of this world and no more visible!
{
Destroy(true);
return;
@@ -193,6 +192,16 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
int NumAdded = a_Dest->GetInventory().AddItem(m_Item);
if (NumAdded > 0)
{
+ // Check achievements
+ switch (m_Item.m_ItemType)
+ {
+ case E_BLOCK_LOG: a_Dest->AwardAchievement(achMineWood); break;
+ case E_ITEM_LEATHER: a_Dest->AwardAchievement(achKillCow); break;
+ case E_ITEM_DIAMOND: a_Dest->AwardAchievement(achDiamonds); break;
+ case E_ITEM_BLAZE_ROD: a_Dest->AwardAchievement(achBlazeRod); break;
+ default: break;
+ }
+
m_Item.m_ItemCount -= NumAdded;
m_World->BroadcastCollectPickup(*this, *a_Dest);
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h
index 74b917bce..2dcbecaaf 100644
--- a/src/Entities/Pickup.h
+++ b/src/Entities/Pickup.h
@@ -49,9 +49,6 @@ public:
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
private:
- Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
-
- Vector3d m_WaterSpeed;
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 863aaa799..0dfdcfd8b 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -16,6 +16,9 @@
#include "../Items/ItemHandler.h"
#include "../Vector3.h"
+#include "../WorldStorage/StatSerializer.h"
+#include "../CompositeChat.h"
+
#include "inifile/iniFile.h"
#include "json/json.h"
@@ -76,18 +79,16 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
cTimer t1;
m_LastPlayerListTime = t1.GetNowTime();
-
- m_TimeLastTeleportPacket = 0;
m_PlayerName = a_PlayerName;
- m_bDirtyPosition = true; // So chunks are streamed to player at spawn
if (!LoadFromDisk())
{
m_Inventory.Clear();
- SetPosX(cRoot::Get()->GetDefaultWorld()->GetSpawnX());
- SetPosY(cRoot::Get()->GetDefaultWorld()->GetSpawnY());
- SetPosZ(cRoot::Get()->GetDefaultWorld()->GetSpawnZ());
+ cWorld * DefaultWorld = cRoot::Get()->GetDefaultWorld();
+ SetPosX(DefaultWorld->GetSpawnX());
+ SetPosY(DefaultWorld->GetSpawnY());
+ SetPosZ(DefaultWorld->GetSpawnZ());
LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
@@ -193,6 +194,8 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
}
+
+ m_Stats.AddValue(statMinutesPlayed, 1);
if (!a_Chunk.IsValid())
{
@@ -208,25 +211,22 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
m_BowCharge += 1;
}
- //handle updating experience
+ // Handle updating experience
if (m_bDirtyExperience)
{
SendExperience();
}
- if (m_bDirtyPosition)
+ if (GetPosition() != m_LastPos) // Change in position from last tick?
{
// Apply food exhaustion from movement:
ApplyFoodExhaustionFromMovement();
cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this);
- BroadcastMovementUpdate(m_ClientHandle);
m_ClientHandle->StreamChunks();
}
- else
- {
- BroadcastMovementUpdate(m_ClientHandle);
- }
+
+ BroadcastMovementUpdate(m_ClientHandle);
if (m_Health > 0) // make sure player is alive
{
@@ -377,7 +377,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta)
}
LOGD("Player \"%s\" gained/lost %d experience, total is now: %d",
- m_PlayerName.c_str(), a_Xp_delta, m_CurrentXp);
+ GetName().c_str(), a_Xp_delta, m_CurrentXp);
// Set experience to be updated
m_bDirtyExperience = true;
@@ -391,7 +391,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta)
void cPlayer::StartChargingBow(void)
{
- LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str());
+ LOGD("Player \"%s\" started charging their bow", GetName().c_str());
m_IsChargingBow = true;
m_BowCharge = 0;
}
@@ -402,7 +402,7 @@ void cPlayer::StartChargingBow(void)
int cPlayer::FinishChargingBow(void)
{
- LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
+ LOGD("Player \"%s\" finished charging their bow at a charge of %d", GetName().c_str(), m_BowCharge);
int res = m_BowCharge;
m_IsChargingBow = false;
m_BowCharge = 0;
@@ -415,7 +415,7 @@ int cPlayer::FinishChargingBow(void)
void cPlayer::CancelChargingBow(void)
{
- LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
+ LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", GetName().c_str(), m_BowCharge);
m_IsChargingBow = false;
m_BowCharge = 0;
}
@@ -437,7 +437,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
cWorld * World = GetWorld();
if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height))
{
- BLOCKTYPE BlockType = World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ BLOCKTYPE BlockType = World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT);
if (BlockType != E_BLOCK_AIR)
{
m_bTouchGround = true;
@@ -456,8 +456,18 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
else
{
float Dist = (float)(m_LastGroundHeight - floor(GetPosY()));
+
+ if (Dist >= 2.0) // At least two blocks - TODO: Use m_LastJumpHeight instead of m_LastGroundHeight above
+ {
+ // Increment statistic
+ m_Stats.AddValue(statDistFallen, (StatValue)floor(Dist * 100 + 0.5));
+ }
+
int Damage = (int)(Dist - 3.f);
- if (m_LastJumpHeight > m_LastGroundHeight) Damage++;
+ if (m_LastJumpHeight > m_LastGroundHeight)
+ {
+ Damage++;
+ }
m_LastJumpHeight = (float)GetPosY();
if (Damage > 0)
@@ -466,7 +476,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
TakeDamage(dtFalling, NULL, Damage, Damage, 0);
// Fall particles
- GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */);
+ GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, (int)GetPosY() - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
}
m_LastGroundHeight = (float)GetPosY();
@@ -590,7 +600,7 @@ void cPlayer::FinishEating(void)
m_EatingFinishTick = -1;
// Send the packets:
- m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED);
+ m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
m_World->BroadcastEntityAnimation(*this, 0);
m_World->BroadcastEntityMetadata(*this);
@@ -807,37 +817,41 @@ void cPlayer::SetFlying(bool a_IsFlying)
-void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin))
{
if (IsGameModeCreative())
{
// No damage / health in creative mode if not void or plugin damage
- return;
+ return false;
}
}
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
{
- cPlayer* Attacker = (cPlayer*) a_TDI.Attacker;
+ cPlayer * Attacker = (cPlayer *)a_TDI.Attacker;
if ((m_Team != NULL) && (m_Team == Attacker->m_Team))
{
if (!m_Team->AllowsFriendlyFire())
{
// Friendly fire is disabled
- return;
+ return false;
}
}
}
- super::DoTakeDamage(a_TDI);
-
- // Any kind of damage adds food exhaustion
- AddFoodExhaustion(0.3f);
-
- SendHealth();
+ if (super::DoTakeDamage(a_TDI))
+ {
+ // Any kind of damage adds food exhaustion
+ AddFoodExhaustion(0.3f);
+ SendHealth();
+
+ m_Stats.AddValue(statDamageTaken, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
+ return true;
+ }
+ return false;
}
@@ -865,6 +879,8 @@ void cPlayer::KilledBy(cEntity * a_Killer)
Pickups.Add(cItem(E_ITEM_RED_APPLE));
}
+ m_Stats.AddValue(statItemsDropped, Pickups.Size());
+
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
SaveToDisk(); // Save it, yeah the world is a tough place !
@@ -874,9 +890,9 @@ void cPlayer::KilledBy(cEntity * a_Killer)
}
else if (a_Killer->IsPlayer())
{
- GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
+ cPlayer * Killer = (cPlayer *)a_Killer;
- m_World->GetScoreBoard().AddPlayerScore(((cPlayer *)a_Killer)->GetName(), cObjective::otPlayerKillCount, 1);
+ GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str()));
}
else
{
@@ -886,6 +902,8 @@ void cPlayer::KilledBy(cEntity * a_Killer)
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
}
+ m_Stats.AddValue(statDeaths);
+
m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1);
}
@@ -893,9 +911,37 @@ void cPlayer::KilledBy(cEntity * a_Killer)
+void cPlayer::Killed(cEntity * a_Victim)
+{
+ cScoreboard & ScoreBoard = m_World->GetScoreBoard();
+
+ if (a_Victim->IsPlayer())
+ {
+ m_Stats.AddValue(statPlayerKills);
+
+ ScoreBoard.AddPlayerScore(GetName(), cObjective::otPlayerKillCount, 1);
+ }
+ else if (a_Victim->IsMob())
+ {
+ if (((cMonster *)a_Victim)->GetMobFamily() == cMonster::mfHostile)
+ {
+ AwardAchievement(achKillMonster);
+ }
+
+ m_Stats.AddValue(statMobKills);
+ }
+
+ ScoreBoard.AddPlayerScore(GetName(), cObjective::otTotalKillCount, 1);
+}
+
+
+
+
+
void cPlayer::Respawn(void)
{
m_Health = GetMaxHealth();
+ SetInvulnerableTicks(20);
// Reset food level:
m_FoodLevel = MAX_FOOD_LEVEL;
@@ -1110,6 +1156,47 @@ void cPlayer::SetIP(const AString & a_IP)
+unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach)
+{
+ eStatistic Prerequisite = cStatInfo::GetPrerequisite(a_Ach);
+
+ // Check if the prerequisites are met
+ if (Prerequisite != statInvalid)
+ {
+ if (m_Stats.GetValue(Prerequisite) == 0)
+ {
+ return 0;
+ }
+ }
+
+ StatValue Old = m_Stats.GetValue(a_Ach);
+
+ if (Old > 0)
+ {
+ return m_Stats.AddValue(a_Ach);
+ }
+ else
+ {
+ // First time, announce it
+ cCompositeChat Msg;
+ Msg.SetMessageType(mtSuccess);
+ Msg.AddShowAchievementPart(GetName(), cStatInfo::GetName(a_Ach));
+ m_World->BroadcastChat(Msg);
+
+ // Increment the statistic
+ StatValue New = m_Stats.AddValue(a_Ach);
+
+ // Achievement Get!
+ m_ClientHandle->SendStatistics(m_Stats);
+
+ return New;
+ }
+}
+
+
+
+
+
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
{
SetPosition(a_PosX, a_PosY, a_PosZ);
@@ -1124,6 +1211,17 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
+void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees)
+{
+ SetYaw(a_YawDegrees);
+ SetPitch(a_PitchDegrees);
+ m_ClientHandle->SendPlayerMoveLook();
+}
+
+
+
+
+
Vector3d cPlayer::GetThrowStartPos(void) const
{
Vector3d res = GetEyePosition();
@@ -1154,9 +1252,9 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
-void cPlayer::ForceSetSpeed(Vector3d a_Direction)
+void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
{
- SetSpeed(a_Direction);
+ SetSpeed(a_Speed);
m_ClientHandle->SendEntityVelocity(*this);
}
@@ -1183,6 +1281,9 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos )
// TODO: should do some checks to see if player is not moving through terrain
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
+
+ Vector3d DeltaPos = a_NewPos - GetPosition();
+ UpdateMovementStats(DeltaPos);
SetPosition( a_NewPos );
SetStance(a_NewPos.y + 1.62);
@@ -1214,7 +1315,7 @@ void cPlayer::AddToGroup( const AString & a_GroupName )
{
cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName );
m_Groups.push_back( Group );
- LOGD("Added %s to group %s", m_PlayerName.c_str(), a_GroupName.c_str() );
+ LOGD("Added %s to group %s", GetName().c_str(), a_GroupName.c_str() );
ResolveGroups();
ResolvePermissions();
}
@@ -1238,13 +1339,13 @@ void cPlayer::RemoveFromGroup( const AString & a_GroupName )
if( bRemoved )
{
- LOGD("Removed %s from group %s", m_PlayerName.c_str(), a_GroupName.c_str() );
+ LOGD("Removed %s from group %s", GetName().c_str(), a_GroupName.c_str() );
ResolveGroups();
ResolvePermissions();
}
else
{
- LOGWARN("Tried to remove %s from group %s but was not in that group", m_PlayerName.c_str(), a_GroupName.c_str() );
+ LOGWARN("Tried to remove %s from group %s but was not in that group", GetName().c_str(), a_GroupName.c_str() );
}
}
@@ -1350,7 +1451,7 @@ void cPlayer::ResolveGroups()
if( AllGroups.find( CurrentGroup ) != AllGroups.end() )
{
LOGWARNING("ERROR: Player \"%s\" is in the group multiple times (\"%s\"). Please fix your settings in users.ini!",
- m_PlayerName.c_str(), CurrentGroup->GetName().c_str()
+ GetName().c_str(), CurrentGroup->GetName().c_str()
);
}
else
@@ -1362,7 +1463,7 @@ void cPlayer::ResolveGroups()
{
if( AllGroups.find( *itr ) != AllGroups.end() )
{
- LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", m_PlayerName.c_str(), (*itr)->GetName().c_str() );
+ LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", GetName().c_str(), (*itr)->GetName().c_str() );
continue;
}
ToIterate.push_back( *itr );
@@ -1413,10 +1514,7 @@ void cPlayer::TossEquippedItem(char a_Amount)
Drops.push_back(DroppedItem);
}
- double vX = 0, vY = 0, vZ = 0;
- EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
- vY = -vY * 2 + 1.f;
- m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
+ TossItems(Drops);
}
@@ -1432,6 +1530,7 @@ void cPlayer::TossHeldItem(char a_Amount)
char OriginalItemAmount = Item.m_ItemCount;
Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount);
Drops.push_back(Item);
+
if (OriginalItemAmount > a_Amount)
{
Item.m_ItemCount = OriginalItemAmount - a_Amount;
@@ -1442,10 +1541,7 @@ void cPlayer::TossHeldItem(char a_Amount)
}
}
- double vX = 0, vY = 0, vZ = 0;
- EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
- vY = -vY * 2 + 1.f;
- m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
+ TossItems(Drops);
}
@@ -1457,10 +1553,21 @@ void cPlayer::TossPickup(const cItem & a_Item)
cItems Drops;
Drops.push_back(a_Item);
+ TossItems(Drops);
+}
+
+
+
+
+
+void cPlayer::TossItems(const cItems & a_Items)
+{
+ m_Stats.AddValue(statItemsDropped, a_Items.Size());
+
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
- m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
+ m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
}
@@ -1489,6 +1596,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);
@@ -1507,25 +1615,19 @@ void cPlayer::LoadPermissionsFromDisk()
cIniFile IniFile;
if (IniFile.ReadFile("users.ini"))
{
- std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", "");
- if (!Groups.empty())
+ AString Groups = IniFile.GetValueSet(GetName(), "Groups", "Default");
+ AStringVector Split = StringSplitAndTrim(Groups, ",");
+
+ for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
{
- AStringVector Split = StringSplitAndTrim(Groups, ",");
- for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
+ if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr))
{
- if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr))
- {
- LOGWARNING("The group %s for player %s was not found!", itr->c_str(), m_PlayerName.c_str());
- }
- AddToGroup(*itr);
+ LOGWARNING("The group %s for player %s was not found!", itr->c_str(), GetName().c_str());
}
- }
- else
- {
- AddToGroup("Default");
+ AddToGroup(*itr);
}
- AString Color = IniFile.GetValue(m_PlayerName, "Color", "-");
+ AString Color = IniFile.GetValue(GetName(), "Color", "-");
if (!Color.empty())
{
m_Color = Color[0];
@@ -1534,8 +1636,10 @@ void cPlayer::LoadPermissionsFromDisk()
else
{
cGroupManager::GenerateDefaultUsersIni(IniFile);
+ IniFile.AddValue("Groups", GetName(), "Default");
AddToGroup("Default");
}
+ IniFile.WriteFile("users.ini");
ResolvePermissions();
}
@@ -1547,14 +1651,14 @@ bool cPlayer::LoadFromDisk()
LoadPermissionsFromDisk();
// Log player permissions, cause it's what the cool kids do
- LOGINFO("Player %s has permissions:", m_PlayerName.c_str() );
+ LOGINFO("Player %s has permissions:", GetName().c_str() );
for( PermissionMap::iterator itr = m_ResolvedPermissions.begin(); itr != m_ResolvedPermissions.end(); ++itr )
{
if( itr->second ) LOG(" - %s", itr->first.c_str() );
}
AString SourceFile;
- Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() );
+ Printf(SourceFile, "players/%s.json", GetName().c_str() );
cFile f;
if (!f.Open(SourceFile, cFile::fmRead))
@@ -1584,10 +1688,7 @@ bool cPlayer::LoadFromDisk()
SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble());
SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble());
SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble());
- m_LastPosX = GetPosX();
- m_LastPosY = GetPosY();
- m_LastPosZ = GetPosZ();
- m_LastFoodPos = GetPosition();
+ m_LastPos = GetPosition();
}
Json::Value & JSON_PlayerRotation = root["rotation"];
@@ -1618,9 +1719,14 @@ bool cPlayer::LoadFromDisk()
m_Inventory.LoadFromJson(root["inventory"]);
m_LoadedWorldName = root.get("world", "world").asString();
+
+ // Load the player stats.
+ // We use the default world name (like bukkit) because stats are shared between dimensions/worlds.
+ cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats);
+ StatSerializer.Load();
LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
- m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
+ GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
);
return true;
@@ -1676,12 +1782,12 @@ bool cPlayer::SaveToDisk()
std::string JsonData = writer.write(root);
AString SourceFile;
- Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() );
+ Printf(SourceFile, "players/%s.json", GetName().c_str() );
cFile f;
if (!f.Open(SourceFile, cFile::fmWrite))
{
- LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_PlayerName.c_str(), SourceFile.c_str());
+ LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", GetName().c_str(), SourceFile.c_str());
return false;
}
if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size())
@@ -1689,6 +1795,16 @@ bool cPlayer::SaveToDisk()
LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str());
return false;
}
+
+ // Save the player stats.
+ // We use the default world name (like bukkit) because stats are shared between dimensions/worlds.
+ cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats);
+ if (!StatSerializer.Save())
+ {
+ LOGERROR("Could not save stats for player %s", GetName().c_str());
+ return false;
+ }
+
return true;
}
@@ -1703,7 +1819,10 @@ cPlayer::StringList cPlayer::GetResolvedPermissions()
const PermissionMap& ResolvedPermissions = m_ResolvedPermissions;
for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr )
{
- if( itr->second ) Permissions.push_back( itr->first );
+ if (itr->second)
+ {
+ Permissions.push_back( itr->first );
+ }
}
return Permissions;
@@ -1842,23 +1961,108 @@ void cPlayer::HandleFloater()
+bool cPlayer::IsClimbing(void) const
+{
+ int PosX = POSX_TOINT;
+ int PosY = POSY_TOINT;
+ int PosZ = POSZ_TOINT;
+
+ if ((PosY < 0) || (PosY >= cChunkDef::Height))
+ {
+ return false;
+ }
+
+ BLOCKTYPE Block = m_World->GetBlock(PosX, PosY, PosZ);
+ switch (Block)
+ {
+ case E_BLOCK_LADDER:
+ case E_BLOCK_VINES:
+ {
+ return true;
+ }
+ default: return false;
+ }
+}
+
+
+
+
+
+void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
+{
+ StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5);
+
+ if (m_AttachedTo == NULL)
+ {
+ if (IsClimbing())
+ {
+ if (a_DeltaPos.y > 0.0) // Going up
+ {
+ m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5));
+ }
+ }
+ else if (IsSubmerged())
+ {
+ m_Stats.AddValue(statDistDove, Value);
+ }
+ else if (IsSwimming())
+ {
+ m_Stats.AddValue(statDistSwum, Value);
+ }
+ else if (IsOnGround())
+ {
+ m_Stats.AddValue(statDistWalked, Value);
+ }
+ else
+ {
+ if (Value >= 25) // Ignore small/slow movement
+ {
+ m_Stats.AddValue(statDistFlown, Value);
+ }
+ }
+ }
+ else
+ {
+ switch (m_AttachedTo->GetEntityType())
+ {
+ case cEntity::etMinecart: m_Stats.AddValue(statDistMinecart, Value); break;
+ case cEntity::etBoat: m_Stats.AddValue(statDistBoat, Value); break;
+ case cEntity::etMonster:
+ {
+ cMonster * Monster = (cMonster *)m_AttachedTo;
+ switch (Monster->GetMobType())
+ {
+ case cMonster::mtPig: m_Stats.AddValue(statDistPig, Value); break;
+ case cMonster::mtHorse: m_Stats.AddValue(statDistHorse, Value); break;
+ default: break;
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+}
+
+
+
+
+
void cPlayer::ApplyFoodExhaustionFromMovement()
{
if (IsGameModeCreative())
{
return;
}
-
- // Calculate the distance travelled, update the last pos:
- Vector3d Movement(GetPosition() - m_LastFoodPos);
- Movement.y = 0; // Only take XZ movement into account
- m_LastFoodPos = GetPosition();
-
+
// If riding anything, apply no food exhaustion
if (m_AttachedTo != NULL)
{
return;
}
+
+ // Calculate the distance travelled, update the last pos:
+ Vector3d Movement(GetPosition() - m_LastPos);
+ Movement.y = 0; // Only take XZ movement into account
// Apply the exhaustion based on distance travelled:
double BaseExhaustion = Movement.Length();
@@ -1887,9 +2091,9 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
void cPlayer::Detach()
{
super::Detach();
- int PosX = (int)floor(GetPosX());
- int PosY = (int)floor(GetPosY());
- int PosZ = (int)floor(GetPosZ());
+ int PosX = POSX_TOINT;
+ int PosY = POSY_TOINT;
+ int PosZ = POSZ_TOINT;
// Search for a position within an area to teleport player after detachment
// Position must be solid land, and occupied by a nonsolid block
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index ea32dbfb9..b7cb27d6c 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -7,6 +7,8 @@
#include "../World.h"
#include "../ClientHandle.h"
+#include "../Statistics.h"
+
@@ -125,10 +127,19 @@ public:
inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export
+ /** Returns whether the player is climbing (ladders, vines e.t.c). */
+ bool IsClimbing(void) const;
+
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
// tolua_begin
+ /** Sends the "look" packet to the player, forcing them to set their rotation to the specified values.
+ a_YawDegrees is clipped to range [-180, +180),
+ a_PitchDegrees is clipped to range [-180, +180) but the client only uses [-90, +90]
+ */
+ void SendRotation(double a_YawDegrees, double a_PitchDegrees);
+
/** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */
Vector3d GetThrowStartPos(void) const;
@@ -168,6 +179,15 @@ public:
cTeam * UpdateTeam(void);
// tolua_end
+
+ /** Return the associated statistic and achievement manager. */
+ cStatManager & GetStatManager() { return m_Stats; }
+
+ /** Awards the player an achievement.
+ If all prerequisites are met, this method will award the achievement and will broadcast a chat message.
+ If the achievement has been already awarded to the player, this method will just increment the stat counter.
+ Returns the _new_ stat value. (0 = Could not award achievement) */
+ unsigned int AwardAchievement(const eStatistic a_Ach);
void SetIP(const AString & a_IP);
@@ -175,7 +195,7 @@ public:
void LoginSetGameMode(eGameMode a_GameMode);
/** Forces the player to move in the given direction. */
- void ForceSetSpeed(Vector3d a_Direction); // tolua_export
+ void ForceSetSpeed(const Vector3d & a_Speed); // tolua_export
/** Tries to move to a new position, with attachment-related checks (y == -999) */
void MoveTo(const Vector3d & a_NewPos); // tolua_export
@@ -300,6 +320,8 @@ public:
void AbortEating(void);
virtual void KilledBy(cEntity * a_Killer) override;
+
+ virtual void Killed(cEntity * a_Victim) override;
void Respawn(void); // tolua_export
@@ -369,6 +391,9 @@ public:
/** If true the player can fly even when he's not in creative. */
void SetCanFly(bool a_CanFly);
+ /** Update movement-related statistics. */
+ void UpdateMovementStats(const Vector3d & a_DeltaPos);
+
/** Returns wheter the player can fly or not. */
virtual bool CanFly(void) const { return m_CanFly; }
// tolua_end
@@ -417,9 +442,6 @@ protected:
/** Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned */
int m_FoodPoisonedTicksRemaining;
- /** Last position that has been recorded for food-related processing: */
- Vector3d m_LastFoodPos;
-
float m_LastJumpHeight;
float m_LastGroundHeight;
bool m_bTouchGround;
@@ -484,6 +506,8 @@ protected:
cTeam * m_Team;
+ cStatManager m_Stats;
+
void ResolvePermissions(void);
@@ -492,7 +516,7 @@ protected:
virtual void Destroyed(void);
/** Filters out damage for creative mode/friendly fire */
- virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
/** Stops players from burning in creative mode */
virtual void TickBurning(cChunk & a_Chunk) override;
@@ -503,6 +527,9 @@ protected:
/** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */
void HandleFloater(void);
+ /** Tosses a list of items. */
+ void TossItems(const cItems & a_Items);
+
/** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */
void ApplyFoodExhaustionFromMovement();
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index acb10539d..95c494569 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -4,15 +4,24 @@
// 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"
#include "../LineBlockTracer.h"
#include "../BoundingBox.h"
#include "../ChunkMap.h"
#include "../Chunk.h"
+#include "ArrowEntity.h"
+#include "ThrownEggEntity.h"
+#include "ThrownEnderPearlEntity.h"
+#include "ExpBottleEntity.h"
+#include "ThrownSnowballEntity.h"
+#include "FireChargeEntity.h"
+#include "FireworkEntity.h"
+#include "GhastFireballEntity.h"
+
@@ -371,13 +380,14 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
SetYawFromSpeed();
SetPitchFromSpeed();
- // DEBUG:
+ /*
LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ(),
GetYaw(), GetPitch()
);
+ */
}
@@ -400,495 +410,3 @@ void cProjectileEntity::CollectedBy(cPlayer * a_Dest)
// Overriden in arrow
UNUSED(a_Dest);
}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cArrowEntity:
-
-cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
- super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
- m_PickupState(psNoPickup),
- m_DamageCoeff(2),
- m_IsCritical(false),
- m_Timer(0),
- m_HitGroundTimer(0),
- m_bIsCollected(false),
- m_HitBlockPos(Vector3i(0, 0, 0))
-{
- SetSpeed(a_Speed);
- SetMass(0.1);
- SetYawFromSpeed();
- SetPitchFromSpeed();
- LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
- m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetYaw(), GetPitch()
- );
-}
-
-
-
-
-
-cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
- super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
- m_PickupState(psInSurvivalOrCreative),
- m_DamageCoeff(2),
- m_IsCritical((a_Force >= 1)),
- m_Timer(0),
- m_HitGroundTimer(0),
- m_bIsCollected(false),
- m_HitBlockPos(0, 0, 0)
-{
-}
-
-
-
-
-
-bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
-{
- switch (m_PickupState)
- {
- case psNoPickup: return false;
- case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
- case psInCreative: return a_Player.IsGameModeCreative();
- }
- ASSERT(!"Unhandled pickup state");
- return false;
-}
-
-
-
-
-
-void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- if (a_HitFace == BLOCK_FACE_NONE) { return; }
-
- super::OnHitSolidBlock(a_HitPos, a_HitFace);
- int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
-
- switch (a_HitFace)
- {
- case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
- case BLOCK_FACE_YM:
- {
- break;
- }
- default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
- }
-
- m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
-
- // Broadcast arrow hit sound
- m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
-}
-
-
-
-
-
-void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
-{
- if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
- {
- // Not an entity that interacts with an arrow
- return;
- }
-
- int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
- if (m_IsCritical)
- {
- Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
- }
- a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
-
- // Broadcast successful hit sound
- m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
-
- Destroy();
-}
-
-
-
-
-
-void cArrowEntity::CollectedBy(cPlayer * a_Dest)
-{
- if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
- {
- int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
- if (NumAdded > 0) // Only play effects if there was space in inventory
- {
- m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
- // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
- m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
- m_bIsCollected = true;
- }
- }
-}
-
-
-
-
-
-void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- super::Tick(a_Dt, a_Chunk);
- m_Timer += a_Dt;
-
- if (m_bIsCollected)
- {
- if (m_Timer > 500.f) // 0.5 seconds
- {
- Destroy();
- return;
- }
- }
- else if (m_Timer > 1000 * 60 * 5) // 5 minutes
- {
- Destroy();
- return;
- }
-
- if (m_IsInGround)
- {
- // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
- // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
- // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
- // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
-
- if (m_HitGroundTimer != -1) // Sent a teleport already, don't do again
- {
- if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
- {
- m_World->BroadcastTeleportEntity(*this);
- m_HitGroundTimer = -1;
- }
- else
- {
- m_HitGroundTimer += a_Dt;
- }
- }
-
- int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
- cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
-
- if (Chunk == NULL)
- {
- // Inside an unloaded chunk, abort
- return;
- }
-
- if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
- {
- m_IsInGround = false; // Yes, begin simulating physics again
- }
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cThrownEggEntity:
-
-cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
- super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- if (m_World->GetTickRandomNumber(7) == 1)
- {
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- }
- else if (m_World->GetTickRandomNumber(32) == 1)
- {
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- }
- Destroy();
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cThrownEnderPearlEntity :
-
-cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
- super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- // Teleport the creator here, make them take 5 damage:
- if (m_Creator != NULL)
- {
- // TODO: The coords might need some tweaking based on the block face
- m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
- m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
- }
-
- Destroy();
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cThrownSnowballEntity :
-
-cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
- super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- Destroy();
-}
-
-
-
-
-
-void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
-{
- int TotalDamage = 0;
- if (a_EntityHit.IsMob())
- {
- cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
- if (MobType == cMonster::mtBlaze)
- {
- TotalDamage = 3;
- }
- else if (MobType == cMonster::mtEnderDragon)
- {
- TotalDamage = 1;
- }
- }
- a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
-
- Destroy(true);
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cBottleOEnchantingEntity :
-
-cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
-super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- // Spawn an experience orb with a reward between 3 and 11.
- m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
- m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
-
- Destroy();
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cFireworkEntity :
-
-cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
-super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
- m_ExplodeTimer(0),
- m_FireworkItem(a_Item)
-{
-}
-
-
-
-
-
-void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
-{
- int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
- int PosY = POSY_TOINT;
-
- if ((PosY < 0) || (PosY >= cChunkDef::Height))
- {
- goto setspeed;
- }
-
- if (m_IsInGround)
- {
- if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
- {
- m_IsInGround = false;
- }
- else
- {
- return;
- }
- }
- else
- {
- if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
- {
- OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
- return;
- }
- }
-
-setspeed:
- AddSpeedY(1);
- AddPosition(GetSpeed() * (a_Dt / 1000));
-}
-
-
-
-
-
-void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- super::Tick(a_Dt, a_Chunk);
-
- if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
- {
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
- Destroy();
- }
-
- m_ExplodeTimer++;
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cGhastFireballEntity :
-
-cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
- super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
-{
- SetSpeed(a_Speed);
- SetGravity(0);
-}
-
-
-
-
-
-void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
-}
-
-
-
-
-
-void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- Destroy();
- Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
-}
-
-
-
-
-
-void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
-{
- Destroy();
- Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cFireChargeEntity :
-
-cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
- super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
-{
- SetSpeed(a_Speed);
- SetGravity(0);
-}
-
-
-
-
-
-void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
- {
- m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
- }
-}
-
-
-
-
-
-void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
- Destroy();
- Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
-}
-
-
-
-
-
-void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
-{
- Destroy();
- Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
-
- // TODO: Some entities are immune to hits
- a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
-}
-
-
-
-
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index efb7ae783..ae06b072f 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -94,300 +94,4 @@ protected:
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
- // tolua_begin
-} ;
-
-
-
-
-
-class cArrowEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
- /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
- enum ePickupState
- {
- psNoPickup = 0,
- psInSurvivalOrCreative = 1,
- psInCreative = 2,
- } ;
-
- // tolua_end
-
- CLASS_PROTODEF(cArrowEntity);
-
- /// Creates a new arrow with psNoPickup state and default damage modifier coeff
- cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
- /// Creates a new arrow as shot by a player, initializes it from the player object
- cArrowEntity(cPlayer & a_Player, double a_Force);
-
- // tolua_begin
-
- /// Returns whether the arrow can be picked up by players
- ePickupState GetPickupState(void) const { return m_PickupState; }
-
- /// Sets a new pickup state
- void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
-
- /// Returns the damage modifier coeff.
- double GetDamageCoeff(void) const { return m_DamageCoeff; }
-
- /// Sets the damage modifier coeff
- void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
-
- /// Returns true if the specified player can pick the arrow up
- bool CanPickup(const cPlayer & a_Player) const;
-
- /// Returns true if the arrow is set as critical
- bool IsCritical(void) const { return m_IsCritical; }
-
- /// Sets the IsCritical flag
- void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
-
- // tolua_end
-
-protected:
-
- /// Determines when the arrow can be picked up by players
- ePickupState m_PickupState;
-
- /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
- double m_DamageCoeff;
-
- /// If true, the arrow deals more damage
- bool m_IsCritical;
-
- /// Timer for pickup collection animation or five minute timeout
- float m_Timer;
-
- /// Timer for client arrow position confirmation via TeleportEntity
- float m_HitGroundTimer;
-
- /// If true, the arrow is in the process of being collected - don't go to anyone else
- bool m_bIsCollected;
-
- /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
- Vector3i m_HitBlockPos;
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
- virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
- virtual void CollectedBy(cPlayer * a_Player) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- // tolua_begin
-} ;
-
-
-
-
-
-class cThrownEggEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cThrownEggEntity);
-
- cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // tolua_end
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-class cThrownEnderPearlEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cThrownEnderPearlEntity);
-
- cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // tolua_end
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-class cThrownSnowballEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cThrownSnowballEntity);
-
- cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
- virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-class cExpBottleEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cExpBottleEntity);
-
- cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
-
- // tolua_begin
-
-};
-
-
-
-
-
-class cFireworkEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cFireworkEntity);
-
- cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
- const cItem & GetItem(void) const { return m_FireworkItem; }
-
-protected:
-
- // cProjectileEntity overrides:
- virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
-private:
-
- int m_ExplodeTimer;
- cItem m_FireworkItem;
-
- // tolua_begin
-
-};
-
-
-
-
-
-class cGhastFireballEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cGhastFireballEntity);
-
- cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
- virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
-
- // TODO: Deflecting the fireballs by arrow- or sword- hits
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-class cFireChargeEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cFireChargeEntity);
-
- cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
- virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-// tolua_end
-
-
-
+} ; // tolua_export
diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp
index 02f31f5bb..fd9a4e7ac 100644
--- a/src/Entities/TNTEntity.cpp
+++ b/src/Entities/TNTEntity.cpp
@@ -30,8 +30,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) :
void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
{
a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT
- m_bDirtyPosition = false;
- m_bDirtySpeed = false;
m_bDirtyOrientation = false;
m_bDirtyHead = false;
}
diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp
new file mode 100644
index 000000000..224019091
--- /dev/null
+++ b/src/Entities/ThrownEggEntity.cpp
@@ -0,0 +1,59 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ThrownEggEntity.h"
+#include "../World.h"
+
+
+
+
+
+cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ TrySpawnChicken(a_HitPos);
+
+ Destroy();
+}
+
+
+
+
+
+void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ // TODO: If entity is Ender Crystal, destroy it
+
+ TrySpawnChicken(a_HitPos);
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
+
+
+
+
+
+void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
+{
+ if (m_World->GetTickRandomNumber(7) == 1)
+ {
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ }
+ else if (m_World->GetTickRandomNumber(32) == 1)
+ {
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ }
+}
diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h
new file mode 100644
index 000000000..5ba8f051b
--- /dev/null
+++ b/src/Entities/ThrownEggEntity.h
@@ -0,0 +1,37 @@
+//
+// ThrownEggEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cThrownEggEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cThrownEggEntity);
+
+ cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+
+ // Randomly decides whether to spawn a chicken where the egg lands.
+ void TrySpawnChicken(const Vector3d & a_HitPos);
+
+} ; // tolua_export
diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp
new file mode 100644
index 000000000..c37161145
--- /dev/null
+++ b/src/Entities/ThrownEnderPearlEntity.cpp
@@ -0,0 +1,54 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ThrownEnderPearlEntity.h"
+
+
+
+
+
+cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ // TODO: Tweak a_HitPos based on block face.
+ TeleportCreator(a_HitPos);
+
+ Destroy();
+}
+
+
+
+
+
+void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ // TODO: If entity is Ender Crystal, destroy it
+
+ TeleportCreator(a_HitPos);
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
+
+
+
+
+
+void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
+{
+ // Teleport the creator here, make them take 5 damage:
+ if (m_Creator != NULL)
+ {
+ m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
+ m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
+ }
+}
diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h
new file mode 100644
index 000000000..ddee5babe
--- /dev/null
+++ b/src/Entities/ThrownEnderPearlEntity.h
@@ -0,0 +1,37 @@
+//
+// ThrownEnderPearlEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cThrownEnderPearlEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cThrownEnderPearlEntity);
+
+ cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+
+ // Teleports the creator where the ender pearl lands.
+ void TeleportCreator(const Vector3d & a_HitPos);
+
+} ; // tolua_export
diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp
new file mode 100644
index 000000000..427f630f7
--- /dev/null
+++ b/src/Entities/ThrownSnowballEntity.cpp
@@ -0,0 +1,48 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ThrownSnowballEntity.h"
+#include "../World.h"
+
+
+
+
+
+cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ Destroy();
+}
+
+
+
+
+
+void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ if (a_EntityHit.IsMob())
+ {
+ cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
+ if (MobType == cMonster::mtBlaze)
+ {
+ TotalDamage = 3;
+ }
+ else if (MobType == cMonster::mtEnderDragon)
+ {
+ TotalDamage = 1;
+ }
+ }
+ // TODO: If entity is Ender Crystal, destroy it
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h
new file mode 100644
index 000000000..a09512e37
--- /dev/null
+++ b/src/Entities/ThrownSnowballEntity.h
@@ -0,0 +1,34 @@
+//
+// ThrownSnowballEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cThrownSnowballEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cThrownSnowballEntity);
+
+ cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+
+} ; // tolua_export
diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp
index e6634bb0d..42bf5f3f9 100644
--- a/src/FastRandom.cpp
+++ b/src/FastRandom.cpp
@@ -91,7 +91,8 @@ int cFastRandom::m_SeedCounter = 0;
cFastRandom::cFastRandom(void) :
- m_Seed(m_SeedCounter++)
+ m_Seed(m_SeedCounter++),
+ m_Counter(0)
{
}
@@ -172,3 +173,13 @@ float cFastRandom::NextFloat(float a_Range, int a_Salt)
+
+int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
+{
+ cFastRandom Random;
+ return Random.NextInt(a_End - a_Begin + 1) + a_Begin;
+}
+
+
+
+
diff --git a/src/FastRandom.h b/src/FastRandom.h
index bf70822cf..567198a31 100644
--- a/src/FastRandom.h
+++ b/src/FastRandom.h
@@ -43,6 +43,9 @@ public:
/// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness
float NextFloat(float a_Range, int a_Salt);
+
+ /** Returns a random int in the range [a_Begin .. a_End] */
+ int GenerateRandomInteger(int a_Begin, int a_End);
protected:
int m_Seed;
diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp
index 1810d7c49..bd7fd8079 100644
--- a/src/FurnaceRecipe.cpp
+++ b/src/FurnaceRecipe.cpp
@@ -56,7 +56,6 @@ void cFurnaceRecipe::ReloadRecipes(void)
std::ifstream f;
char a_File[] = "furnace.txt";
f.open(a_File, std::ios::in);
- std::string input;
if (!f.good())
{
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 32a687201..47ba080c6 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -212,7 +212,7 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile)
void cBiomeGenList::InitializeBiomes(const AString & a_Biomes)
{
- AStringVector Split = StringSplit(a_Biomes, ",");
+ AStringVector Split = StringSplitAndTrim(a_Biomes, ",");
// Convert each string in the list into biome:
for (AStringVector::const_iterator itr = Split.begin(); itr != Split.end(); ++itr)
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index 1147744c0..3dacb5066 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Generating ${SOURCE})
diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp
index 98b7c8681..872e3341d 100644
--- a/src/Generating/Caves.cpp
+++ b/src/Generating/Caves.cpp
@@ -35,13 +35,6 @@ reduced in complexity in order for this generator to be useful, so the caves' sh
-/// How many nests in each direction are generated for a given chunk. Must be an even number
-#define NEIGHBORHOOD_SIZE 8
-
-
-
-
-
const int MIN_RADIUS = 3;
const int MAX_RADIUS = 8;
@@ -122,27 +115,19 @@ typedef std::vector<cCaveTunnel *> cCaveTunnels;
/// A collection of connected tunnels, possibly branching.
-class cStructGenWormNestCaves::cCaveSystem
+class cStructGenWormNestCaves::cCaveSystem :
+ public cGridStructGen::cStructure
{
+ typedef cGridStructGen::cStructure super;
+
public:
// The generating block position; is read directly in cStructGenWormNestCaves::GetCavesForChunk()
int m_BlockX;
int m_BlockZ;
- cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise);
+ cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise);
~cCaveSystem();
- /// Carves the cave system into the chunk specified
- void ProcessChunk(
- int a_ChunkX, int a_ChunkZ,
- cChunkDef::BlockTypes & a_BlockTypes,
- cChunkDef::HeightMap & a_HeightMap
- );
-
- #ifdef _DEBUG
- AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const;
- #endif // _DEBUG
-
protected:
int m_Size;
cCaveTunnels m_Tunnels;
@@ -157,6 +142,9 @@ protected:
/// Returns a radius based on the location provided.
int GetRadius(cNoise & a_Noise, int a_OriginX, int a_OriginY, int a_OriginZ);
+
+ // cGridStructGen::cStructure overrides:
+ virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -200,13 +188,14 @@ void cCaveTunnel::Randomize(cNoise & a_Noise)
for (int i = 0; i < 4; i++)
{
// For each already present point, insert a point in between it and its predecessor, shifted randomly.
- int PrevX = m_Points.front().m_BlockX;
- int PrevY = m_Points.front().m_BlockY;
- int PrevZ = m_Points.front().m_BlockZ;
- int PrevR = m_Points.front().m_Radius;
+ cCaveDefPoint & Point = m_Points.front();
+ int PrevX = Point.m_BlockX;
+ int PrevY = Point.m_BlockY;
+ int PrevZ = Point.m_BlockZ;
+ int PrevR = Point.m_Radius;
cCaveDefPoints Pts;
Pts.reserve(m_Points.size() * 2 + 1);
- Pts.push_back(m_Points.front());
+ Pts.push_back(Point);
for (cCaveDefPoints::const_iterator itr = m_Points.begin() + 1, end = m_Points.end(); itr != end; ++itr)
{
int Random = a_Noise.IntNoise3DInt(PrevX, PrevY, PrevZ + i) / 11;
@@ -238,18 +227,25 @@ void cCaveTunnel::Randomize(cNoise & a_Noise)
bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & a_Dst)
{
+ if (a_Src.size() < 2)
+ {
+ // There are no midpoints, nothing to smooth
+ return true;
+ }
+
// Smoothing: for each line segment, add points on its 1/4 lengths
bool res = false;
- int Num = a_Src.size() - 2; // this many intermediary points
+ size_t Num = a_Src.size() - 2; // this many intermediary points
a_Dst.clear();
a_Dst.reserve(Num * 2 + 2);
cCaveDefPoints::const_iterator itr = a_Src.begin() + 1;
- a_Dst.push_back(a_Src.front());
- int PrevX = a_Src.front().m_BlockX;
- int PrevY = a_Src.front().m_BlockY;
- int PrevZ = a_Src.front().m_BlockZ;
- int PrevR = a_Src.front().m_Radius;
- for (int i = 0; i <= Num; ++i, ++itr)
+ const cCaveDefPoint & Source = a_Src.front();
+ a_Dst.push_back(Source);
+ int PrevX = Source.m_BlockX;
+ int PrevY = Source.m_BlockY;
+ int PrevZ = Source.m_BlockZ;
+ int PrevR = Source.m_Radius;
+ for (size_t i = 0; i <= Num; ++i, ++itr)
{
int dx = itr->m_BlockX - PrevX;
int dy = itr->m_BlockY - PrevY;
@@ -310,9 +306,10 @@ void cCaveTunnel::FinishLinear(void)
std::swap(Pts, m_Points);
m_Points.reserve(Pts.size() * 3);
- int PrevX = Pts.front().m_BlockX;
- int PrevY = Pts.front().m_BlockY;
- int PrevZ = Pts.front().m_BlockZ;
+ cCaveDefPoint & PrevPoint = Pts.front();
+ int PrevX = PrevPoint.m_BlockX;
+ int PrevY = PrevPoint.m_BlockY;
+ int PrevZ = PrevPoint.m_BlockZ;
for (cCaveDefPoints::const_iterator itr = Pts.begin() + 1, end = Pts.end(); itr != end; ++itr)
{
int x1 = itr->m_BlockX;
@@ -433,9 +430,10 @@ void cCaveTunnel::FinishLinear(void)
void cCaveTunnel::CalcBoundingBox(void)
{
- m_MinBlockX = m_MaxBlockX = m_Points.front().m_BlockX;
- m_MinBlockY = m_MaxBlockY = m_Points.front().m_BlockY;
- m_MinBlockZ = m_MaxBlockZ = m_Points.front().m_BlockZ;
+ cCaveDefPoint & Point = m_Points.front();
+ m_MinBlockX = m_MaxBlockX = Point.m_BlockX;
+ m_MinBlockY = m_MaxBlockY = Point.m_BlockY;
+ m_MinBlockZ = m_MaxBlockZ = Point.m_BlockZ;
for (cCaveDefPoints::const_iterator itr = m_Points.begin() + 1, end = m_Points.end(); itr != end; ++itr)
{
m_MinBlockX = std::min(m_MinBlockX, itr->m_BlockX - itr->m_Radius);
@@ -576,17 +574,16 @@ AString cCaveTunnel::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) cons
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenWormNestCaves::cCaveSystem:
-cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) :
- m_BlockX(a_BlockX),
- m_BlockZ(a_BlockZ),
+cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) :
+ super(a_OriginX, a_OriginZ),
m_Size(a_Size)
{
- int Num = 1 + a_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) % 3;
+ int Num = 1 + a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) % 3;
for (int i = 0; i < Num; i++)
{
- int OriginX = a_BlockX + (a_Noise.IntNoise3DInt(13 * a_BlockX, 17 * a_BlockZ, 11 * i) / 19) % a_MaxOffset;
- int OriginZ = a_BlockZ + (a_Noise.IntNoise3DInt(17 * a_BlockX, 13 * a_BlockZ, 11 * i) / 23) % a_MaxOffset;
- int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_BlockX, 13 * a_BlockZ, 11 * i) / 17) % 20;
+ int OriginX = a_OriginX + (a_Noise.IntNoise3DInt(13 * a_OriginX, 17 * a_OriginZ, 11 * i) / 19) % a_MaxOffset;
+ int OriginZ = a_OriginZ + (a_Noise.IntNoise3DInt(17 * a_OriginX, 13 * a_OriginZ, 11 * i) / 23) % a_MaxOffset;
+ int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_OriginX, 13 * a_OriginZ, 11 * i) / 17) % 20;
// Generate three branches from the origin point:
// The tunnels generated depend on X, Y, Z and Branches,
@@ -612,64 +609,17 @@ cStructGenWormNestCaves::cCaveSystem::~cCaveSystem()
-void cStructGenWormNestCaves::cCaveSystem::ProcessChunk(
- int a_ChunkX, int a_ChunkZ,
- cChunkDef::BlockTypes & a_BlockTypes,
- cChunkDef::HeightMap & a_HeightMap
-)
-{
- for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr)
- {
- (*itr)->ProcessChunk(a_ChunkX, a_ChunkZ, a_BlockTypes, a_HeightMap);
- } // for itr - m_Tunnels[]
-}
-
-
-
-
-
-#ifdef _DEBUG
-AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const
+void cStructGenWormNestCaves::cCaveSystem::DrawIntoChunk(cChunkDesc & a_ChunkDesc)
{
- AString SVG;
- SVG.reserve(512 * 1024);
+ int ChunkX = a_ChunkDesc.GetChunkX();
+ int ChunkZ = a_ChunkDesc.GetChunkZ();
+ cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
+ cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap();
for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr)
{
- SVG.append((*itr)->ExportAsSVG(a_Color, a_OffsetX, a_OffsetZ));
+ (*itr)->ProcessChunk(ChunkX, ChunkZ, BlockTypes, HeightMap);
} // for itr - m_Tunnels[]
-
- // Base point highlight:
- AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
- a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ
- );
- AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
- a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5
- );
-
- // A gray line from the base point to the first point of the ravine, for identification:
- AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
- a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ,
- a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX,
- a_OffsetZ + m_Tunnels.front()->m_Points.front().m_BlockZ
- );
-
- // Offset guides:
- if (a_OffsetX > 0)
- {
- AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M %d,0 L %d,1024\"/>\n",
- a_OffsetX, a_OffsetX
- );
- }
- if (a_OffsetZ > 0)
- {
- AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M 0,%d L 1024,%d\"/>\n",
- a_OffsetZ, a_OffsetZ
- );
- }
-
- return SVG;
}
-#endif // _DEBUG
@@ -740,142 +690,9 @@ int cStructGenWormNestCaves::cCaveSystem::GetRadius(cNoise & a_Noise, int a_Orig
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenWormNestCaves:
-cStructGenWormNestCaves::~cStructGenWormNestCaves()
-{
- ClearCache();
-}
-
-
-
-
-
-void cStructGenWormNestCaves::ClearCache(void)
+cGridStructGen::cStructurePtr cStructGenWormNestCaves::CreateStructure(int a_OriginX, int a_OriginZ)
{
- for (cCaveSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
- {
- delete *itr;
- } // for itr - m_Cache[]
- m_Cache.clear();
-}
-
-
-
-
-
-void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc)
-{
- int ChunkX = a_ChunkDesc.GetChunkX();
- int ChunkZ = a_ChunkDesc.GetChunkZ();
- cCaveSystems Caves;
- GetCavesForChunk(ChunkX, ChunkZ, Caves);
- for (cCaveSystems::const_iterator itr = Caves.begin(); itr != Caves.end(); ++itr)
- {
- (*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap());
- } // for itr - Caves[]
-}
-
-
-
-
-
-void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenWormNestCaves::cCaveSystems & a_Caves)
-{
- int BaseX = a_ChunkX * cChunkDef::Width / m_Grid;
- int BaseZ = a_ChunkZ * cChunkDef::Width / m_Grid;
- 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_Caves:
- int StartX = BaseX * m_Grid;
- int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Grid;
- int StartZ = BaseZ * m_Grid;
- int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Grid;
- for (cCaveSystems::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_Caves.push_back(*itr);
- itr = m_Cache.erase(itr);
- }
- else
- {
- // don't want
- ++itr;
- }
- } // for itr - m_Cache[]
-
- for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
- {
- int RealX = (BaseX + x) * m_Grid;
- for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
- {
- int RealZ = (BaseZ + z) * m_Grid;
- bool Found = false;
- for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr)
- {
- if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
- {
- Found = true;
- break;
- }
- }
- if (!Found)
- {
- a_Caves.push_back(new cCaveSystem(RealX, RealZ, m_MaxOffset, m_Size, m_Noise));
- }
- }
- }
-
- // Copy a_Caves into m_Cache to the beginning:
- cCaveSystems CavesCopy(a_Caves);
- m_Cache.splice(m_Cache.begin(), CavesCopy, CavesCopy.begin(), CavesCopy.end());
-
- // Trim the cache if it's too long:
- if (m_Cache.size() > 100)
- {
- cCaveSystems::iterator itr = m_Cache.begin();
- std::advance(itr, 100);
- for (cCaveSystems::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());
- }
-
- /*
- // Uncomment this block for debugging the caves' shapes in 2D using an SVG export
- #ifdef _DEBUG
- AString SVG;
- SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n");
- SVG.reserve(2 * 1024 * 1024);
- for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr)
- {
- int Color = 0x10 * abs((*itr)->m_BlockX / m_Grid);
- Color |= 0x1000 * abs((*itr)->m_BlockZ / m_Grid);
- SVG.append((*itr)->ExportAsSVG(Color, 512, 512));
- }
- SVG.append("</svg>\n");
-
- AString fnam;
- Printf(fnam, "wnc\\%03d_%03d.svg", a_ChunkX, a_ChunkZ);
- cFile File(fnam, cFile::fmWrite);
- File.Write(SVG.c_str(), SVG.size());
- #endif // _DEBUG
- //*/
+ return cStructurePtr(new cCaveSystem(a_OriginX, a_OriginZ, m_MaxOffset, m_Size, m_Noise));
}
diff --git a/src/Generating/Caves.h b/src/Generating/Caves.h
index 7c45c056b..254dcddbd 100644
--- a/src/Generating/Caves.h
+++ b/src/Generating/Caves.h
@@ -12,7 +12,7 @@
#pragma once
-#include "ComposableGenerator.h"
+#include "GridStructGen.h"
#include "../Noise.h"
@@ -64,10 +64,12 @@ protected:
class cStructGenWormNestCaves :
- public cFinishGen
+ public cGridStructGen
{
+ typedef cGridStructGen super;
public:
cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) :
+ super(a_Seed, a_Grid, a_Grid, a_Size + a_MaxOffset, a_Size + a_MaxOffset, 100),
m_Noise(a_Seed),
m_Size(a_Size),
m_MaxOffset(a_MaxOffset),
@@ -75,26 +77,16 @@ public:
{
}
- ~cStructGenWormNestCaves();
-
protected:
class cCaveSystem; // fwd: Caves.cpp
- typedef std::list<cCaveSystem *> cCaveSystems;
cNoise m_Noise;
int m_Size; // relative size of the cave systems' caves. Average number of blocks of each initial tunnel
int m_MaxOffset; // maximum offset of the cave nest origin from the grid cell the nest belongs to
int m_Grid; // average spacing of the nests
- cCaveSystems m_Cache;
-
- /// Clears everything from the cache
- void ClearCache(void);
-
- /// Returns all caves that *may* intersect the given chunk. All the caves are valid until the next call to this function.
- void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves);
-
- // cStructGen override:
- virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cGridStructGen override:
+ virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 6c00b5905..4dd626ed4 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -21,9 +21,11 @@
#include "DistortedHeightmap.h"
#include "EndGen.h"
#include "MineShafts.h"
+#include "NetherFortGen.h"
#include "Noise3DGenerator.h"
#include "POCPieceGenerator.h"
#include "Ravines.h"
+#include "VillageGen.h"
@@ -31,6 +33,7 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cTerrainCompositionGen:
+
cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
{
AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
@@ -191,9 +194,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 +207,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 +360,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 +372,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));
@@ -389,6 +406,15 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
}
+ else if (NoCaseCompare(*itr, "Villages") == 0)
+ {
+ int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384);
+ int MaxDepth = a_IniFile.GetValueSetI("Generator", "VillageMaxDepth", 2);
+ int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
+ int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
+ int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
+ m_FinishGens.push_back(new cVillageGen(Seed, GridSize, MaxDepth, MaxSize, MinDensity, MaxDensity, *m_BiomeGen, *m_HeightGen));
+ }
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
diff --git a/src/Generating/GridStructGen.cpp b/src/Generating/GridStructGen.cpp
new file mode 100644
index 000000000..474242557
--- /dev/null
+++ b/src/Generating/GridStructGen.cpp
@@ -0,0 +1,168 @@
+
+// GridStructGen.cpp
+
+// Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid
+
+#include "Globals.h"
+#include "GridStructGen.h"
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cEmptyStructure:
+
+/** A cStructure descendant representing an empty structure.
+Used when the generator descended from cGridStructGen doesn't return any structure, to keep at least the
+Origin coords so that the structure isn't queried over and over again. */
+class cEmptyStructure :
+ public cGridStructGen::cStructure
+{
+ typedef cGridStructGen::cStructure super;
+
+public:
+ cEmptyStructure(int a_OriginX, int a_OriginZ) :
+ super(a_OriginX, a_OriginZ)
+ {
+ }
+
+protected:
+ virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override
+ {
+ // Do nothing
+ }
+} ;
+
+
+
+
+
+cGridStructGen::cGridStructGen(
+ int a_Seed,
+ int a_GridSizeX, int a_GridSizeZ,
+ int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
+ size_t a_MaxCacheSize
+) :
+ m_Seed(a_Seed),
+ m_GridSizeX(a_GridSizeX),
+ m_GridSizeZ(a_GridSizeZ),
+ m_MaxStructureSizeX(a_MaxStructureSizeX),
+ m_MaxStructureSizeZ(a_MaxStructureSizeZ),
+ m_MaxCacheSize(a_MaxCacheSize)
+{
+ size_t NumStructuresPerQuery = (size_t)((m_MaxStructureSizeX / m_GridSizeX + 1) * (m_MaxStructureSizeZ / m_GridSizeZ + 1));
+ if (NumStructuresPerQuery > m_MaxCacheSize)
+ {
+ m_MaxCacheSize = NumStructuresPerQuery * 4;
+ LOGINFO(
+ "cGridStructGen: The cache size is too small (%u), increasing the cache size to %u to avoid inefficiency.",
+ (unsigned)a_MaxCacheSize, (unsigned)m_MaxCacheSize
+ );
+ }
+}
+
+
+
+
+
+void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures)
+{
+ // Calculate the min and max grid coords of the structures to be returned:
+ int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX;
+ int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ;
+ int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + cChunkDef::Width - 1;
+ int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + cChunkDef::Width - 1;
+ int MinGridX = MinBlockX / m_GridSizeX;
+ int MinGridZ = MinBlockZ / m_GridSizeZ;
+ int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX;
+ int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ;
+ int MinX = MinGridX * m_GridSizeX;
+ int MaxX = MaxGridX * m_GridSizeX;
+ int MinZ = MinGridZ * m_GridSizeZ;
+ int MaxZ = MaxGridZ * m_GridSizeZ;
+
+ // Walk the cache, move each structure that we want into a_Structures:
+ for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
+ {
+ if (
+ ((*itr)->m_OriginX >= MinX) && ((*itr)->m_OriginX < MaxX) &&
+ ((*itr)->m_OriginZ >= MinZ) && ((*itr)->m_OriginZ < MaxZ)
+ )
+ {
+ // want
+ a_Structures.push_back(*itr);
+ itr = m_Cache.erase(itr);
+ }
+ else
+ {
+ // don't want
+ ++itr;
+ }
+ } // for itr - m_Cache[]
+
+ // Create those structures that haven't been in the cache:
+ for (int x = MinGridX; x < MaxGridX; x++)
+ {
+ int OriginX = x * m_GridSizeX;
+ for (int z = MinGridZ; z < MaxGridZ; z++)
+ {
+ int OriginZ = z * m_GridSizeZ;
+ bool Found = false;
+ for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr)
+ {
+ if (((*itr)->m_OriginX == OriginX) && ((*itr)->m_OriginZ == OriginZ))
+ {
+ Found = true;
+ break;
+ }
+ } // for itr - a_Structures[]
+ if (!Found)
+ {
+ cStructurePtr Structure = CreateStructure(OriginX, OriginZ);
+ if (Structure.get() == NULL)
+ {
+ Structure.reset(new cEmptyStructure(OriginX, OriginZ));
+ }
+ a_Structures.push_back(Structure);
+ }
+ } // for z
+ } // for x
+
+ // Copy a_Forts into m_Cache to the beginning:
+ cStructurePtrs StructuresCopy (a_Structures);
+ m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end());
+
+ // Trim the cache if it's too long:
+ size_t CacheSize = 0;
+ for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
+ {
+ CacheSize += (*itr)->GetCacheCost();
+ if (CacheSize > m_MaxCacheSize)
+ {
+ // Erase all items from this one till the cache end
+ m_Cache.erase(itr, m_Cache.end());
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cGridStructGen::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int ChunkX = a_ChunkDesc.GetChunkX();
+ int ChunkZ = a_ChunkDesc.GetChunkZ();
+ cStructurePtrs Structures;
+ GetStructuresForChunk(ChunkX, ChunkZ, Structures);
+ for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr)
+ {
+ (*itr)->DrawIntoChunk(a_ChunkDesc);
+ } // for itr - Structures[]
+}
+
+
+
+
+
diff --git a/src/Generating/GridStructGen.h b/src/Generating/GridStructGen.h
new file mode 100644
index 000000000..630a5e44e
--- /dev/null
+++ b/src/Generating/GridStructGen.h
@@ -0,0 +1,124 @@
+
+// GridStructGen.h
+
+// Declares the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+
+
+
+
+
+/** Generates structures in a semi-random grid.
+Defines a grid in the XZ space with predefined cell size in each direction. Each cell then receives exactly
+one structure (provided by the descendant class). The structure is placed within the cell, but doesn't need
+to be bounded by the cell, it can be well outside the cell; the generator uses the MaxStructureSize parameter
+to determine how far away from the cell the structure can be at most.
+This class provides a cache for the structures generated for successive chunks and manages that cache. It
+also provides the cFinishGen override that uses the cache to actually generate the structure into chunk data.
+
+After generating each chunk the cache is checked for size, each item in the cache has a cost associated with
+it and the cache is trimmed (from its least-recently-used end) so that the sum of the cost in the cache is
+less than m_MaxCacheSize
+
+To use this class, declare a descendant class that implements the overridable methods, then create an
+instance of that class. The descendant must provide the CreateStructure() function that is called to generate
+a structure at the specific grid cell.
+
+The descendant must use a specific cStructure descendant to provide the actual structure that gets generated.
+The structure must provide the DrawIntoChunk() function that generates the structure into the chunk data, and
+can override the GetCacheCost() function that returns the cost of that structure in the cache.
+*/
+class cGridStructGen :
+ public cFinishGen
+{
+public:
+ /** Represents a single structure that occupies the grid point. Knows how to draw itself into a chunk. */
+ class cStructure
+ {
+ public:
+ /** The origin (the coords of the gridpoint for which the structure is generated) */
+ int m_OriginX, m_OriginZ;
+
+
+ /** Creates a structure that has its originset at the specified coords. */
+ cStructure (int a_OriginX, int a_OriginZ) :
+ m_OriginX(a_OriginX),
+ m_OriginZ(a_OriginZ)
+ {
+ }
+
+ // Force a virtual destructor in descendants:
+ virtual ~cStructure() {}
+
+ /** Draws self into the specified chunk */
+ virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) = 0;
+
+ /** Returns the cost of keeping this structure in the cache */
+ virtual size_t GetCacheCost(void) const { return 1; }
+ } ;
+ typedef SharedPtr<cStructure> cStructurePtr;
+ typedef std::list<cStructurePtr> cStructurePtrs;
+
+
+ cGridStructGen(
+ int a_Seed,
+ int a_GridSizeX, int a_GridSizeZ,
+ int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
+ size_t a_MaxCacheSize
+ );
+
+protected:
+ /** Seed for generating the semi-random grid. */
+ int m_Seed;
+
+ /** The size of each grid's cell in the X axis */
+ int m_GridSizeX;
+
+ /** The size of each grid's cell in the Z axis */
+ int m_GridSizeZ;
+
+ /** Maximum theoretical size of the structure in the X axis.
+ This limits the structures considered for a single chunk, so the lesser the number, the better performance.
+ Structures large than this may get cropped. */
+ int m_MaxStructureSizeX;
+
+ /** Maximum theoretical size of the structure in the Z axis.
+ This limits the structures considered for a single chunk, so the lesser the number, the better performance.
+ Structures large than this may get cropped. */
+ int m_MaxStructureSizeZ;
+
+ /** Maximum allowed sum of costs for items in the cache. Items that are over this cost are removed from the
+ cache, oldest-first */
+ size_t m_MaxCacheSize;
+
+ /** Cache for the most recently generated structures, ordered by the recentness. */
+ cStructurePtrs m_Cache;
+
+
+ /** Clears everything from the cache */
+ void ClearCache(void);
+
+ /** Returns all structures that may intersect the given chunk.
+ The structures are considered as intersecting iff their bounding box (defined by m_MaxStructureSize)
+ around their gridpoint intersects the chunk. */
+ void GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures);
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // Functions for the descendants to override:
+ /** Create a new structure at the specified gridpoint */
+ virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) = 0;
+} ;
+
+
+
+
+
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index 28dc37567..81ae6481d 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -25,12 +25,6 @@ in a depth-first processing. Each of the descendants will branch randomly, if no
-static const int NEIGHBORHOOD_SIZE = 3;
-
-
-
-
-
class cMineShaft abstract
{
public:
@@ -234,10 +228,12 @@ protected:
-class cStructGenMineShafts::cMineShaftSystem
+class cStructGenMineShafts::cMineShaftSystem :
+ public cGridStructGen::cStructure
{
+ typedef cGridStructGen::cStructure super;
+
public:
- int m_BlockX, m_BlockZ; ///< The pivot point on which the system is generated
int m_GridSize; ///< Maximum offset of the dirtroom from grid center, * 2, in each direction
int m_MaxRecursion; ///< Maximum recursion level (initialized from cStructGenMineShafts::m_MaxRecursion)
int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
@@ -249,17 +245,15 @@ public:
cMineShafts m_MineShafts; ///< List of cMineShaft descendants that comprise this system
cCuboid m_BoundingBox; ///< Bounding box into which all of the components need to fit
- /// Creates and generates the entire system
+
+ /** Creates and generates the entire system */
cMineShaftSystem(
- int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
+ int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
);
~cMineShaftSystem();
- /// Carves the system into the chunk data
- void ProcessChunk(cChunkDesc & a_Chunk);
-
/** Creates new cMineShaft descendant connected at the specified point, heading the specified direction,
if it fits, appends it to the list and calls its AppendBranches()
*/
@@ -269,8 +263,11 @@ public:
int a_RecursionLevel
);
- /// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid
+ /** Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid */
bool CanAppend(const cCuboid & a_BoundingBox);
+
+ // cGridStructGen::cStructure overrides:
+ virtual void DrawIntoChunk(cChunkDesc & a_Chunk);
} ;
@@ -281,11 +278,10 @@ public:
// cStructGenMineShafts::cMineShaftSystem:
cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem(
- int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
+ int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
) :
- m_BlockX(a_BlockX),
- m_BlockZ(a_BlockZ),
+ super(a_OriginX, a_OriginZ),
m_GridSize(a_GridSize),
m_MaxRecursion(8), // TODO: settable
m_ProbLevelCorridor(a_ProbLevelCorridor),
@@ -330,7 +326,7 @@ cStructGenMineShafts::cMineShaftSystem::~cMineShaftSystem()
-void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk)
+void cStructGenMineShafts::cMineShaftSystem::DrawIntoChunk(cChunkDesc & a_Chunk)
{
for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
{
@@ -409,15 +405,15 @@ cMineShaftDirtRoom::cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem &
super(a_Parent, mskDirtRoom)
{
// Make the room of random size, min 10 x 4 x 10; max 18 x 12 x 18:
- int rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 0, a_Parent.m_BlockZ) / 7;
+ int rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 0, a_Parent.m_OriginZ) / 7;
int OfsX = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
rnd >>= 12;
int OfsZ = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
- rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 1000, a_Parent.m_BlockZ) / 11;
- m_BoundingBox.p1.x = a_Parent.m_BlockX + OfsX;
+ rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 1000, a_Parent.m_OriginZ) / 11;
+ m_BoundingBox.p1.x = a_Parent.m_OriginX + OfsX;
m_BoundingBox.p2.x = m_BoundingBox.p1.x + 10 + (rnd % 8);
rnd >>= 4;
- m_BoundingBox.p1.z = a_Parent.m_BlockZ + OfsZ;
+ m_BoundingBox.p1.z = a_Parent.m_OriginZ + OfsZ;
m_BoundingBox.p2.z = m_BoundingBox.p1.z + 10 + (rnd % 8);
rnd >>= 4;
m_BoundingBox.p1.y = 20;
@@ -543,7 +539,7 @@ cMineShaft * cMineShaftCorridor::CreateAndFit(
{
cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ);
BoundingBox.p2.y += 3;
- int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
+ int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
int NumSegments = 2 + (rnd) % (MAX_SEGMENTS - 1); // 2 .. MAX_SEGMENTS
switch (a_Direction)
{
@@ -985,7 +981,7 @@ cMineShaft * cMineShaftCrossing::CreateAndFit(
)
{
cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ);
- int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
+ int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
BoundingBox.p2.y += 3;
if ((rnd % 4) < 2)
{
@@ -1127,7 +1123,7 @@ cMineShaft * cMineShaftStaircase::CreateAndFit(
cNoise & a_Noise
)
{
- int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
+ int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
cCuboid Box;
switch (a_Direction)
{
@@ -1287,6 +1283,7 @@ cStructGenMineShafts::cStructGenMineShafts(
int a_Seed, int a_GridSize, int a_MaxSystemSize,
int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase
) :
+ super(a_Seed, a_GridSize, a_GridSize, a_MaxSystemSize, a_MaxSystemSize, 100),
m_Noise(a_Seed),
m_GridSize(a_GridSize),
m_MaxSystemSize(a_MaxSystemSize),
@@ -1300,125 +1297,9 @@ cStructGenMineShafts::cStructGenMineShafts(
-cStructGenMineShafts::~cStructGenMineShafts()
-{
- ClearCache();
-}
-
-
-
-
-
-void cStructGenMineShafts::ClearCache(void)
-{
- for (cMineShaftSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
- {
- delete *itr;
- } // for itr - m_Cache[]
- m_Cache.clear();
-}
-
-
-
-
-
-void cStructGenMineShafts::GetMineShaftSystemsForChunk(
- int a_ChunkX, int a_ChunkZ,
- cStructGenMineShafts::cMineShaftSystems & a_MineShafts
-)
-{
- 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_Caves:
- 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 (cMineShaftSystems::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_MineShafts.push_back(*itr);
- itr = m_Cache.erase(itr);
- }
- else
- {
- // don't want
- ++itr;
- }
- } // for itr - m_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 (cMineShaftSystems::const_iterator itr = a_MineShafts.begin(), end = a_MineShafts.end(); itr != end; ++itr)
- {
- if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
- {
- Found = true;
- break;
- }
- } // for itr - a_Mineshafts
- if (!Found)
- {
- a_MineShafts.push_back(new cMineShaftSystem(RealX, RealZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase));
- }
- } // for z
- } // for x
-
- // Copy a_MineShafts into m_Cache to the beginning:
- cMineShaftSystems MineShaftsCopy(a_MineShafts);
- m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end());
-
- // Trim the cache if it's too long:
- if (m_Cache.size() > 100)
- {
- cMineShaftSystems::iterator itr = m_Cache.begin();
- std::advance(itr, 100);
- for (cMineShaftSystems::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 cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc)
+cGridStructGen::cStructurePtr cStructGenMineShafts::CreateStructure(int a_OriginX, int a_OriginZ)
{
- int ChunkX = a_ChunkDesc.GetChunkX();
- int ChunkZ = a_ChunkDesc.GetChunkZ();
- cMineShaftSystems MineShafts;
- GetMineShaftSystemsForChunk(ChunkX, ChunkZ, MineShafts);
- for (cMineShaftSystems::const_iterator itr = MineShafts.begin(); itr != MineShafts.end(); ++itr)
- {
- (*itr)->ProcessChunk(a_ChunkDesc);
- } // for itr - MineShafts[]
+ return cStructurePtr(new cMineShaftSystem(a_OriginX, a_OriginZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase));
}
diff --git a/src/Generating/MineShafts.h b/src/Generating/MineShafts.h
index ba32e75ad..c29b6cdac 100644
--- a/src/Generating/MineShafts.h
+++ b/src/Generating/MineShafts.h
@@ -9,7 +9,7 @@
#pragma once
-#include "ComposableGenerator.h"
+#include "GridStructGen.h"
#include "../Noise.h"
@@ -17,16 +17,16 @@
class cStructGenMineShafts :
- public cFinishGen
+ public cGridStructGen
{
+ typedef cGridStructGen super;
+
public:
cStructGenMineShafts(
int a_Seed, int a_GridSize, int a_MaxSystemSize,
int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase
);
- virtual ~cStructGenMineShafts();
-
protected:
friend class cMineShaft;
friend class cMineShaftDirtRoom;
@@ -34,26 +34,16 @@ protected:
friend class cMineShaftCrossing;
friend class cMineShaftStaircase;
class cMineShaftSystem; // fwd: MineShafts.cpp
- typedef std::list<cMineShaftSystem *> cMineShaftSystems;
- cNoise m_Noise;
- int m_GridSize; ///< Average spacing of the systems
- int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system
- int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
- int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor
- int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing
- cMineShaftSystems m_Cache; ///< Cache of the most recently used systems. MoveToFront used.
+ cNoise m_Noise;
+ int m_GridSize; ///< Average spacing of the systems
+ int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system
+ int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
+ int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor
+ int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing
- /// Clears everything from the cache
- void ClearCache(void);
-
- /** Returns all systems that *may* intersect the given chunk.
- All the systems are valid until the next call to this function (which may delete some of the pointers).
- */
- void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems);
-
- // cFinishGen overrides:
- virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+ // cGridStructGen overrides:
+ virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;
diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp
new file mode 100644
index 000000000..3867ec80c
--- /dev/null
+++ b/src/Generating/NetherFortGen.cpp
@@ -0,0 +1,131 @@
+
+// NetherFortGen.cpp
+
+// Implements the cNetherFortGen class representing the nether fortress generator
+
+#include "Globals.h"
+#include "NetherFortGen.h"
+#include "Prefabs/NetherFortPrefabs.h"
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen::cNetherFort:
+
+class cNetherFortGen::cNetherFort :
+ public cGridStructGen::cStructure
+{
+ typedef cGridStructGen::cStructure super;
+
+public:
+ cNetherFortGen & m_ParentGen;
+ int m_GridSize;
+ int m_Seed;
+ cPlacedPieces m_Pieces;
+
+
+ cNetherFort(cNetherFortGen & a_ParentGen, int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxDepth, int a_Seed) :
+ super(a_OriginX, a_OriginZ),
+ m_ParentGen(a_ParentGen),
+ 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(cNetherFortGen::m_PiecePool, a_Seed + i);
+ pg.PlacePieces(a_OriginX, BlockY, a_OriginZ, a_MaxDepth, m_Pieces);
+ }
+ }
+
+
+ ~cNetherFort()
+ {
+ cPieceGenerator::FreePieces(m_Pieces);
+ }
+
+
+ /** Carves the system into the chunk data */
+ virtual void DrawIntoChunk(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[]
+ }
+};
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Performance test of the NetherFort generator:
+
+/*
+#include "OSSupport/Timer.h"
+static class cNetherFortPerfTest
+{
+public:
+ cNetherFortPerfTest(void)
+ {
+ cTimer Timer;
+ long long StartTime = Timer.GetNowTime();
+
+ const int GridSize = 512;
+ const int MaxDepth = 12;
+ const int NumIterations = 100;
+ for (int i = 0; i < NumIterations; i++)
+ {
+ cNetherFortGen FortGen(i, GridSize, MaxDepth);
+ delete new cNetherFortGen::cNetherFort(FortGen, 0, 0, GridSize, MaxDepth, i);
+ }
+
+ long long EndTime = Timer.GetNowTime();
+ printf("%d forts took %lld msec (%f sec) to generate\n", NumIterations, EndTime - StartTime, ((double)(EndTime - StartTime)) / 1000);
+ exit(0);
+ }
+
+} g_PerfTest;
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen:
+
+cPrefabPiecePool cNetherFortGen::m_PiecePool(g_NetherFortPrefabs, g_NetherFortPrefabsCount, g_NetherFortStartingPrefabs, g_NetherFortStartingPrefabsCount);
+
+
+
+
+
+cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) :
+ super(a_Seed, a_GridSize, a_GridSize, a_MaxDepth * 10, a_MaxDepth * 10, 200),
+ m_MaxDepth(a_MaxDepth)
+{
+ /*
+ // DEBUG: Try one round of placement:
+ cPlacedPieces Pieces;
+ cBFSPieceGenerator pg(m_PiecePool, a_Seed);
+ pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces);
+ //*/
+}
+
+
+
+
+
+cGridStructGen::cStructurePtr cNetherFortGen::CreateStructure(int a_OriginX, int a_OriginZ)
+{
+ return cStructurePtr(new cNetherFort(*this, a_OriginX, a_OriginZ, m_GridSizeX, m_MaxDepth, m_Seed));
+}
+
diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h
new file mode 100644
index 000000000..f35801a3c
--- /dev/null
+++ b/src/Generating/NetherFortGen.h
@@ -0,0 +1,45 @@
+
+// NetherFortGen.h
+
+// Declares the cNetherFortGen class representing the nether fortress generator
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+#include "PrefabPiecePool.h"
+#include "GridStructGen.h"
+
+
+
+
+
+class cNetherFortGen :
+ public cGridStructGen
+{
+ typedef cGridStructGen super;
+
+public:
+ cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth);
+
+protected:
+ friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp
+ class cNetherFort; // fwd: NetherFortGen.cpp
+
+ /** Maximum depth of the piece-generator tree */
+ int m_MaxDepth;
+
+ /** The pool of pieces to use for generating. Static, so that it's shared by multiple generators. */
+ static cPrefabPiecePool m_PiecePool;
+
+
+ // cGridStructGen overrides:
+ virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
+} ;
+
+
+
+
diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp
index 9ed4b565e..491f4d206 100644
--- a/src/Generating/POCPieceGenerator.cpp
+++ b/src/Generating/POCPieceGenerator.cpp
@@ -186,6 +186,11 @@ cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) :
cPOCPieceGenerator::~cPOCPieceGenerator()
{
cPieceGenerator::FreePieces(m_Pieces);
+ for (cPieces::iterator itr = m_AvailPieces.begin(), end = m_AvailPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ m_AvailPieces.clear();
}
diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp
index 8999a5ff7..5de231f75 100644
--- a/src/Generating/PieceGenerator.cpp
+++ b/src/Generating/PieceGenerator.cpp
@@ -286,7 +286,8 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece
m_Parent(a_Parent),
m_Piece(&a_Piece),
m_Coords(a_Coords),
- m_NumCCWRotations(a_NumCCWRotations)
+ m_NumCCWRotations(a_NumCCWRotations),
+ m_HasBeenMovedToGround(false)
{
m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
@@ -297,6 +298,36 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece
+cPiece::cConnector cPlacedPiece::GetRotatedConnector(size_t a_Index) const
+{
+ cPiece::cConnectors Connectors = m_Piece->GetConnectors();
+ ASSERT(Connectors.size() >= a_Index);
+ return m_Piece->RotateMoveConnector(Connectors[a_Index], m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z);
+}
+
+
+
+
+
+cPiece::cConnector cPlacedPiece::GetRotatedConnector(const cPiece::cConnector & a_Connector) const
+{
+ return m_Piece->RotateMoveConnector(a_Connector, m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z);
+}
+
+
+
+
+
+void cPlacedPiece::MoveToGroundBy(int a_OffsetY)
+{
+ m_Coords.y += a_OffsetY;
+ m_HasBeenMovedToGround = true;
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPieceGenerator:
@@ -331,7 +362,31 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i
// Choose a random one of the starting pieces:
cPieces StartingPieces = m_PiecePool.GetStartingPieces();
- cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()];
+ int Total = 0;
+ for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
+ {
+ Total += m_PiecePool.GetStartingPieceWeight(**itr);
+ }
+ cPiece * StartingPiece;
+ if (Total > 0)
+ {
+ int Chosen = rnd % Total;
+ StartingPiece = StartingPieces.front();
+ for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
+ {
+ Chosen -= m_PiecePool.GetStartingPieceWeight(**itr);
+ if (Chosen <= 0)
+ {
+ StartingPiece = *itr;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // All pieces returned zero weight, but we need one to start. Choose with equal chance:
+ StartingPiece = StartingPieces[rnd % StartingPieces.size()];
+ }
rnd = rnd >> 16;
// Choose a random supported rotation:
@@ -339,9 +394,9 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i
int NumRotations = 1;
for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
{
- if (StartingPiece->CanRotateCCW(i))
+ if (StartingPiece->CanRotateCCW((int)i))
{
- Rotations[NumRotations] = i;
+ Rotations[NumRotations] = (int)i;
NumRotations += 1;
}
}
@@ -388,22 +443,26 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// Get a list of available connections:
const int * RotTable = DirectionRotationTable[a_Connector.m_Direction];
cConnections Connections;
- cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type);
+ int WantedConnectorType = -a_Connector.m_Type;
+ cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType);
Connections.reserve(AvailablePieces.size());
Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
-
- /*
- // DEBUG:
- printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
- //*/
-
+ int WeightTotal = 0;
for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
{
+ // Get the relative chance of this piece being generated in this path:
+ int Weight = m_PiecePool.GetPieceWeight(a_ParentPiece, a_Connector, **itrP);
+ if (Weight <= 0)
+ {
+ continue;
+ }
+
+ // Try fitting each of the piece's connector:
cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
{
- if (itrC->m_Type != a_Connector.m_Type)
+ if (itrC->m_Type != WantedConnectorType)
{
continue;
}
@@ -419,7 +478,9 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// Doesn't fit in this rotation
continue;
}
- Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
+ // Fits, add it to list of possibile connections:
+ Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations, Weight));
+ WeightTotal += Weight;
} // for itrC - Connectors[]
} // for itrP - AvailablePieces[]
if (Connections.empty())
@@ -427,21 +488,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// No available connections, bail out
return false;
}
+ ASSERT(WeightTotal > 0);
- // Choose a random connection from the list:
- int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
- cConnection & Conn = Connections[rnd % Connections.size()];
+ // Choose a random connection from the list, based on the weights:
+ int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal;
+ size_t ChosenIndex = 0;
+ for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex)
+ {
+ rnd -= itr->m_Weight;
+ if (rnd <= 0)
+ {
+ // This is the piece to choose
+ break;
+ }
+ }
+ cConnection & Conn = Connections[ChosenIndex];
// Place the piece:
- /*
- // DEBUG
- printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
- Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
- BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
- Conn.m_NumCCWRotations
- );
- //*/
-
Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
ConnPos -= NewPos;
cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
@@ -449,12 +512,6 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// Add the new piece's connectors to the list of free connectors:
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
-
- /*
- // DEBUG:
- printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
- //*/
-
for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
{
if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
@@ -524,10 +581,11 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPieceGenerator::cConnection:
-cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
+cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight) :
m_Piece(&a_Piece),
m_Connector(a_Connector),
- m_NumCCWRotations(a_NumCCWRotations)
+ m_NumCCWRotations(a_NumCCWRotations),
+ m_Weight(a_Weight)
{
}
diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h
index bef9d3463..fd8576706 100644
--- a/src/Generating/PieceGenerator.h
+++ b/src/Generating/PieceGenerator.h
@@ -38,7 +38,8 @@ public:
/** Position relative to the piece */
Vector3i m_Pos;
- /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */
+ /** Type of the connector. Any arbitrary number; the generator connects only connectors of opposite
+ (negative) types. */
int m_Type;
/** Direction in which the connector is facing.
@@ -85,6 +86,13 @@ typedef std::vector<cPiece *> cPieces;
+// fwd:
+class cPlacedPiece;
+
+
+
+
+
/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
placed and adjust the returned piece vectors. */
class cPiecePool
@@ -101,6 +109,26 @@ public:
Multiple starting points are supported, one of the returned piece will be chosen. */
virtual cPieces GetStartingPieces(void) = 0;
+ /** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector.
+ a_ExistingConnector is the original connector, before any movement or rotation is applied to it.
+ This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used.
+ The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen.
+ */
+ virtual int GetPieceWeight(
+ const cPlacedPiece & a_PlacedPiece,
+ const cPiece::cConnector & a_ExistingConnector,
+ const cPiece & a_NewPiece
+ ) { return 1; }
+
+ /** Returns the relative weight with which the a_NewPiece is to be selected for placing as the first piece.
+ This allows the pool to tweak the piece's chances.
+ The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will not be chosen.
+ If all pieces return 0, a random piece is chosen, with all equal chances.
+ */
+ virtual int GetStartingPieceWeight(
+ const cPiece & a_NewPiece
+ ) { return 1; }
+
/** Called after a piece is placed, to notify the pool that it has been used.
The pool may adjust the pieces it will return the next time. */
virtual void PiecePlaced(const cPiece & a_Piece) = 0;
@@ -120,19 +148,41 @@ class cPlacedPiece
public:
cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations);
- const cPiece & GetPiece (void) const { return *m_Piece; }
- const Vector3i & GetCoords (void) const { return m_Coords; }
- int GetNumCCWRotations(void) const { return m_NumCCWRotations; }
- const cCuboid & GetHitBox (void) const { return m_HitBox; }
- int GetDepth (void) const { return m_Depth; }
+ const cPlacedPiece * GetParent (void) const { return m_Parent; }
+ const cPiece & GetPiece (void) const { return *m_Piece; }
+ const Vector3i & GetCoords (void) const { return m_Coords; }
+ int GetNumCCWRotations (void) const { return m_NumCCWRotations; }
+ const cCuboid & GetHitBox (void) const { return m_HitBox; }
+ int GetDepth (void) const { return m_Depth; }
+ bool HasBeenMovedToGround(void) const { return m_HasBeenMovedToGround; }
+
+ /** Returns the coords as a modifiable object. */
+ Vector3i & GetCoords(void) { return m_Coords; }
+
+ /** Returns the connector at the specified index, rotated in the actual placement.
+ Undefined behavior if a_Index is out of range. */
+ cPiece::cConnector GetRotatedConnector(size_t a_Index) const;
+
+ /** Returns a copy of the specified connector, modified to account for the translation and rotation for
+ this placement. */
+ cPiece::cConnector GetRotatedConnector(const cPiece::cConnector & a_Connector) const;
+
+ /** Moves the placed piece Y-wise by the specified offset.
+ Sets m_HasBeenMovedToGround to true, too.
+ Used eg. by village houses. */
+ void MoveToGroundBy(int a_OffsetY);
protected:
const cPlacedPiece * m_Parent;
const cPiece * m_Piece;
Vector3i m_Coords;
int m_NumCCWRotations;
- cCuboid m_HitBox;
- int m_Depth;
+ cCuboid m_HitBox; // Hitbox of the placed piece, in world coords
+ int m_Depth; // Depth in the generated piece tree
+
+ /** Set to true once the piece has been moved Y-wise.
+ Used eg. by village houses. */
+ bool m_HasBeenMovedToGround;
};
typedef std::vector<cPlacedPiece *> cPlacedPieces;
@@ -157,8 +207,9 @@ protected:
cPiece * m_Piece; // The piece being connected
cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
+ int m_Weight; // Relative chance that this connection will be chosen
- cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations);
+ cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight);
};
typedef std::vector<cConnection> cConnections;
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
index 1af1faec1..2ab1455b9 100644
--- a/src/Generating/Prefab.cpp
+++ b/src/Generating/Prefab.cpp
@@ -15,18 +15,159 @@ uses a prefabricate in a cBlockArea for drawing itself.
+#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
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 5, 6, // MaxX, MaxY, MaxZ
+
+ // 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,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 1000,
+
+ // MoveToGround:
+ false,
+};
+
+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_HitBox(
+ a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ,
+ a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ
+ ),
m_AllowedRotations(a_Def.m_AllowedRotations),
- m_MergeStrategy(a_Def.m_MergeStrategy)
+ m_MergeStrategy(a_Def.m_MergeStrategy),
+ m_ShouldExtendFloor(a_Def.m_ShouldExtendFloor),
+ m_DefaultWeight(a_Def.m_DefaultWeight),
+ m_AddWeightIfSame(a_Def.m_AddWeightIfSame),
+ m_MoveToGround(a_Def.m_MoveToGround)
{
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);
+ ParseDepthWeight(a_Def.m_DepthWeight);
+ AddRotatedBlockAreas();
+}
+
+
+
+
+
+cPrefab::cPrefab(const cBlockArea & a_Image, int a_AllowedRotations) :
+ m_Size(a_Image.GetSize()),
+ m_AllowedRotations(a_AllowedRotations),
+ m_MergeStrategy(cBlockArea::msOverwrite),
+ m_ShouldExtendFloor(false),
+ m_DefaultWeight(1),
+ m_AddWeightIfSame(0),
+ m_MoveToGround(false)
+{
+ m_HitBox.p1.Set(0, 0, 0);
+ m_HitBox.p2.Set(m_Size.x - 1, m_Size.y - 1, m_Size.z - 1);
+ m_BlockArea[0].CopyFrom(a_Image);
+ AddRotatedBlockAreas();
+}
+
+
+
+
+
+void cPrefab::AddRotatedBlockAreas(void)
+{
// 1 CCW rotation:
if ((m_AllowedRotations & 0x01) != 0)
{
@@ -56,12 +197,64 @@ cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
{
- Vector3i Placement = a_Placement->GetCoords();
+ Draw(a_Dest, a_Placement->GetCoords(), a_Placement->GetNumCCWRotations());
+}
+
+
+
+
+void cPrefab::Draw(cChunkDesc & a_Dest, const Vector3i & a_Placement, int a_NumRotations) const
+{
+ // Draw the basic image:
+ Vector3i Placement(a_Placement);
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);
+ const cBlockArea & Image = m_BlockArea[a_NumRotations];
+ a_Dest.WriteBlockArea(Image, Placement.x, Placement.y, Placement.z, m_MergeStrategy);
+ // If requested, draw the floor (from the bottom of the prefab down to the nearest non-air)
+ if (m_ShouldExtendFloor)
+ {
+ int MaxX = Image.GetSizeX();
+ int MaxZ = Image.GetSizeZ();
+ for (int z = 0; z < MaxZ; z++)
+ {
+ int RelZ = Placement.z + z;
+ if ((RelZ < 0) || (RelZ >= cChunkDef::Width))
+ {
+ // Z coord outside the chunk
+ continue;
+ }
+ for (int x = 0; x < MaxX; x++)
+ {
+ int RelX = Placement.x + x;
+ if ((RelX < 0) || (RelX >= cChunkDef::Width))
+ {
+ // X coord outside the chunk
+ continue;
+ }
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ Image.GetRelBlockTypeMeta(x, 0, z, BlockType, BlockMeta);
+ if ((BlockType == E_BLOCK_AIR) || (BlockType == E_BLOCK_SPONGE))
+ {
+ // Do not expand air nor sponge blocks
+ continue;
+ }
+ for (int y = Placement.y - 1; y >= 0; y--)
+ {
+ BLOCKTYPE ExistingBlock = a_Dest.GetBlockType(RelX, y, RelZ);
+ if (ExistingBlock != E_BLOCK_AIR)
+ {
+ // End the expansion for this column, reached the end
+ break;
+ }
+ a_Dest.SetBlockTypeMeta(RelX, y, RelZ, BlockType, BlockMeta);
+ } // for y
+ } // for x
+ } // for z
+ }
}
@@ -84,12 +277,53 @@ bool cPrefab::HasConnectorType(int a_ConnectorType) const
+int cPrefab::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector) const
+{
+ // Use the default or per-depth weight:
+ cDepthWeight::const_iterator itr = m_DepthWeight.find(a_PlacedPiece.GetDepth() + 1);
+ int res = (itr == m_DepthWeight.end()) ? m_DefaultWeight : itr->second;
+
+ // If the piece is the same as the parent, apply the m_AddWeightIfSame modifier:
+ const cPiece * ParentPiece = &a_PlacedPiece.GetPiece();
+ const cPiece * ThisPiece = this;
+ if (ThisPiece == ParentPiece)
+ {
+ res += m_AddWeightIfSame;
+ }
+ return res;
+}
+
+
+
+
+
+void cPrefab::SetDefaultWeight(int a_DefaultWeight)
+{
+ m_DefaultWeight = a_DefaultWeight;
+}
+
+
+
+
+
+void cPrefab::AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Direction, int a_Type)
+{
+ m_Connectors.push_back(cConnector(a_RelX, a_RelY, a_RelZ, a_Type, a_Direction));
+}
+
+
+
+
+
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] = -1;
+ 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:
@@ -104,15 +338,15 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
continue;
}
unsigned char Src = (unsigned char)CharDef[0][0];
- BLOCKTYPE BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
+ 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));
+ ASSERT((BlockMeta <= 15));
}
- ASSERT(a_CharMapOut[Src] == -1); // Any duplicates letter-wise?
- a_CharMapOut[Src] = (BlockType << 4) | BlockMeta;
+ a_CharMapOut[Src].m_BlockMeta = BlockMeta;
} // for itr - Lines[]
}
@@ -130,11 +364,9 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma
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++)
{
- int MappedValue = a_CharMap[BlockImage[x]];
- ASSERT(MappedValue != -1); // Using a letter not defined in the CharMap?
- BLOCKTYPE BlockType = MappedValue >> 4;
- NIBBLETYPE BlockMeta = MappedValue & 0x0f;
- m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, BlockType, BlockMeta);
+ 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);
}
}
}
@@ -146,6 +378,8 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma
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)
{
@@ -188,6 +422,54 @@ void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
+void cPrefab::ParseDepthWeight(const char * a_DepthWeightDef)
+{
+ // The member needn't be defined at all, if so, skip:
+ if (a_DepthWeightDef == NULL)
+ {
+ return;
+ }
+
+ // Split into individual records: "Record | Record | Record"
+ AStringVector Defs = StringSplitAndTrim(a_DepthWeightDef, "|");
+
+ // Add each record's contents:
+ for (AStringVector::const_iterator itr = Defs.begin(), end = Defs.end(); itr != end; ++itr)
+ {
+ // Split into components: "Depth : Weight"
+ AStringVector Components = StringSplitAndTrim(*itr, ":");
+ if (Components.size() != 2)
+ {
+ LOGWARNING("Bad prefab DepthWeight record: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+
+ // Parse depth:
+ int Depth = atoi(Components[0].c_str());
+ if ((Depth == 0) && (Components[0] != "0"))
+ {
+ LOGWARNING("Bad prefab DepthWeight record, cannot parse depth \"%s\", skipping.", Components[0].c_str());
+ continue;
+ }
+
+ // Parse weight:
+ int Weight = atoi(Components[1].c_str());
+ if ((Weight == 0) && (Components[1] != "0"))
+ {
+ LOGWARNING("Bad prefab DepthWeight record, cannot parse weight \"%s\", skipping.", Components[1].c_str());
+ continue;
+ }
+
+ // Save to map:
+ ASSERT(m_DepthWeight.find(Depth) == m_DepthWeight.end()); // Not a duplicate
+ m_DepthWeight[Depth] = Weight;
+ } // for itr - Defs[]
+}
+
+
+
+
+
cPiece::cConnectors cPrefab::GetConnectors(void) const
{
return m_Connectors;
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
index 0b254c03b..8b4e4b4ef 100644
--- a/src/Generating/Prefab.h
+++ b/src/Generating/Prefab.h
@@ -37,24 +37,106 @@ public:
int m_SizeX;
int m_SizeY;
int m_SizeZ;
+
+ /** The hitbox used for collision-checking between prefabs. Relative to the bounds. */
+ int m_HitboxMinX, m_HitboxMinY, m_HitboxMinZ;
+ int m_HitboxMaxX, m_HitboxMaxY, m_HitboxMaxZ;
+
+ /** The mapping between characters in m_Image and the blocktype / blockmeta.
+ Format: "Char: BlockType: BlockMeta \n Char: BlockType : BlockMeta \n ..." */
const char * m_CharMap;
+
+ /** The actual image to be used for the prefab. Organized YZX (Y changes the least often).
+ Each character represents a single block, the type is mapped through m_CharMap. */
const char * m_Image;
+
+ /** List of connectors.
+ Format: "Type: X, Y, Z : Direction \n Type : X, Y, Z : Direction \n ...".
+ Type is an arbitrary number, Direction is the BlockFace constant value (0 .. 5). */
const char * m_Connectors;
+
+ /** Bitmask specifying the allowed rotations.
+ N rotations CCW are allowed if bit N is set. */
int m_AllowedRotations;
+
+ /** The merge strategy to use while drawing the prefab. */
cBlockArea::eMergeStrategy m_MergeStrategy;
+
+ /** If set to true, the prefab will extend its lowermost blocks until a solid block is found,
+ thus creating a foundation for the prefab. This is used for houses to be "on the ground", as well as
+ nether fortresses not to float. */
+ bool m_ShouldExtendFloor;
+
+ /** Chance of this piece being used, if no other modifier is active. */
+ int m_DefaultWeight;
+
+ /** Chances of this piece being used, per depth of the generated piece tree.
+ The starting piece has a depth of 0, the pieces connected to it are depth 1, etc.
+ The specified depth stands for the depth of the new piece (not the existing already-placed piece),
+ so valid depths start at 1.
+ Format: "Depth : Weight | Depth : Weight | Depth : Weight ..."
+ Depths that are not specified will use the m_DefaultWeight value. */
+ const char * m_DepthWeight;
+
+ /** The weight to add to this piece's base per-depth chance if the previous piece is the same.
+ Can be positive or negative.
+ This is used e. g. to make nether bridges prefer spanning multiple segments or to penalize turrets next to each other. */
+ int m_AddWeightIfSame;
+
+ /** If true, the piece will be moved Y-wise so that its first connector is sitting on the terrain.
+ This is used e. g. for village houses. */
+ bool m_MoveToGround;
};
+
+ /** Creates a prefab from the provided definition. */
cPrefab(const sDef & a_Def);
+ /** Creates a prefab based on the given BlockArea and allowed rotations. */
+ cPrefab(const cBlockArea & a_Image, int a_AllowedRotations);
+
/** 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;
+ /** Draws the prefab into the specified chunks, according to the specified placement and rotations. */
+ void Draw(cChunkDesc & a_Dest, const Vector3i & a_Placement, int a_NumRotations) const;
+
/** Returns true if the prefab has any connector of the specified type. */
bool HasConnectorType(int a_ConnectorType) const;
+
+ /** Returns the weight (chance) of this prefab generating as the next piece after the specified placed piece.
+ PiecePool implementations can use this for their GetPieceWeight() implementations. */
+ int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector) const;
+
+ /** Sets the (unmodified) DefaultWeight property for this piece. */
+ void SetDefaultWeight(int a_DefaultWeight);
+
+ /** Returns the unmodified DefaultWeight property for the piece. */
+ int GetDefaultWeight(void) const { return m_DefaultWeight; }
+
+ /** Sets the AddWeightIfSame member, that is used to modify the weight when the previous piece is the same prefab */
+ void SetAddWeightIfSame(int a_AddWeightIfSame) { m_AddWeightIfSame = a_AddWeightIfSame; }
+
+ /** Adds the specified connector to the list of connectors this piece supports. */
+ void AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Direction, int a_Type);
+
+ /** Returns whether the prefab should be moved Y-wise to ground before drawing, rather than staying
+ at the coords governed by the connectors. */
+ bool ShouldMoveToGround(void) const { return m_MoveToGround; }
protected:
- /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
- typedef int CharMap[256];
+ /** 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 sBlockTypeDef block type definition. */
+ typedef sBlockTypeDef CharMap[256];
+
+ /** Maps generator tree depth to weight. */
+ typedef std::map<int, int> cDepthWeight;
/** The cBlockArea that contains the block definitions for the prefab.
@@ -64,7 +146,7 @@ protected:
/** The size of the prefab */
Vector3i m_Size;
- /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
+ /** The hitbox used for collision-checking between prefabs. */
cCuboid m_HitBox;
/** The connectors through which the piece connects to other pieces */
@@ -75,6 +157,30 @@ protected:
/** The merge strategy to use when drawing the prefab into a block area */
cBlockArea::eMergeStrategy m_MergeStrategy;
+
+ /** If set to true, the prefab will extend its lowermost blocks until a solid block is found,
+ thus creating a foundation for the prefab. This is used for houses to be "on the ground", as well as
+ nether fortresses not to float. */
+ bool m_ShouldExtendFloor;
+
+ /** Chance of this piece being used, if no other modifier is active. */
+ int m_DefaultWeight;
+
+ /** Chances of this piece being used, per depth of the generated piece tree.
+ The starting piece has a depth of 0, the pieces connected to it are depth 1, etc.
+ The specified depth stands for the depth of the new piece (not the existing already-placed piece),
+ so valid depths start at 1.
+ Depths that are not specified will use the m_DefaultWeight value. */
+ cDepthWeight m_DepthWeight;
+
+ /** The weight to add to this piece's base per-depth chance if the previous piece is the same.
+ Can be positive or negative.
+ This is used e. g. to make nether bridges prefer spanning multiple segments or to penalize turrets next to each other. */
+ int m_AddWeightIfSame;
+
+ /** If true, the piece will be moved Y-wise so that its first connector is sitting on the terrain.
+ This is used e. g. for village houses. */
+ bool m_MoveToGround;
// cPiece overrides:
@@ -83,6 +189,10 @@ protected:
virtual cCuboid GetHitBox(void) const override;
virtual bool CanRotateCCW(int a_NumRotations) const override;
+ /** Based on the m_AllowedRotations, adds rotated cBlockAreas to the m_BlockArea array.
+ To be called only from this class's constructor! */
+ void AddRotatedBlockAreas(void);
+
/** 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);
@@ -91,6 +201,9 @@ protected:
/** Parses the connectors definition text into m_Connectors member. */
void ParseConnectors(const char * a_ConnectorsDef);
+
+ /** Parses the per-depth weight into m_DepthWeight member. */
+ void ParseDepthWeight(const char * a_DepthWeightDef);
};
diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp
new file mode 100644
index 000000000..122b9d2af
--- /dev/null
+++ b/src/Generating/PrefabPiecePool.cpp
@@ -0,0 +1,158 @@
+
+// PrefabPiecePool.cpp
+
+// Implements the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces
+
+#include "Globals.h"
+#include "PrefabPiecePool.h"
+
+
+
+
+
+cPrefabPiecePool::cPrefabPiecePool(
+ const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
+ const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
+)
+{
+ AddPieceDefs(a_PieceDefs, a_NumPieceDefs);
+ if (a_StartingPieceDefs != NULL)
+ {
+ AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs);
+ }
+}
+
+
+
+
+
+cPrefabPiecePool::~cPrefabPiecePool()
+{
+ Clear();
+}
+
+
+
+
+
+void cPrefabPiecePool::Clear(void)
+{
+ m_PiecesByConnector.clear();
+ for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ m_AllPieces.clear();
+ for (cPieces::iterator itr = m_StartingPieces.begin(), end = m_StartingPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ m_StartingPieces.clear();
+}
+
+
+
+
+
+void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs)
+{
+ ASSERT(a_PieceDefs != NULL);
+ for (size_t i = 0; i < a_NumPieceDefs; i++)
+ {
+ cPrefab * Prefab = new cPrefab(a_PieceDefs[i]);
+ m_AllPieces.push_back(Prefab);
+ AddToPerConnectorMap(Prefab);
+ }
+}
+
+
+
+
+
+void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs)
+{
+ ASSERT(a_StartingPieceDefs != NULL);
+ for (size_t i = 0; i < a_NumStartingPieceDefs; i++)
+ {
+ cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]);
+ m_StartingPieces.push_back(Prefab);
+ }
+}
+
+
+
+
+
+void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab)
+{
+ cPiece::cConnectors Connectors = ((const cPiece *)a_Prefab)->GetConnectors();
+ for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
+ {
+ m_PiecesByConnector[itr->m_Type].push_back(a_Prefab);
+ }
+}
+
+
+
+
+cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType)
+{
+ return m_PiecesByConnector[a_ConnectorType];
+}
+
+
+
+
+
+cPieces cPrefabPiecePool::GetStartingPieces(void)
+{
+ if (m_StartingPieces.empty())
+ {
+ return m_AllPieces;
+ }
+ else
+ {
+ return m_StartingPieces;
+ }
+}
+
+
+
+
+
+int cPrefabPiecePool::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece)
+{
+ return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
+}
+
+
+
+
+
+int cPrefabPiecePool::GetStartingPieceWeight(const cPiece & a_NewPiece)
+{
+ return ((const cPrefab &)a_NewPiece).GetDefaultWeight();
+}
+
+
+
+
+
+void cPrefabPiecePool::PiecePlaced(const cPiece & a_Piece)
+{
+ // Do nothing
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cPrefabPiecePool::Reset(void)
+{
+ // Do nothing
+}
+
+
+
+
diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h
new file mode 100644
index 000000000..b9c1f0483
--- /dev/null
+++ b/src/Generating/PrefabPiecePool.h
@@ -0,0 +1,85 @@
+
+// PrefabPiecePool.h
+
+// Declares the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "Prefab.h"
+
+
+
+
+
+class cPrefabPiecePool :
+ public cPiecePool
+{
+public:
+ /** Creates an empty instance. Prefabs can be added by calling AddPieceDefs() and AddStartingPieceDefs(). */
+ cPrefabPiecePool(void);
+
+ /** Creates a piece pool with prefabs from the specified definitions.
+ If both a_PieceDefs and a_StartingPieceDefs are given, only the a_StartingPieceDefs are used as starting
+ pieces for the pool, and they do not participate in the generation any further.
+ If only a_PieceDefs is given, any such piece can be chosen as a starting piece, and all the pieces are used
+ for generating.
+ More pieces can be added to the instance afterwards by calling AddPieceDefs() and AddStartingPieceDefs(). */
+ cPrefabPiecePool(
+ const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
+ const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
+ );
+
+ /** Destroys the pool, freeing all pieces. */
+ ~cPrefabPiecePool();
+
+ /** Removes and frees all pieces from this pool. */
+ void Clear(void);
+
+ /** Adds pieces from the specified definitions into m_AllPieces. Also adds the pieces into
+ the m_PiecesByConnector map.
+ May be called multiple times with different PieceDefs, will add all such pieces. */
+ void AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs);
+
+ /** Adds pieces from the specified definitions into m_StartingPieces. Doesn't add them to
+ the m_PiecesByConnector map.
+ May be called multiple times with different PieceDefs, will add all such pieces. */
+ void AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs);
+
+protected:
+
+ /** The type used to map a connector type to the list of pieces with that connector */
+ typedef std::map<int, cPieces> cPiecesMap;
+
+ /** 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 map that has all pieces by their connector types
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPiecesMap m_PiecesByConnector;
+
+
+ /** Adds the prefab to the m_PiecesByConnector map for all its connectors. */
+ void AddToPerConnectorMap(cPrefab * a_Prefab);
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override;
+ virtual int GetStartingPieceWeight(const cPiece & a_NewPiece) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
diff --git a/src/Generating/Prefabs/AlchemistVillagePrefabs.cpp b/src/Generating/Prefabs/AlchemistVillagePrefabs.cpp
new file mode 100644
index 000000000..eb0d30fdf
--- /dev/null
+++ b/src/Generating/Prefabs/AlchemistVillagePrefabs.cpp
@@ -0,0 +1,3184 @@
+
+// AlchemistVillagePrefabs.cpp
+
+// Defines the prefabs in the group AlchemistVillage
+
+// NOTE: This file has been generated automatically by GalExport!
+// Any manual changes will be overwritten by the next automatic export!
+
+#include "Globals.h"
+#include "AlchemistVillagePrefabs.h"
+
+
+
+
+
+const cPrefab::sDef g_AlchemistVillagePrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BarWithBasement:
+ // The data has been exported from the gallery Desert, area index 82, ID 598, created by STR_Warrior
+ {
+ // Size:
+ 11, 12, 10, // SizeX = 11, SizeY = 12, SizeZ = 10
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 11, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A:171: 8\n" /* carpet */
+ "B:101: 0\n" /* ironbars */
+ "C: 64:12\n" /* wooddoorblock */
+ "D:128: 2\n" /* sandstonestairs */
+ "E: 24: 1\n" /* sandstone */
+ "F: 44: 9\n" /* step */
+ "G:126: 8\n" /* woodenslab */
+ "H:128: 7\n" /* sandstonestairs */
+ "I: 44: 1\n" /* step */
+ "J: 64: 7\n" /* wooddoorblock */
+ "K:128: 6\n" /* sandstonestairs */
+ "a: 1: 0\n" /* stone */
+ "b: 24: 0\n" /* sandstone */
+ "c: 12: 0\n" /* sand */
+ "d:134: 4\n" /* 134 */
+ "e: 5: 1\n" /* wood */
+ "f:134: 5\n" /* 134 */
+ "g: 65: 5\n" /* ladder */
+ "h: 17: 3\n" /* tree */
+ "i: 69:11\n" /* lever */
+ "j:134: 0\n" /* 134 */
+ "k:134: 1\n" /* 134 */
+ "l: 50: 4\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 5: 0\n" /* wood */
+ "o: 96:12\n" /* trapdoor */
+ "p: 24: 2\n" /* sandstone */
+ "q:128: 5\n" /* sandstonestairs */
+ "r:107: 6\n" /* fencegate */
+ "s:128: 4\n" /* sandstonestairs */
+ "t:134: 3\n" /* 134 */
+ "u: 85: 0\n" /* fence */
+ "v:134: 7\n" /* 134 */
+ "w:107: 5\n" /* fencegate */
+ "x: 64: 5\n" /* wooddoorblock */
+ "y: 65: 3\n" /* ladder */
+ "z: 50: 3\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aabbbbbbbaa"
+ /* 3 */ "aabbbbbbbaa"
+ /* 4 */ "aabbbbbbbaa"
+ /* 5 */ "aabbbbbbbaa"
+ /* 6 */ "aabbbbbbbaa"
+ /* 7 */ "aabbbbbbbaa"
+ /* 8 */ "aaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "ccccccccccc"
+ /* 1 */ "cbbbbbbbbbc"
+ /* 2 */ "cbdef.defbc"
+ /* 3 */ "cbdef.defbc"
+ /* 4 */ "cbdef.defbc"
+ /* 5 */ "cb.......bc"
+ /* 6 */ "cb.......bc"
+ /* 7 */ "cbg......bc"
+ /* 8 */ "cbbbbbbbbbc"
+ /* 9 */ "ccccccccccc"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "ccccccccccc"
+ /* 1 */ "cbbbbbbbbbc"
+ /* 2 */ "cbeee.eeebc"
+ /* 3 */ "cbeee.eeebc"
+ /* 4 */ "cbehe.ehebc"
+ /* 5 */ "cb.i...i.bc"
+ /* 6 */ "cb.......bc"
+ /* 7 */ "cbg......bc"
+ /* 8 */ "cbbbbbbbbbc"
+ /* 9 */ "ccccccccccc"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "ccccccccccc"
+ /* 1 */ "cbbbbbbbbbc"
+ /* 2 */ "cbjek.jekbc"
+ /* 3 */ "cbjek.jekbc"
+ /* 4 */ "cbjek.jekbc"
+ /* 5 */ "cb.......bc"
+ /* 6 */ "cb.......bc"
+ /* 7 */ "cbg..l...bc"
+ /* 8 */ "cbbbbbbbbbc"
+ /* 9 */ "ccccccccccc"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "ccccccccccc"
+ /* 1 */ "ccccccccccc"
+ /* 2 */ "ccnnnnnnncc"
+ /* 3 */ "cnnnnnnnnnc"
+ /* 4 */ "cnnnnnnnnnc"
+ /* 5 */ "cnnnnnnnnnc"
+ /* 6 */ "cnnnnnnnnnc"
+ /* 7 */ "cnonnnnnnnc"
+ /* 8 */ "cnccccccccc"
+ /* 9 */ "ccccccccccc"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...p...p..."
+ /* 1 */ "..........."
+ /* 2 */ "pbbbqrsbbbp"
+ /* 3 */ "bkt.....ttb"
+ /* 4 */ "bku.....ujb"
+ /* 5 */ "b.........b"
+ /* 6 */ "bfvvd.....b"
+ /* 7 */ "b...w..kujb"
+ /* 8 */ "pxbbbbbbbbp"
+ /* 9 */ "..y........"
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...p...p..."
+ /* 1 */ "..........."
+ /* 2 */ "pbbb...bbbp"
+ /* 3 */ "b..z...z..b"
+ /* 4 */ "b.A.....A.b"
+ /* 5 */ "B.........B"
+ /* 6 */ "b.........b"
+ /* 7 */ "b.......A.b"
+ /* 8 */ "pCbbBBBbbbp"
+ /* 9 */ "..y........"
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...D...D..."
+ /* 1 */ "...E...b..."
+ /* 2 */ "pbbbqFsbbbp"
+ /* 3 */ "bGGGGGGGGGb"
+ /* 4 */ "bGGGGGGGGGb"
+ /* 5 */ "sGGGGGGGGGq"
+ /* 6 */ "bGGGGGGGGGb"
+ /* 7 */ "bGGGGGGGGGb"
+ /* 8 */ "pbbbHHHbbbp"
+ /* 9 */ "..y........"
+
+ // Level 8
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "bIIIIbIIIIb"
+ /* 3 */ "IpbbbbbbbpI"
+ /* 4 */ "Ib.......bI"
+ /* 5 */ "bb.......bb"
+ /* 6 */ "Ib.......bI"
+ /* 7 */ "IpJbbbbbbpI"
+ /* 8 */ "bI.IIbIIIIb"
+ /* 9 */ "..........."
+
+ // Level 9
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ ".pbbBBBbbp."
+ /* 4 */ ".b.......b."
+ /* 5 */ ".B.......B."
+ /* 6 */ ".b.......b."
+ /* 7 */ ".pCbBBBbbp."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+
+ // Level 10
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ ".pbbKKKbbp."
+ /* 4 */ ".bGGGGGGGb."
+ /* 5 */ ".sGGGGGGGq."
+ /* 6 */ ".bGGGGGGGb."
+ /* 7 */ ".pbbHHHbbp."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+
+ // Level 11
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ ".bIIIbIIIb."
+ /* 4 */ ".I.......I."
+ /* 5 */ ".b.......b."
+ /* 6 */ ".I.......I."
+ /* 7 */ ".bIIIbIIIb."
+ /* 8 */ "..........."
+ /* 9 */ "...........",
+
+ // Connectors:
+ "-1: 5, 5, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 70,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // BarWithBasement
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BarWithoutBasement:
+ // The data has been exported from the gallery Desert, area index 81, ID 597, created by STR_Warrior
+ {
+ // Size:
+ 11, 8, 10, // SizeX = 11, SizeY = 8, SizeZ = 10
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 7, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A:128: 7\n" /* sandstonestairs */
+ "B: 44: 1\n" /* step */
+ "C: 64: 3\n" /* wooddoorblock */
+ "D: 64: 8\n" /* wooddoorblock */
+ "E:128: 6\n" /* sandstonestairs */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e:128: 5\n" /* sandstonestairs */
+ "f:107: 6\n" /* fencegate */
+ "g:128: 4\n" /* sandstonestairs */
+ "h:134: 1\n" /* 134 */
+ "i:134: 3\n" /* 134 */
+ "j: 85: 0\n" /* fence */
+ "k:134: 0\n" /* 134 */
+ "l:134: 5\n" /* 134 */
+ "m: 19: 0\n" /* sponge */
+ "n:134: 7\n" /* 134 */
+ "o:134: 4\n" /* 134 */
+ "p:107: 5\n" /* fencegate */
+ "q: 64: 5\n" /* wooddoorblock */
+ "r: 65: 3\n" /* ladder */
+ "s: 50: 3\n" /* torch */
+ "t:171: 8\n" /* carpet */
+ "u:101: 0\n" /* ironbars */
+ "v: 64:12\n" /* wooddoorblock */
+ "w:128: 2\n" /* sandstonestairs */
+ "x: 24: 1\n" /* sandstone */
+ "y: 44: 9\n" /* step */
+ "z:126: 8\n" /* woodenslab */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaabbbaaaa"
+ /* 3 */ "abbbbbbbbba"
+ /* 4 */ "abbbbbbbbba"
+ /* 5 */ "abbbbbbbbba"
+ /* 6 */ "abbbbbbbbba"
+ /* 7 */ "abbbbbbbbba"
+ /* 8 */ "abaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...c...c..."
+ /* 1 */ "..........."
+ /* 2 */ "cdddefgdddc"
+ /* 3 */ "dhi.....iid"
+ /* 4 */ "dhj.....jkd"
+ /* 5 */ "d.........d"
+ /* 6 */ "dlnno.....d"
+ /* 7 */ "d...p..hjkd"
+ /* 8 */ "cqddddddddc"
+ /* 9 */ "..r........"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...c...c..."
+ /* 1 */ "..........."
+ /* 2 */ "cddd...dddc"
+ /* 3 */ "d..s...s..d"
+ /* 4 */ "d.t.....t.d"
+ /* 5 */ "u.........u"
+ /* 6 */ "d.........d"
+ /* 7 */ "d.......t.d"
+ /* 8 */ "cvdduuudddc"
+ /* 9 */ "..r........"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...w...w..."
+ /* 1 */ "...x...d..."
+ /* 2 */ "cdddeygdddc"
+ /* 3 */ "dzzzzzzzzzd"
+ /* 4 */ "dzzzzzzzzzd"
+ /* 5 */ "gzzzzzzzzze"
+ /* 6 */ "dzzzzzzzzzd"
+ /* 7 */ "dzzzzzzzzzd"
+ /* 8 */ "cdddAAAdddc"
+ /* 9 */ "..r........"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "dBBBBdBBBBd"
+ /* 3 */ "BcdddddddcB"
+ /* 4 */ "Bd.......dB"
+ /* 5 */ "dd.......dd"
+ /* 6 */ "Bd.......dB"
+ /* 7 */ "BcCddddddcB"
+ /* 8 */ "dB.BBdBBBBd"
+ /* 9 */ "..........."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ ".cdduuuddc."
+ /* 4 */ ".d.......d."
+ /* 5 */ ".u.......u."
+ /* 6 */ ".d.......d."
+ /* 7 */ ".cDduuuddc."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ ".cddEEEddc."
+ /* 4 */ ".dzzzzzzzd."
+ /* 5 */ ".gzzzzzzze."
+ /* 6 */ ".dzzzzzzzd."
+ /* 7 */ ".cddAAAddc."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ ".dBBBdBBBd."
+ /* 4 */ ".B.......B."
+ /* 5 */ ".d.......d."
+ /* 6 */ ".B.......B."
+ /* 7 */ ".dBBBdBBBd."
+ /* 8 */ "..........."
+ /* 9 */ "...........",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 80,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // BarWithoutBasement
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlackSmith:
+ // The data has been exported from the gallery Desert, area index 97, ID 642, created by STR_Warrior
+ {
+ // Size:
+ 11, 5, 13, // SizeX = 11, SizeY = 5, SizeZ = 13
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 4, 13, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 0\n" /* sandstone */
+ "d: 24: 2\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 43: 0\n" /* doubleslab */
+ "g: 53: 5\n" /* woodstairs */
+ "h: 53: 4\n" /* woodstairs */
+ "i: 10: 0\n" /* lava */
+ "j: 54: 5\n" /* chest */
+ "k: 64:12\n" /* wooddoorblock */
+ "l: 50: 3\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n:101: 0\n" /* ironbars */
+ "o: 50: 1\n" /* torch */
+ "p: 50: 2\n" /* torch */
+ "q:128: 2\n" /* sandstonestairs */
+ "r: 44: 9\n" /* step */
+ "s:126: 8\n" /* woodenslab */
+ "t:128: 4\n" /* sandstonestairs */
+ "u:128: 5\n" /* sandstonestairs */
+ "v:128: 7\n" /* sandstonestairs */
+ "w: 44: 1\n" /* step */
+ "x: 43: 1\n" /* doubleslab */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaaaaaabaa"
+ /* 3 */ "acacacabbba"
+ /* 4 */ "acaccaabbba"
+ /* 5 */ "acccccabbba"
+ /* 6 */ "acaadddbbba"
+ /* 7 */ "aaacdddbbba"
+ /* 8 */ "aaaadddbbba"
+ /* 9 */ "abbbbbbbbba"
+ /* 10 */ "abbbbbbbbba"
+ /* 11 */ "abbbbbbbbba"
+ /* 12 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "......d...d"
+ /* 1 */ "..........."
+ /* 2 */ "......dcecd"
+ /* 3 */ ".d....c...c"
+ /* 4 */ "..f...c...c"
+ /* 5 */ "......c...c"
+ /* 6 */ "....ddc...c"
+ /* 7 */ ".gh.dic...c"
+ /* 8 */ "dcccccd...c"
+ /* 9 */ "cj........c"
+ /* 10 */ "c.........c"
+ /* 11 */ "c.........c"
+ /* 12 */ "dcccccccccd"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "......d...d"
+ /* 1 */ "..........."
+ /* 2 */ "......dckcd"
+ /* 3 */ ".d....c..lc"
+ /* 4 */ "......n...c"
+ /* 5 */ "......c...c"
+ /* 6 */ "....nnc...n"
+ /* 7 */ "....n.c...n"
+ /* 8 */ "dcccccd...n"
+ /* 9 */ "co........c"
+ /* 10 */ "n.........c"
+ /* 11 */ "c........pc"
+ /* 12 */ "dcccnnncccd"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "......q...q"
+ /* 1 */ "......c...c"
+ /* 2 */ "......dcccd"
+ /* 3 */ ".drrrrcsssc"
+ /* 4 */ ".rsssstsssc"
+ /* 5 */ ".rsssscsssc"
+ /* 6 */ ".rssddcsssu"
+ /* 7 */ ".rssd.csssu"
+ /* 8 */ "dcccccdsssu"
+ /* 9 */ "csssssssssc"
+ /* 10 */ "tsssssssssc"
+ /* 11 */ "csssssssssc"
+ /* 12 */ "dcccvvvcccd"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "......cwwwc"
+ /* 3 */ ".w.w.ww...w"
+ /* 4 */ "......w...w"
+ /* 5 */ ".w....w...w"
+ /* 6 */ "....xwx...w"
+ /* 7 */ ".w..w.w...c"
+ /* 8 */ "cwwwxwc...w"
+ /* 9 */ "w.........w"
+ /* 10 */ "w.........w"
+ /* 11 */ "w.........w"
+ /* 12 */ "cwwwwcwwwwc",
+
+ // Connectors:
+ "-1: 8, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 50,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BlackSmith
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LargeHouse1:
+ // The data has been exported from the gallery Desert, area index 77, ID 577, created by STR_Warrior
+ {
+ // Size:
+ 15, 13, 11, // SizeX = 15, SizeY = 13, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, -1, // MinX, MinY, MinZ
+ 14, 12, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A:128: 4\n" /* sandstonestairs */
+ "B:128: 5\n" /* sandstonestairs */
+ "C:128: 7\n" /* sandstonestairs */
+ "D: 44: 1\n" /* step */
+ "E:128: 2\n" /* sandstonestairs */
+ "F:128: 0\n" /* sandstonestairs */
+ "G: 87: 0\n" /* netherstone */
+ "H:128: 3\n" /* sandstonestairs */
+ "I: 51: 0\n" /* fire */
+ "J: 44: 9\n" /* step */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 85: 0\n" /* fence */
+ "f: 5: 1\n" /* wood */
+ "g: 64: 6\n" /* wooddoorblock */
+ "h: 64: 0\n" /* wooddoorblock */
+ "i: 61: 2\n" /* furnace */
+ "j:118: 0\n" /* cauldronblock */
+ "k:134: 4\n" /* 134 */
+ "l: 65: 2\n" /* ladder */
+ "m: 19: 0\n" /* sponge */
+ "n:101: 0\n" /* ironbars */
+ "o: 50: 1\n" /* torch */
+ "p:140: 0\n" /* flowerpotblock */
+ "q: 64:12\n" /* wooddoorblock */
+ "r: 50: 3\n" /* torch */
+ "s: 64: 8\n" /* wooddoorblock */
+ "t: 69:12\n" /* lever */
+ "u: 50: 4\n" /* torch */
+ "v:128: 6\n" /* sandstonestairs */
+ "w: 44:10\n" /* step */
+ "x:128: 1\n" /* sandstonestairs */
+ "y: 47: 0\n" /* bookshelf */
+ "z: 96:10\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaabbbbbbbaaa"
+ /* 2 */ "aaaabbbbbbbbaaa"
+ /* 3 */ "aaaaabbbbbbbbaa"
+ /* 4 */ "aaaaabbbbbbbaaa"
+ /* 5 */ "aaaaabbbbbbbaaa"
+ /* 6 */ "aaaaabbbbbbbaaa"
+ /* 7 */ "aaaaabbbbbbbaaa"
+ /* 8 */ "aaaaabbbbbbbaaa"
+ /* 9 */ "aaaaabbbbbbbaaa"
+ /* 10 */ "aaaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "....cdddddddc.."
+ /* 1 */ "eeeed......fd.c"
+ /* 2 */ "e...g.......d.."
+ /* 3 */ "e...d.......h.."
+ /* 4 */ "e...dijk..l.d.."
+ /* 5 */ "e...dddd.dddd.c"
+ /* 6 */ "eeeed.......d.."
+ /* 7 */ "mmmmd.......d.."
+ /* 8 */ "mmmmd.......d.."
+ /* 9 */ "mmmmd.......d.."
+ /* 10 */ "mmmmcdddddddc.."
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "....cddnnnddc.."
+ /* 1 */ "....do.....pd.c"
+ /* 2 */ "....q.......d.r"
+ /* 3 */ "....d.......s.."
+ /* 4 */ "....d.t...l.d.u"
+ /* 5 */ "....dddd.dddd.c"
+ /* 6 */ "....n..r.r..n.."
+ /* 7 */ "mmmmn.......n.."
+ /* 8 */ "mmmmn.......n.."
+ /* 9 */ "mmmmd.......d.."
+ /* 10 */ "mmmmcddnnnddc.."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "....cddvvvddc.."
+ /* 1 */ "....dwwwwwwwddx"
+ /* 2 */ "....dwwwwwwwd.."
+ /* 3 */ "....dwwwwwwwd.."
+ /* 4 */ "....dyyywwzwd.."
+ /* 5 */ "....ddddddddddx"
+ /* 6 */ "....AwwwwwwwB.."
+ /* 7 */ "mmmmAwwwwwwwB.."
+ /* 8 */ "mmmmAwwwwwwwB.."
+ /* 9 */ "mmmmdwwwwwwwd.."
+ /* 10 */ "mmmmcddCCCddc.."
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "....dDDDdDDDd.."
+ /* 1 */ "....DcdddddcD.."
+ /* 2 */ "....Dd.....dD.."
+ /* 3 */ "....Dd.....dD.."
+ /* 4 */ "....Dd.....dD.."
+ /* 5 */ "....dcdd.ddcd.."
+ /* 6 */ "....D.......D.."
+ /* 7 */ "mmmmD.......D.."
+ /* 8 */ "mmmmD.......D.."
+ /* 9 */ "mmmmD.......D.."
+ /* 10 */ "mmmmdDDDdDDDd.."
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".....cddnddc..."
+ /* 2 */ ".....n.....n..."
+ /* 3 */ ".....n.....n..."
+ /* 4 */ ".....n.....n..."
+ /* 5 */ ".....cdd.ddc..."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".....cddvddc..."
+ /* 2 */ ".....AwwwwwB..."
+ /* 3 */ ".....AwwwwwB..."
+ /* 4 */ ".....AwwwwwB..."
+ /* 5 */ ".....cdddddc..."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".....dDDdDDd..."
+ /* 2 */ ".....D.ddd.D..."
+ /* 3 */ ".....d.ddd.d..."
+ /* 4 */ ".....D.ddd.D..."
+ /* 5 */ ".....dDDdDDd..."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 8
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ ".......cEc....."
+ /* 3 */ ".......FGx....."
+ /* 4 */ ".......cHc....."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 9
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ ".......c.c....."
+ /* 3 */ "........I......"
+ /* 4 */ ".......c.c....."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 10
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ ".......cvc....."
+ /* 3 */ ".......A.B....."
+ /* 4 */ ".......cCc....."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 11
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ ".......ddd....."
+ /* 3 */ ".......dJd....."
+ /* 4 */ ".......ddd....."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+
+ // Level 12
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ ".......D.D....."
+ /* 3 */ "..............."
+ /* 4 */ ".......D.D....."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "...............",
+
+ // Connectors:
+ "-1: 14, 1, 3: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 60,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LargeHouse1
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LargeTower:
+ // The data has been exported from the gallery Desert, area index 80, ID 596, created by STR_Warrior
+ {
+ // Size:
+ 7, 11, 7, // SizeX = 7, SizeY = 11, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 7, 10, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c:128: 2\n" /* sandstonestairs */
+ "d:128: 0\n" /* sandstonestairs */
+ "e: 24: 2\n" /* sandstone */
+ "f: 24: 0\n" /* sandstone */
+ "g: 71: 3\n" /* irondoorblock */
+ "h:128: 1\n" /* sandstonestairs */
+ "i:128: 3\n" /* sandstonestairs */
+ "j: 77: 4\n" /* stonebutton */
+ "k: 71: 8\n" /* irondoorblock */
+ "l:128: 6\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 4\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p: 50: 4\n" /* torch */
+ "q:128: 7\n" /* sandstonestairs */
+ "r: 85: 0\n" /* fence */
+ "s: 24: 1\n" /* sandstone */
+ "t: 44: 1\n" /* step */
+ "u: 89: 0\n" /* lightstone */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaabaaa"
+ /* 2 */ "aabbbaa"
+ /* 3 */ "aabbbaa"
+ /* 4 */ "aabbbaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "mc...cm"
+ /* 1 */ "defgfeh"
+ /* 2 */ ".f...f."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ "defffeh"
+ /* 6 */ "mi...im"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "m.j...m"
+ /* 1 */ ".efkfe."
+ /* 2 */ ".f...f."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ ".efffe."
+ /* 6 */ "m.....m"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..lfl.."
+ /* 2 */ ".n...o."
+ /* 3 */ ".f...f."
+ /* 4 */ ".n.p.o."
+ /* 5 */ "..qfq.."
+ /* 6 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..frf.."
+ /* 2 */ ".f...f."
+ /* 3 */ ".r...r."
+ /* 4 */ ".f...f."
+ /* 5 */ "..frf.."
+ /* 6 */ "......."
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..frf.."
+ /* 2 */ ".f...f."
+ /* 3 */ ".r...r."
+ /* 4 */ ".f...f."
+ /* 5 */ "..frf.."
+ /* 6 */ "......."
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..frf.."
+ /* 2 */ ".f...f."
+ /* 3 */ ".r...r."
+ /* 4 */ ".f...f."
+ /* 5 */ "..frf.."
+ /* 6 */ "......."
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..cfc.."
+ /* 2 */ ".d...h."
+ /* 3 */ ".f...f."
+ /* 4 */ ".d...h."
+ /* 5 */ "..ifi.."
+ /* 6 */ "......."
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ffsff."
+ /* 2 */ ".f...f."
+ /* 3 */ ".s...s."
+ /* 4 */ ".f...f."
+ /* 5 */ ".ffsff."
+ /* 6 */ "......."
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "...l..."
+ /* 1 */ ".efffe."
+ /* 2 */ ".ftttf."
+ /* 3 */ "nftftfo"
+ /* 4 */ ".ftttf."
+ /* 5 */ ".efffe."
+ /* 6 */ "...q..."
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "...t..."
+ /* 1 */ ".t...t."
+ /* 2 */ "......."
+ /* 3 */ "t..u..t"
+ /* 4 */ "......."
+ /* 5 */ ".t...t."
+ /* 6 */ "...t...",
+
+ // Connectors:
+ "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LargeTower
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse:
+ // The data has been exported from the gallery Desert, area index 65, ID 551, created by STR_Warrior
+ {
+ // Size:
+ 5, 5, 7, // SizeX = 5, SizeY = 5, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 5, 4, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 3\n" /* wooddoorblock */
+ "f: 61: 2\n" /* furnace */
+ "g: 65: 2\n" /* ladder */
+ "h: 64: 8\n" /* wooddoorblock */
+ "i:101: 0\n" /* ironbars */
+ "j: 50: 4\n" /* torch */
+ "k:128: 2\n" /* sandstonestairs */
+ "l:126: 8\n" /* woodenslab */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 4\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p:128: 7\n" /* sandstonestairs */
+ "q: 44: 1\n" /* step */
+ "r: 96: 6\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aabaa"
+ /* 3 */ "abbba"
+ /* 4 */ "abbba"
+ /* 5 */ "abbba"
+ /* 6 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "c...c"
+ /* 1 */ "....."
+ /* 2 */ "cdedc"
+ /* 3 */ "d...d"
+ /* 4 */ "d...d"
+ /* 5 */ "df.gd"
+ /* 6 */ "cdddc"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "c...c"
+ /* 1 */ "....."
+ /* 2 */ "cdhdc"
+ /* 3 */ "d...d"
+ /* 4 */ "i...i"
+ /* 5 */ "dj.gd"
+ /* 6 */ "cdidc"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "k...k"
+ /* 1 */ "d...d"
+ /* 2 */ "cdddc"
+ /* 3 */ "dllld"
+ /* 4 */ "nlllo"
+ /* 5 */ "dllgd"
+ /* 6 */ "cdpdc"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "dqdqd"
+ /* 3 */ "q...q"
+ /* 4 */ "d...d"
+ /* 5 */ "q..rq"
+ /* 6 */ "dqdqd",
+
+ // Connectors:
+ "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse2:
+ // The data has been exported from the gallery Desert, area index 72, ID 562, created by STR_Warrior
+ {
+ // Size:
+ 7, 5, 11, // SizeX = 7, SizeY = 5, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 7, 4, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 3\n" /* wooddoorblock */
+ "f: 65: 5\n" /* ladder */
+ "g: 85: 0\n" /* fence */
+ "h:101: 0\n" /* ironbars */
+ "i: 64: 8\n" /* wooddoorblock */
+ "j: 50: 3\n" /* torch */
+ "k:128: 2\n" /* sandstonestairs */
+ "l:128: 6\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:126: 8\n" /* woodenslab */
+ "o:128: 4\n" /* sandstonestairs */
+ "p:128: 5\n" /* sandstonestairs */
+ "q:128: 7\n" /* sandstonestairs */
+ "r: 44: 1\n" /* step */
+ "s: 96: 0\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaabaa"
+ /* 3 */ "abbbbba"
+ /* 4 */ "abbbbba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aabaaaa"
+ /* 7 */ "aaaaaaa"
+ /* 8 */ "aaaaaaa"
+ /* 9 */ "aaaaaaa"
+ /* 10 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ ".c...c."
+ /* 1 */ "......."
+ /* 2 */ "cdddedc"
+ /* 3 */ "d.....d"
+ /* 4 */ "d.....d"
+ /* 5 */ "df....d"
+ /* 6 */ "cd.dddc"
+ /* 7 */ "g.....g"
+ /* 8 */ "g.....g"
+ /* 9 */ "g.....g"
+ /* 10 */ "ggggggg"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ ".c...c."
+ /* 1 */ "......."
+ /* 2 */ "cdhdidc"
+ /* 3 */ "d..j..d"
+ /* 4 */ "h.....h"
+ /* 5 */ "df....d"
+ /* 6 */ "cd.dhdc"
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ ".k...k."
+ /* 1 */ ".d...d."
+ /* 2 */ "cdldddc"
+ /* 3 */ "dnnnnnd"
+ /* 4 */ "onnnnnp"
+ /* 5 */ "dfnnnnd"
+ /* 6 */ "cdddqdc"
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "drrdrrd"
+ /* 3 */ "r.....r"
+ /* 4 */ "d.....d"
+ /* 5 */ "rs....r"
+ /* 6 */ "drrdrrd"
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ ".......",
+
+ // Connectors:
+ "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse2
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse3:
+ // The data has been exported from the gallery Desert, area index 66, ID 553, created by STR_Warrior
+ {
+ // Size:
+ 9, 5, 7, // SizeX = 9, SizeY = 5, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 65: 2\n" /* ladder */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:101: 0\n" /* ironbars */
+ "i: 50: 4\n" /* torch */
+ "j:128: 2\n" /* sandstonestairs */
+ "k:126: 8\n" /* woodenslab */
+ "l:128: 4\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 5\n" /* sandstonestairs */
+ "o:128: 7\n" /* sandstonestairs */
+ "p: 44: 1\n" /* step */
+ "q: 96: 2\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "aaaaaaaaa"
+ /* 2 */ "aaaabaaaa"
+ /* 3 */ "abbbbbbba"
+ /* 4 */ "abbbbbbba"
+ /* 5 */ "abbbbbbba"
+ /* 6 */ "aaaaaaaaa"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "..c...c.."
+ /* 1 */ "........."
+ /* 2 */ "cdddedddc"
+ /* 3 */ "d.......d"
+ /* 4 */ "d.......d"
+ /* 5 */ "d......fd"
+ /* 6 */ "cdddddddc"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "..c...c.."
+ /* 1 */ "........."
+ /* 2 */ "cdddgdddc"
+ /* 3 */ "d.......d"
+ /* 4 */ "h.......h"
+ /* 5 */ "d.i....fd"
+ /* 6 */ "cddhhhddc"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "..j...j.."
+ /* 1 */ "..d...d.."
+ /* 2 */ "cdddddddc"
+ /* 3 */ "dkkkkkkkd"
+ /* 4 */ "lkkkkkkkn"
+ /* 5 */ "dkkkkkkfd"
+ /* 6 */ "cddoooddc"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "dpppdpppd"
+ /* 3 */ "p.......p"
+ /* 4 */ "d.......d"
+ /* 5 */ "p......qp"
+ /* 6 */ "dpppdpppd",
+
+ // Connectors:
+ "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse3
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse4:
+ // The data has been exported from the gallery Desert, area index 70, ID 560, created by STR_Warrior
+ {
+ // Size:
+ 5, 5, 11, // SizeX = 5, SizeY = 5, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 5, 4, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 65: 5\n" /* ladder */
+ "g:134: 3\n" /* 134 */
+ "h: 85: 0\n" /* fence */
+ "i:134: 2\n" /* 134 */
+ "j: 61: 2\n" /* furnace */
+ "k:134: 6\n" /* 134 */
+ "l:134: 4\n" /* 134 */
+ "m: 19: 0\n" /* sponge */
+ "n: 64:12\n" /* wooddoorblock */
+ "o: 50: 2\n" /* torch */
+ "p:101: 0\n" /* ironbars */
+ "q:171: 8\n" /* carpet */
+ "r:128: 2\n" /* sandstonestairs */
+ "s:126: 8\n" /* woodenslab */
+ "t:128: 4\n" /* sandstonestairs */
+ "u:128: 5\n" /* sandstonestairs */
+ "v:128: 7\n" /* sandstonestairs */
+ "w: 44: 1\n" /* step */
+ "x: 96: 1\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aabaa"
+ /* 3 */ "abbba"
+ /* 4 */ "abbba"
+ /* 5 */ "abbba"
+ /* 6 */ "abbba"
+ /* 7 */ "abbba"
+ /* 8 */ "abbba"
+ /* 9 */ "abbba"
+ /* 10 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "c...c"
+ /* 1 */ "....."
+ /* 2 */ "cdedc"
+ /* 3 */ "df..d"
+ /* 4 */ "d...d"
+ /* 5 */ "d..gd"
+ /* 6 */ "d..hd"
+ /* 7 */ "d..id"
+ /* 8 */ "d...d"
+ /* 9 */ "djkld"
+ /* 10 */ "cdddc"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "c...c"
+ /* 1 */ "....."
+ /* 2 */ "cdndc"
+ /* 3 */ "df..d"
+ /* 4 */ "d..od"
+ /* 5 */ "p...p"
+ /* 6 */ "p..qp"
+ /* 7 */ "p...p"
+ /* 8 */ "d...d"
+ /* 9 */ "d...d"
+ /* 10 */ "cdpdc"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "r...r"
+ /* 1 */ "d...d"
+ /* 2 */ "cdddc"
+ /* 3 */ "dfssd"
+ /* 4 */ "dsssd"
+ /* 5 */ "tsssu"
+ /* 6 */ "tsssu"
+ /* 7 */ "tsssu"
+ /* 8 */ "dsssd"
+ /* 9 */ "dsssd"
+ /* 10 */ "cdvdc"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "dwdwd"
+ /* 3 */ "wx..w"
+ /* 4 */ "w...w"
+ /* 5 */ "w...w"
+ /* 6 */ "d...d"
+ /* 7 */ "w...w"
+ /* 8 */ "w...w"
+ /* 9 */ "w...w"
+ /* 10 */ "dwdwd",
+
+ // Connectors:
+ "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse4
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse5:
+ // The data has been exported from the gallery Desert, area index 68, ID 558, created by STR_Warrior
+ {
+ // Size:
+ 9, 5, 9, // SizeX = 9, SizeY = 5, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 65: 2\n" /* ladder */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:101: 0\n" /* ironbars */
+ "i: 50: 1\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 2\n" /* sandstonestairs */
+ "l:126: 8\n" /* woodenslab */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 6\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p:128: 4\n" /* sandstonestairs */
+ "q:128: 7\n" /* sandstonestairs */
+ "r: 44: 1\n" /* step */
+ "s: 96: 6\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "aaaaaaaaa"
+ /* 2 */ "aaaaaabaa"
+ /* 3 */ "aaaaabbba"
+ /* 4 */ "aaaaabbba"
+ /* 5 */ "abbbbbbba"
+ /* 6 */ "abbbbbbba"
+ /* 7 */ "abbbbbbba"
+ /* 8 */ "aaaaaaaaa"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmc...c"
+ /* 1 */ "mmmm....."
+ /* 2 */ "mmmmcdedc"
+ /* 3 */ "mmmmd...d"
+ /* 4 */ "cdddd...d"
+ /* 5 */ "d.......d"
+ /* 6 */ "d.......d"
+ /* 7 */ "d......fd"
+ /* 8 */ "cdddddddc"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmc...c"
+ /* 1 */ "mmmm....."
+ /* 2 */ "mmmmcdgdc"
+ /* 3 */ "mmmmd...d"
+ /* 4 */ "cdhdd...h"
+ /* 5 */ "d.......h"
+ /* 6 */ "h.......d"
+ /* 7 */ "di....jfd"
+ /* 8 */ "cddhhhddc"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmk...k"
+ /* 1 */ "mmmmd...d"
+ /* 2 */ "mmmmcdddc"
+ /* 3 */ "mmmmdllld"
+ /* 4 */ "cdnddlllo"
+ /* 5 */ "dlllllllo"
+ /* 6 */ "pllllllld"
+ /* 7 */ "dllllllfd"
+ /* 8 */ "cddqqqddc"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "mmmm....."
+ /* 1 */ "mmmm....."
+ /* 2 */ "mmmmcrdrd"
+ /* 3 */ "mmmmr...r"
+ /* 4 */ "drrrd...d"
+ /* 5 */ "r.......r"
+ /* 6 */ "r.......r"
+ /* 7 */ "r......sr"
+ /* 8 */ "drrrdrrrd",
+
+ // Connectors:
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse6:
+ // The data has been exported from the gallery Desert, area index 69, ID 559, created by STR_Warrior
+ {
+ // Size:
+ 9, 5, 9, // SizeX = 9, SizeY = 5, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 2: 0\n" /* grass */
+ "c: 5: 0\n" /* wood */
+ "d: 85: 0\n" /* fence */
+ "e: 24: 2\n" /* sandstone */
+ "f: 24: 0\n" /* sandstone */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h: 38: 1\n" /* rose */
+ "i: 38: 2\n" /* rose */
+ "j: 38: 5\n" /* rose */
+ "k: 65: 2\n" /* ladder */
+ "l: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */
+ "n:101: 0\n" /* ironbars */
+ "o: 50: 1\n" /* torch */
+ "p: 50: 4\n" /* torch */
+ "q:128: 2\n" /* sandstonestairs */
+ "r:126: 8\n" /* woodenslab */
+ "s:128: 6\n" /* sandstonestairs */
+ "t:128: 5\n" /* sandstonestairs */
+ "u:128: 4\n" /* sandstonestairs */
+ "v:128: 7\n" /* sandstonestairs */
+ "w: 44: 1\n" /* step */
+ "x: 96: 6\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "abbbaaaaa"
+ /* 2 */ "abbbaacaa"
+ /* 3 */ "abbbaccca"
+ /* 4 */ "aaaaaccca"
+ /* 5 */ "accccccca"
+ /* 6 */ "accccccca"
+ /* 7 */ "accccccca"
+ /* 8 */ "aaaaaaaaa"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "dddde...e"
+ /* 1 */ "d........"
+ /* 2 */ "d...efgfe"
+ /* 3 */ "dhijf...f"
+ /* 4 */ "effff...f"
+ /* 5 */ "f.......f"
+ /* 6 */ "f.......f"
+ /* 7 */ "f......kf"
+ /* 8 */ "efffffffe"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "....e...e"
+ /* 1 */ "........."
+ /* 2 */ "....eflfe"
+ /* 3 */ "....f...f"
+ /* 4 */ "efnff...n"
+ /* 5 */ "f.......n"
+ /* 6 */ "n.......f"
+ /* 7 */ "fo....pkf"
+ /* 8 */ "effnnnffe"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "....q...q"
+ /* 1 */ "....f...f"
+ /* 2 */ "....efffe"
+ /* 3 */ "....frrrf"
+ /* 4 */ "efsffrrrt"
+ /* 5 */ "frrrrrrrt"
+ /* 6 */ "urrrrrrrf"
+ /* 7 */ "frrrrrrkf"
+ /* 8 */ "effvvvffe"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "....ewfwf"
+ /* 3 */ "....w...w"
+ /* 4 */ "fwwwf...f"
+ /* 5 */ "w.......w"
+ /* 6 */ "w.......w"
+ /* 7 */ "w......xw"
+ /* 8 */ "fwwwfwwwf",
+
+ // Connectors:
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse6
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleHouse7:
+ // The data has been exported from the gallery Desert, area index 73, ID 563, created by xoft
+ {
+ // Size:
+ 9, 5, 11, // SizeX = 9, SizeY = 5, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 65: 2\n" /* ladder */
+ "g:101: 0\n" /* ironbars */
+ "h: 64:12\n" /* wooddoorblock */
+ "i: 50: 1\n" /* torch */
+ "j: 50: 2\n" /* torch */
+ "k:128: 2\n" /* sandstonestairs */
+ "l:128: 6\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:126: 8\n" /* woodenslab */
+ "o:128: 4\n" /* sandstonestairs */
+ "p:128: 5\n" /* sandstonestairs */
+ "q:128: 7\n" /* sandstonestairs */
+ "r: 44: 1\n" /* step */
+ "s: 96: 6\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "aaaaaaaaa"
+ /* 2 */ "aaaaaabaa"
+ /* 3 */ "abbbbbbba"
+ /* 4 */ "abbbbbbba"
+ /* 5 */ "abbbbbbba"
+ /* 6 */ "aaaaabbba"
+ /* 7 */ "aaaaabbba"
+ /* 8 */ "aaaaabbba"
+ /* 9 */ "aaaaabbba"
+ /* 10 */ "aaaaaaaaa"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "....c...c"
+ /* 1 */ "........."
+ /* 2 */ "cdddddedc"
+ /* 3 */ "d.......d"
+ /* 4 */ "d.......d"
+ /* 5 */ "d.......d"
+ /* 6 */ "cdddd...d"
+ /* 7 */ "mmmmd...d"
+ /* 8 */ "mmmmd...d"
+ /* 9 */ "mmmmd..fd"
+ /* 10 */ "mmmmddddc"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "....c...c"
+ /* 1 */ "........."
+ /* 2 */ "cdgdddhdc"
+ /* 3 */ "d.......d"
+ /* 4 */ "g.......d"
+ /* 5 */ "di......g"
+ /* 6 */ "cdgdd...g"
+ /* 7 */ "mmmmd...g"
+ /* 8 */ "mmmmg..jd"
+ /* 9 */ "mmmmd..fd"
+ /* 10 */ "mmmmddgdc"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "....k...k"
+ /* 1 */ "....d...d"
+ /* 2 */ "cdldddddc"
+ /* 3 */ "dnnnnnnnd"
+ /* 4 */ "onnnnnnnd"
+ /* 5 */ "dnnnnnnnp"
+ /* 6 */ "cdqddnnnp"
+ /* 7 */ "mmmmdnnnp"
+ /* 8 */ "mmmmonnnd"
+ /* 9 */ "mmmmdnnfd"
+ /* 10 */ "mmmmddqdc"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "drrrdrdrd"
+ /* 3 */ "r.......r"
+ /* 4 */ "r.......r"
+ /* 5 */ "r.......r"
+ /* 6 */ "drrrd...d"
+ /* 7 */ "mmmmr...r"
+ /* 8 */ "mmmmr...r"
+ /* 9 */ "mmmmr..sr"
+ /* 10 */ "mmmmdrrrd",
+
+ // Connectors:
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleHouse7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LittleTower:
+ // The data has been exported from the gallery Desert, area index 79, ID 595, created by STR_Warrior
+ {
+ // Size:
+ 5, 8, 7, // SizeX = 5, SizeY = 8, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 5, 7, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 65: 5\n" /* ladder */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:101: 0\n" /* ironbars */
+ "i: 50: 4\n" /* torch */
+ "j:128: 2\n" /* sandstonestairs */
+ "k:126: 8\n" /* woodenslab */
+ "l:128: 4\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 5\n" /* sandstonestairs */
+ "o:128: 7\n" /* sandstonestairs */
+ "p:128: 6\n" /* sandstonestairs */
+ "q: 44: 1\n" /* step */
+ "r: 96: 5\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aabaa"
+ /* 3 */ "abbba"
+ /* 4 */ "abbba"
+ /* 5 */ "abbba"
+ /* 6 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "c...c"
+ /* 1 */ "....."
+ /* 2 */ "cdedc"
+ /* 3 */ "df..d"
+ /* 4 */ "d...d"
+ /* 5 */ "d...d"
+ /* 6 */ "cdddc"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "c...c"
+ /* 1 */ "....."
+ /* 2 */ "cdgdc"
+ /* 3 */ "df..d"
+ /* 4 */ "h...h"
+ /* 5 */ "d..id"
+ /* 6 */ "cdhdc"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "j...j"
+ /* 1 */ "d...d"
+ /* 2 */ "cdddc"
+ /* 3 */ "dfkkd"
+ /* 4 */ "lkkkn"
+ /* 5 */ "dkkkd"
+ /* 6 */ "cdodc"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "cdddc"
+ /* 3 */ "df..d"
+ /* 4 */ "d...d"
+ /* 5 */ "d...d"
+ /* 6 */ "cdddc"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "cdhdc"
+ /* 3 */ "df..d"
+ /* 4 */ "h...h"
+ /* 5 */ "d..id"
+ /* 6 */ "cdhdc"
+
+ // Level 6
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "cdpdc"
+ /* 3 */ "dfkkd"
+ /* 4 */ "lkkkn"
+ /* 5 */ "dkkkd"
+ /* 6 */ "cdodc"
+
+ // Level 7
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "dqdqd"
+ /* 3 */ "qr..q"
+ /* 4 */ "d...d"
+ /* 5 */ "q...q"
+ /* 6 */ "dqdqd",
+
+ // Connectors:
+ "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LittleTower
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MediumHouse1:
+ // The data has been exported from the gallery Desert, area index 71, ID 561, created by STR_Warrior
+ {
+ // Size:
+ 15, 8, 9, // SizeX = 15, SizeY = 8, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 15, 7, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 3\n" /* wooddoorblock */
+ "f: 85: 0\n" /* fence */
+ "g: 64: 0\n" /* wooddoorblock */
+ "h: 65: 5\n" /* ladder */
+ "i: 64: 8\n" /* wooddoorblock */
+ "j:101: 0\n" /* ironbars */
+ "k: 50: 4\n" /* torch */
+ "l:128: 2\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:126: 8\n" /* woodenslab */
+ "o:128: 4\n" /* sandstonestairs */
+ "p:128: 7\n" /* sandstonestairs */
+ "q: 44: 1\n" /* step */
+ "r: 50: 3\n" /* torch */
+ "s:128: 6\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaabaaaaaaaaa"
+ /* 3 */ "abbbbbbbbbaaaaa"
+ /* 4 */ "abbbbbbbbbaaaaa"
+ /* 5 */ "abbbbbbbbbbaaaa"
+ /* 6 */ "abbbbbbbbbaaaaa"
+ /* 7 */ "abbbbbbbbbaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "...c...c......."
+ /* 1 */ "..............."
+ /* 2 */ "cddddeddddcffff"
+ /* 3 */ "d.........d...f"
+ /* 4 */ "d.........d...f"
+ /* 5 */ "d.........g...f"
+ /* 6 */ "d.........d...f"
+ /* 7 */ "d.........dh..f"
+ /* 8 */ "cdddddddddcffff"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "...c...c......."
+ /* 1 */ "..............."
+ /* 2 */ "cddddiddddc...."
+ /* 3 */ "d.........d...."
+ /* 4 */ "j.........d...."
+ /* 5 */ "j.........i...."
+ /* 6 */ "j.........d...."
+ /* 7 */ "d..k...k..dh..."
+ /* 8 */ "cdddjjjdddc...."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "...l...l......."
+ /* 1 */ "...d...d......."
+ /* 2 */ "cdddddddddc...."
+ /* 3 */ "dnnnnnnnnnd...."
+ /* 4 */ "onnnnnnnnnd...."
+ /* 5 */ "onnnnnnnnnd...."
+ /* 6 */ "onnnnnnnnnd...."
+ /* 7 */ "dnnnnnnnnndh..."
+ /* 8 */ "cdddpppdddc...."
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "dqqqqdqqqqd...."
+ /* 3 */ "q..cdddc..q...."
+ /* 4 */ "q..d...d..q...."
+ /* 5 */ "d.........d...."
+ /* 6 */ "q..d...d..q...."
+ /* 7 */ "q..cdddc..q...."
+ /* 8 */ "dqqqqdqqqqd...."
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "...cdjdc......."
+ /* 4 */ "...dr..d......."
+ /* 5 */ "..............."
+ /* 6 */ "...d...d......."
+ /* 7 */ "...cdjdc......."
+ /* 8 */ "..............."
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "...cdsdc......."
+ /* 4 */ "...dnnnd......."
+ /* 5 */ "...dnnnd......."
+ /* 6 */ "...dnnnd......."
+ /* 7 */ "...cdpdc......."
+ /* 8 */ "..............."
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "...dqdqd......."
+ /* 4 */ "...q...q......."
+ /* 5 */ "...d...d......."
+ /* 6 */ "...q...q......."
+ /* 7 */ "...dqdqd......."
+ /* 8 */ "...............",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 80,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // MediumHouse1
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MediumHouse2:
+ // The data has been exported from the gallery Desert, area index 74, ID 573, created by STR_Warrior
+ {
+ // Size:
+ 11, 9, 9, // SizeX = 11, SizeY = 9, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 8, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A: 96: 3\n" /* trapdoor */
+ "B: 96: 6\n" /* trapdoor */
+ "C:128: 2\n" /* sandstonestairs */
+ "D:128: 0\n" /* sandstonestairs */
+ "E: 87: 0\n" /* netherstone */
+ "F:128: 1\n" /* sandstonestairs */
+ "G:128: 3\n" /* sandstonestairs */
+ "H: 51: 0\n" /* fire */
+ "I: 44: 9\n" /* step */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 65: 3\n" /* ladder */
+ "f: 85: 0\n" /* fence */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h:134: 1\n" /* 134 */
+ "i:134: 2\n" /* 134 */
+ "j: 61: 2\n" /* furnace */
+ "k:134: 6\n" /* 134 */
+ "l:134: 4\n" /* 134 */
+ "m: 19: 0\n" /* sponge */
+ "n: 65: 2\n" /* ladder */
+ "o:101: 0\n" /* ironbars */
+ "p: 50: 2\n" /* torch */
+ "q: 47: 0\n" /* bookshelf */
+ "r: 64:12\n" /* wooddoorblock */
+ "s: 50: 3\n" /* torch */
+ "t:171: 8\n" /* carpet */
+ "u:128: 6\n" /* sandstonestairs */
+ "v:126: 8\n" /* woodenslab */
+ "w:128: 5\n" /* sandstonestairs */
+ "x:128: 4\n" /* sandstonestairs */
+ "y:128: 7\n" /* sandstonestairs */
+ "z: 44: 1\n" /* step */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "abbbaaaaaaa"
+ /* 2 */ "abbbaaaaaaa"
+ /* 3 */ "abbbaaaaaaa"
+ /* 4 */ "abbbaaaabaa"
+ /* 5 */ "abbbbbbbbba"
+ /* 6 */ "abbbbbbbbba"
+ /* 7 */ "abbbbbbbbba"
+ /* 8 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "cdddc......"
+ /* 1 */ "de..dfff.f."
+ /* 2 */ "d...d....f."
+ /* 3 */ "d...d....f."
+ /* 4 */ "d...ddddgdc"
+ /* 5 */ "d.........d"
+ /* 6 */ "dhf.......d"
+ /* 7 */ "dhi.jkl..nd"
+ /* 8 */ "cdddddddddc"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "cdodc......"
+ /* 1 */ "de..o......"
+ /* 2 */ "d...o......"
+ /* 3 */ "o..pd......"
+ /* 4 */ "o...qdodrdc"
+ /* 5 */ "o......s..d"
+ /* 6 */ "d.t.......o"
+ /* 7 */ "d........nd"
+ /* 8 */ "cdddooodddc"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "cdudc......"
+ /* 1 */ "devvw......"
+ /* 2 */ "dvvvw......"
+ /* 3 */ "xvvvd......"
+ /* 4 */ "xvvvddudddc"
+ /* 5 */ "xvvvvvvvvvd"
+ /* 6 */ "dvvvvvvvvvw"
+ /* 7 */ "dvvvqqqvvnd"
+ /* 8 */ "cdddyyydddc"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "dzzzd......"
+ /* 1 */ "zA..z......"
+ /* 2 */ "z...z......"
+ /* 3 */ "z...z......"
+ /* 4 */ "d...dzzzzzd"
+ /* 5 */ "zddd......z"
+ /* 6 */ "zddd......z"
+ /* 7 */ "zddd.....Bz"
+ /* 8 */ "dzzzzdzzzzd"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "..........."
+ /* 5 */ ".cCc......."
+ /* 6 */ ".DEF......."
+ /* 7 */ ".cGc......."
+ /* 8 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "..........."
+ /* 5 */ ".c.c......."
+ /* 6 */ "..H........"
+ /* 7 */ ".c.c......."
+ /* 8 */ "..........."
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "..........."
+ /* 5 */ ".ddd......."
+ /* 6 */ ".dId......."
+ /* 7 */ ".ddd......."
+ /* 8 */ "..........."
+
+ // Level 8
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "..........."
+ /* 5 */ ".z.z......."
+ /* 6 */ "..........."
+ /* 7 */ ".z.z......."
+ /* 8 */ "...........",
+
+ // Connectors:
+ "-1: 8, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 80,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // MediumHouse2
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MediumHouse3:
+ // The data has been exported from the gallery Desert, area index 76, ID 575, created by STR_Warrior
+ {
+ // Size:
+ 12, 10, 11, // SizeX = 12, SizeY = 10, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 12, 9, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 3: 0\n" /* dirt */
+ "c: 2: 0\n" /* grass */
+ "d: 5: 0\n" /* wood */
+ "e: 24: 0\n" /* sandstone */
+ "f: 24: 2\n" /* sandstone */
+ "g: 85: 0\n" /* fence */
+ "h: 64: 3\n" /* wooddoorblock */
+ "i: 64: 6\n" /* wooddoorblock */
+ "j: 65: 4\n" /* ladder */
+ "k: 65: 2\n" /* ladder */
+ "l: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 2\n" /* torch */
+ "o:101: 0\n" /* ironbars */
+ "p: 64: 8\n" /* wooddoorblock */
+ "q: 64:12\n" /* wooddoorblock */
+ "r:128: 2\n" /* sandstonestairs */
+ "s:128: 6\n" /* sandstonestairs */
+ "t:126: 8\n" /* woodenslab */
+ "u:128: 5\n" /* sandstonestairs */
+ "v:128: 7\n" /* sandstonestairs */
+ "w: 44: 1\n" /* step */
+ "x: 96: 4\n" /* trapdoor */
+ "y:126: 0\n" /* woodenslab */
+ "z:128: 4\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "bbbbbaaaaaaa"
+ /* 3 */ "bbbbbaaaaaaa"
+ /* 4 */ "bbbbbaaaaaaa"
+ /* 5 */ "bbbbbaaaaaaa"
+ /* 6 */ "bbbaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "cccccaaaadaa"
+ /* 3 */ "cccccaddddda"
+ /* 4 */ "cccccdddddda"
+ /* 5 */ "cccccaddddda"
+ /* 6 */ "cccaadddddda"
+ /* 7 */ "aaaaddddddda"
+ /* 8 */ "aaaadddaaaaa"
+ /* 9 */ "aaaadddaaaaa"
+ /* 10 */ "aaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ ".....e.....f"
+ /* 1 */ "............"
+ /* 2 */ "gggggfeeehef"
+ /* 3 */ "g....e.....e"
+ /* 4 */ "g....i.....e"
+ /* 5 */ "g....e.....e"
+ /* 6 */ "gggfe......e"
+ /* 7 */ "mmme......je"
+ /* 8 */ "mmme...eeeef"
+ /* 9 */ "mmme..kemmmm"
+ /* 10 */ "mmmfeeefmmmm"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ ".....el...nf"
+ /* 1 */ "............"
+ /* 2 */ ".....fooepef"
+ /* 3 */ ".....e.....e"
+ /* 4 */ ".....q.....e"
+ /* 5 */ ".....e.....o"
+ /* 6 */ "...ge......e"
+ /* 7 */ "mmme......je"
+ /* 8 */ "mmme...eeoof"
+ /* 9 */ "mmme..kemmmm"
+ /* 10 */ "mmmgeeegmmmm"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ ".....r.....r"
+ /* 1 */ ".....e.....e"
+ /* 2 */ ".....fsseeef"
+ /* 3 */ ".....ettttte"
+ /* 4 */ ".....ettttte"
+ /* 5 */ ".....etttttu"
+ /* 6 */ "...getttttte"
+ /* 7 */ "mmmettttttje"
+ /* 8 */ "mmmettteevvf"
+ /* 9 */ "mmmettkemmmm"
+ /* 10 */ "mmmgeeegmmmm"
+
+ // Level 5
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ ".....ewwewwe"
+ /* 3 */ ".....w.....w"
+ /* 4 */ ".....w.....w"
+ /* 5 */ ".....w.....e"
+ /* 6 */ "...geeeg...w"
+ /* 7 */ "mmme...e..xw"
+ /* 8 */ "mmme...ewwwe"
+ /* 9 */ "mmme..kemmmm"
+ /* 10 */ "mmmgeeegmmmm"
+
+ // Level 6
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "............"
+ /* 4 */ "............"
+ /* 5 */ "............"
+ /* 6 */ "...ge.eg...."
+ /* 7 */ "mmme...e...."
+ /* 8 */ "mmmo........"
+ /* 9 */ "mmme..kemmmm"
+ /* 10 */ "mmmgeoegmmmm"
+
+ // Level 7
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "............"
+ /* 4 */ "............"
+ /* 5 */ "............"
+ /* 6 */ "...ge.eg...."
+ /* 7 */ "mmme...e...."
+ /* 8 */ "mmmo........"
+ /* 9 */ "mmmel.kemmmm"
+ /* 10 */ "mmmgeoegmmmm"
+
+ // Level 8
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "............"
+ /* 4 */ "............"
+ /* 5 */ "............"
+ /* 6 */ "...fesef...."
+ /* 7 */ "mmmeyyye...."
+ /* 8 */ "mmmzyyyu...."
+ /* 9 */ "mmmeyykemmmm"
+ /* 10 */ "mmmfevefmmmm"
+
+ // Level 9
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "............"
+ /* 4 */ "............"
+ /* 5 */ "............"
+ /* 6 */ "...w.w.w...."
+ /* 7 */ "mmm........."
+ /* 8 */ "mmmw...w...."
+ /* 9 */ "mmm.....mmmm"
+ /* 10 */ "mmmw.w.wmmmm",
+
+ // Connectors:
+ "-1: 9, 2, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 80,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // MediumHouse3
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // SmallHouse9:
+ // The data has been exported from the gallery Desert, area index 67, ID 556, created by STR_Warrior
+ {
+ // Size:
+ 9, 5, 11, // SizeX = 9, SizeY = 5, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 65: 2\n" /* ladder */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:101: 0\n" /* ironbars */
+ "i: 50: 2\n" /* torch */
+ "j: 50: 1\n" /* torch */
+ "k:128: 2\n" /* sandstonestairs */
+ "l:126: 8\n" /* woodenslab */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 5\n" /* sandstonestairs */
+ "o:128: 6\n" /* sandstonestairs */
+ "p:128: 4\n" /* sandstonestairs */
+ "q:128: 7\n" /* sandstonestairs */
+ "r: 44: 1\n" /* step */
+ "s: 96: 6\n" /* trapdoor */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "aaaaaaaaa"
+ /* 2 */ "aaaaaabaa"
+ /* 3 */ "aaaaabbba"
+ /* 4 */ "aaaaabbba"
+ /* 5 */ "aaaaabbba"
+ /* 6 */ "aaaaabbba"
+ /* 7 */ "abbbbbbba"
+ /* 8 */ "abbbbbbba"
+ /* 9 */ "abbbbbbba"
+ /* 10 */ "aaaaaaaaa"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmc...c"
+ /* 1 */ "mmmm....."
+ /* 2 */ "mmmmcdedc"
+ /* 3 */ "mmmmd...d"
+ /* 4 */ "mmmmd...d"
+ /* 5 */ "mmmmd...d"
+ /* 6 */ "cdddd...d"
+ /* 7 */ "d.......d"
+ /* 8 */ "d.......d"
+ /* 9 */ "d......fd"
+ /* 10 */ "cdddddddc"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmc...c"
+ /* 1 */ "mmmm....."
+ /* 2 */ "mmmmcdgdc"
+ /* 3 */ "mmmmd...d"
+ /* 4 */ "mmmmd...d"
+ /* 5 */ "mmmmd...h"
+ /* 6 */ "cdhdd...h"
+ /* 7 */ "d.......h"
+ /* 8 */ "h......id"
+ /* 9 */ "dj.....fd"
+ /* 10 */ "cddhhhddc"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmk...k"
+ /* 1 */ "mmmmd...d"
+ /* 2 */ "mmmmcdddc"
+ /* 3 */ "mmmmdllld"
+ /* 4 */ "mmmmdllld"
+ /* 5 */ "mmmmdllln"
+ /* 6 */ "cdoddllln"
+ /* 7 */ "dllllllln"
+ /* 8 */ "pllllllld"
+ /* 9 */ "dllllllfd"
+ /* 10 */ "cddqqqddc"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "mmmm....."
+ /* 1 */ "mmmm....."
+ /* 2 */ "mmmmdrdrd"
+ /* 3 */ "mmmmr...r"
+ /* 4 */ "mmmmr...r"
+ /* 5 */ "mmmmr...r"
+ /* 6 */ "drrrd...d"
+ /* 7 */ "r.......r"
+ /* 8 */ "r.......r"
+ /* 9 */ "r......sr"
+ /* 10 */ "drrrdrrrd",
+
+ // Connectors:
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // SmallHouse9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Temple:
+ // The data has been exported from the gallery Desert, area index 83, ID 599, created by STR_Warrior
+ {
+ // Size:
+ 13, 9, 9, // SizeX = 13, SizeY = 9, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 13, 8, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A: 44: 9\n" /* step */
+ "a: 12: 0\n" /* sand */
+ "b: 5: 0\n" /* wood */
+ "c: 24: 2\n" /* sandstone */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 17: 0\n" /* tree */
+ "g:128: 5\n" /* sandstonestairs */
+ "h:128: 4\n" /* sandstonestairs */
+ "i:128: 7\n" /* sandstonestairs */
+ "j:128: 6\n" /* sandstonestairs */
+ "k:118: 3\n" /* cauldronblock */
+ "l:155: 1\n" /* quartzblock */
+ "m: 19: 0\n" /* sponge */
+ "n: 64:12\n" /* wooddoorblock */
+ "o: 50: 3\n" /* torch */
+ "p:101: 0\n" /* ironbars */
+ "q:140: 0\n" /* flowerpotblock */
+ "r: 24: 1\n" /* sandstone */
+ "s:128: 2\n" /* sandstonestairs */
+ "t:126: 8\n" /* woodenslab */
+ "u: 44: 1\n" /* step */
+ "v:128: 0\n" /* sandstonestairs */
+ "w: 87: 0\n" /* netherstone */
+ "x:128: 1\n" /* sandstonestairs */
+ "y:128: 3\n" /* sandstonestairs */
+ "z: 51: 0\n" /* fire */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaabbababbaaa"
+ /* 3 */ "abbbbbbbbbbba"
+ /* 4 */ "abbbbbbbbbbba"
+ /* 5 */ "abbbbbbbbbbba"
+ /* 6 */ "abbbbbbbbbbba"
+ /* 7 */ "abbbbbbbbbbba"
+ /* 8 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "....c...c...."
+ /* 1 */ "............."
+ /* 2 */ "cdddddedddddc"
+ /* 3 */ "dfg.......hfd"
+ /* 4 */ "di.........id"
+ /* 5 */ "d...........d"
+ /* 6 */ "dj.........jd"
+ /* 7 */ "dfg.khlgk.hfd"
+ /* 8 */ "cdddddddddddc"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "....c...c...."
+ /* 1 */ "............."
+ /* 2 */ "cdddddndddddc"
+ /* 3 */ "df...o.o...fd"
+ /* 4 */ "d...........d"
+ /* 5 */ "p...........p"
+ /* 6 */ "d...........d"
+ /* 7 */ "df...qrq...fd"
+ /* 8 */ "cdpppdddpppdc"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "....s...s...."
+ /* 1 */ "....r...d...."
+ /* 2 */ "cdddddddddddc"
+ /* 3 */ "dftttttttttfd"
+ /* 4 */ "dtttttttttttd"
+ /* 5 */ "htttttttttttg"
+ /* 6 */ "dtttttttttttd"
+ /* 7 */ "dftttttttttfd"
+ /* 8 */ "cdiiidddiiidc"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "duuuuuduuuuud"
+ /* 3 */ "u...........u"
+ /* 4 */ "u.ddd...ddd.u"
+ /* 5 */ "d.ddd...ddd.d"
+ /* 6 */ "u.ddd...ddd.u"
+ /* 7 */ "u...........u"
+ /* 8 */ "duuuuuduuuuud"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "..csc...csc.."
+ /* 5 */ "..vwx...vwx.."
+ /* 6 */ "..cyc...cyc.."
+ /* 7 */ "............."
+ /* 8 */ "............."
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "..c.c...c.c.."
+ /* 5 */ "...z.....z..."
+ /* 6 */ "..c.c...c.c.."
+ /* 7 */ "............."
+ /* 8 */ "............."
+
+ // Level 7
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "..ddd...ddd.."
+ /* 5 */ "..dAd...dAd.."
+ /* 6 */ "..ddd...ddd.."
+ /* 7 */ "............."
+ /* 8 */ "............."
+
+ // Level 8
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "..u.u...u.u.."
+ /* 5 */ "............."
+ /* 6 */ "..u.u...u.u.."
+ /* 7 */ "............."
+ /* 8 */ ".............",
+
+ // Connectors:
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 50,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Temple
+}; // g_AlchemistVillagePrefabs
+
+
+
+
+
+
+const cPrefab::sDef g_AlchemistVillageStartingPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Well:
+ // The data has been exported from the gallery Desert, area index 90, ID 631, created by STR_Warrior
+ {
+ // Size:
+ 5, 21, 5, // SizeX = 5, SizeY = 21, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 20, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 24: 0\n" /* sandstone */
+ "c: 8: 0\n" /* water */
+ "d: 24: 2\n" /* sandstone */
+ "e:128: 1\n" /* sandstonestairs */
+ "f: 44: 1\n" /* step */
+ "g:128: 0\n" /* sandstonestairs */
+ "h:128: 3\n" /* sandstonestairs */
+ "i:128: 2\n" /* sandstonestairs */
+ "j: 44: 9\n" /* step */
+ "k:126: 0\n" /* woodenslab */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 6
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 7
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 8
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 9
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 10
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 11
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 12
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 13
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 14
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 15
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 16
+ /* z\x* 01234 */
+ /* 0 */ "defgd"
+ /* 1 */ "h...h"
+ /* 2 */ "f...f"
+ /* 3 */ "i...i"
+ /* 4 */ "defgd"
+
+ // Level 17
+ /* z\x* 01234 */
+ /* 0 */ "d...d"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "d...d"
+
+ // Level 18
+ /* z\x* 01234 */
+ /* 0 */ "djjjd"
+ /* 1 */ "j...j"
+ /* 2 */ "j...j"
+ /* 3 */ "j...j"
+ /* 4 */ "djjjd"
+
+ // Level 19
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bkkkb"
+ /* 2 */ "bkkkb"
+ /* 3 */ "bkkkb"
+ /* 4 */ "bbbbb"
+
+ // Level 20
+ /* z\x* 01234 */
+ /* 0 */ "f.f.f"
+ /* 1 */ "....."
+ /* 2 */ "f...f"
+ /* 3 */ "....."
+ /* 4 */ "f.f.f",
+
+ // Connectors:
+ "2: 2, 16, 4: 3\n" /* Type 2, direction Z+ */
+ "2: 0, 16, 2: 4\n" /* Type 2, direction X- */
+ "2: 2, 16, 0: 2\n" /* Type 2, direction Z- */
+ "2: 4, 16, 2: 5\n" /* Type 2, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Well
+};
+
+
+
+
+
+// The prefab counts:
+
+const size_t g_AlchemistVillagePrefabsCount = ARRAYCOUNT(g_AlchemistVillagePrefabs);
+
+const size_t g_AlchemistVillageStartingPrefabsCount = ARRAYCOUNT(g_AlchemistVillageStartingPrefabs);
+
diff --git a/src/Generating/Prefabs/AlchemistVillagePrefabs.h b/src/Generating/Prefabs/AlchemistVillagePrefabs.h
new file mode 100644
index 000000000..dddc5530a
--- /dev/null
+++ b/src/Generating/Prefabs/AlchemistVillagePrefabs.h
@@ -0,0 +1,15 @@
+
+// AlchemistVillagePrefabs.h
+
+// Declares the prefabs in the group AlchemistVillage
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_AlchemistVillagePrefabs[];
+extern const cPrefab::sDef g_AlchemistVillageStartingPrefabs[];
+extern const size_t g_AlchemistVillagePrefabsCount;
+extern const size_t g_AlchemistVillageStartingPrefabsCount;
diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt
new file mode 100644
index 000000000..a1f09112d
--- /dev/null
+++ b/src/Generating/Prefabs/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+cmake_minimum_required (VERSION 2.6)
+project (MCServer)
+
+include_directories ("${PROJECT_SOURCE_DIR}/../../")
+
+file(GLOB SOURCE
+ "*.cpp"
+ "*.h"
+)
+
+add_library(Generating_Prefabs ${SOURCE})
+
+target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks)
diff --git a/src/Generating/Prefabs/JapaneseVillagePrefabs.cpp b/src/Generating/Prefabs/JapaneseVillagePrefabs.cpp
new file mode 100644
index 000000000..5ec222f84
--- /dev/null
+++ b/src/Generating/Prefabs/JapaneseVillagePrefabs.cpp
@@ -0,0 +1,3200 @@
+
+// JapaneseVillagePrefabs.cpp
+
+// Defines the prefabs in the group JapaneseVillage
+
+// NOTE: This file has been generated automatically by GalExport!
+// Any manual changes will be overwritten by the next automatic export!
+
+#include "Globals.h"
+#include "JapaneseVillagePrefabs.h"
+
+
+
+
+
+const cPrefab::sDef g_JapaneseVillagePrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Arch:
+ // The data has been exported from the gallery Plains, area index 144, ID 488, created by Aloe_vera
+ {
+ // Size:
+ 11, 7, 5, // SizeX = 11, SizeY = 7, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 6, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 2: 0\n" /* grass */
+ "b: 13: 0\n" /* gravel */
+ "c:113: 0\n" /* netherbrickfence */
+ "d: 50: 5\n" /* torch */
+ "e: 44: 8\n" /* step */
+ "f: 44: 0\n" /* step */
+ "g: 43: 0\n" /* doubleslab */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaabbbaaaa"
+ /* 1 */ "aaaabbbaaaa"
+ /* 2 */ "aaaabbbaaaa"
+ /* 3 */ "aaaabbbaaaa"
+ /* 4 */ "aaaabbbaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..c.....c.."
+ /* 1 */ "..c.....c.."
+ /* 2 */ "..c.....c.."
+ /* 3 */ "..c.....c.."
+ /* 4 */ "..c.....c.."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..c.....c.."
+ /* 1 */ "..........."
+ /* 2 */ "..c.....c.."
+ /* 3 */ "..........."
+ /* 4 */ "..c.....c.."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..d.....d.."
+ /* 1 */ "..........."
+ /* 2 */ "..c.....c.."
+ /* 3 */ "..........."
+ /* 4 */ "..d.....d.."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...eeeee..."
+ /* 1 */ "..........."
+ /* 2 */ "..c.....c.."
+ /* 3 */ "..........."
+ /* 4 */ "...eeeee..."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..f.....f.."
+ /* 1 */ ".egfffffge."
+ /* 2 */ ".egeeeeege."
+ /* 3 */ ".egfffffge."
+ /* 4 */ "..f.....f.."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "gf.......fg"
+ /* 3 */ "..........."
+ /* 4 */ "...........",
+
+ // Connectors:
+ "2: 5, 1, 4: 3\n" /* Type 2, direction Z+ */
+ "2: 5, 1, 0: 2\n" /* Type 2, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Arch
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Forge:
+ // The data has been exported from the gallery Plains, area index 79, ID 145, created by Aloe_vera
+ {
+ // Size:
+ 16, 11, 14, // SizeX = 16, SizeY = 11, SizeZ = 14
+
+ // Hitbox (relative to bounding box):
+ 0, 0, -1, // MinX, MinY, MinZ
+ 16, 10, 14, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 17: 1\n" /* tree */
+ "c: 67: 0\n" /* stairs */
+ "d: 5: 2\n" /* wood */
+ "e: 67: 2\n" /* stairs */
+ "f:113: 0\n" /* netherbrickfence */
+ "g:118: 2\n" /* cauldronblock */
+ "h: 67: 6\n" /* stairs */
+ "i: 67: 4\n" /* stairs */
+ "j: 87: 0\n" /* netherstone */
+ "k: 67: 7\n" /* stairs */
+ "l: 54: 5\n" /* chest */
+ "m: 19: 0\n" /* sponge */
+ "n: 61: 2\n" /* furnace */
+ "o:101: 0\n" /* ironbars */
+ "p: 51: 0\n" /* fire */
+ "q: 50: 4\n" /* torch */
+ "r: 50: 2\n" /* torch */
+ "s: 35: 0\n" /* wool */
+ "t: 67: 3\n" /* stairs */
+ "u: 50: 3\n" /* torch */
+ "v: 44: 8\n" /* step */
+ "w: 43: 0\n" /* doubleslab */
+ "x: 44: 0\n" /* step */
+ "y: 17: 5\n" /* tree */
+ "z: 17: 9\n" /* tree */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmmmmmmm"
+ /* 2 */ "mmaaaaaaaaaaaamm"
+ /* 3 */ "mmaaaaaaaaaaaamm"
+ /* 4 */ "mmaaaaaaaaaaaamm"
+ /* 5 */ "mmaaaaaaaaaaaamm"
+ /* 6 */ "mmaaaaaaaaaaaamm"
+ /* 7 */ "mmaaaaaaaaaaaamm"
+ /* 8 */ "mmaaaaaaaaaaaamm"
+ /* 9 */ "mmaaaaaaaaaaaamm"
+ /* 10 */ "mmaaaaaaaaaaaamm"
+ /* 11 */ "mmaaaaaaaaaaaamm"
+ /* 12 */ "mmmmmmmmmmmmmmmm"
+ /* 13 */ "mmmmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ ".....bbbbbbbbb.."
+ /* 3 */ ".....cdddddddb.."
+ /* 4 */ ".....cddaaaadb.."
+ /* 5 */ "..beeedaaaaadb.."
+ /* 6 */ "..bddddaaaaadb.."
+ /* 7 */ "..bddddaaaaadb.."
+ /* 8 */ "..bddddaaaaadb.."
+ /* 9 */ "..bddddaaaaadb.."
+ /* 10 */ "..bddddddddddb.."
+ /* 11 */ "..bbbbbbbbbbbb.."
+ /* 12 */ "................"
+ /* 13 */ "................"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ ".....bfffbfffb.."
+ /* 3 */ ".............a.."
+ /* 4 */ ".............a.."
+ /* 5 */ "..b.....ghh..a.."
+ /* 6 */ "..f.....haa..b.."
+ /* 7 */ "..f.....ija..b.."
+ /* 8 */ "..f.....kaa..a.."
+ /* 9 */ "..f..........a.."
+ /* 10 */ "..fl.........a.."
+ /* 11 */ "..bffffbbffffb.."
+ /* 12 */ "................"
+ /* 13 */ "................"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ ".....bfffbfffb.."
+ /* 3 */ ".............a.."
+ /* 4 */ ".............a.."
+ /* 5 */ "..b......nn..a.."
+ /* 6 */ "..f.....oaa..b.."
+ /* 7 */ "..f.....opa..b.."
+ /* 8 */ "..f.....oaa..a.."
+ /* 9 */ "..f..........a.."
+ /* 10 */ "..f..........a.."
+ /* 11 */ "..bffffbbffffb.."
+ /* 12 */ "................"
+ /* 13 */ "................"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".........q...q.."
+ /* 2 */ "....rbsssbsssb.."
+ /* 3 */ ".............a.."
+ /* 4 */ "..q..........a.."
+ /* 5 */ "..b......ce..a.."
+ /* 6 */ "..s......ea..b.."
+ /* 7 */ "..s......aa..b.."
+ /* 8 */ "..s......ta..a.."
+ /* 9 */ "..s..........a.."
+ /* 10 */ "..s..........a.."
+ /* 11 */ ".rbssssbbssssb.."
+ /* 12 */ "..u....uu....u.."
+ /* 13 */ "................"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ ".vwxxxxxxxxxxwv."
+ /* 1 */ "vvvvvvvvvvvvvvvv"
+ /* 2 */ "wvbyybyyybbyybvw"
+ /* 3 */ "xvz..........zvx"
+ /* 4 */ "xvz..........zvx"
+ /* 5 */ "xvb..........zvx"
+ /* 6 */ "xvz.......a..bvx"
+ /* 7 */ "xvz......ca..bvx"
+ /* 8 */ "xvz.......a..zvx"
+ /* 9 */ "xvz..........zvx"
+ /* 10 */ "xvz..........zvx"
+ /* 11 */ "wvbyyyyyyyyyybvw"
+ /* 12 */ "vvvvvvvvvvvvvvvv"
+ /* 13 */ ".vwxxxxxxxxxxwv."
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "wx............xw"
+ /* 1 */ "x..............x"
+ /* 2 */ "..xxxxxxxxxxxx.."
+ /* 3 */ "..xwwwwwwwwwwx.."
+ /* 4 */ "..xwvvvvvvvvvx.."
+ /* 5 */ "..xwv.......vx.."
+ /* 6 */ "..xwv.....a.vx.."
+ /* 7 */ "..xwv.....a.vx.."
+ /* 8 */ "..xwv.....a.vx.."
+ /* 9 */ "..xwvvvvvvvvvx.."
+ /* 10 */ "..xwwwwwwwwwwx.."
+ /* 11 */ "..xxxxxxxxxxxx.."
+ /* 12 */ "x..............x"
+ /* 13 */ "wx............xw"
+
+ // Level 7
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "....xxxxxxxx...."
+ /* 5 */ "....xxxxxxxx...."
+ /* 6 */ "....xwwwwwax...."
+ /* 7 */ "....xwvvvvax...."
+ /* 8 */ "....xwwwwwax...."
+ /* 9 */ "....xxxxxxxx...."
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ "................"
+
+ // Level 8
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "................"
+ /* 5 */ "................"
+ /* 6 */ "..........a....."
+ /* 7 */ ".......xx.a....."
+ /* 8 */ "..........a....."
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ "................"
+
+ // Level 9
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "................"
+ /* 5 */ "................"
+ /* 6 */ "..........a....."
+ /* 7 */ "..........a....."
+ /* 8 */ "..........a....."
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ "................"
+
+ // Level 10
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "................"
+ /* 5 */ "................"
+ /* 6 */ "..........a....."
+ /* 7 */ "..........a....."
+ /* 8 */ "..........a....."
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ "................",
+
+ // Connectors:
+ "-1: 0, 1, 3: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Forge
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Garden2:
+ // The data has been exported from the gallery Plains, area index 147, ID 491, created by Aloe_vera
+ {
+ // Size:
+ 16, 5, 16, // SizeX = 16, SizeY = 5, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 15, 4, 15, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 8: 0\n" /* water */
+ "c: 2: 0\n" /* grass */
+ "d: 17: 1\n" /* tree */
+ "e: 13: 0\n" /* gravel */
+ "f: 31: 2\n" /* tallgrass */
+ "g: 18: 5\n" /* leaves */
+ "h: 38: 7\n" /* rose */
+ "i: 17: 9\n" /* tree */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+ /* 15 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaaa"
+ /* 6 */ "aaaabbaaaaaaaaaa"
+ /* 7 */ "aaabbbaaaaaaaaaa"
+ /* 8 */ "aaabbaaaaaaaaaaa"
+ /* 9 */ "aaaabaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+ /* 15 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "cccccccccccccccc"
+ /* 1 */ "ccdccccccccdcccc"
+ /* 2 */ "cccccceecccccdcc"
+ /* 3 */ "ccccccceeccccccc"
+ /* 4 */ "cccccccceccccccc"
+ /* 5 */ "cccbbbbceccccccc"
+ /* 6 */ "cccbbbbceecccccc"
+ /* 7 */ "ccbbbbbcceeeeccc"
+ /* 8 */ "ccbbbbbccccceecc"
+ /* 9 */ "ccbbbbcccccccecc"
+ /* 10 */ "ccccbcccccccceec"
+ /* 11 */ "ccccccccccccccec"
+ /* 12 */ "ccccccccaaacccec"
+ /* 13 */ "cccccccccaccccec"
+ /* 14 */ "ccccccccccccceec"
+ /* 15 */ "cccccccccccceecc"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "......f...gg.g.."
+ /* 1 */ "..gg.....gggggg."
+ /* 2 */ "ffgg......ghgggg"
+ /* 3 */ ".............gg."
+ /* 4 */ "...........f...."
+ /* 5 */ "...........h.ff."
+ /* 6 */ ".............fh."
+ /* 7 */ "...............f"
+ /* 8 */ "................"
+ /* 9 */ ".......ff.f....."
+ /* 10 */ ".f.....ffggf...."
+ /* 11 */ ".......gggg.f..."
+ /* 12 */ ".f......iddg...."
+ /* 13 */ ".....f..gdgg...."
+ /* 14 */ "....ff...gg....."
+ /* 15 */ "................"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "...........g.g.."
+ /* 2 */ ".............gg."
+ /* 3 */ "................"
+ /* 4 */ "................"
+ /* 5 */ "................"
+ /* 6 */ "................"
+ /* 7 */ "................"
+ /* 8 */ "................"
+ /* 9 */ "................"
+ /* 10 */ ".........g......"
+ /* 11 */ "........ggg....."
+ /* 12 */ "........ggg....."
+ /* 13 */ ".........g......"
+ /* 14 */ "................"
+ /* 15 */ "................",
+
+ // Connectors:
+ "-1: 12, 3, 15: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Garden2
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseMid:
+ // The data has been exported from the gallery Plains, area index 62, ID 119, created by Aloe_vera
+ {
+ // Size:
+ 10, 9, 9, // SizeX = 10, SizeY = 9, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, -1, // MinX, MinY, MinZ
+ 10, 8, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b:135: 2\n" /* 135 */
+ "c:135: 0\n" /* 135 */
+ "d: 17: 9\n" /* tree */
+ "e:135: 3\n" /* 135 */
+ "f: 85: 0\n" /* fence */
+ "g: 17: 1\n" /* tree */
+ "h:171: 0\n" /* carpet */
+ "i: 50: 5\n" /* torch */
+ "j: 35: 0\n" /* wool */
+ "k: 17: 5\n" /* tree */
+ "l:124: 0\n" /* redstonelampon */
+ "m: 19: 0\n" /* sponge */
+ "n: 69: 9\n" /* lever */
+ "o: 44: 8\n" /* step */
+ "p: 43: 0\n" /* doubleslab */
+ "q: 44: 0\n" /* step */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "maaaaaaaaa"
+ /* 1 */ "maaaaaaaaa"
+ /* 2 */ "aaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaa"
+ /* 7 */ "maaaaaaaaa"
+ /* 8 */ "maaaaaaaaa"
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".aaaaaaaaa"
+ /* 1 */ ".aaaaaaaaa"
+ /* 2 */ "baaaaaaaaa"
+ /* 3 */ "caaaaaaaaa"
+ /* 4 */ "caadaaaaaa"
+ /* 5 */ "caaaaaaaaa"
+ /* 6 */ "eaaaaaaaaa"
+ /* 7 */ ".aaaaaaaaa"
+ /* 8 */ ".aaaaaaaaa"
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".fffffffff"
+ /* 1 */ ".f.......f"
+ /* 2 */ ".f.ggggg.f"
+ /* 3 */ "...ghhhg.f"
+ /* 4 */ "....hhhg.f"
+ /* 5 */ "...ghhhg.f"
+ /* 6 */ ".f.ggggg.f"
+ /* 7 */ ".f.......f"
+ /* 8 */ ".fffffffff"
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".....i...i"
+ /* 1 */ ".........."
+ /* 2 */ ".i.jjgjj.."
+ /* 3 */ "...g...j.."
+ /* 4 */ ".......g.i"
+ /* 5 */ "...g...j.."
+ /* 6 */ ".i.jjgjj.."
+ /* 7 */ ".........."
+ /* 8 */ ".....i...i"
+
+ // Level 4
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".........."
+ /* 2 */ "...jjgjj.."
+ /* 3 */ "...g...j.."
+ /* 4 */ "...j...g.."
+ /* 5 */ "...g...j.."
+ /* 6 */ "...jjgjj.."
+ /* 7 */ ".........."
+ /* 8 */ ".........."
+
+ // Level 5
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ "...f...f.."
+ /* 2 */ "..fgkgkgf."
+ /* 3 */ "..fd...d.."
+ /* 4 */ "...d.lng.."
+ /* 5 */ "..fd...d.."
+ /* 6 */ "..fgkgkgf."
+ /* 7 */ "...f...f.."
+ /* 8 */ ".........."
+
+ // Level 6
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "...ooooo.."
+ /* 1 */ "..opppppo."
+ /* 2 */ ".opgjjjgpo"
+ /* 3 */ ".opjgggjpo"
+ /* 4 */ ".opjgggjpo"
+ /* 5 */ ".opjgggjpo"
+ /* 6 */ ".opgjjjgpo"
+ /* 7 */ "..opppppo."
+ /* 8 */ "...ooooo.."
+
+ // Level 7
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".opq...qpo"
+ /* 1 */ ".pq.....qp"
+ /* 2 */ ".q.qqqqq.q"
+ /* 3 */ "...qpppq.."
+ /* 4 */ "...qpppq.."
+ /* 5 */ "...qpppq.."
+ /* 6 */ ".q.qqqqq.q"
+ /* 7 */ ".pq.....qp"
+ /* 8 */ ".opq...qpo"
+
+ // Level 8
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".q.......q"
+ /* 1 */ ".........."
+ /* 2 */ ".........."
+ /* 3 */ ".........."
+ /* 4 */ ".....q...."
+ /* 5 */ ".........."
+ /* 6 */ ".........."
+ /* 7 */ ".........."
+ /* 8 */ ".q.......q",
+
+ // Connectors:
+ "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseMid
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseSmall:
+ // The data has been exported from the gallery Plains, area index 68, ID 131, created by Aloe_vera
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 7, 5, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b: 17: 1\n" /* tree */
+ "c: 35: 0\n" /* wool */
+ "d: 50: 4\n" /* torch */
+ "e: 85: 0\n" /* fence */
+ "f: 44: 8\n" /* step */
+ "g: 43: 0\n" /* doubleslab */
+ "h: 44: 0\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "maaaaam"
+ /* 2 */ "maaaaam"
+ /* 3 */ "maaaaam"
+ /* 4 */ "maaaaam"
+ /* 5 */ "maaaaam"
+ /* 6 */ "mmmmmmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".bcc.b."
+ /* 2 */ ".c...c."
+ /* 3 */ ".c...c."
+ /* 4 */ ".c...c."
+ /* 5 */ ".bcccb."
+ /* 6 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ ".....d."
+ /* 1 */ ".bee.b."
+ /* 2 */ ".c...c."
+ /* 3 */ ".e...e."
+ /* 4 */ ".c...c."
+ /* 5 */ ".beeeb."
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ ".fffff."
+ /* 1 */ "fbcccbf"
+ /* 2 */ "fc...cf"
+ /* 3 */ "fc...cf"
+ /* 4 */ "fc...cf"
+ /* 5 */ "fbcccbf"
+ /* 6 */ ".fffff."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "gh...hg"
+ /* 1 */ "hhhhhhh"
+ /* 2 */ ".hgggh."
+ /* 3 */ ".hgggh."
+ /* 4 */ ".hgggh."
+ /* 5 */ "hhhhhhh"
+ /* 6 */ "gh...hg"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "...h..."
+ /* 4 */ "......."
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseSmall
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseSmallDblWithDoor:
+ // The data has been exported from the gallery Plains, area index 113, ID 265, created by Aloe_vera
+ {
+ // Size:
+ 11, 6, 7, // SizeX = 11, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 5, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b: 17: 9\n" /* tree */
+ "c: 17: 1\n" /* tree */
+ "d: 35: 0\n" /* wool */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171:12\n" /* carpet */
+ "g:135: 1\n" /* 135 */
+ "h:126: 2\n" /* woodenslab */
+ "i:135: 2\n" /* 135 */
+ "j: 50: 4\n" /* torch */
+ "k: 64:12\n" /* wooddoorblock */
+ "l: 85: 0\n" /* fence */
+ "m: 19: 0\n" /* sponge */
+ "n: 44: 8\n" /* step */
+ "o: 43: 0\n" /* doubleslab */
+ "p: 44: 0\n" /* step */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaabaaaam"
+ /* 3 */ "maaaabaaaam"
+ /* 4 */ "maaaabaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".cdedcdddc."
+ /* 2 */ ".dfff.fffd."
+ /* 3 */ ".dgffdfhfd."
+ /* 4 */ ".diifdfffd."
+ /* 5 */ ".cdddcdddc."
+ /* 6 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ ".j...j...j."
+ /* 1 */ ".cdkdclllc."
+ /* 2 */ ".d.......l."
+ /* 3 */ ".l...l...l."
+ /* 4 */ ".d...l...l."
+ /* 5 */ ".clllclllc."
+ /* 6 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ ".nnnnnnnnn."
+ /* 1 */ "ncdddcdddcn"
+ /* 2 */ "nd...d...dn"
+ /* 3 */ "nd...d...dn"
+ /* 4 */ "nd...d...dn"
+ /* 5 */ "ncdddcdddcn"
+ /* 6 */ ".nnnnnnnnn."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "op.......po"
+ /* 1 */ "ppppppppppp"
+ /* 2 */ ".pooooooop."
+ /* 3 */ ".ponndnnop."
+ /* 4 */ ".pooooooop."
+ /* 5 */ "ppppppppppp"
+ /* 6 */ "op.......po"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "...ppppp..."
+ /* 4 */ "..........."
+ /* 5 */ "..........."
+ /* 6 */ "...........",
+
+ // Connectors:
+ "-1: 3, 1, -1: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseSmallDblWithDoor
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseSmallDouble:
+ // The data has been exported from the gallery Plains, area index 72, ID 135, created by Aloe_vera
+ {
+ // Size:
+ 11, 6, 7, // SizeX = 11, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 5, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b: 17: 1\n" /* tree */
+ "c: 35: 0\n" /* wool */
+ "d:171:12\n" /* carpet */
+ "e:135: 1\n" /* 135 */
+ "f:126: 2\n" /* woodenslab */
+ "g:135: 2\n" /* 135 */
+ "h: 50: 4\n" /* torch */
+ "i: 85: 0\n" /* fence */
+ "j: 44: 8\n" /* step */
+ "k: 43: 0\n" /* doubleslab */
+ "l: 44: 0\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".bcc.bcccb."
+ /* 2 */ ".cddd.dddc."
+ /* 3 */ ".ceddcdfdc."
+ /* 4 */ ".cggdcdddc."
+ /* 5 */ ".bcccbcccb."
+ /* 6 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ ".h...h...h."
+ /* 1 */ ".bii.biiib."
+ /* 2 */ ".c.......c."
+ /* 3 */ ".i...i...i."
+ /* 4 */ ".c...i...c."
+ /* 5 */ ".biiibiiib."
+ /* 6 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ ".jjjjjjjjj."
+ /* 1 */ "jbiiibiiibj"
+ /* 2 */ "jc.......cj"
+ /* 3 */ "jc...c...cj"
+ /* 4 */ "jc...c...cj"
+ /* 5 */ "jbcccbcccbj"
+ /* 6 */ ".jjjjjjjjj."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "kl...l...lk"
+ /* 1 */ "lllllllllll"
+ /* 2 */ ".lkkklkkkl."
+ /* 3 */ ".lkjklkkkl."
+ /* 4 */ ".lkkklkkkl."
+ /* 5 */ "lllllllllll"
+ /* 6 */ "kl...l...lk"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "...l...l..."
+ /* 4 */ "..........."
+ /* 5 */ "..........."
+ /* 6 */ "...........",
+
+ // Connectors:
+ "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseSmallDouble
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseSmallWithDoor:
+ // The data has been exported from the gallery Plains, area index 112, ID 264, created by Aloe_vera
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 7, 5, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b: 17: 1\n" /* tree */
+ "c: 35: 0\n" /* wool */
+ "d: 64: 7\n" /* wooddoorblock */
+ "e: 50: 4\n" /* torch */
+ "f: 64:12\n" /* wooddoorblock */
+ "g: 85: 0\n" /* fence */
+ "h: 44: 8\n" /* step */
+ "i: 43: 0\n" /* doubleslab */
+ "j: 44: 0\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "maaaaam"
+ /* 2 */ "maaaaam"
+ /* 3 */ "maaaaam"
+ /* 4 */ "maaaaam"
+ /* 5 */ "maaaaam"
+ /* 6 */ "mmmmmmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".bcdcb."
+ /* 2 */ ".c...c."
+ /* 3 */ ".c...c."
+ /* 4 */ ".c...c."
+ /* 5 */ ".bcccb."
+ /* 6 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ ".....e."
+ /* 1 */ ".bcfcb."
+ /* 2 */ ".g...g."
+ /* 3 */ ".g...g."
+ /* 4 */ ".g...g."
+ /* 5 */ ".bgggb."
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ ".hhhhh."
+ /* 1 */ "hbcccbh"
+ /* 2 */ "hc...ch"
+ /* 3 */ "hc...ch"
+ /* 4 */ "hc...ch"
+ /* 5 */ "hbcccbh"
+ /* 6 */ ".hhhhh."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "ij...ji"
+ /* 1 */ "jjjjjjj"
+ /* 2 */ ".jiiij."
+ /* 3 */ ".jiiij."
+ /* 4 */ ".jiiij."
+ /* 5 */ "jjjjjjj"
+ /* 6 */ "ij...ji"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "...j..."
+ /* 4 */ "......."
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseSmallWithDoor
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseWide:
+ // The data has been exported from the gallery Plains, area index 64, ID 121, created by STR_Warrior
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, 0, -1, // MinX, MinY, MinZ
+ 11, 5, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b: 17: 1\n" /* tree */
+ "c: 35: 0\n" /* wool */
+ "d:171: 0\n" /* carpet */
+ "e:126: 1\n" /* woodenslab */
+ "f: 64: 5\n" /* wooddoorblock */
+ "g: 85: 0\n" /* fence */
+ "h: 50: 1\n" /* torch */
+ "i: 50: 2\n" /* torch */
+ "j: 64:12\n" /* wooddoorblock */
+ "k:126:11\n" /* woodenslab */
+ "l: 17: 5\n" /* tree */
+ "m: 19: 0\n" /* sponge */
+ "n:126: 3\n" /* woodenslab */
+ "o:125: 3\n" /* woodendoubleslab */
+ "p: 5: 3\n" /* wood */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmaaaaaaamm"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "maaaaaaaaam"
+ /* 7 */ "maaaaaaaaam"
+ /* 8 */ "maaaaaaaaam"
+ /* 9 */ "mmaaaaaaamm"
+ /* 10 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..bcbcbcb.."
+ /* 2 */ ".b.d.....b."
+ /* 3 */ ".cded....c."
+ /* 4 */ ".bded....b."
+ /* 5 */ ".c.d.....c."
+ /* 6 */ ".b.......b."
+ /* 7 */ ".c.......c."
+ /* 8 */ ".b.......b."
+ /* 9 */ "..bcbfbcb.."
+ /* 10 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..bgbgbgb.."
+ /* 2 */ ".b.......b."
+ /* 3 */ ".g.......g."
+ /* 4 */ ".bh.....ib."
+ /* 5 */ ".g.......g."
+ /* 6 */ ".b.......b."
+ /* 7 */ ".g.......g."
+ /* 8 */ ".b.......b."
+ /* 9 */ "..bgbjbgb.."
+ /* 10 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...kkkkk..."
+ /* 1 */ "..bcbcbcb.."
+ /* 2 */ ".b.......b."
+ /* 3 */ "kc.......ck"
+ /* 4 */ "kb.......bk"
+ /* 5 */ "kc.......ck"
+ /* 6 */ "kb.......bk"
+ /* 7 */ "kc.......ck"
+ /* 8 */ ".b.......b."
+ /* 9 */ "..bcblbcb.."
+ /* 10 */ "...kkkkk..."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ ".kn.....nk."
+ /* 1 */ "konnnnnnnok"
+ /* 2 */ "nnnnnnnnnnn"
+ /* 3 */ ".nnpppppnn."
+ /* 4 */ ".nnpkkkpnn."
+ /* 5 */ ".nnpkkkpnn."
+ /* 6 */ ".nnpkkkpnn."
+ /* 7 */ ".nnpppppnn."
+ /* 8 */ "nnnnnnnnnnn"
+ /* 9 */ "kknnnnnnnok"
+ /* 10 */ ".kn.....nk."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "n.........n"
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "....nnn...."
+ /* 5 */ "....non...."
+ /* 6 */ "....nnn...."
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "n.........n",
+
+ // Connectors:
+ "-1: 5, 1, 10: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseWide
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseWithGarden:
+ // The data has been exported from the gallery Plains, area index 67, ID 130, created by Aloe_vera
+ {
+ // Size:
+ 16, 9, 16, // SizeX = 16, SizeY = 9, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 16, 8, 16, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 5: 2\n" /* wood */
+ "c: 2: 0\n" /* grass */
+ "d:113: 0\n" /* netherbrickfence */
+ "e: 17: 1\n" /* tree */
+ "f: 35: 0\n" /* wool */
+ "g:126: 2\n" /* woodenslab */
+ "h: 31: 2\n" /* tallgrass */
+ "i:125: 2\n" /* woodendoubleslab */
+ "j: 38: 3\n" /* rose */
+ "k: 38: 2\n" /* rose */
+ "l: 38: 1\n" /* rose */
+ "m: 19: 0\n" /* sponge */
+ "n: 17: 2\n" /* tree */
+ "o: 50: 4\n" /* torch */
+ "p: 85: 0\n" /* fence */
+ "q:140: 0\n" /* flowerpotblock */
+ "r: 50: 3\n" /* torch */
+ "s: 44: 8\n" /* step */
+ "t: 50: 1\n" /* torch */
+ "u: 50: 2\n" /* torch */
+ "v: 43: 0\n" /* doubleslab */
+ "w: 44: 0\n" /* step */
+ "x: 18:10\n" /* leaves */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmaammmmm"
+ /* 1 */ "aabbbbbbbbbbaaam"
+ /* 2 */ "aabbbbbbbbbbaaam"
+ /* 3 */ "aabbbbbbbbbbaaam"
+ /* 4 */ "aabbbbbbbbbbaaam"
+ /* 5 */ "aabbbbbbbbbbaaam"
+ /* 6 */ "aabbbbbbbbbbaaam"
+ /* 7 */ "aabbbbbbbbbbaaam"
+ /* 8 */ "aabbbbbbbbbbaaam"
+ /* 9 */ "aabbbbbbbbbbaaam"
+ /* 10 */ "aaaaaaaaaaaaaaam"
+ /* 11 */ "aaaaaaaaaaaaaaam"
+ /* 12 */ "aaaaaaaaaaaaaaam"
+ /* 13 */ "aaaaaaaaaaaaaaam"
+ /* 14 */ "aaaaaaaaaaaaaaam"
+ /* 15 */ "mmmmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmccmmmmm"
+ /* 1 */ "ccbbbbbbbbbbcccm"
+ /* 2 */ "ccbbbbbbbbbbcccm"
+ /* 3 */ "ccbbbbbbbbbbcccm"
+ /* 4 */ "ccbbbbbbbbbbcccm"
+ /* 5 */ "ccbbbbbbbbbbcccm"
+ /* 6 */ "ccbbbbbbbbbbcccm"
+ /* 7 */ "ccbbbbbbbbbbcccm"
+ /* 8 */ "ccbbbbbbbbbbcccm"
+ /* 9 */ "ccbbbbbbbbbbcccm"
+ /* 10 */ "cccccccccccccccm"
+ /* 11 */ "cccccccccccccccm"
+ /* 12 */ "cccccccccccccccm"
+ /* 13 */ "cccccccccccccacm"
+ /* 14 */ "cccccccccccccccm"
+ /* 15 */ "mmmmmmmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "ddeffeffe..eddd."
+ /* 2 */ "d.fbbgggg..f..d."
+ /* 3 */ "d.fbgggggggf.hd."
+ /* 4 */ "d.fbgggggggf..d."
+ /* 5 */ "d.eggggggggehhd."
+ /* 6 */ "d.fgiiggiigf.hd."
+ /* 7 */ "d.fgiiggiigf..d."
+ /* 8 */ "d.fggggggggf..d."
+ /* 9 */ "d.efffeefffe.hd."
+ /* 10 */ "d.............d."
+ /* 11 */ "djhhk.jhh..hh.d."
+ /* 12 */ "d.jlk.hj.h....d."
+ /* 13 */ "d..jh.hh..h..nd."
+ /* 14 */ "ddddddddddddddd."
+ /* 15 */ "................"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "........o..o...."
+ /* 1 */ "..eppeffe..e...."
+ /* 2 */ "..pqq......p...."
+ /* 3 */ "..pq.......p...."
+ /* 4 */ "..pq.......p...."
+ /* 5 */ "..e........e...."
+ /* 6 */ "..p........p...."
+ /* 7 */ "..p........p...."
+ /* 8 */ "..p........p...."
+ /* 9 */ "..epppeepppe...."
+ /* 10 */ "......rr........"
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ ".............n.."
+ /* 14 */ "................"
+ /* 15 */ "................"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "..ssssssssss...."
+ /* 1 */ ".seffeffeffes..."
+ /* 2 */ ".sf..r.....fs..."
+ /* 3 */ ".sf........fs..."
+ /* 4 */ ".sf........fs..."
+ /* 5 */ ".set......ues..."
+ /* 6 */ ".sf........fs..."
+ /* 7 */ ".sf........fs..."
+ /* 8 */ ".sf........fs..."
+ /* 9 */ ".sefffeefffes..."
+ /* 10 */ "..ssssssssss...."
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ ".............n.."
+ /* 14 */ "................"
+ /* 15 */ "................"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ ".vw........wv..."
+ /* 1 */ ".wwwwwwwwwwww..."
+ /* 2 */ "..wvvvvvvvvw...."
+ /* 3 */ "..wvvvvvvvvw...."
+ /* 4 */ "..wvvvvvvvvw...."
+ /* 5 */ "..wvvvvvvvvw...."
+ /* 6 */ "..wvvvvvvvvw...."
+ /* 7 */ "..wvvvvvvvvw...."
+ /* 8 */ "..wvvvvvvvvw...."
+ /* 9 */ ".wwwwwwwwwwww..."
+ /* 10 */ ".vw........wv..."
+ /* 11 */ "............xxx."
+ /* 12 */ "...........xxxxx"
+ /* 13 */ "...........xxnxx"
+ /* 14 */ "...........xxxxx"
+ /* 15 */ "............xxx."
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "....wwwwww......"
+ /* 4 */ "....wvvvvw......"
+ /* 5 */ "....wvvvvw......"
+ /* 6 */ "....wvvvvw......"
+ /* 7 */ "....wwwwww......"
+ /* 8 */ "................"
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "............xxx."
+ /* 12 */ "...........xxxxx"
+ /* 13 */ "...........xxnxx"
+ /* 14 */ "...........xxxxx"
+ /* 15 */ "............xxx."
+
+ // Level 7
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "................"
+ /* 5 */ "......ww........"
+ /* 6 */ "................"
+ /* 7 */ "................"
+ /* 8 */ "................"
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ "............xxx."
+ /* 13 */ "............xnx."
+ /* 14 */ "............xx.."
+ /* 15 */ "................"
+
+ // Level 8
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "................"
+ /* 5 */ "................"
+ /* 6 */ "................"
+ /* 7 */ "................"
+ /* 8 */ "................"
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ ".............x.."
+ /* 13 */ "............xxx."
+ /* 14 */ ".............x.."
+ /* 15 */ "................",
+
+ // Connectors:
+ "-1: 9, 2, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseWithGarden
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseWithSakura1:
+ // The data has been exported from the gallery Plains, area index 75, ID 141, created by Aloe_vera
+ {
+ // Size:
+ 13, 7, 15, // SizeX = 13, SizeY = 7, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 13, 6, 15, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 2: 0\n" /* grass */
+ "c: 17: 5\n" /* tree */
+ "d: 5: 2\n" /* wood */
+ "e: 17: 9\n" /* tree */
+ "f:113: 0\n" /* netherbrickfence */
+ "g: 17: 1\n" /* tree */
+ "h: 35: 0\n" /* wool */
+ "i: 31: 2\n" /* tallgrass */
+ "j: 54: 2\n" /* chest */
+ "k: 38: 6\n" /* rose */
+ "l: 38: 2\n" /* rose */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 4\n" /* torch */
+ "o: 85: 0\n" /* fence */
+ "p: 44: 8\n" /* step */
+ "q: 35: 6\n" /* wool */
+ "r: 43: 0\n" /* doubleslab */
+ "s: 44: 0\n" /* step */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "bbbbbbbbbbbbb"
+ /* 1 */ "bbbbbbbbbbbbb"
+ /* 2 */ "bbbaccdabbbbb"
+ /* 3 */ "bbbedddebbbbb"
+ /* 4 */ "bbbedddebbbbb"
+ /* 5 */ "bbbedddebbbbb"
+ /* 6 */ "bbbacccabbbbb"
+ /* 7 */ "bbbbbbbbbbbbb"
+ /* 8 */ "bbbbbbbbbbbbb"
+ /* 9 */ "bbbbbbbbbbbbb"
+ /* 10 */ "bbbbbbbbbbabb"
+ /* 11 */ "bbbbbbbbbbbbb"
+ /* 12 */ "bbbbbbbbbbbbb"
+ /* 13 */ "bbbbbbbbbbbbb"
+ /* 14 */ "bbbbbbbbbbbbb"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ffff...ffffff"
+ /* 1 */ "f...........f"
+ /* 2 */ "f..ghh.g..i.f"
+ /* 3 */ "f..h...h..i.f"
+ /* 4 */ "f..h...h....f"
+ /* 5 */ "fi.h..jh..i.f"
+ /* 6 */ "f..ghhhg....f"
+ /* 7 */ "f.........i.f"
+ /* 8 */ "fii.........f"
+ /* 9 */ "f.k..k.i....f"
+ /* 10 */ "fl.i..i...g.f"
+ /* 11 */ "f.i..i.k....f"
+ /* 12 */ "f.l.k.......f"
+ /* 13 */ "f.....l.....f"
+ /* 14 */ "fffffffffffff"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".......n....."
+ /* 2 */ "...goo.g....."
+ /* 3 */ "...h...h....."
+ /* 4 */ "...o...o....."
+ /* 5 */ "...h...h....."
+ /* 6 */ "...gooog....."
+ /* 7 */ "............."
+ /* 8 */ "............."
+ /* 9 */ "............."
+ /* 10 */ "..........g.."
+ /* 11 */ "............."
+ /* 12 */ "............."
+ /* 13 */ "............."
+ /* 14 */ "............."
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "...ppppp....."
+ /* 2 */ "..pghhhgp...."
+ /* 3 */ "..ph...hp...."
+ /* 4 */ "..ph...hp...."
+ /* 5 */ "..ph...hp...."
+ /* 6 */ "..pghhhgp...."
+ /* 7 */ "...ppppp....."
+ /* 8 */ "............."
+ /* 9 */ "..........q.."
+ /* 10 */ ".........qgq."
+ /* 11 */ "..........q.."
+ /* 12 */ "............."
+ /* 13 */ "............."
+ /* 14 */ "............."
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "..rs...sr...."
+ /* 2 */ "..sssssss...."
+ /* 3 */ "...srrrs....."
+ /* 4 */ "...srrrs....."
+ /* 5 */ "...srrrs....."
+ /* 6 */ "..sssssss...."
+ /* 7 */ "..rs...sr...."
+ /* 8 */ "............."
+ /* 9 */ ".........qqq."
+ /* 10 */ ".........qqq."
+ /* 11 */ ".........qqq."
+ /* 12 */ "............."
+ /* 13 */ "............."
+ /* 14 */ "............."
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ ".....s......."
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "............."
+ /* 9 */ "............."
+ /* 10 */ "..........q.."
+ /* 11 */ "............."
+ /* 12 */ "............."
+ /* 13 */ "............."
+ /* 14 */ ".............",
+
+ // Connectors:
+ "-1: 5, 2, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseWithSakura1
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseWithSpa:
+ // The data has been exported from the gallery Plains, area index 73, ID 139, created by Aloe_vera
+ {
+ // Size:
+ 16, 8, 14, // SizeX = 16, SizeY = 8, SizeZ = 14
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 15, 7, 13, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b: 3: 0\n" /* dirt */
+ "c: 2: 0\n" /* grass */
+ "d: 8: 0\n" /* water */
+ "e:135: 3\n" /* 135 */
+ "f:135: 1\n" /* 135 */
+ "g:113: 0\n" /* netherbrickfence */
+ "h: 17: 1\n" /* tree */
+ "i: 35: 0\n" /* wool */
+ "j:171:12\n" /* carpet */
+ "k: 64: 6\n" /* wooddoorblock */
+ "l:126: 2\n" /* woodenslab */
+ "m: 19: 0\n" /* sponge */
+ "n:135: 2\n" /* 135 */
+ "o: 64: 7\n" /* wooddoorblock */
+ "p: 50: 4\n" /* torch */
+ "q: 85: 0\n" /* fence */
+ "r: 64:12\n" /* wooddoorblock */
+ "s: 50: 3\n" /* torch */
+ "t: 44: 8\n" /* step */
+ "u: 43: 0\n" /* doubleslab */
+ "v: 44: 0\n" /* step */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".aaaaaaaaaaaaaa."
+ /* 2 */ ".aaaaaaaaaaaaaa."
+ /* 3 */ ".aaaaaaaaaaaaaa."
+ /* 4 */ ".aaaaaaaaaaaaaa."
+ /* 5 */ ".aaaaaaaaaaaaaa."
+ /* 6 */ ".aaaaaaaaaaaaaa."
+ /* 7 */ ".aaaaaabbbbbbbbb"
+ /* 8 */ ".aaaaaabbbbbbbbb"
+ /* 9 */ ".aaaaaabbbbbbbbb"
+ /* 10 */ ".aaaaaabbbbbbbbb"
+ /* 11 */ ".aaaaaabbbbbbbbb"
+ /* 12 */ ".aaaaaabbbbbbbbb"
+ /* 13 */ ".......bbbbbbbbb"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmmmmm"
+ /* 1 */ "maaaaaaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaaaaaam"
+ /* 6 */ "maaaaaaaaaaaaaam"
+ /* 7 */ "maaaaaaaaaaccccc"
+ /* 8 */ "maaaaaaacccccccc"
+ /* 9 */ "maaaaaaacccccccc"
+ /* 10 */ "maaaaaaacccccccc"
+ /* 11 */ "maaaaaaccccccccc"
+ /* 12 */ "maaaaaaccccccccc"
+ /* 13 */ "mmmmmmmccccccccc"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".aaaaaaaaaaaaaa."
+ /* 2 */ ".aaaaaaaaaaaaaa."
+ /* 3 */ ".aaaaaaaaaaaaaa."
+ /* 4 */ ".aaaaaaaaaaaaaa."
+ /* 5 */ ".aaaaaaaaaaaaaa."
+ /* 6 */ ".aaddaaaaaaaaaa."
+ /* 7 */ ".aaddaaeeef....."
+ /* 8 */ ".aaddaaf........"
+ /* 9 */ ".aaddaaf........"
+ /* 10 */ ".aaddaae........"
+ /* 11 */ ".aaddaa........."
+ /* 12 */ ".aaaaaa........."
+ /* 13 */ "................"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".ggggghiiihiiih."
+ /* 2 */ ".geee.ijjjjjjji."
+ /* 3 */ ".gf...kjjjijlji."
+ /* 4 */ ".gf...innjijjji."
+ /* 5 */ ".g....hiiohiiih."
+ /* 6 */ ".g....g........."
+ /* 7 */ ".g.............."
+ /* 8 */ ".g.............."
+ /* 9 */ ".g.............."
+ /* 10 */ ".g....g........."
+ /* 11 */ ".g....g........."
+ /* 12 */ ".gggggg........."
+ /* 13 */ "................"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "......p...p...p."
+ /* 1 */ ".g....hqqqhqqqh."
+ /* 2 */ "......i.......i."
+ /* 3 */ "......r...q...q."
+ /* 4 */ "......i...q...i."
+ /* 5 */ "......hqqrhqqqh."
+ /* 6 */ "......g...s....."
+ /* 7 */ "................"
+ /* 8 */ "................"
+ /* 9 */ "................"
+ /* 10 */ "................"
+ /* 11 */ "................"
+ /* 12 */ ".g....g........."
+ /* 13 */ "................"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ ".tttttttttttttt."
+ /* 1 */ "tggggghqqqhqqqht"
+ /* 2 */ "tg....i.......it"
+ /* 3 */ "tg....i...i...it"
+ /* 4 */ "tg....i...i...it"
+ /* 5 */ "tg....hiiihiiiht"
+ /* 6 */ "tg....gtttttttt."
+ /* 7 */ "tg....gt........"
+ /* 8 */ "tg....gt........"
+ /* 9 */ "tg....gt........"
+ /* 10 */ "tg....gt........"
+ /* 11 */ "tg....gt........"
+ /* 12 */ "tggggggt........"
+ /* 13 */ ".tttttt........."
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "uv............vu"
+ /* 1 */ "vvvvvvvvvvvvvvvv"
+ /* 2 */ ".vuuuuuuuuuuuuv."
+ /* 3 */ ".vuuuuuutuuuuuv."
+ /* 4 */ ".vuuuuuuuuuuuuv."
+ /* 5 */ ".vuuuuvvvvvvvvvv"
+ /* 6 */ ".vuuuuv.......vu"
+ /* 7 */ ".vuuuuv........."
+ /* 8 */ ".vuuuuv........."
+ /* 9 */ ".vuuuuv........."
+ /* 10 */ ".vuuuuv........."
+ /* 11 */ ".vuuuuv........."
+ /* 12 */ "vvvvvvvv........"
+ /* 13 */ "uv....vu........"
+
+ // Level 7
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "...vvvvvvvvvv..."
+ /* 4 */ "...vv..........."
+ /* 5 */ "...vv..........."
+ /* 6 */ "...vv..........."
+ /* 7 */ "...vv..........."
+ /* 8 */ "...vv..........."
+ /* 9 */ "...vv..........."
+ /* 10 */ "...vv..........."
+ /* 11 */ "................"
+ /* 12 */ "................"
+ /* 13 */ "................",
+
+ // Connectors:
+ "",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseWithSpa
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MediumSakuraTree:
+ // The data has been exported from the gallery Plains, area index 146, ID 490, created by STR_Warrior
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 9, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 2: 0\n" /* grass */
+ "c: 31: 1\n" /* tallgrass */
+ "d: 38: 7\n" /* rose */
+ "e: 17: 1\n" /* tree */
+ "f: 38: 0\n" /* rose */
+ "g: 38: 8\n" /* rose */
+ "h: 38: 5\n" /* rose */
+ "i: 35: 6\n" /* wool */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "bbbbbbb"
+ /* 1 */ "bbbbbbb"
+ /* 2 */ "bbbbbbb"
+ /* 3 */ "bbbabbb"
+ /* 4 */ "bbbbbbb"
+ /* 5 */ "bbbbbbb"
+ /* 6 */ "bbbbbbb"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..c.c.."
+ /* 2 */ ".dccdc."
+ /* 3 */ "..cefc."
+ /* 4 */ ".ccfgh."
+ /* 5 */ "..ccc.."
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "...e..."
+ /* 4 */ "......."
+ /* 5 */ "......."
+ /* 6 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..i...."
+ /* 2 */ "......."
+ /* 3 */ "...e.i."
+ /* 4 */ ".i....."
+ /* 5 */ "......."
+ /* 6 */ "......."
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..i...."
+ /* 2 */ "...i..."
+ /* 3 */ "..ieii."
+ /* 4 */ ".i.ii.."
+ /* 5 */ "...i..."
+ /* 6 */ "......."
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..ii..."
+ /* 2 */ "..iii.."
+ /* 3 */ ".iieii."
+ /* 4 */ ".iiii.."
+ /* 5 */ "..iii.."
+ /* 6 */ "......."
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "..iii.."
+ /* 2 */ ".iiiii."
+ /* 3 */ ".iieii."
+ /* 4 */ ".iiiii."
+ /* 5 */ "..iii.."
+ /* 6 */ "......."
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "...i..."
+ /* 2 */ "..iiii."
+ /* 3 */ ".iiiii."
+ /* 4 */ "..iii.."
+ /* 5 */ "...i..."
+ /* 6 */ "......."
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "...i..."
+ /* 3 */ "..iii.."
+ /* 4 */ "...i..."
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "-1: 3, 2, 0: 2\n" /* Type -1, direction Z- */
+ "3: 6, 2, 3: 5\n" /* Type 3, direction X+ */
+ "-3: 0, 2, 3: 4\n" /* Type -3, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // MediumSakuraTree
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Restaurant:
+ // The data has been exported from the gallery Plains, area index 61, ID 117, created by Aloe_vera
+ {
+ // Size:
+ 15, 10, 15, // SizeX = 15, SizeY = 10, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ -1, 0, -1, // MinX, MinY, MinZ
+ 14, 9, 15, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b:135: 0\n" /* 135 */
+ "c:135: 2\n" /* 135 */
+ "d:135: 1\n" /* 135 */
+ "e: 17: 9\n" /* tree */
+ "f:135: 3\n" /* 135 */
+ "g: 85: 0\n" /* fence */
+ "h: 17: 1\n" /* tree */
+ "i:171: 0\n" /* carpet */
+ "j:171:12\n" /* carpet */
+ "k:126: 1\n" /* woodenslab */
+ "l: 50: 5\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 35: 0\n" /* wool */
+ "o: 50: 3\n" /* torch */
+ "p: 50: 1\n" /* torch */
+ "q: 50: 4\n" /* torch */
+ "r: 35:14\n" /* wool */
+ "s: 44: 8\n" /* step */
+ "t: 43: 0\n" /* doubleslab */
+ "u: 44: 0\n" /* step */
+ "v: 17: 5\n" /* tree */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmaaaaaaammmm"
+ /* 1 */ "maaaaaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaaaaam"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaa"
+ /* 11 */ "maaaaaaaaaaaaam"
+ /* 12 */ "maaaaaaaaaaaaam"
+ /* 13 */ "maaaaaaaaaaaaam"
+ /* 14 */ "mmmmaaaaaaammmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "....bcccccd...."
+ /* 1 */ ".aaaaaaaaaaaaa."
+ /* 2 */ ".aaaaaaaaaaaaa."
+ /* 3 */ ".aaaaaaaaaaaaa."
+ /* 4 */ "caaaaaaaaaaaaac"
+ /* 5 */ "baaaaaaaaaaaaad"
+ /* 6 */ "baaaaaaaaaaaaad"
+ /* 7 */ "baaaaaaaaaaeaad"
+ /* 8 */ "baaaaaaaaaaaaad"
+ /* 9 */ "baaaaaaaaaaaaad"
+ /* 10 */ "faaaaaaaaaaaaaf"
+ /* 11 */ ".aaaaaaaaaaaaa."
+ /* 12 */ ".aaaaaaaaaaaaa."
+ /* 13 */ ".aaaaaaaaaaaaa."
+ /* 14 */ "....bfffffd...."
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".gggg.....gggg."
+ /* 2 */ ".g...........g."
+ /* 3 */ ".g.hhhhhhhhh.g."
+ /* 4 */ ".g.hiiijiiih.g."
+ /* 5 */ "...hikijikih..."
+ /* 6 */ "...hiiijiiihg.."
+ /* 7 */ "...hjjjjjjj...."
+ /* 8 */ "...hiiijiiihg.."
+ /* 9 */ "...hikijikih..."
+ /* 10 */ ".g.hiiijiiih.g."
+ /* 11 */ ".g.hhhhhhhhh.g."
+ /* 12 */ ".g...........g."
+ /* 13 */ ".gggg.....gggg."
+ /* 14 */ "..............."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".l..g.....g..l."
+ /* 2 */ "..............."
+ /* 3 */ "...hnnnhnnnh..."
+ /* 4 */ ".g.n.......n.g."
+ /* 5 */ "...n.......n..."
+ /* 6 */ "...n.......hl.."
+ /* 7 */ "...h..........."
+ /* 8 */ "...n.......hl.."
+ /* 9 */ "...n.......n..."
+ /* 10 */ ".g.n.......n.g."
+ /* 11 */ "...hnnnhnnnh..."
+ /* 12 */ "..............."
+ /* 13 */ ".l..g.....g..l."
+ /* 14 */ "..............."
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "....g.....g...."
+ /* 2 */ "..............."
+ /* 3 */ "...hn.nhn.nh..."
+ /* 4 */ ".g.n...o...n.g."
+ /* 5 */ "...n.......n..."
+ /* 6 */ "...n.......h..."
+ /* 7 */ "...hp......e..."
+ /* 8 */ "...n.......h..."
+ /* 9 */ "...n.......n..."
+ /* 10 */ ".g.n...q...n.g."
+ /* 11 */ "...hn.nhn.nh..."
+ /* 12 */ "..............."
+ /* 13 */ "....g.....g...."
+ /* 14 */ "..............."
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "....g.....g...."
+ /* 2 */ "....ggggggg...."
+ /* 3 */ "...hnnnhnnnh..."
+ /* 4 */ ".ggn.......ngg."
+ /* 5 */ "..gn.......ng.."
+ /* 6 */ "..gn.......hg.."
+ /* 7 */ "..gh..r.r..ng.."
+ /* 8 */ "..gn.......hg.."
+ /* 9 */ "..gn.......ng.."
+ /* 10 */ ".ggn.......ngg."
+ /* 11 */ "...hnnnhnnnh..."
+ /* 12 */ "....ggggggg...."
+ /* 13 */ "....g.....g...."
+ /* 14 */ "..............."
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "...stuuuuuts..."
+ /* 2 */ "..sttttttttts.."
+ /* 3 */ ".sthvvvhvvvhts."
+ /* 4 */ ".tte.......ett."
+ /* 5 */ ".ute.......etu."
+ /* 6 */ ".ute.......htu."
+ /* 7 */ ".uth..g.g..etu."
+ /* 8 */ ".ute.......htu."
+ /* 9 */ ".ute.......etu."
+ /* 10 */ ".tte.......ett."
+ /* 11 */ ".sthvvvhvvvhts."
+ /* 12 */ "..sttttttttts.."
+ /* 13 */ "...stuuuuuts..."
+ /* 14 */ "..............."
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".stu.......uts."
+ /* 2 */ ".tu.........ut."
+ /* 3 */ ".u.uuuuuuuuu.u."
+ /* 4 */ "...utttttttu..."
+ /* 5 */ "...utttttttu..."
+ /* 6 */ "...utttttttu..."
+ /* 7 */ "...utttttttu..."
+ /* 8 */ "...utttttttu..."
+ /* 9 */ "...utttttttu..."
+ /* 10 */ "...utttttttu..."
+ /* 11 */ ".u.uuuuuuuuu.u."
+ /* 12 */ ".tu.........ut."
+ /* 13 */ ".stu.......uts."
+ /* 14 */ "..............."
+
+ // Level 8
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".u...........u."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ ".....uuuuu....."
+ /* 6 */ ".....utttu....."
+ /* 7 */ ".....utttu....."
+ /* 8 */ ".....utttu....."
+ /* 9 */ ".....uuuuu....."
+ /* 10 */ "..............."
+ /* 11 */ "..............."
+ /* 12 */ "..............."
+ /* 13 */ ".u...........u."
+ /* 14 */ "..............."
+
+ // Level 9
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ ".......u......."
+ /* 8 */ "..............."
+ /* 9 */ "..............."
+ /* 10 */ "..............."
+ /* 11 */ "..............."
+ /* 12 */ "..............."
+ /* 13 */ "..............."
+ /* 14 */ "...............",
+
+ // Connectors:
+ "-1: 14, 1, 7: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Restaurant
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // SakuraDouble:
+ // The data has been exported from the gallery Plains, area index 76, ID 142, created by Aloe_vera
+ {
+ // Size:
+ 12, 8, 6, // SizeX = 12, SizeY = 8, SizeZ = 6
+
+ // Hitbox (relative to bounding box):
+ -1, 0, -1, // MinX, MinY, MinZ
+ 12, 7, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 2: 0\n" /* grass */
+ "c: 17: 1\n" /* tree */
+ "d: 35: 6\n" /* wool */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "bbbbbbbbbbbb"
+ /* 1 */ "bbbbbbbbbbbb"
+ /* 2 */ "bbabbbbbbbbb"
+ /* 3 */ "bbbbbbbbbabb"
+ /* 4 */ "bbbbbbbbbbbb"
+ /* 5 */ "bbbbbbbbbbbb"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "..c........."
+ /* 3 */ ".........c.."
+ /* 4 */ "............"
+ /* 5 */ "............"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "..c........."
+ /* 3 */ ".........c.."
+ /* 4 */ "............"
+ /* 5 */ "............"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "..d........."
+ /* 1 */ "ddddd......."
+ /* 2 */ "ddcdd...ddd."
+ /* 3 */ "ddddd...dcd."
+ /* 4 */ "..d.....ddd."
+ /* 5 */ "............"
+
+ // Level 5
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ ".ddd........"
+ /* 1 */ ".ddd....ddd."
+ /* 2 */ "ddddd..ddddd"
+ /* 3 */ ".ddd...ddcdd"
+ /* 4 */ ".ddd...ddddd"
+ /* 5 */ "........ddd."
+
+ // Level 6
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "..d......d.."
+ /* 2 */ ".ddd....ddd."
+ /* 3 */ "..d....ddddd"
+ /* 4 */ "........ddd."
+ /* 5 */ ".........d.."
+
+ // Level 7
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ ".........d.."
+ /* 4 */ "............"
+ /* 5 */ "............",
+
+ // Connectors:
+ "-1: -1, 2, 2: 4\n" /* Type -1, direction X- */
+ "3: 5, 2, 6: 3\n" /* Type 3, direction Z+ */
+ "-3: 6, 2, -1: 2\n" /* Type -3, direction Z- */
+ "-3: 12, 2, 2: 5\n" /* Type -3, direction X+ */
+ "3: 12, 2, 2: 5\n" /* Type 3, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // SakuraDouble
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // SakuraSmall:
+ // The data has been exported from the gallery Plains, area index 145, ID 489, created by Aloe_vera
+ {
+ // Size:
+ 5, 7, 5, // SizeX = 5, SizeY = 7, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ -1, 0, -1, // MinX, MinY, MinZ
+ 5, 6, 5, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 2: 0\n" /* grass */
+ "c: 17: 1\n" /* tree */
+ "d: 35: 6\n" /* wool */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bbbbb"
+ /* 2 */ "bbabb"
+ /* 3 */ "bbbbb"
+ /* 4 */ "bbbbb"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "..c.."
+ /* 3 */ "....."
+ /* 4 */ "....."
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "..c.."
+ /* 3 */ "....."
+ /* 4 */ "....."
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "..d.."
+ /* 1 */ "ddddd"
+ /* 2 */ "ddcdd"
+ /* 3 */ "ddddd"
+ /* 4 */ "..d.."
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ ".ddd."
+ /* 1 */ ".ddd."
+ /* 2 */ "ddddd"
+ /* 3 */ ".ddd."
+ /* 4 */ ".ddd."
+
+ // Level 6
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "..d.."
+ /* 2 */ ".ddd."
+ /* 3 */ "..d.."
+ /* 4 */ ".....",
+
+ // Connectors:
+ "-1: 2, 2, -1: 2\n" /* Type -1, direction Z- */
+ "3: 5, 2, 2: 5\n" /* Type 3, direction X+ */
+ "-3: -1, 2, 2: 4\n" /* Type -3, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // SakuraSmall
+}; // g_JapaneseVillagePrefabs
+
+
+
+
+
+
+const cPrefab::sDef g_JapaneseVillageStartingPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HighTemple:
+ // The data has been exported from the gallery Plains, area index 70, ID 133, created by Aloe_vera
+ {
+ // Size:
+ 11, 19, 11, // SizeX = 11, SizeY = 19, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 18, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 2\n" /* wood */
+ "b:135: 0\n" /* 135 */
+ "c:135: 2\n" /* 135 */
+ "d:135: 1\n" /* 135 */
+ "e: 17: 9\n" /* tree */
+ "f:135: 3\n" /* 135 */
+ "g: 85: 0\n" /* fence */
+ "h: 17: 1\n" /* tree */
+ "i:171: 0\n" /* carpet */
+ "j: 50: 5\n" /* torch */
+ "k: 35: 0\n" /* wool */
+ "l: 17: 5\n" /* tree */
+ "m: 19: 0\n" /* sponge */
+ "n:124: 0\n" /* redstonelampon */
+ "o: 69: 9\n" /* lever */
+ "p: 44: 8\n" /* step */
+ "q: 43: 0\n" /* doubleslab */
+ "r: 44: 0\n" /* step */
+ "s: 50: 4\n" /* torch */
+ "t: 50: 1\n" /* torch */
+ "u: 50: 3\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmaaaaammm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "aaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaa"
+ /* 8 */ "maaaaaaaaam"
+ /* 9 */ "maaaaaaaaam"
+ /* 10 */ "mmmaaaaammm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "...bcccd..."
+ /* 1 */ ".aaaaaaaaa."
+ /* 2 */ ".aaaaaaaaa."
+ /* 3 */ "caaaaaaaaac"
+ /* 4 */ "baaaaaaaaad"
+ /* 5 */ "baaeaaaaaad"
+ /* 6 */ "baaaaaaaaad"
+ /* 7 */ "faaaaaaaaaf"
+ /* 8 */ ".aaaaaaaaa."
+ /* 9 */ ".aaaaaaaaa."
+ /* 10 */ "...bfffd..."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ggg...ggg."
+ /* 2 */ ".g.......g."
+ /* 3 */ ".g.hhhhh.g."
+ /* 4 */ "...hiiih..."
+ /* 5 */ "....iiih..."
+ /* 6 */ "...hiiih..."
+ /* 7 */ ".g.hhhhh.g."
+ /* 8 */ ".g.......g."
+ /* 9 */ ".ggg...ggg."
+ /* 10 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".j.g...g.j."
+ /* 2 */ "..........."
+ /* 3 */ ".g.kkhkk.g."
+ /* 4 */ "...h...k..."
+ /* 5 */ ".......h..."
+ /* 6 */ "...h...k..."
+ /* 7 */ ".g.kkhkk.g."
+ /* 8 */ "..........."
+ /* 9 */ ".j.g...g.j."
+ /* 10 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "...g...g..."
+ /* 2 */ "..........."
+ /* 3 */ ".g.kkhkk.g."
+ /* 4 */ "...h...k..."
+ /* 5 */ "...k...h..."
+ /* 6 */ "...h...k..."
+ /* 7 */ ".g.kkhkk.g."
+ /* 8 */ "..........."
+ /* 9 */ "...g...g..."
+ /* 10 */ "..........."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "...g...g..."
+ /* 2 */ "...ggggg..."
+ /* 3 */ ".gghlhlhgg."
+ /* 4 */ "..ge...eg.."
+ /* 5 */ "..ge.nohg.."
+ /* 6 */ "..ge...eg.."
+ /* 7 */ ".gghlhlhgg."
+ /* 8 */ "...ggggg..."
+ /* 9 */ "...g...g..."
+ /* 10 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..pqrrrqp.."
+ /* 2 */ ".pqqqqqqqp."
+ /* 3 */ ".qqhkkkhqq."
+ /* 4 */ ".rqkhhhkqr."
+ /* 5 */ ".rqkhhhkqr."
+ /* 6 */ ".rqkhhhkqr."
+ /* 7 */ ".qqhkkkhqq."
+ /* 8 */ ".pqqqqqqqp."
+ /* 9 */ "..pqrrrqp.."
+ /* 10 */ "..........."
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".qr.....rq."
+ /* 2 */ ".........r."
+ /* 3 */ "...hhhhh..."
+ /* 4 */ "...hiiih..."
+ /* 5 */ "....iiih..."
+ /* 6 */ "...hiiih..."
+ /* 7 */ "...hhhhh..."
+ /* 8 */ ".r.......r."
+ /* 9 */ ".qr.....rq."
+ /* 10 */ "..........."
+
+ // Level 8
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "...kkhkk..."
+ /* 4 */ "...h...k..."
+ /* 5 */ ".......h..."
+ /* 6 */ "...h...k..."
+ /* 7 */ "...kkhkk..."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+
+ // Level 9
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ ".....s....."
+ /* 3 */ "...kkhkk..."
+ /* 4 */ "...h...k..."
+ /* 5 */ "...k...ht.."
+ /* 6 */ "...h...k..."
+ /* 7 */ "...kkhkk..."
+ /* 8 */ ".....u....."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+
+ // Level 10
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "...ggggg..."
+ /* 3 */ "..ghlhlhg.."
+ /* 4 */ "..ge...eg.."
+ /* 5 */ "..ge.nohg.."
+ /* 6 */ "..ge...eg.."
+ /* 7 */ "..ghlhlhg.."
+ /* 8 */ "...ggggg..."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+
+ // Level 11
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..prrrrrp.."
+ /* 2 */ ".pqqqqqqqp."
+ /* 3 */ ".qqhkkkhqq."
+ /* 4 */ ".rqkhhhkqr."
+ /* 5 */ ".rqkhhhkqr."
+ /* 6 */ ".rqkhhhkqr."
+ /* 7 */ ".qqhkkkhqr."
+ /* 8 */ ".pqqqqqqqp."
+ /* 9 */ "..pqrrrqp.."
+ /* 10 */ "..........."
+
+ // Level 12
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".qr.....rq."
+ /* 2 */ ".r.......r."
+ /* 3 */ "...hhhhh..."
+ /* 4 */ "...hiiih..."
+ /* 5 */ "....iiih..."
+ /* 6 */ "...hiiih..."
+ /* 7 */ "...hhhhh..."
+ /* 8 */ ".r.......r."
+ /* 9 */ ".qr.....rq."
+ /* 10 */ "..........."
+
+ // Level 13
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "...kkhkk..."
+ /* 4 */ "...h...k..."
+ /* 5 */ ".......h..."
+ /* 6 */ "...h...k..."
+ /* 7 */ "...kkhkk..."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+
+ // Level 14
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ ".....s....."
+ /* 3 */ "...kkhkk..."
+ /* 4 */ "...h...k..."
+ /* 5 */ "...k...ht.."
+ /* 6 */ "...h...k..."
+ /* 7 */ "...kkhkk..."
+ /* 8 */ ".....u....."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+
+ // Level 15
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "...ggggg..."
+ /* 3 */ "..ghlhlhg.."
+ /* 4 */ "..ge...eg.."
+ /* 5 */ "..ge.nohg.."
+ /* 6 */ "..ge...eg.."
+ /* 7 */ "..ghlhlhg.."
+ /* 8 */ "...ggggg..."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+
+ // Level 16
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..pqrrrqp.."
+ /* 2 */ ".pqqqqqqqp."
+ /* 3 */ ".qqrrrrrqq."
+ /* 4 */ ".rqrrrrrqr."
+ /* 5 */ ".rqrrrrrqr."
+ /* 6 */ ".rqrrrrrqr."
+ /* 7 */ ".qqrrrrrqq."
+ /* 8 */ ".pqqqqqqqp."
+ /* 9 */ "..pqrrrqp.."
+ /* 10 */ "..........."
+
+ // Level 17
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".qr.....rq."
+ /* 2 */ ".rr.....rr."
+ /* 3 */ "...rrrrr..."
+ /* 4 */ "...rqqqr..."
+ /* 5 */ "...rqqqr..."
+ /* 6 */ "...rqqqr..."
+ /* 7 */ "...rrrrr..."
+ /* 8 */ ".rr.....rr."
+ /* 9 */ ".qr.....rq."
+ /* 10 */ "..........."
+
+ // Level 18
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "..........."
+ /* 5 */ ".....r....."
+ /* 6 */ "..........."
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "...........",
+
+ // Connectors:
+ "2: 0, 1, 5: 4\n" /* Type 2, direction X- */
+ "2: 5, 1, 0: 2\n" /* Type 2, direction Z- */
+ "2: 10, 1, 5: 5\n" /* Type 2, direction X+ */
+ "2: 5, 1, 10: 3\n" /* Type 2, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HighTemple
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Well:
+ // The data has been exported from the gallery Plains, area index 143, ID 487, created by STR_Warrior
+ {
+ // Size:
+ 7, 14, 7, // SizeX = 7, SizeY = 14, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 13, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 4: 0\n" /* cobblestone */
+ "c: 8: 0\n" /* water */
+ "d: 3: 0\n" /* dirt */
+ "e: 2: 0\n" /* grass */
+ "f: 13: 0\n" /* gravel */
+ "g: 67: 1\n" /* stairs */
+ "h: 67: 2\n" /* stairs */
+ "i: 67: 0\n" /* stairs */
+ "j: 67: 3\n" /* stairs */
+ "k: 85: 0\n" /* fence */
+ "l: 44: 8\n" /* step */
+ "m: 19: 0\n" /* sponge */
+ "n: 44: 0\n" /* step */
+ "o: 43: 0\n" /* doubleslab */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcc.ba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "eefffee"
+ /* 1 */ "ebbbbbe"
+ /* 2 */ "fbcccbf"
+ /* 3 */ "fbcccbf"
+ /* 4 */ "fbcccbf"
+ /* 5 */ "ebbbbbe"
+ /* 6 */ "eefffee"
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".bghib."
+ /* 2 */ ".j...j."
+ /* 3 */ ".i...g."
+ /* 4 */ ".h...h."
+ /* 5 */ ".bgjib."
+ /* 6 */ "......."
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".k...k."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ ".k...k."
+ /* 6 */ "......."
+
+ // Level 11
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".k...k."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ ".k...k."
+ /* 6 */ "......."
+
+ // Level 12
+ /* z\x* 0123456 */
+ /* 0 */ ".lnnnl."
+ /* 1 */ "loooool"
+ /* 2 */ "nooooon"
+ /* 3 */ "nooooon"
+ /* 4 */ "nooooon"
+ /* 5 */ "loooool"
+ /* 6 */ ".lnnnl."
+
+ // Level 13
+ /* z\x* 0123456 */
+ /* 0 */ "n.....n"
+ /* 1 */ "......."
+ /* 2 */ "..nnn.."
+ /* 3 */ "..non.."
+ /* 4 */ "..nnn.."
+ /* 5 */ "......."
+ /* 6 */ "n.....n",
+
+ // Connectors:
+ "2: 0, 9, 3: 4\n" /* Type 2, direction X- */
+ "2: 3, 9, 0: 2\n" /* Type 2, direction Z- */
+ "2: 6, 9, 3: 5\n" /* Type 2, direction X+ */
+ "2: 3, 9, 6: 3\n" /* Type 2, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Well
+};
+
+
+
+
+
+// The prefab counts:
+
+const size_t g_JapaneseVillagePrefabsCount = ARRAYCOUNT(g_JapaneseVillagePrefabs);
+
+const size_t g_JapaneseVillageStartingPrefabsCount = ARRAYCOUNT(g_JapaneseVillageStartingPrefabs);
+
diff --git a/src/Generating/Prefabs/JapaneseVillagePrefabs.h b/src/Generating/Prefabs/JapaneseVillagePrefabs.h
new file mode 100644
index 000000000..501b6c1cd
--- /dev/null
+++ b/src/Generating/Prefabs/JapaneseVillagePrefabs.h
@@ -0,0 +1,15 @@
+
+// JapaneseVillagePrefabs.h
+
+// Declares the prefabs in the group JapaneseVillage
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_JapaneseVillagePrefabs[];
+extern const cPrefab::sDef g_JapaneseVillageStartingPrefabs[];
+extern const size_t g_JapaneseVillagePrefabsCount;
+extern const size_t g_JapaneseVillageStartingPrefabsCount;
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp
new file mode 100644
index 000000000..2c97f28ea
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp
@@ -0,0 +1,5495 @@
+
+// NetherFortPrefabs.cpp
+
+// Defines the prefabs in the group NetherFort
+
+// NOTE: This file has been generated automatically by GalExport!
+// Any manual changes will be overwritten by the next automatic export!
+
+#include "Globals.h"
+#include "NetherFortPrefabs.h"
+
+
+
+
+
+const cPrefab::sDef g_NetherFortPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyCorridor:
+ // The data has been exported from the gallery Nether, area index 37, ID 288, created by Aloe_vera
+ {
+ // Size:
+ 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 6, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 4\n" /* netherbrickstairs */
+ "c:114: 7\n" /* netherbrickstairs */
+ "d:114: 5\n" /* netherbrickstairs */
+ "e: 44: 6\n" /* step */
+ "f:113: 0\n" /* netherbrickfence */
+ "g:114: 2\n" /* netherbrickstairs */
+ "h:114: 3\n" /* netherbrickstairs */
+ "i:114: 0\n" /* netherbrickstairs */
+ "j:114: 1\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "mmmmaaaaammmm"
+ /* 6 */ "mmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaa.aaa.aaaa"
+ /* 5 */ "mmbcaaaaacdmm"
+ /* 6 */ "mmmbcccccdmmm"
+ /* 7 */ "mmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "aaaa.eee.aaaa"
+ /* 5 */ "mmaaaaaaaaamm"
+ /* 6 */ "mmaaaaaaaaamm"
+ /* 7 */ "mmaaaaaaaaamm"
+ /* 8 */ "mmaaaaaaaaamm"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "afafafafafafa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "afaa.....aafa"
+ /* 5 */ "mmaaa...aaamm"
+ /* 6 */ "mmf.......fmm"
+ /* 7 */ "mmf.......fmm"
+ /* 8 */ "mmfffffffffmm"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "afafafafafafa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "afaa.....aafa"
+ /* 5 */ "mmaaa...aaamm"
+ /* 6 */ "mm.........mm"
+ /* 7 */ "mm.........mm"
+ /* 8 */ "mm.........mm"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "afafafafafafa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "afaa.....aafa"
+ /* 5 */ "mmaaa...aaamm"
+ /* 6 */ "mm.........mm"
+ /* 7 */ "mm.........mm"
+ /* 8 */ "mm.........mm"
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ggggggggggggg"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "hhiaaaaaaahhh"
+ /* 5 */ "mmihhhhhhhjmm"
+ /* 6 */ "mmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmm",
+
+ // Connectors:
+ "1: 12, 2, 2: 5\n" /* Type 1, direction X+ */
+ "1: 0, 2, 2: 4\n" /* Type 1, direction X- */
+ "-1: 12, 2, 2: 5\n" /* Type -1, direction X+ */
+ "-1: 0, 2, 2: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 20,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BalconyCorridor
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyTee2:
+ // The data has been exported from the gallery Nether, area index 38, ID 289, created by Aloe_vera
+ {
+ // Size:
+ 13, 7, 11, // SizeX = 13, SizeY = 7, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 6, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 4\n" /* netherbrickstairs */
+ "c:114: 7\n" /* netherbrickstairs */
+ "d:114: 5\n" /* netherbrickstairs */
+ "e: 44: 6\n" /* step */
+ "f:113: 0\n" /* netherbrickfence */
+ "g:114: 0\n" /* netherbrickstairs */
+ "h:114: 1\n" /* netherbrickstairs */
+ "i:114: 2\n" /* netherbrickstairs */
+ "j:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmaaaaammmm"
+ /* 1 */ "mmmmaaaaammmm"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "mmmmaaaaammmm"
+ /* 8 */ "mmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmaaaaammmm"
+ /* 1 */ "mmmmaaaaammmm"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaa.aaa.aaaa"
+ /* 7 */ "mmbcaaaaacdmm"
+ /* 8 */ "mmmbcccccdmmm"
+ /* 9 */ "mmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmma...ammmm"
+ /* 2 */ "aaaaa...aaaaa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "aaaa.eee.aaaa"
+ /* 7 */ "mmaaaaaaaaamm"
+ /* 8 */ "mmaaaaaaaaamm"
+ /* 9 */ "mmaaaaaaaaamm"
+ /* 10 */ "mmaaaaaaaaamm"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmf...fmmmm"
+ /* 2 */ "afafa...afafa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "afaa.....aafa"
+ /* 7 */ "mmaaa...aaamm"
+ /* 8 */ "mmf.......fmm"
+ /* 9 */ "mmf.......fmm"
+ /* 10 */ "mmfffffffffmm"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmf...fmmmm"
+ /* 2 */ "afafa...afafa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "afaa.....aafa"
+ /* 7 */ "mmaaa...aaamm"
+ /* 8 */ "mm.........mm"
+ /* 9 */ "mm.........mm"
+ /* 10 */ "mm.........mm"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmf...fmmmm"
+ /* 2 */ "afafa...afafa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "afaa.....aafa"
+ /* 7 */ "mmaaa...aaamm"
+ /* 8 */ "mm.........mm"
+ /* 9 */ "mm.........mm"
+ /* 10 */ "mm.........mm"
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmgaaahmmmm"
+ /* 1 */ "mmmmgaaahmmmm"
+ /* 2 */ "iiiiiaaaiiiii"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "jjgaaaaaaajjj"
+ /* 7 */ "mmgjjjjjjjhmm"
+ /* 8 */ "mmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmm",
+
+ // Connectors:
+ "1: 12, 2, 4: 5\n" /* Type 1, direction X+ */
+ "1: 6, 2, 0: 2\n" /* Type 1, direction Z- */
+ "1: 0, 2, 4: 4\n" /* Type 1, direction X- */
+ "-1: 12, 2, 4: 5\n" /* Type -1, direction X+ */
+ "-1: 6, 2, 0: 2\n" /* Type -1, direction Z- */
+ "-1: 0, 2, 4: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 20,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BalconyTee2
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatform:
+ // The data has been exported from the gallery Nether, area index 26, ID 276, created by tonibm1999
+ {
+ // Size:
+ 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 9, 6, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 52: 0\n" /* mobspawner */
+ "c:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmmmmmmm"
+ /* 1 */ "aaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaa"
+ /* 6 */ "mmmmmmmmmm"
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmmmmmmm"
+ /* 1 */ "aaaaaaaaaa"
+ /* 2 */ "..aaaaaaaa"
+ /* 3 */ "..aaaaaaaa"
+ /* 4 */ "..aaaaaaaa"
+ /* 5 */ "aaaaaaaaaa"
+ /* 6 */ "mmmmmmmmmm"
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmaaaaaa"
+ /* 1 */ "aaaaaaaaaa"
+ /* 2 */ "...aaaaaaa"
+ /* 3 */ "...aaaaaaa"
+ /* 4 */ "...aaaaaaa"
+ /* 5 */ "aaaaaaaaaa"
+ /* 6 */ "mmmmaaaaaa"
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmaaaaaa"
+ /* 1 */ "mmaaa....a"
+ /* 2 */ ".........a"
+ /* 3 */ "......b..a"
+ /* 4 */ ".........a"
+ /* 5 */ "mmaaa....a"
+ /* 6 */ "mmmmaaaaaa"
+
+ // Level 4
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmcccccc"
+ /* 1 */ "mmmcc....c"
+ /* 2 */ ".........c"
+ /* 3 */ ".........c"
+ /* 4 */ ".........c"
+ /* 5 */ "mmmcc....c"
+ /* 6 */ "mmmmcccccc"
+
+ // Level 5
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmmmmmmm"
+ /* 1 */ "mmmmm....c"
+ /* 2 */ "m........c"
+ /* 3 */ "m........c"
+ /* 4 */ "m........c"
+ /* 5 */ "mmmmm....c"
+ /* 6 */ "mmmmmmmmmm"
+
+ // Level 6
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmmmmmmmmm"
+ /* 1 */ "mmmmm....m"
+ /* 2 */ "mm.......c"
+ /* 3 */ "mm.......c"
+ /* 4 */ "mm.......c"
+ /* 5 */ "mmmmm....m"
+ /* 6 */ "mmmmmmmmmm",
+
+ // Connectors:
+ "0: 0, 1, 3: 4\n" /* Type 0, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:0|2:0|3:0|4:0|5:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BlazePlatform
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatformOverhang:
+ // The data has been exported from the gallery Nether, area index 20, ID 162, created by STR_Warrior
+ {
+ // Size:
+ 14, 11, 7, // SizeX = 14, SizeY = 11, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 13, 20, 6, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmmmmm"
+ /* 2 */ "aammmmmmmmmmmm"
+ /* 3 */ "aammmmmmmmmmmm"
+ /* 4 */ "aammmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmmmmm"
+ /* 2 */ "aabcmmmmmmmmmm"
+ /* 3 */ "aabcmmmmmmmmmm"
+ /* 4 */ "aabcmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmmmmm"
+ /* 2 */ "aaaaabmmmmmmmm"
+ /* 3 */ "aaaaabmmmmmmmm"
+ /* 4 */ "aaaaabmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmm"
+
+ // Level 3
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmmmmmmm"
+ /* 1 */ "dddddddmmmmmmm"
+ /* 2 */ "aaaaaabmmmmmmm"
+ /* 3 */ "aaaaaabmmmmmmm"
+ /* 4 */ "aaaaaabmmmmmmm"
+ /* 5 */ "eeeeeeemmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmm"
+
+ // Level 4
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmmmmmmm"
+ /* 1 */ "aaaaaaadmmmmmm"
+ /* 2 */ "aaaaaaabmmmmmm"
+ /* 3 */ "aaaaaaabmmmmmm"
+ /* 4 */ "aaaaaaabmmmmmm"
+ /* 5 */ "aaaaaaaemmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmm"
+
+ // Level 5
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmmmmmmm"
+ /* 1 */ "aaaaaaaabddddm"
+ /* 2 */ "......faaaaabm"
+ /* 3 */ "......faaaaabm"
+ /* 4 */ "......faaaaabm"
+ /* 5 */ "aaaaaaaaabeebm"
+ /* 6 */ "mmmmmmmmmmmmmm"
+
+ // Level 6
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmgdddbm"
+ /* 1 */ "mmmmmmaaaaaaad"
+ /* 2 */ ".......faaaaab"
+ /* 3 */ ".......faaaaab"
+ /* 4 */ ".......faaaaab"
+ /* 5 */ "mmmmmmaaaaaaae"
+ /* 6 */ "mmmmmmmmgeeebm"
+
+ // Level 7
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmaaaaam"
+ /* 1 */ "mmmmmmhaa...aa"
+ /* 2 */ ".............a"
+ /* 3 */ "..........i..a"
+ /* 4 */ ".............a"
+ /* 5 */ "mmmmmmhaa...aa"
+ /* 6 */ "mmmmmmmmaaaaam"
+
+ // Level 8
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmmhhhhhm"
+ /* 1 */ "mmmmmmhhh...hh"
+ /* 2 */ "mm...........h"
+ /* 3 */ "mm...........h"
+ /* 4 */ "mm...........h"
+ /* 5 */ "mmmmmmhhh...hh"
+ /* 6 */ "mmmmmmmmhhhhhm"
+
+ // Level 9
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmm.....m"
+ /* 1 */ "mmmmmm........"
+ /* 2 */ "mmmm.........."
+ /* 3 */ "mmmm.........."
+ /* 4 */ "mmmm.........."
+ /* 5 */ "mmmmmm........"
+ /* 6 */ "mmmmmmmm.....m"
+
+ // Level 10
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "mmmmmmmm.....m"
+ /* 1 */ "mmmmmm........"
+ /* 2 */ "mmmmmm........"
+ /* 3 */ "mmmmmm........"
+ /* 4 */ "mmmmmm........"
+ /* 5 */ "mmmmmm........"
+ /* 6 */ "mmmmmmmm.....m",
+
+ // Connectors:
+ "0: 0, 5, 3: 4\n" /* Type 0, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:0|2:0|3:0|4:0|5:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BlazePlatformOverhang
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCircleCrossing:
+ // The data has been exported from the gallery Nether, area index 49, ID 308, created by Aloe_vera
+ {
+ // Size:
+ 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 17, 14, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "mmmmmmaaammmmmm"
+ /* 2 */ "mmmmmmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "aammmmmmmmmmmaa"
+ /* 7 */ "aammmmmmmmmmmaa"
+ /* 8 */ "aammmmmmmmmmmaa"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+ /* 12 */ "mmmmmmmmmmmmmmm"
+ /* 13 */ "mmmmmmaaammmmmm"
+ /* 14 */ "mmmmmmaaammmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "mmmmmmaaammmmmm"
+ /* 2 */ "mmmmmmbbbmmmmmm"
+ /* 3 */ "mmmmmmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "aacmmmmmmmmmdaa"
+ /* 7 */ "aacmmmmmmmmmdaa"
+ /* 8 */ "aacmmmmmmmmmdaa"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+ /* 12 */ "mmmmmmeeemmmmmm"
+ /* 13 */ "mmmmmmaaammmmmm"
+ /* 14 */ "mmmmmmaaammmmmm"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "mmmmmeaaammmmmm"
+ /* 2 */ "mmmmmdaaammmmmm"
+ /* 3 */ "mmmmmdbbbmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mdeemmmmmmmeecm"
+ /* 6 */ "aaacmmmmmmmdaaa"
+ /* 7 */ "aaacmmmmmmmdaaa"
+ /* 8 */ "aaacmmmmmmmdaaa"
+ /* 9 */ "mdbcmmmmmmmbbcm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmdeeecmmmmm"
+ /* 12 */ "mmmmmdaaacmmmmm"
+ /* 13 */ "mmmmmbaaabmmmmm"
+ /* 14 */ "mmmmmmaaammmmmm"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "deeeedaaaceeeec"
+ /* 1 */ "daaaaaaaaaaaaac"
+ /* 2 */ "daaaaaaaaaaaaac"
+ /* 3 */ "daaaaaaaaaaaaac"
+ /* 4 */ "daaacbbaabdaaac"
+ /* 5 */ "eaaacmmmmmdaaae"
+ /* 6 */ "aaaacmmmmmdaaaa"
+ /* 7 */ "aaaacmmmmmdaaaa"
+ /* 8 */ "aaaacmmmmmdaaaa"
+ /* 9 */ "baaacmmmmmdaaab"
+ /* 10 */ "daaaceeeeedaaac"
+ /* 11 */ "daaaaaaaaaaaaac"
+ /* 12 */ "daaaaaaaaaaaaac"
+ /* 13 */ "daaaaaaaaaaaaac"
+ /* 14 */ "dbbbbdaaacbbbbb"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaammmmmaaaaa"
+ /* 6 */ "aaaaammmmmaaaaa"
+ /* 7 */ "aaaaammmmmaaaaa"
+ /* 8 */ "aaaaammmmmaaaaa"
+ /* 9 */ "aaaaammmmmaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaa"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaa...aaaaaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "a.............a"
+ /* 3 */ "a.............a"
+ /* 4 */ "a...aaaaaaa...a"
+ /* 5 */ "a...ammmmma...a"
+ /* 6 */ "....ammmmma...."
+ /* 7 */ "....ammmmma...."
+ /* 8 */ "....ammmmma...."
+ /* 9 */ "a...ammmmma...a"
+ /* 10 */ "a...aaaaaaa...a"
+ /* 11 */ "a.............a"
+ /* 12 */ "a.............a"
+ /* 13 */ "a.............a"
+ /* 14 */ "aaaaaa...aaaaaa"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmm...mmmmmm"
+ /* 1 */ "m.............m"
+ /* 2 */ "m.............m"
+ /* 3 */ "m.............m"
+ /* 4 */ "m.............m"
+ /* 5 */ "m....mmmmm....m"
+ /* 6 */ ".....mmmmm....."
+ /* 7 */ ".....mmmmm....."
+ /* 8 */ ".....mmmmm....."
+ /* 9 */ "m....mmmmm....m"
+ /* 10 */ "m.............m"
+ /* 11 */ "m.............m"
+ /* 12 */ "m.............m"
+ /* 13 */ "m.............m"
+ /* 14 */ "mmmmmm...mmmmmm"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmm...mmmmmm"
+ /* 1 */ "m.............m"
+ /* 2 */ "m.............m"
+ /* 3 */ "m.............m"
+ /* 4 */ "m.............m"
+ /* 5 */ "m....mmmmm....m"
+ /* 6 */ ".....mmmmm....."
+ /* 7 */ ".....mmmmm....."
+ /* 8 */ ".....mmmmm....."
+ /* 9 */ "m....mmmmm....m"
+ /* 10 */ "m.............m"
+ /* 11 */ "m.............m"
+ /* 12 */ "m.............m"
+ /* 13 */ "m.............m"
+ /* 14 */ "mmmmmm...mmmmmm",
+
+ // Connectors:
+ "0: 0, 5, 7: 4\n" /* Type 0, direction X- */
+ "0: 7, 5, 0: 2\n" /* Type 0, direction Z- */
+ "0: 14, 5, 7: 5\n" /* Type 0, direction X+ */
+ "0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 5,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ -1000,
+
+ // MoveToGround:
+ false,
+ }, // BridgeCircleCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrossing:
+ // The data has been exported from the gallery Nether, area index 17, ID 159, created by Aloe_vera
+ {
+ // Size:
+ 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 17, 14, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "mmmmmmaaammmmmm"
+ /* 2 */ "mmmmmmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "aammmmmmmmmmmaa"
+ /* 7 */ "aammmmmmmmmmmaa"
+ /* 8 */ "aammmmmmmmmmmaa"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+ /* 12 */ "mmmmmmmmmmmmmmm"
+ /* 13 */ "mmmmmmaaammmmmm"
+ /* 14 */ "mmmmmmaaammmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "mmmmmmaaammmmmm"
+ /* 2 */ "mmmmmmbbbmmmmmm"
+ /* 3 */ "mmmmmmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "aacmmmmmmmmmdaa"
+ /* 7 */ "aacmmmmmmmmmdaa"
+ /* 8 */ "aacmmmmmmmmmdaa"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+ /* 12 */ "mmmmmmeeemmmmmm"
+ /* 13 */ "mmmmmmaaammmmmm"
+ /* 14 */ "mmmmmmaaammmmmm"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "mmmmmmaaammmmmm"
+ /* 2 */ "mmmmmmaaammmmmm"
+ /* 3 */ "mmmmmmbbbmmmmmm"
+ /* 4 */ "mmmmmmfffmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "aaacfmmmmmfdaaa"
+ /* 7 */ "aaacfmmmmmfdaaa"
+ /* 8 */ "aaacfmmmmmfdaaa"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmfffmmmmmm"
+ /* 11 */ "mmmmmmeeemmmmmm"
+ /* 12 */ "mmmmmmaaammmmmm"
+ /* 13 */ "mmmmmmaaammmmmm"
+ /* 14 */ "mmmmmmaaammmmmm"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmdaaacmmmmm"
+ /* 1 */ "mmmmmdaaacmmmmm"
+ /* 2 */ "mmmmmdaaacmmmmm"
+ /* 3 */ "mmmmmdaaacmmmmm"
+ /* 4 */ "mmmmmdaaacmmmmm"
+ /* 5 */ "eeeeeeaaaeeeeee"
+ /* 6 */ "aaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+ /* 9 */ "bbbbbdaaacbbbbb"
+ /* 10 */ "mmmmmdaaacmmmmm"
+ /* 11 */ "mmmmmdaaacmmmmm"
+ /* 12 */ "mmmmmdaaacmmmmm"
+ /* 13 */ "mmmmmdaaacmmmmm"
+ /* 14 */ "mmmmmdaaacmmmmm"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmaaaaammmmm"
+ /* 1 */ "mmmmmaaaaammmmm"
+ /* 2 */ "mmmmmaaaaammmmm"
+ /* 3 */ "mmmmmaaaaammmmm"
+ /* 4 */ "mmmmmaaaaammmmm"
+ /* 5 */ "aaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaa"
+ /* 10 */ "mmmmmaaaaammmmm"
+ /* 11 */ "mmmmmaaaaammmmm"
+ /* 12 */ "mmmmmaaaaammmmm"
+ /* 13 */ "mmmmmaaaaammmmm"
+ /* 14 */ "mmmmmaaaaammmmm"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmma...ammmmm"
+ /* 1 */ "mmmmma...ammmmm"
+ /* 2 */ "mmmmma...ammmmm"
+ /* 3 */ "mmmmma...ammmmm"
+ /* 4 */ "mmmmma...ammmmm"
+ /* 5 */ "aaaaaa...aaaaaa"
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "aaaaaa...aaaaaa"
+ /* 10 */ "mmmmma...ammmmm"
+ /* 11 */ "mmmmma...ammmmm"
+ /* 12 */ "mmmmma...ammmmm"
+ /* 13 */ "mmmmma...ammmmm"
+ /* 14 */ "mmmmma...ammmmm"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmm...mmmmmm"
+ /* 1 */ "mmmmmm...mmmmmm"
+ /* 2 */ "mmmmmm...mmmmmm"
+ /* 3 */ "mmmmmm...mmmmmm"
+ /* 4 */ "mmmmmm...mmmmmm"
+ /* 5 */ "mmmmmm...mmmmmm"
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "mmmmmm...mmmmmm"
+ /* 10 */ "mmmmmm...mmmmmm"
+ /* 11 */ "mmmmmm...mmmmmm"
+ /* 12 */ "mmmmmm...mmmmmm"
+ /* 13 */ "mmmmmm...mmmmmm"
+ /* 14 */ "mmmmmm...mmmmmm"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmm...mmmmmm"
+ /* 1 */ "mmmmmm...mmmmmm"
+ /* 2 */ "mmmmmm...mmmmmm"
+ /* 3 */ "mmmmmm...mmmmmm"
+ /* 4 */ "mmmmmm...mmmmmm"
+ /* 5 */ "mmmmmm...mmmmmm"
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+ /* 9 */ "mmmmmm...mmmmmm"
+ /* 10 */ "mmmmmm...mmmmmm"
+ /* 11 */ "mmmmmm...mmmmmm"
+ /* 12 */ "mmmmmm...mmmmmm"
+ /* 13 */ "mmmmmm...mmmmmm"
+ /* 14 */ "mmmmmm...mmmmmm",
+
+ // Connectors:
+ "0: 0, 5, 7: 4\n" /* Type 0, direction X- */
+ "0: 7, 5, 0: 2\n" /* Type 0, direction Z- */
+ "0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */
+ "0: 14, 5, 7: 5\n" /* Type 0, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "1:1000",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BridgeCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble1:
+ // The data has been exported from the gallery Nether, area index 19, ID 161, created by Aloe_vera
+ {
+ // Size:
+ 9, 6, 5, // SizeX = 9, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 8, 15, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmmmmmm"
+ /* 1 */ "aammmmmmm"
+ /* 2 */ "aammmmmmm"
+ /* 3 */ "aammmmmmm"
+ /* 4 */ "mmmmmmmmm"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmmmmmm"
+ /* 1 */ "aabmmmmmm"
+ /* 2 */ "aabmmmmmm"
+ /* 3 */ "aabmmmmmm"
+ /* 4 */ "mmmmmmmmm"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmmmmmm"
+ /* 1 */ "aaabcmmmm"
+ /* 2 */ "aaabcmmmm"
+ /* 3 */ "aaabcmmmm"
+ /* 4 */ "mmmmmmmmm"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "dddddddmm"
+ /* 1 */ "aaaaaaaam"
+ /* 2 */ "aaaaaaaaa"
+ /* 3 */ "aaaaaaamm"
+ /* 4 */ "eeeeemmmm"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "aaaaammmm"
+ /* 2 */ "aaaaaammm"
+ /* 3 */ "aaaaaammm"
+ /* 4 */ "aaaaaaaam"
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaammm"
+ /* 1 */ "mmmmmmmmm"
+ /* 2 */ "mmmmmmmmm"
+ /* 3 */ "mmmmmmmmm"
+ /* 4 */ "aaaaaaamm",
+
+ // Connectors:
+ "1: 0, 5, 2: 4\n" /* Type 1, direction X- */
+ "0: 0, 5, 2: 4\n" /* Type 0, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:0|2:0|3:0|4:0|5:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BridgeCrumble1
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble2:
+ // The data has been exported from the gallery Nether, area index 18, ID 160, created by Aloe_vera
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 15, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmm"
+ /* 2 */ "aammmmmmmmmmm"
+ /* 3 */ "aammmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmmmmmmmmmm"
+ /* 1 */ "aabmmmmmmmmmm"
+ /* 2 */ "aabmmmmmmmmmm"
+ /* 3 */ "aabmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmmmmmmmmmm"
+ /* 1 */ "aaabcmmmmmmmm"
+ /* 2 */ "aaabcmmmmmmmm"
+ /* 3 */ "aaabcmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmmmm"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "dddddddddmmmm"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaammmm"
+ /* 3 */ "aaaaaaaaaaaam"
+ /* 4 */ "eeeeeeeeemmmm"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaam"
+ /* 1 */ "aaaaaaaaaammm"
+ /* 2 */ "aaaaaaaaaaamm"
+ /* 3 */ "aaaaaaaaammmm"
+ /* 4 */ "aaaaaaaaaaaaa"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaammmm"
+ /* 1 */ "mmmmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmmmm"
+ /* 4 */ "aaaaaaaaaammm",
+
+ // Connectors:
+ "0: 0, 5, 2: 4\n" /* Type 0, direction X- */
+ "1: 0, 5, 2: 4\n" /* Type 1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:0|2:0|3:0|4:0|5:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BridgeCrumble2
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeDoubleCrumble:
+ // The data has been exported from the gallery Nether, area index 46, ID 305, created by STR_Warrior
+ {
+ // Size:
+ 5, 7, 16, // SizeX = 5, SizeY = 7, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 16, 15, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 7\n" /* netherbrickstairs */
+ "c:114: 6\n" /* netherbrickstairs */
+ "d:114: 4\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "maaam"
+ /* 1 */ "maaam"
+ /* 2 */ "mmmmm"
+ /* 3 */ "mmmmm"
+ /* 4 */ "mmmmm"
+ /* 5 */ "mmmmm"
+ /* 6 */ "mmmmm"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmmm"
+ /* 11 */ "mmmmm"
+ /* 12 */ "mmmmm"
+ /* 13 */ "mmmmm"
+ /* 14 */ "maaam"
+ /* 15 */ "maaam"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "maaam"
+ /* 1 */ "maaam"
+ /* 2 */ "mbbbm"
+ /* 3 */ "mmmmm"
+ /* 4 */ "mmmmm"
+ /* 5 */ "mmmmm"
+ /* 6 */ "mmmmm"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmmm"
+ /* 11 */ "mmmmm"
+ /* 12 */ "mmmmm"
+ /* 13 */ "mcccm"
+ /* 14 */ "maaam"
+ /* 15 */ "maaam"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "daaae"
+ /* 1 */ "daaae"
+ /* 2 */ "daaae"
+ /* 3 */ "daaae"
+ /* 4 */ "daaae"
+ /* 5 */ "mamae"
+ /* 6 */ "mmmam"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmae"
+ /* 11 */ "dmaae"
+ /* 12 */ "daaae"
+ /* 13 */ "daaae"
+ /* 14 */ "daaae"
+ /* 15 */ "daaae"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaama"
+ /* 4 */ "mamaa"
+ /* 5 */ "mmmmm"
+ /* 6 */ "mmmmm"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmma"
+ /* 11 */ "mmmaa"
+ /* 12 */ "amaaa"
+ /* 13 */ "aaaaa"
+ /* 14 */ "aaaaa"
+ /* 15 */ "aaaaa"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "ammma"
+ /* 1 */ "ammma"
+ /* 2 */ "ammma"
+ /* 3 */ "mmmma"
+ /* 4 */ "mmmmm"
+ /* 5 */ "mmmmm"
+ /* 6 */ "mmmmm"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmmm"
+ /* 11 */ "mmmma"
+ /* 12 */ "mmmmm"
+ /* 13 */ "ammma"
+ /* 14 */ "ammma"
+ /* 15 */ "ammma"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "mmmmm"
+ /* 1 */ "mmmmm"
+ /* 2 */ "mmmmm"
+ /* 3 */ "mmmmm"
+ /* 4 */ "mmmmm"
+ /* 5 */ "mmmmm"
+ /* 6 */ "mmmmm"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmmm"
+ /* 11 */ "mmmmm"
+ /* 12 */ "mmmmm"
+ /* 13 */ "mmmmm"
+ /* 14 */ "mmmmm"
+ /* 15 */ "mmmmm"
+
+ // Level 6
+ /* z\x* 01234 */
+ /* 0 */ "mmmmm"
+ /* 1 */ "mmmmm"
+ /* 2 */ "mmmmm"
+ /* 3 */ "mmmmm"
+ /* 4 */ "mmmmm"
+ /* 5 */ "mmmmm"
+ /* 6 */ "mmmmm"
+ /* 7 */ "mmmmm"
+ /* 8 */ "mmmmm"
+ /* 9 */ "mmmmm"
+ /* 10 */ "mmmmm"
+ /* 11 */ "mmmmm"
+ /* 12 */ "mmmmm"
+ /* 13 */ "mmmmm"
+ /* 14 */ "mmmmm"
+ /* 15 */ "mmmmm",
+
+ // Connectors:
+ "0: 2, 4, 0: 2\n" /* Type 0, direction Z- */
+ "0: 2, 4, 15: 3\n" /* Type 0, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 1000,
+
+ // MoveToGround:
+ false,
+ }, // BridgeDoubleCrumble
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeFunnelDown:
+ // The data has been exported from the gallery Nether, area index 0, ID 2, created by Aloe_vera
+ {
+ // Size:
+ 15, 12, 12, // SizeX = 15, SizeY = 12, SizeZ = 12
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 21, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 6\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 5\n" /* netherbrickstairs */
+ "e: 44:14\n" /* step */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmaaammmmmm"
+ /* 10 */ "mmmmmmaaammmmmm"
+ /* 11 */ "mmmmmmaaammmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmbbbmmmmmm"
+ /* 9 */ "mmmmmmaaammmmmm"
+ /* 10 */ "mmmmmmaaammmmmm"
+ /* 11 */ "mmmmmmaaammmmmm"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmcbbbdmmmmm"
+ /* 8 */ "mmmmmcaaadmmmmm"
+ /* 9 */ "mmmmmcaaadmmmmm"
+ /* 10 */ "mmmmmcaaadmmmmm"
+ /* 11 */ "mmmmmcaaadmmmmm"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmaaaaammmmm"
+ /* 8 */ "mmmmmaaaaammmmm"
+ /* 9 */ "mmmmmaaaaammmmm"
+ /* 10 */ "mmmmmaaaaammmmm"
+ /* 11 */ "mmmmmaaaaammmmm"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmcbbbbbdmmmm"
+ /* 7 */ "mmmmaaaaaaammmm"
+ /* 8 */ "mmmma.....ammmm"
+ /* 9 */ "mmmmaa...aammmm"
+ /* 10 */ "mmmmma...ammmmm"
+ /* 11 */ "mmmmma...ammmmm"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aadmmmmmmmmmcaa"
+ /* 2 */ "aadmmmmmmmmmcaa"
+ /* 3 */ "aadmmmmmmmmmcaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmcbbbbbbbdmmm"
+ /* 6 */ "mmmaaaaaaaaaamm"
+ /* 7 */ "mmma.......ammm"
+ /* 8 */ "mmmaa.....aammm"
+ /* 9 */ "mmmmam...mammmm"
+ /* 10 */ "mmmmmm...mmmmmm"
+ /* 11 */ "mmmmmm...mmmmmm"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aaademmmmmecaaa"
+ /* 2 */ "aaademmmmmecaaa"
+ /* 3 */ "aaademmmmmecaaa"
+ /* 4 */ "mmaaabbbbbaaaam"
+ /* 5 */ "mmaaaaaaaaaaaam"
+ /* 6 */ "mma.........amm"
+ /* 7 */ "mmaa.......aamm"
+ /* 8 */ "mmmam.....mammm"
+ /* 9 */ "mmmmmm...mmmmmm"
+ /* 10 */ "mmmmmm...mmmmmm"
+ /* 11 */ "mmmmmm...mmmmmm"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "bbbbbbbbbbbbbbb"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "faaaaaaaaaaaaaa"
+ /* 5 */ "ma...........am"
+ /* 6 */ "maa.........aam"
+ /* 7 */ "mmam.......mamm"
+ /* 8 */ "mmmmm.....mmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+
+ // Level 8
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "a.............a"
+ /* 5 */ "aa...........aa"
+ /* 6 */ "mam.........mam"
+ /* 7 */ "mmmm.......mmmm"
+ /* 8 */ "mmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+
+ // Level 9
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "a.............a"
+ /* 5 */ "am............a"
+ /* 6 */ "mmm.........mmm"
+ /* 7 */ "mmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+
+ // Level 10
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "m.............m"
+ /* 5 */ "mm............m"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm"
+
+ // Level 11
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "m.............m"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmm",
+
+ // Connectors:
+ "0: 7, 4, 11: 3\n" /* Type 0, direction Z+ */
+ "0: 0, 9, 2: 4\n" /* Type 0, direction X- */
+ "0: 14, 9, 2: 5\n" /* Type 0, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 5,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BridgeFunnelDown
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeLevelCrossing:
+ // The data has been exported from the gallery Nether, area index 61, ID 321, created by Aloe_vera
+ {
+ // Size:
+ 16, 14, 16, // SizeX = 16, SizeY = 14, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 15, 23, 15, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmmm"
+ /* 12 */ "maaammmmmmmmmmmm"
+ /* 13 */ "maaammmmmmmmmmmm"
+ /* 14 */ "maaammmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmmmmm"
+ /* 1 */ "aabmmmmmmmmmmcaa"
+ /* 2 */ "aabmmmmmmmmmmcaa"
+ /* 3 */ "aabmmmmmmmmmmcaa"
+ /* 4 */ "mmmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmmm"
+ /* 12 */ "maaammmmmmmmmmmm"
+ /* 13 */ "maaammmmmmmmmmmm"
+ /* 14 */ "maaammmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmmmmm"
+ /* 1 */ "aaabdmmmmmmdcaaa"
+ /* 2 */ "aaabdmmmmmmdcaaa"
+ /* 3 */ "aaabdmmmmmmdcaaa"
+ /* 4 */ "mmmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmmm"
+ /* 12 */ "maaammmmmmmmmmmm"
+ /* 13 */ "maaammmmmmmmmmmm"
+ /* 14 */ "maaammmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "eeeeeeeeeeeeeeee"
+ /* 1 */ "aaaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaaa"
+ /* 4 */ "ffffffffffffffff"
+ /* 5 */ "mmmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmmm"
+ /* 12 */ "maaammmmmmmmmmmm"
+ /* 13 */ "maaammmmmmmmmmmm"
+ /* 14 */ "maaammmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaaa"
+ /* 5 */ "faaabmmmmmmmmmmm"
+ /* 6 */ "caaabmmmmmmmmmmm"
+ /* 7 */ "caaabmmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmmm"
+ /* 12 */ "maaammmmmmmmmmmm"
+ /* 13 */ "maaammmmmmmmmmmm"
+ /* 14 */ "maaammmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "a...aaaaaaaaaaaa"
+ /* 5 */ "a...ammmmmmmmmmm"
+ /* 6 */ "aaaaammmmmmmmmmm"
+ /* 7 */ "aaaaammmmmmmmmmm"
+ /* 8 */ "caaabmmmmmmmmmmm"
+ /* 9 */ "caaabmmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmmmmmmm"
+ /* 12 */ "maaammmmmmmmmmmm"
+ /* 13 */ "maaammmmmmmmmmmm"
+ /* 14 */ "maaammmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmaaam"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "m...mmmmmmmmaaam"
+ /* 5 */ "a...ammmmmmmmmmm"
+ /* 6 */ "a...ammmmmmmmmmm"
+ /* 7 */ "a...ammmmmmmmmmm"
+ /* 8 */ "aaaaammmmmmmmmmm"
+ /* 9 */ "aaaaammmmmmmmmmm"
+ /* 10 */ "caaabmmmmmmmmmmm"
+ /* 11 */ "caaabmmmmmmmmmmm"
+ /* 12 */ "maaabmmmmmmmmmmm"
+ /* 13 */ "maaabmmmmmmmmmmm"
+ /* 14 */ "maaafmmmmmmmaaam"
+ /* 15 */ "mmmmmmmmmmmmaaam"
+
+ // Level 7
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmaaam"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "................"
+ /* 4 */ "m...mmmmmmmmaaam"
+ /* 5 */ "m...mmmmmmmmmmmm"
+ /* 6 */ "m...mmmmmmmmmmmm"
+ /* 7 */ "a...ammmmmmmmmmm"
+ /* 8 */ "a...ammmmmmmmmmm"
+ /* 9 */ "a...ammmmmmmmmmm"
+ /* 10 */ "aaaaammmmmmmmmmm"
+ /* 11 */ "aaaaaeemmmmmmmmm"
+ /* 12 */ "caaaaaammmmmmmmm"
+ /* 13 */ "caaaaaammmmmmmmm"
+ /* 14 */ "caaaaaammmmmaaam"
+ /* 15 */ "fffffffmmmmmaaam"
+
+ // Level 8
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmmaaam"
+ /* 1 */ "mmmmmmmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmmmmmmm"
+ /* 4 */ "m...mmmmmmmmaaam"
+ /* 5 */ "m...mmmmmmmmmmmm"
+ /* 6 */ "m...mmmmmmmmmmmm"
+ /* 7 */ "m...mmmmmmmmmmmm"
+ /* 8 */ "m...mmmmmmmmmmmm"
+ /* 9 */ "a...ammmmmmmmmmm"
+ /* 10 */ "a...ammmmmmmmmmm"
+ /* 11 */ "a...aaaeemmmmmmm"
+ /* 12 */ "a.....aaammmmmmm"
+ /* 13 */ "a.....aaammmmmmm"
+ /* 14 */ "a.....aaammmaaam"
+ /* 15 */ "aaaaaaaffmmmaaam"
+
+ // Level 9
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmcaaab"
+ /* 1 */ "mmmmmmmmmmmcaaab"
+ /* 2 */ "mmmmmmmmmmmcaaab"
+ /* 3 */ "mmmmmmmmmmmcaaab"
+ /* 4 */ "mmmmmmmmmmmcaaab"
+ /* 5 */ "mmmmmmmmmmmcaaab"
+ /* 6 */ "m...mmmmmmmcaaab"
+ /* 7 */ "m...mmmmmmmcaaab"
+ /* 8 */ "m...mmmmmmmcaaab"
+ /* 9 */ "m...mmmmmmmcaaab"
+ /* 10 */ "m...mmmmmmmcaaab"
+ /* 11 */ "m...maaaaeecaaab"
+ /* 12 */ "m.......aaaaaaab"
+ /* 13 */ "m.......aaaaaaab"
+ /* 14 */ "m.......aaaaaaab"
+ /* 15 */ "mmmmmaaaafffaaab"
+
+ // Level 10
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmaaaaa"
+ /* 1 */ "mmmmmmmmmmmaaaaa"
+ /* 2 */ "mmmmmmmmmmmaaaaa"
+ /* 3 */ "mmmmmmmmmmmaaaaa"
+ /* 4 */ "mmmmmmmmmmmaaaaa"
+ /* 5 */ "mmmmmmmmmmmaaaaa"
+ /* 6 */ "mmmmmmmmmmmaaaaa"
+ /* 7 */ "mmmmmmmmmmmaaaaa"
+ /* 8 */ "m...mmmmmmmaaaaa"
+ /* 9 */ "m...mmmmmmmaaaaa"
+ /* 10 */ "m...mmmmmmmaaaaa"
+ /* 11 */ "m...mmmaaaaaaaaa"
+ /* 12 */ "m.........aaaaaa"
+ /* 13 */ "m.........aaaaaa"
+ /* 14 */ "m.........aaaaaa"
+ /* 15 */ "mmmmmmmaaaaaaaaa"
+
+ // Level 11
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmma...a"
+ /* 1 */ "mmmmmmmmmmma...a"
+ /* 2 */ "mmmmmmmmmmma...a"
+ /* 3 */ "mmmmmmmmmmma...a"
+ /* 4 */ "mmmmmmmmmmma...a"
+ /* 5 */ "mmmmmmmmmmma...a"
+ /* 6 */ "mmmmmmmmmmma...a"
+ /* 7 */ "mmmmmmmmmmma...a"
+ /* 8 */ "mmmmmmmmmmma...a"
+ /* 9 */ "mmmmmmmmmmma...a"
+ /* 10 */ "mmmmmmmmmmma...a"
+ /* 11 */ "mmmmmmmmmaaa...a"
+ /* 12 */ "mmmm...........a"
+ /* 13 */ "mmmm...........a"
+ /* 14 */ "mmmm...........a"
+ /* 15 */ "mmmmmmmmmaaa...a"
+
+ // Level 12
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmm...m"
+ /* 1 */ "mmmmmmmmmmmm...m"
+ /* 2 */ "mmmmmmmmmmmm...m"
+ /* 3 */ "mmmmmmmmmmmm...m"
+ /* 4 */ "mmmmmmmmmmmm...m"
+ /* 5 */ "mmmmmmmmmmmm...m"
+ /* 6 */ "mmmmmmmmmmmm...m"
+ /* 7 */ "mmmmmmmmmmmm...m"
+ /* 8 */ "mmmmmmmmmmmm...m"
+ /* 9 */ "mmmmmmmmmmmm...m"
+ /* 10 */ "mmmmmmmmmmmm...m"
+ /* 11 */ "mmmmmmmmmmmm...m"
+ /* 12 */ "mmmmmm.........m"
+ /* 13 */ "mmmmmm.........m"
+ /* 14 */ "mmmmmm.........m"
+ /* 15 */ "mmmmmmmmmmmm...m"
+
+ // Level 13
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmmmmm...m"
+ /* 1 */ "mmmmmmmmmmmm...m"
+ /* 2 */ "mmmmmmmmmmmm...m"
+ /* 3 */ "mmmmmmmmmmmm...m"
+ /* 4 */ "mmmmmmmmmmmm...m"
+ /* 5 */ "mmmmmmmmmmmm...m"
+ /* 6 */ "mmmmmmmmmmmm...m"
+ /* 7 */ "mmmmmmmmmmmm...m"
+ /* 8 */ "mmmmmmmmmmmm...m"
+ /* 9 */ "mmmmmmmmmmmm...m"
+ /* 10 */ "mmmmmmmmmmmm...m"
+ /* 11 */ "mmmmmmmmmmmm...m"
+ /* 12 */ "mmmmmmmm.......m"
+ /* 13 */ "mmmmmmmm.......m"
+ /* 14 */ "mmmmmmmm.......m"
+ /* 15 */ "mmmmmmmmmmmm...m",
+
+ // Connectors:
+ "0: 0, 5, 2: 4\n" /* Type 0, direction X- */
+ "0: 15, 5, 2: 5\n" /* Type 0, direction X+ */
+ "0: 13, 11, 0: 2\n" /* Type 0, direction Z- */
+ "0: 13, 11, 15: 3\n" /* Type 0, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 20,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BridgeLevelCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeSegment:
+ // The data has been exported from the gallery Nether, area index 16, ID 158, created by Aloe_vera
+ {
+ // Size:
+ 15, 8, 5, // SizeX = 15, SizeY = 8, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 17, 4, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aabmmmmmmmmmcaa"
+ /* 2 */ "aabmmmmmmmmmcaa"
+ /* 3 */ "aabmmmmmmmmmcaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aaabdmmmmmdcaaa"
+ /* 2 */ "aaabdmmmmmdcaaa"
+ /* 3 */ "aaabdmmmmmdcaaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "eeeeeeeeeeeeeee"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "fffffffffffffff"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "aaaaaaaaaaaaaaa"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "mmmmmmmmmmmmmmm"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "mmmmmmmmmmmmmmm",
+
+ // Connectors:
+ "0: 0, 5, 2: 4\n" /* Type 0, direction X- */
+ "0: 14, 5, 2: 5\n" /* Type 0, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 500,
+
+ // DepthWeight:
+ "4:-3000|8:-3000|12:-3000|16:-3000|20:-3000",
+
+ // AddWeightIfSame:
+ 1000,
+
+ // MoveToGround:
+ false,
+ }, // BridgeSegment
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeTee:
+ // The data has been exported from the gallery Nether, area index 39, ID 290, created by STR_Warrior
+ {
+ // Size:
+ 15, 8, 10, // SizeX = 15, SizeY = 8, SizeZ = 10
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 17, 9, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aammmmmmmmmmmaa"
+ /* 2 */ "aammmmmmmmmmmaa"
+ /* 3 */ "aammmmmmmmmmmaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmmmmmm"
+ /* 8 */ "mmmmmmaaammmmmm"
+ /* 9 */ "mmmmmmaaammmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aabmmmmmmmmmcaa"
+ /* 2 */ "aabmmmmmmmmmcaa"
+ /* 3 */ "aabmmmmmmmmmcaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmmmmmm"
+ /* 7 */ "mmmmmmdddmmmmmm"
+ /* 8 */ "mmmmmmaaammmmmm"
+ /* 9 */ "mmmmmmaaammmmmm"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "aaabemmmmmecaaa"
+ /* 2 */ "aaabemmmmmecaaa"
+ /* 3 */ "aaabemmmmmecaaa"
+ /* 4 */ "mmmmmmmmmmmmmmm"
+ /* 5 */ "mmmmmmeeemmmmmm"
+ /* 6 */ "mmmmmmdddmmmmmm"
+ /* 7 */ "mmmmmmaaammmmmm"
+ /* 8 */ "mmmmmmaaammmmmm"
+ /* 9 */ "mmmmmmaaammmmmm"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "ddddddddddddddd"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "fffffcaaabfffff"
+ /* 5 */ "mmmmmcaaabmmmmm"
+ /* 6 */ "mmmmmcaaabmmmmm"
+ /* 7 */ "mmmmmcaaabmmmmm"
+ /* 8 */ "mmmmmcaaabmmmmm"
+ /* 9 */ "mmmmmcaaabmmmmm"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+ /* 5 */ "mmmmmaaaaammmmm"
+ /* 6 */ "mmmmmaaaaammmmm"
+ /* 7 */ "mmmmmaaaaammmmm"
+ /* 8 */ "mmmmmaaaaammmmm"
+ /* 9 */ "mmmmmaaaaammmmm"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "aaaaaa...aaaaaa"
+ /* 5 */ "mmmmma...ammmmm"
+ /* 6 */ "mmmmma...ammmmm"
+ /* 7 */ "mmmmma...ammmmm"
+ /* 8 */ "mmmmma...ammmmm"
+ /* 9 */ "mmmmma...ammmmm"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "mmmmmm...mmmmmm"
+ /* 5 */ "mmmmmm...mmmmmm"
+ /* 6 */ "mmmmmm...mmmmmm"
+ /* 7 */ "mmmmmm...mmmmmm"
+ /* 8 */ "mmmmmm...mmmmmm"
+ /* 9 */ "mmmmmm...mmmmmm"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmmmmmmmmmm"
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "mmmmmm...mmmmmm"
+ /* 5 */ "mmmmmm...mmmmmm"
+ /* 6 */ "mmmmmm...mmmmmm"
+ /* 7 */ "mmmmmm...mmmmmm"
+ /* 8 */ "mmmmmm...mmmmmm"
+ /* 9 */ "mmmmmm...mmmmmm",
+
+ // Connectors:
+ "0: 0, 5, 2: 4\n" /* Type 0, direction X- */
+ "0: 7, 5, 9: 3\n" /* Type 0, direction Z+ */
+ "0: 14, 5, 2: 5\n" /* Type 0, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "1:500",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // BridgeTee
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Corridor11:
+ // The data has been exported from the gallery Nether, area index 36, ID 287, created by Aloe_vera
+ {
+ // Size:
+ 11, 6, 5, // SizeX = 11, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 5, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "aaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "abababababa"
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "abababababa"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "abababababa"
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "abababababa"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "abababababa"
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "..........."
+ /* 4 */ "abababababa"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "ccccccccccc"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaa"
+ /* 4 */ "ddddddddddd",
+
+ // Connectors:
+ "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 300,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // Corridor11
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Corridor13:
+ // The data has been exported from the gallery Nether, area index 35, ID 286, created by Aloe_vera
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 5, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "aaaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ababababababa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "ababababababa"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ababababababa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "ababababababa"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ababababababa"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "ababababababa"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ccccccccccccc"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "ddddddddddddd",
+
+ // Connectors:
+ "1: 12, 1, 2: 5\n" /* Type 1, direction X+ */
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "-1: 12, 1, 2: 5\n" /* Type -1, direction X+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 300,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // Corridor13
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Corridor5:
+ // The data has been exported from the gallery Nether, area index 65, ID 330, created by xoft
+ {
+ // Size:
+ 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 5, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "aaaaa"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "ababa"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "ababa"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "ababa"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "ababa"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "ababa"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "ababa"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "ccccc"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "ddddd",
+
+ // Connectors:
+ "1: 4, 1, 2: 5\n" /* Type 1, direction X+ */
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "-1: 4, 1, 2: 5\n" /* Type -1, direction X+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 500,
+
+ // DepthWeight:
+ "6:0|12:0|18:0",
+
+ // AddWeightIfSame:
+ 500,
+
+ // MoveToGround:
+ false,
+ }, // Corridor5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorCorner5:
+ // The data has been exported from the gallery Nether, area index 10, ID 40, created by xoft
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 5, 10, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaa"
+ /* 5 */ "aaaaa......"
+ /* 6 */ "aaaaa......"
+ /* 7 */ "aaaaa......"
+ /* 8 */ "aaaaa......"
+ /* 9 */ "aaaaa......"
+ /* 10 */ "aaaaa......"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "a.........."
+ /* 2 */ "a.........."
+ /* 3 */ "a.........."
+ /* 4 */ "a...aaaaaaa"
+ /* 5 */ "a...a......"
+ /* 6 */ "a...a......"
+ /* 7 */ "a...a......"
+ /* 8 */ "a...a......"
+ /* 9 */ "a...a......"
+ /* 10 */ "a...a......"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "abababababa"
+ /* 1 */ "b.........."
+ /* 2 */ "a.........."
+ /* 3 */ "b.........."
+ /* 4 */ "a...abababa"
+ /* 5 */ "b...b......"
+ /* 6 */ "a...a......"
+ /* 7 */ "b...b......"
+ /* 8 */ "a...a......"
+ /* 9 */ "b...b......"
+ /* 10 */ "a...a......"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "abababababa"
+ /* 1 */ "b.........."
+ /* 2 */ "a.........."
+ /* 3 */ "b.........."
+ /* 4 */ "a...abababa"
+ /* 5 */ "b...b......"
+ /* 6 */ "a...a......"
+ /* 7 */ "b...b......"
+ /* 8 */ "a...a......"
+ /* 9 */ "b...b......"
+ /* 10 */ "a...a......"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "abababababa"
+ /* 1 */ "b.........."
+ /* 2 */ "a.........."
+ /* 3 */ "b.........."
+ /* 4 */ "a...abababa"
+ /* 5 */ "b...b......"
+ /* 6 */ "a...a......"
+ /* 7 */ "b...b......"
+ /* 8 */ "a...a......"
+ /* 9 */ "b...b......"
+ /* 10 */ "a...a......"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "ccccccccccc"
+ /* 1 */ "daaaaaaaaaa"
+ /* 2 */ "daaaaaaaaaa"
+ /* 3 */ "daaaaaaaaaa"
+ /* 4 */ "daaaeeeeeee"
+ /* 5 */ "daaaf......"
+ /* 6 */ "daaaf......"
+ /* 7 */ "daaaf......"
+ /* 8 */ "daaaf......"
+ /* 9 */ "daaaf......"
+ /* 10 */ "daaaf......",
+
+ // Connectors:
+ "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */
+ "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */
+ "-1: 2, 1, 10: 3\n" /* Type -1, direction Z+ */
+ "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // CorridorCorner5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorCornerChest5:
+ // The data has been exported from the gallery Nether, area index 42, ID 293, created by STR_Warrior
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 5, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 54: 5\n" /* chest */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaa"
+ /* 5 */ "aaaaammmmmm"
+ /* 6 */ "aaaaammmmmm"
+ /* 7 */ "aaaaammmmmm"
+ /* 8 */ "aaaaammmmmm"
+ /* 9 */ "aaaaammmmmm"
+ /* 10 */ "aaaaammmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "ab........."
+ /* 2 */ "a.........."
+ /* 3 */ "a.........."
+ /* 4 */ "a...aaaaaaa"
+ /* 5 */ "a...ammmmmm"
+ /* 6 */ "a...ammmmmm"
+ /* 7 */ "a...ammmmmm"
+ /* 8 */ "a...ammmmmm"
+ /* 9 */ "a...ammmmmm"
+ /* 10 */ "a...ammmmmm"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "acacacacaca"
+ /* 1 */ "c.........."
+ /* 2 */ "a.........."
+ /* 3 */ "c.........."
+ /* 4 */ "a...acacaca"
+ /* 5 */ "c...cmmmmmm"
+ /* 6 */ "a...ammmmmm"
+ /* 7 */ "c...cmmmmmm"
+ /* 8 */ "a...ammmmmm"
+ /* 9 */ "c...cmmmmmm"
+ /* 10 */ "a...ammmmmm"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "acacacacaca"
+ /* 1 */ "c.........."
+ /* 2 */ "a.........."
+ /* 3 */ "c.........."
+ /* 4 */ "a...acacaca"
+ /* 5 */ "c...cmmmmmm"
+ /* 6 */ "a...ammmmmm"
+ /* 7 */ "c...cmmmmmm"
+ /* 8 */ "a...ammmmmm"
+ /* 9 */ "c...cmmmmmm"
+ /* 10 */ "a...ammmmmm"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "acacacacaca"
+ /* 1 */ "c.........."
+ /* 2 */ "a.........."
+ /* 3 */ "c.........."
+ /* 4 */ "a...acacaca"
+ /* 5 */ "c...cmmmmmm"
+ /* 6 */ "a...ammmmmm"
+ /* 7 */ "c...cmmmmmm"
+ /* 8 */ "a...ammmmmm"
+ /* 9 */ "c...cmmmmmm"
+ /* 10 */ "a...ammmmmm"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "deeeeeeeeee"
+ /* 1 */ "daaaaaaaaaa"
+ /* 2 */ "daaaaaaaaaa"
+ /* 3 */ "daaaaaaaaaa"
+ /* 4 */ "daaafgggggg"
+ /* 5 */ "daaafmmmmmm"
+ /* 6 */ "daaafmmmmmm"
+ /* 7 */ "daaafmmmmmm"
+ /* 8 */ "daaafmmmmmm"
+ /* 9 */ "daaafmmmmmm"
+ /* 10 */ "daaafmmmmmm",
+
+ // Connectors:
+ "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */
+ "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */
+ "-1: 2, 1, 10: 3\n" /* Type -1, direction Z+ */
+ "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // CorridorCornerChest5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorCrossing:
+ // The data has been exported from the gallery Nether, area index 63, ID 328, created by xoft
+ {
+ // Size:
+ 9, 6, 9, // SizeX = 9, SizeY = 6, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 8, 5, 8, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 012345678 */
+ /* 0 */ "mmaaaaamm"
+ /* 1 */ "mmaaaaamm"
+ /* 2 */ "aaaaaaaaa"
+ /* 3 */ "aaaaaaaaa"
+ /* 4 */ "aaaaaaaaa"
+ /* 5 */ "aaaaaaaaa"
+ /* 6 */ "aaaaaaaaa"
+ /* 7 */ "mmaaaaamm"
+ /* 8 */ "mmaaaaamm"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "mma...amm"
+ /* 1 */ "mma...amm"
+ /* 2 */ "aaa...aaa"
+ /* 3 */ "........."
+ /* 4 */ "........."
+ /* 5 */ "........."
+ /* 6 */ "aaa...aaa"
+ /* 7 */ "mma...amm"
+ /* 8 */ "mma...amm"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "mma...amm"
+ /* 1 */ "mmb...bmm"
+ /* 2 */ "aba...aba"
+ /* 3 */ "........."
+ /* 4 */ "........."
+ /* 5 */ "........."
+ /* 6 */ "aba...aba"
+ /* 7 */ "mmb...bmm"
+ /* 8 */ "mma...amm"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "mma...amm"
+ /* 1 */ "mmb...bmm"
+ /* 2 */ "aba...aba"
+ /* 3 */ "........."
+ /* 4 */ "........."
+ /* 5 */ "........."
+ /* 6 */ "aba...aba"
+ /* 7 */ "mmb...bmm"
+ /* 8 */ "mma...amm"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "mma...amm"
+ /* 1 */ "mmb...bmm"
+ /* 2 */ "aba...aba"
+ /* 3 */ "........."
+ /* 4 */ "........."
+ /* 5 */ "........."
+ /* 6 */ "aba...aba"
+ /* 7 */ "mmb...bmm"
+ /* 8 */ "mma...amm"
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "mmcaaadmm"
+ /* 1 */ "mmcaaadmm"
+ /* 2 */ "eeeaaaeee"
+ /* 3 */ "aaaaaaaaa"
+ /* 4 */ "aaaaaaaaa"
+ /* 5 */ "aaaaaaaaa"
+ /* 6 */ "ffcaaadff"
+ /* 7 */ "mmcaaadmm"
+ /* 8 */ "mmcaaadmm",
+
+ // Connectors:
+ "1: 8, 1, 4: 5\n" /* Type 1, direction X+ */
+ "1: 4, 1, 0: 2\n" /* Type 1, direction Z- */
+ "1: 4, 1, 8: 3\n" /* Type 1, direction Z+ */
+ "1: 0, 1, 4: 4\n" /* Type 1, direction X- */
+ "-1: 8, 1, 4: 5\n" /* Type -1, direction X+ */
+ "-1: 4, 1, 8: 3\n" /* Type -1, direction Z+ */
+ "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */
+ "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ -50,
+
+ // MoveToGround:
+ false,
+ }, // CorridorCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorStairs:
+ // The data has been exported from the gallery Nether, area index 12, ID 42, created by xoft
+ {
+ // Size:
+ 9, 13, 5, // SizeX = 9, SizeY = 13, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 8, 12, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ "aaaaaaaaa"
+ /* 2 */ "aaaaaaaaa"
+ /* 3 */ "aaaaaaaaa"
+ /* 4 */ "aaaaaaaaa"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "aaaaaaaaa"
+ /* 1 */ ".baaaaaaa"
+ /* 2 */ ".baaaaaaa"
+ /* 3 */ ".baaaaaaa"
+ /* 4 */ "aaaaaaaaa"
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "acaaaaaaa"
+ /* 1 */ "..baaaaaa"
+ /* 2 */ "..baaaaaa"
+ /* 3 */ "..baaaaaa"
+ /* 4 */ "acaaaaaaa"
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "acaaaaaaa"
+ /* 1 */ "...baaaaa"
+ /* 2 */ "...baaaaa"
+ /* 3 */ "...baaaaa"
+ /* 4 */ "acaaaaaaa"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "acacaaaaa"
+ /* 1 */ "....baaaa"
+ /* 2 */ "....baaaa"
+ /* 3 */ "....baaaa"
+ /* 4 */ "acacaaaaa"
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "aaacaaaaa"
+ /* 1 */ ".....baaa"
+ /* 2 */ ".....baaa"
+ /* 3 */ ".....baaa"
+ /* 4 */ "aaacaaaaa"
+
+ // Level 6
+ /* z\x* 012345678 */
+ /* 0 */ "daacacaaa"
+ /* 1 */ "a.....baa"
+ /* 2 */ "a.....baa"
+ /* 3 */ "a.....baa"
+ /* 4 */ "eaacacaaa"
+
+ // Level 7
+ /* z\x* 012345678 */
+ /* 0 */ "mdaaacaaa"
+ /* 1 */ "ma.....ba"
+ /* 2 */ "ma.....ba"
+ /* 3 */ "ma.....ba"
+ /* 4 */ "meaaacaaa"
+
+ // Level 8
+ /* z\x* 012345678 */
+ /* 0 */ "mmdaacaca"
+ /* 1 */ "mma......"
+ /* 2 */ "mma......"
+ /* 3 */ "mma......"
+ /* 4 */ "mmeaacaca"
+
+ // Level 9
+ /* z\x* 012345678 */
+ /* 0 */ "mmmdaaaca"
+ /* 1 */ "mmma....."
+ /* 2 */ "mmma....."
+ /* 3 */ "mmma....."
+ /* 4 */ "mmmeaaaca"
+
+ // Level 10
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmdaaca"
+ /* 1 */ "mmmma...."
+ /* 2 */ "mmmma...."
+ /* 3 */ "mmmma...."
+ /* 4 */ "mmmmeaaca"
+
+ // Level 11
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmmdaaa"
+ /* 1 */ "mmmmma..."
+ /* 2 */ "mmmmma..."
+ /* 3 */ "mmmmma..."
+ /* 4 */ "mmmmmeaaa"
+
+ // Level 12
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmmmddd"
+ /* 1 */ "mmmmmmaaa"
+ /* 2 */ "mmmmmmaaa"
+ /* 3 */ "mmmmmmaaa"
+ /* 4 */ "mmmmmmeee",
+
+ // Connectors:
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "1: 8, 8, 2: 5\n" /* Type 1, direction X+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */
+ "-1: 8, 8, 2: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 1000,
+
+ // DepthWeight:
+ "0:0|2:0|4:0|6:0|8:0|10:0|12:0|14:0|16:0|18:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // CorridorStairs
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // DarkCorridor:
+ // The data has been exported from the gallery Nether, area index 3, ID 30, created by STR_Warrior
+ {
+ // Size:
+ 14, 6, 5, // SizeX = 14, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 13, 5, 4, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "aaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "aaaaaaaaaaaaaa"
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ ".............."
+ /* 4 */ "aaaaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "aabaaaaaaaabaa"
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ ".............."
+ /* 4 */ "aabaaaaaaaabaa"
+
+ // Level 3
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "aabaaaaaaaabaa"
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ ".............."
+ /* 4 */ "aabaaaaaaaabaa"
+
+ // Level 4
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "aabaaaaaaaabaa"
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ ".............."
+ /* 4 */ "aabaaaaaaaabaa"
+
+ // Level 5
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "cccccccccccccc"
+ /* 1 */ "aaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaa"
+ /* 4 */ "dddddddddddddd",
+
+ // Connectors:
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "1: 13, 1, 2: 5\n" /* Type 1, direction X+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */
+ "-1: 13, 1, 2: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // DarkCorridor
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LavaStaircase:
+ // The data has been exported from the gallery Nether, area index 28, ID 278, created by Aloe_vera
+ {
+ // Size:
+ 15, 11, 15, // SizeX = 15, SizeY = 11, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 10, 14, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c: 10: 0\n" /* lava */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaa...aaaa"
+ /* 1 */ "aaaaa.........a"
+ /* 2 */ "aaaaa.........a"
+ /* 3 */ "aaaaab........a"
+ /* 4 */ "accca...aaaa..a"
+ /* 5 */ "accca...acca..a"
+ /* 6 */ "acccaaaaacca..a"
+ /* 7 */ "acccccccccca..a"
+ /* 8 */ "acccaaaaacca..a"
+ /* 9 */ "accca...acca..a"
+ /* 10 */ "accca...aaaa..a"
+ /* 11 */ "aaaaab........a"
+ /* 12 */ "aaaaa.........a"
+ /* 13 */ "aaaaa.........a"
+ /* 14 */ "aaaaaaaa...aaaa"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaa...aaaa"
+ /* 1 */ "aaaa..........a"
+ /* 2 */ "aaaa..........a"
+ /* 3 */ "aaaabb........a"
+ /* 4 */ "aaaa..........a"
+ /* 5 */ "a.............a"
+ /* 6 */ "a.............a"
+ /* 7 */ "a.............a"
+ /* 8 */ "a.............a"
+ /* 9 */ "a.............a"
+ /* 10 */ "aaaa..........a"
+ /* 11 */ "aaaabb........a"
+ /* 12 */ "aaaa..........a"
+ /* 13 */ "aaaa..........a"
+ /* 14 */ "aaaaaaaa...aaaa"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaa...aaaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "a.............a"
+ /* 3 */ "a..bb.........a"
+ /* 4 */ "aaaa..........a"
+ /* 5 */ "aaaa..........a"
+ /* 6 */ "a.............a"
+ /* 7 */ "a.............a"
+ /* 8 */ "a.............a"
+ /* 9 */ "aaaa..........a"
+ /* 10 */ "aaaa..........a"
+ /* 11 */ "a..bb.........a"
+ /* 12 */ "a.............a"
+ /* 13 */ "a.............a"
+ /* 14 */ "aaaaaaaa...aaaa"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaa...aaaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "a.............a"
+ /* 3 */ "a..b..........a"
+ /* 4 */ "a..b..........a"
+ /* 5 */ "aaaa..........a"
+ /* 6 */ "aaaa..........a"
+ /* 7 */ "a.............a"
+ /* 8 */ "aaaa..........a"
+ /* 9 */ "aaaa..........a"
+ /* 10 */ "a..b..........a"
+ /* 11 */ "a..b..........a"
+ /* 12 */ "a.............a"
+ /* 13 */ "a.............a"
+ /* 14 */ "aaaaaaaa...aaaa"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "a.............a"
+ /* 3 */ "a.............a"
+ /* 4 */ "a..b..........a"
+ /* 5 */ "a..b..........a"
+ /* 6 */ "aaaa..........a"
+ /* 7 */ "aaaa..........a"
+ /* 8 */ "aaaa..........a"
+ /* 9 */ "a..b..........a"
+ /* 10 */ "a..b..........a"
+ /* 11 */ "a.............a"
+ /* 12 */ "a.............a"
+ /* 13 */ "a.............a"
+ /* 14 */ "aaaaaaaaaaaaaaa"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "a.............a"
+ /* 3 */ "a.............a"
+ /* 4 */ "a.............a"
+ /* 5 */ "a..b..........a"
+ /* 6 */ "...b..........a"
+ /* 7 */ "...b..........a"
+ /* 8 */ "...b..........a"
+ /* 9 */ "a..b..........a"
+ /* 10 */ "a.............a"
+ /* 11 */ "a.............a"
+ /* 12 */ "a.............a"
+ /* 13 */ "a.............a"
+ /* 14 */ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aababababababaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "b.............b"
+ /* 3 */ "a.............a"
+ /* 4 */ "b.............b"
+ /* 5 */ "a.............a"
+ /* 6 */ "..............b"
+ /* 7 */ "..............a"
+ /* 8 */ "..............b"
+ /* 9 */ "a.............a"
+ /* 10 */ "b.............b"
+ /* 11 */ "a.............a"
+ /* 12 */ "b.............b"
+ /* 13 */ "a.............a"
+ /* 14 */ "aababababababaa"
+
+ // Level 8
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aababababababaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "b.............b"
+ /* 3 */ "a.............a"
+ /* 4 */ "b.............b"
+ /* 5 */ "a.............a"
+ /* 6 */ "..............b"
+ /* 7 */ "..............a"
+ /* 8 */ "..............b"
+ /* 9 */ "a.............a"
+ /* 10 */ "b.............b"
+ /* 11 */ "a.............a"
+ /* 12 */ "b.............b"
+ /* 13 */ "a.............a"
+ /* 14 */ "aababababababaa"
+
+ // Level 9
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aababababababaa"
+ /* 1 */ "a.............a"
+ /* 2 */ "b.............b"
+ /* 3 */ "a.............a"
+ /* 4 */ "b.............b"
+ /* 5 */ "a.............a"
+ /* 6 */ "..............b"
+ /* 7 */ "..............a"
+ /* 8 */ "..............b"
+ /* 9 */ "a.............a"
+ /* 10 */ "b.............b"
+ /* 11 */ "a.............a"
+ /* 12 */ "b.............b"
+ /* 13 */ "a.............a"
+ /* 14 */ "aababababababaa"
+
+ // Level 10
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaa",
+
+ // Connectors:
+ "1: 0, 6, 7: 4\n" /* Type 1, direction X- */
+ "1: 9, 1, 14: 3\n" /* Type 1, direction Z+ */
+ "1: 9, 1, 0: 2\n" /* Type 1, direction Z- */
+ "-1: 0, 6, 7: 4\n" /* Type -1, direction X- */
+ "-1: 9, 1, 14: 3\n" /* Type -1, direction Z+ */
+ "-1: 9, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // LavaStaircase
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LavaStaircaseBig:
+ // The data has been exported from the gallery Nether, area index 31, ID 282, created by STR_Warrior
+ {
+ // Size:
+ 12, 15, 15, // SizeX = 12, SizeY = 15, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 11, 14, 14, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 10: 0\n" /* lava */
+ "c:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaa"
+ /* 4 */ "abbbbbaaaaaa"
+ /* 5 */ "abbbbbbaaaaa"
+ /* 6 */ "abbbbbba...."
+ /* 7 */ "abbbbbba...."
+ /* 8 */ "abbbbbba...."
+ /* 9 */ "abbbbbbaaaaa"
+ /* 10 */ "abbbbb.aaaaa"
+ /* 11 */ "aaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaa"
+ /* 4 */ "abbbbbaaaaaa"
+ /* 5 */ "abbbbbba...a"
+ /* 6 */ "abbbbbba...."
+ /* 7 */ "abbbbbba...."
+ /* 8 */ "abbbbbba...."
+ /* 9 */ "abbbbbba...a"
+ /* 10 */ "abbbbb.aaaaa"
+ /* 11 */ "aaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaa"
+ /* 4 */ "abbbbbaa...a"
+ /* 5 */ "abbbbbba...a"
+ /* 6 */ "abbbbbba...."
+ /* 7 */ "abbbbbba...."
+ /* 8 */ "abbbbbba...."
+ /* 9 */ "abbbbbba...a"
+ /* 10 */ "abbbbbaa...a"
+ /* 11 */ "aaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaa......a"
+ /* 2 */ "aaaaa......a"
+ /* 3 */ "aaaaacc....a"
+ /* 4 */ "a.....cc...a"
+ /* 5 */ "a......c...a"
+ /* 6 */ "a......c...a"
+ /* 7 */ "a......c...a"
+ /* 8 */ "a......c...a"
+ /* 9 */ "a......c...a"
+ /* 10 */ "a.....cc...a"
+ /* 11 */ "aaaaacc....a"
+ /* 12 */ "aaaaa......a"
+ /* 13 */ "aaaaa......a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 5
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaa.......a"
+ /* 2 */ "aaaa.......a"
+ /* 3 */ "aaaacc.....a"
+ /* 4 */ "aaaa.......a"
+ /* 5 */ "a..........a"
+ /* 6 */ "a..........a"
+ /* 7 */ "a..........a"
+ /* 8 */ "a..........a"
+ /* 9 */ "a..........a"
+ /* 10 */ "aaaa.......a"
+ /* 11 */ "aaaacc.....a"
+ /* 12 */ "aaaa.......a"
+ /* 13 */ "aaaa.......a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 6
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..cc......a"
+ /* 4 */ "aaaa.......a"
+ /* 5 */ "aaaa.......a"
+ /* 6 */ "a..........a"
+ /* 7 */ "a..........a"
+ /* 8 */ "a..........a"
+ /* 9 */ "aaaa.......a"
+ /* 10 */ "aaaa.......a"
+ /* 11 */ "a..cc......a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 7
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..c.......a"
+ /* 4 */ "a..c.......a"
+ /* 5 */ "aaaa.......a"
+ /* 6 */ "aaaa.......a"
+ /* 7 */ "a..........a"
+ /* 8 */ "aaaa.......a"
+ /* 9 */ "aaaa.......a"
+ /* 10 */ "a..c.......a"
+ /* 11 */ "a..c.......a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 8
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..........a"
+ /* 4 */ "a..c.......a"
+ /* 5 */ "a..c.......a"
+ /* 6 */ "aaaa.......a"
+ /* 7 */ "aaaa.......a"
+ /* 8 */ "aaaa.......a"
+ /* 9 */ "a..c.......a"
+ /* 10 */ "a..c.......a"
+ /* 11 */ "a..........a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 9
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..........a"
+ /* 4 */ "a..........a"
+ /* 5 */ "a..c.......a"
+ /* 6 */ "...c.......a"
+ /* 7 */ "...c.......a"
+ /* 8 */ "...c.......a"
+ /* 9 */ "a..c.......a"
+ /* 10 */ "a..........a"
+ /* 11 */ "a..........a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 10
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..........a"
+ /* 4 */ "a..........a"
+ /* 5 */ "a..........a"
+ /* 6 */ "...........a"
+ /* 7 */ "...........a"
+ /* 8 */ "...........a"
+ /* 9 */ "a..........a"
+ /* 10 */ "a..........a"
+ /* 11 */ "a..........a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 11
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..........a"
+ /* 4 */ "a..........a"
+ /* 5 */ "a..........a"
+ /* 6 */ "...........a"
+ /* 7 */ "...........a"
+ /* 8 */ "...........a"
+ /* 9 */ "a..........a"
+ /* 10 */ "a..........a"
+ /* 11 */ "a..........a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 12
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "a..........a"
+ /* 2 */ "a..........a"
+ /* 3 */ "a..........a"
+ /* 4 */ "a..........a"
+ /* 5 */ "a..........a"
+ /* 6 */ "a..........a"
+ /* 7 */ "a..........a"
+ /* 8 */ "a..........a"
+ /* 9 */ "a..........a"
+ /* 10 */ "a..........a"
+ /* 11 */ "a..........a"
+ /* 12 */ "a..........a"
+ /* 13 */ "a..........a"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 13
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaa"
+
+ // Level 14
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaaaaaaaa"
+ /* 1 */ "abbbbbbbbbba"
+ /* 2 */ "abbbbbbbbbba"
+ /* 3 */ "abbbbbbbbbba"
+ /* 4 */ "abbbbbbbbbba"
+ /* 5 */ "abbbbbbbbbba"
+ /* 6 */ "abbbbbbbbbba"
+ /* 7 */ "abbbbbbbbbba"
+ /* 8 */ "abbbbbbbbbba"
+ /* 9 */ "abbbbbbbbbba"
+ /* 10 */ "abbbbbbbbbba"
+ /* 11 */ "abbbbbbbbbba"
+ /* 12 */ "abbbbbbbbbba"
+ /* 13 */ "abbbbbbbbbba"
+ /* 14 */ "aaaaaaaaaaaa",
+
+ // Connectors:
+ "1: 11, 1, 7: 5\n" /* Type 1, direction X+ */
+ "1: 0, 9, 7: 4\n" /* Type 1, direction X- */
+ "-1: 11, 1, 7: 5\n" /* Type -1, direction X+ */
+ "-1: 0, 9, 7: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ -1000,
+
+ // MoveToGround:
+ false,
+ }, // LavaStaircaseBig
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LavaStairsBridge:
+ // The data has been exported from the gallery Nether, area index 30, ID 281, created by STR_Warrior
+ {
+ // Size:
+ 16, 12, 15, // SizeX = 16, SizeY = 12, SizeZ = 15
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 15, 11, 14, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c: 10: 0\n" /* lava */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 7\n" /* netherbrickstairs */
+ "g: 44:14\n" /* step */
+ "h:114: 6\n" /* netherbrickstairs */
+ "i: 44: 6\n" /* step */
+ "j:114: 0\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaa...aaaaa"
+ /* 1 */ "aaaaa..........a"
+ /* 2 */ "aaaaa..........a"
+ /* 3 */ "aaaaab.........a"
+ /* 4 */ "accca...ddd.aaaa"
+ /* 5 */ "accca...aaa.acca"
+ /* 6 */ "acccaaaaaaaaacca"
+ /* 7 */ "acccccccccccccca"
+ /* 8 */ "acccaaaaaaaaacca"
+ /* 9 */ "accca...aaa.acca"
+ /* 10 */ "accca...eee.aaaa"
+ /* 11 */ "aaaaab.........a"
+ /* 12 */ "aaaaa..........a"
+ /* 13 */ "aaaaa..........a"
+ /* 14 */ "aaaaaaaa...aaaaa"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaa...aaaaa"
+ /* 1 */ "aaaa...........a"
+ /* 2 */ "aaaa...........a"
+ /* 3 */ "aaaabb.........a"
+ /* 4 */ "aaaa........b..a"
+ /* 5 */ "a.......ddd....a"
+ /* 6 */ "a.......fff....a"
+ /* 7 */ "a.......ggg....a"
+ /* 8 */ "a.......hhh....a"
+ /* 9 */ "a.......eee....a"
+ /* 10 */ "aaaa........b..a"
+ /* 11 */ "aaaabb.........a"
+ /* 12 */ "aaaa...........a"
+ /* 13 */ "aaaa...........a"
+ /* 14 */ "aaaaaaaa...aaaaa"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaa...aaaaa"
+ /* 1 */ "a..............a"
+ /* 2 */ "a..............a"
+ /* 3 */ "a..bb..........a"
+ /* 4 */ "aaaa........b..a"
+ /* 5 */ "aaaa...........a"
+ /* 6 */ "a..............a"
+ /* 7 */ "a..............a"
+ /* 8 */ "a..............a"
+ /* 9 */ "aaaa...........a"
+ /* 10 */ "aaaa........b..a"
+ /* 11 */ "a..bb..........a"
+ /* 12 */ "a..............a"
+ /* 13 */ "a..............a"
+ /* 14 */ "aaaaaaaa...aaaaa"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaabbbaaaaa"
+ /* 1 */ "a..............a"
+ /* 2 */ "a..............a"
+ /* 3 */ "a..b...........a"
+ /* 4 */ "a..b........b..a"
+ /* 5 */ "aaaa...........a"
+ /* 6 */ "aaaa...........a"
+ /* 7 */ "a..............a"
+ /* 8 */ "aaaa...........a"
+ /* 9 */ "aaaa...........a"
+ /* 10 */ "a..b........b..a"
+ /* 11 */ "a..b...........a"
+ /* 12 */ "a..............a"
+ /* 13 */ "a..............a"
+ /* 14 */ "aaaaaaaabbbaaaaa"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "a..............a"
+ /* 2 */ "a..............a"
+ /* 3 */ "a...........ggga"
+ /* 4 */ "a..b........iija"
+ /* 5 */ "a..b........iija"
+ /* 6 */ "aaaa........iija"
+ /* 7 */ "aaaa........iija"
+ /* 8 */ "aaaa........iija"
+ /* 9 */ "a..b........iija"
+ /* 10 */ "a..b........iija"
+ /* 11 */ "a...........ggga"
+ /* 12 */ "a..............a"
+ /* 13 */ "a..............a"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "a.............ga"
+ /* 2 */ "a............iia"
+ /* 3 */ "a..............a"
+ /* 4 */ "a..............a"
+ /* 5 */ "a..b...........a"
+ /* 6 */ "...b...........a"
+ /* 7 */ "...b...........a"
+ /* 8 */ "...b...........a"
+ /* 9 */ "a..b...........a"
+ /* 10 */ "a..............a"
+ /* 11 */ "a..............a"
+ /* 12 */ "a............iia"
+ /* 13 */ "a.............ga"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 7
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "a..............a"
+ /* 2 */ "a..............a"
+ /* 3 */ "a..............a"
+ /* 4 */ "a..............a"
+ /* 5 */ "a..............a"
+ /* 6 */ "...............a"
+ /* 7 */ "...............a"
+ /* 8 */ "...............a"
+ /* 9 */ "a..............a"
+ /* 10 */ "a..............a"
+ /* 11 */ "a..............a"
+ /* 12 */ "a..............a"
+ /* 13 */ "a..............a"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 8
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "a..............a"
+ /* 2 */ "a..............a"
+ /* 3 */ "a..............a"
+ /* 4 */ "a..............a"
+ /* 5 */ "a..............a"
+ /* 6 */ "...............a"
+ /* 7 */ "...............a"
+ /* 8 */ "...............a"
+ /* 9 */ "a..............a"
+ /* 10 */ "a..............a"
+ /* 11 */ "a..............a"
+ /* 12 */ "a..............a"
+ /* 13 */ "a..............a"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 9
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "a..............a"
+ /* 2 */ "a..............a"
+ /* 3 */ "a..............a"
+ /* 4 */ "a..............a"
+ /* 5 */ "a..............a"
+ /* 6 */ "a..............a"
+ /* 7 */ "a..............a"
+ /* 8 */ "a..............a"
+ /* 9 */ "a..............a"
+ /* 10 */ "a..............a"
+ /* 11 */ "a..............a"
+ /* 12 */ "a..............a"
+ /* 13 */ "a..............a"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 10
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "aaaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaaaaa"
+ /* 13 */ "aaaaaaaaaaaaaaaa"
+ /* 14 */ "aaaaaaaaaaaaaaaa"
+
+ // Level 11
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "abbaabbaabbaabba"
+ /* 1 */ "b..............b"
+ /* 2 */ "a..............a"
+ /* 3 */ "b..............b"
+ /* 4 */ "a..............a"
+ /* 5 */ "b..............b"
+ /* 6 */ "a..............a"
+ /* 7 */ "b..............b"
+ /* 8 */ "a..............a"
+ /* 9 */ "b..............b"
+ /* 10 */ "a..............a"
+ /* 11 */ "b..............b"
+ /* 12 */ "a..............a"
+ /* 13 */ "b..............b"
+ /* 14 */ "abbaabbaabbaabba",
+
+ // Connectors:
+ "",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // LavaStairsBridge
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MidStaircase:
+ // The data has been exported from the gallery Nether, area index 23, ID 165, created by Aloe_vera
+ {
+ // Size:
+ 13, 8, 13, // SizeX = 13, SizeY = 8, SizeZ = 13
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 7, 12, // MaxX, MaxY, MaxZ
+
+ // 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 */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaabbbbbaaaa"
+ /* 4 */ "aaaabbbbbaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaabbbbbaaaa"
+ /* 9 */ "aaaabbbbbaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaacccccaaaa"
+ /* 4 */ "addecccccfdda"
+ /* 5 */ "...eaaaaad..."
+ /* 6 */ "...eaaaaa...."
+ /* 7 */ "...eaaaaag..."
+ /* 8 */ "agggcccccfgga"
+ /* 9 */ "aaaacccccaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aha.......aha"
+ /* 2 */ "aaa.......aaa"
+ /* 3 */ "a...........a"
+ /* 4 */ "a...........a"
+ /* 5 */ "....eaaaa...."
+ /* 6 */ "....eaaaa...."
+ /* 7 */ "....eaaaa...."
+ /* 8 */ "a...........a"
+ /* 9 */ "a...........a"
+ /* 10 */ "aaa.......aaa"
+ /* 11 */ "aha.......aha"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaiiaaaiiaaa"
+ /* 1 */ "a...........a"
+ /* 2 */ "a...........a"
+ /* 3 */ "a...........a"
+ /* 4 */ "a...........a"
+ /* 5 */ ".....eaaa...."
+ /* 6 */ ".....eaaa...."
+ /* 7 */ ".....eaaa...."
+ /* 8 */ "a...........a"
+ /* 9 */ "a...........a"
+ /* 10 */ "a...........a"
+ /* 11 */ "a...........a"
+ /* 12 */ "aaaiiaaaiiaaa"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaiiaaaiiaaa"
+ /* 1 */ "a...........a"
+ /* 2 */ "a...........a"
+ /* 3 */ "a...........a"
+ /* 4 */ "a...........a"
+ /* 5 */ "......eaa...."
+ /* 6 */ "......eaa...."
+ /* 7 */ "......eaa...."
+ /* 8 */ "a...........a"
+ /* 9 */ "a...........a"
+ /* 10 */ "a...........a"
+ /* 11 */ "a...........a"
+ /* 12 */ "aaaiiaaaiiaaa"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "a...........a"
+ /* 2 */ "a...........a"
+ /* 3 */ "a...........a"
+ /* 4 */ "a...........a"
+ /* 5 */ "a......ea...a"
+ /* 6 */ "a......ea...a"
+ /* 7 */ "a......ea...a"
+ /* 8 */ "a...........a"
+ /* 9 */ "a...........a"
+ /* 10 */ "a...........a"
+ /* 11 */ "a...........a"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaa....eaaaa"
+ /* 6 */ "aaaa....eaaaa"
+ /* 7 */ "aaaa....eaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 7
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "iaiaiaiaiaiai"
+ /* 1 */ "a...........a"
+ /* 2 */ "i...........i"
+ /* 3 */ "a...........a"
+ /* 4 */ "i...........i"
+ /* 5 */ "a...........a"
+ /* 6 */ "i...........i"
+ /* 7 */ "a...........a"
+ /* 8 */ "i...........i"
+ /* 9 */ "a...........a"
+ /* 10 */ "i...........i"
+ /* 11 */ "a...........a"
+ /* 12 */ "iaiaiaiaiaiai",
+
+ // Connectors:
+ "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */
+ "1: 0, 1, 6: 4\n" /* Type 1, direction X- */
+ "-1: 12, 1, 6: 5\n" /* Type -1, direction X+ */
+ "-1: 0, 1, 6: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ -1000,
+
+ // MoveToGround:
+ false,
+ }, // MidStaircase
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // StairsToOpen1:
+ // The data has been exported from the gallery Nether, area index 27, ID 277, created by Aloe_vera
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 19, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "a.....a"
+ /* 3 */ "a.....a"
+ /* 4 */ "a.....a"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "a.....a"
+ /* 4 */ "b.....b"
+ /* 5 */ "a.aaaaa"
+ /* 6 */ "aabaaba"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "a.....a"
+ /* 4 */ "b.....b"
+ /* 5 */ "a..aaaa"
+ /* 6 */ "aabaaba"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "aabbbaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "a.....a"
+ /* 4 */ "b.....b"
+ /* 5 */ "a...aaa"
+ /* 6 */ "aabaaba"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "a.....a"
+ /* 3 */ "a.....a"
+ /* 4 */ "a.....a"
+ /* 5 */ "a....aa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "a.....a"
+ /* 6 */ "aaaaaaa"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "a......"
+ /* 3 */ "a......"
+ /* 4 */ "a......"
+ /* 5 */ "a.....a"
+ /* 6 */ "aaaaaaa"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "m.....m"
+ /* 2 */ "m......"
+ /* 3 */ "m......"
+ /* 4 */ "m......"
+ /* 5 */ "m.....m"
+ /* 6 */ "mmmmmmm"
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "m.....m"
+ /* 2 */ "m......"
+ /* 3 */ "m......"
+ /* 4 */ "m......"
+ /* 5 */ "m.....m"
+ /* 6 */ "mmmmmmm",
+
+ // Connectors:
+ "0: 6, 7, 3: 5\n" /* Type 0, direction X+ */
+ "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:0|3:0|5:0|7:0|9:0|11:0|13:0|15:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // StairsToOpen1
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // StairsToOpen2:
+ // The data has been exported from the gallery Nether, area index 8, ID 35, created by xoft
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 19, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "a.....a"
+ /* 3 */ "a.....a"
+ /* 4 */ "a.....a"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "a.....a"
+ /* 4 */ "b.....b"
+ /* 5 */ "a.aaaaa"
+ /* 6 */ "aabaaba"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "a.....a"
+ /* 4 */ "b.....b"
+ /* 5 */ "a..aaaa"
+ /* 6 */ "aabaaba"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "aabbbaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "a.....a"
+ /* 4 */ "b.....b"
+ /* 5 */ "a...aaa"
+ /* 6 */ "aabaaba"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "a.....a"
+ /* 3 */ "a.....a"
+ /* 4 */ "a.....a"
+ /* 5 */ "a....aa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "a.....a"
+ /* 6 */ "aaaaaaa"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "......a"
+ /* 3 */ "......a"
+ /* 4 */ "......a"
+ /* 5 */ "a.....a"
+ /* 6 */ "aaaaaaa"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "m.....m"
+ /* 2 */ "......m"
+ /* 3 */ "......m"
+ /* 4 */ "......m"
+ /* 5 */ "m.....m"
+ /* 6 */ "mmmmmmm"
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "m.....m"
+ /* 2 */ "......m"
+ /* 3 */ "......m"
+ /* 4 */ "......m"
+ /* 5 */ "m.....m"
+ /* 6 */ "mmmmmmm",
+
+ // Connectors:
+ "0: 0, 7, 3: 4\n" /* Type 0, direction X- */
+ "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:0|3:0|5:0|7:0|9:0|11:0|13:0|15:0",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // StairsToOpen2
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Tee2x4:
+ // The data has been exported from the gallery Nether, area index 40, ID 291, created by Aloe_vera
+ {
+ // Size:
+ 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 5, 6, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmaaaaammmm"
+ /* 1 */ "mmmmaaaaammmm"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmma...ammmm"
+ /* 2 */ "aaaaa...aaaaa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "aaaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmb...bmmmm"
+ /* 2 */ "ababa...ababa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "ababababababa"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmb...bmmmm"
+ /* 2 */ "ababa...ababa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "ababababababa"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmb...bmmmm"
+ /* 2 */ "ababa...ababa"
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "ababababababa"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmcaaadmmmm"
+ /* 1 */ "mmmmcaaadmmmm"
+ /* 2 */ "eeeecaaadeeee"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "fffffffffffff",
+
+ // Connectors:
+ "1: 0, 1, 4: 4\n" /* Type 1, direction X- */
+ "1: 6, 1, 0: 2\n" /* Type 1, direction Z- */
+ "1: 12, 1, 4: 5\n" /* Type 1, direction X+ */
+ "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */
+ "-1: 12, 1, 4: 5\n" /* Type -1, direction X+ */
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // Tee2x4
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Tee4x4:
+ // The data has been exported from the gallery Nether, area index 41, ID 292, created by Aloe_vera
+ {
+ // Size:
+ 13, 6, 9, // SizeX = 13, SizeY = 6, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 5, 8, // MaxX, MaxY, MaxZ
+
+ // 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 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmaaaaammmm"
+ /* 1 */ "mmmmaaaaammmm"
+ /* 2 */ "mmmmaaaaammmm"
+ /* 3 */ "mmmmaaaaammmm"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmma...ammmm"
+ /* 2 */ "mmmma...ammmm"
+ /* 3 */ "mmmma...ammmm"
+ /* 4 */ "aaaaa...aaaaa"
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "aaaaaaaaaaaaa"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmb...bmmmm"
+ /* 2 */ "mmmma...ammmm"
+ /* 3 */ "mmmmb...bmmmm"
+ /* 4 */ "ababa...ababa"
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "ababababababa"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmb...bmmmm"
+ /* 2 */ "mmmma...ammmm"
+ /* 3 */ "mmmmb...bmmmm"
+ /* 4 */ "ababa...ababa"
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "ababababababa"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmma...ammmm"
+ /* 1 */ "mmmmb...bmmmm"
+ /* 2 */ "mmmma...ammmm"
+ /* 3 */ "mmmmb...bmmmm"
+ /* 4 */ "ababa...ababa"
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "ababababababa"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "mmmmcaaadmmmm"
+ /* 1 */ "mmmmcaaadmmmm"
+ /* 2 */ "mmmmcaaadmmmm"
+ /* 3 */ "mmmmcaaadmmmm"
+ /* 4 */ "eeeecaaadeeee"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "fffffffffffff",
+
+ // Connectors:
+ "1: 0, 1, 6: 4\n" /* Type 1, direction X- */
+ "1: 6, 1, 0: 2\n" /* Type 1, direction Z- */
+ "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */
+ "-1: 0, 1, 6: 4\n" /* Type -1, direction X- */
+ "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */
+ "-1: 12, 1, 6: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // Tee4x4
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // TinyCorridorCorner:
+ // The data has been exported from the gallery Nether, area index 66, ID 331, created by xoft
+ {
+ // Size:
+ 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 5, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 0\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "....a"
+ /* 2 */ "....a"
+ /* 3 */ "....a"
+ /* 4 */ "a...a"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "ababa"
+ /* 1 */ "....b"
+ /* 2 */ "....a"
+ /* 3 */ "....b"
+ /* 4 */ "a...a"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "ababa"
+ /* 1 */ "....b"
+ /* 2 */ "....a"
+ /* 3 */ "....b"
+ /* 4 */ "a...a"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "ababa"
+ /* 1 */ "....b"
+ /* 2 */ "....a"
+ /* 3 */ "....b"
+ /* 4 */ "a...a"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "ccccc"
+ /* 1 */ "aaaad"
+ /* 2 */ "aaaad"
+ /* 3 */ "aaaad"
+ /* 4 */ "eaaad",
+
+ // Connectors:
+ "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ -50,
+
+ // MoveToGround:
+ false,
+ }, // TinyCorridorCorner
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // TinyCorridorCornerChest:
+ // The data has been exported from the gallery Nether, area index 67, ID 332, created by Aloe_vera
+ {
+ // Size:
+ 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 5, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 54: 4\n" /* chest */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 1\n" /* netherbrickstairs */
+ "f:114: 0\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "....a"
+ /* 2 */ "...ba"
+ /* 3 */ "....a"
+ /* 4 */ "a...a"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "acaca"
+ /* 1 */ "....c"
+ /* 2 */ "....a"
+ /* 3 */ "....c"
+ /* 4 */ "a...a"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "acaca"
+ /* 1 */ "....c"
+ /* 2 */ "....a"
+ /* 3 */ "....c"
+ /* 4 */ "a...a"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "acaca"
+ /* 1 */ "....c"
+ /* 2 */ "....a"
+ /* 3 */ "....c"
+ /* 4 */ "a...a"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "ddddd"
+ /* 1 */ "aaaae"
+ /* 2 */ "aaaae"
+ /* 3 */ "aaaae"
+ /* 4 */ "faaae",
+
+ // Connectors:
+ "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // TinyCorridorCornerChest
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // TinyCorridorCrossing:
+ // The data has been exported from the gallery Nether, area index 64, ID 329, created by xoft
+ {
+ // Size:
+ 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 5, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 2\n" /* netherbrickstairs */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "a...a"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "a...a"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "a...a"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "a...a"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "a...a"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "a...a"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "a...a"
+ /* 1 */ "....."
+ /* 2 */ "....."
+ /* 3 */ "....."
+ /* 4 */ "a...a"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "baaab"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "caaad",
+
+ // Connectors:
+ "1: 4, 1, 2: 5\n" /* Type 1, direction X+ */
+ "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */
+ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */
+ "1: 2, 1, 0: 2\n" /* Type 1, direction Z- */
+ "-1: 4, 1, 2: 5\n" /* Type -1, direction X+ */
+ "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */
+ "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */
+ "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "1:200|2:400|3:0|4:500",
+
+ // AddWeightIfSame:
+ -50,
+
+ // MoveToGround:
+ false,
+ }, // TinyCorridorCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Turret:
+ // The data has been exported from the gallery Nether, area index 7, ID 34, created by xoft
+ {
+ // Size:
+ 7, 7, 7, // SizeX = 7, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 16, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "a.....a"
+ /* 6 */ "aa...aa"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "a.....a"
+ /* 6 */ "aa...aa"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "aa...aa"
+ /* 1 */ "a.....a"
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "a.....a"
+ /* 6 */ "aa...aa"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "aabbbaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "b.....b"
+ /* 3 */ "b.....b"
+ /* 4 */ "b.....b"
+ /* 5 */ "a.....a"
+ /* 6 */ "aabbbaa"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "a.....a"
+ /* 2 */ "a.....a"
+ /* 3 */ "a.....a"
+ /* 4 */ "a.....a"
+ /* 5 */ "a.....a"
+ /* 6 */ "aaaaaaa"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "0: 0, 1, 3: 4\n" /* Type 0, direction X- */
+ "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */
+ "0: 6, 1, 3: 5\n" /* Type 0, direction X+ */
+ "0: 3, 1, 6: 3\n" /* Type 0, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ -99,
+
+ // MoveToGround:
+ false,
+ }, // Turret
+}; // g_NetherFortPrefabs
+
+
+
+
+
+
+const cPrefab::sDef g_NetherFortStartingPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CentralRoom:
+ // The data has been exported from the gallery Nether, area index 22, ID 164, created by Aloe_vera
+ {
+ // Size:
+ 13, 9, 13, // SizeX = 13, SizeY = 9, SizeZ = 13
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 8, 12, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 10: 0\n" /* lava */
+ "c:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaa...aaaaa"
+ /* 1 */ "aaaaa...aaaaa"
+ /* 2 */ "aa.........aa"
+ /* 3 */ "aa.........aa"
+ /* 4 */ "aa.........aa"
+ /* 5 */ "aa...aaa...aa"
+ /* 6 */ "aa...aba...aa"
+ /* 7 */ "aa...aaa...aa"
+ /* 8 */ "aa.........aa"
+ /* 9 */ "aa.........aa"
+ /* 10 */ "aa.........aa"
+ /* 11 */ "aaaaa...aaaaa"
+ /* 12 */ "aaaaa...aaaaa"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaa...aaaaa"
+ /* 1 */ "aaaca...acaaa"
+ /* 2 */ "aa.........aa"
+ /* 3 */ "ac.........ca"
+ /* 4 */ "aa.........aa"
+ /* 5 */ "ac.........ca"
+ /* 6 */ "aa.........aa"
+ /* 7 */ "ac.........ca"
+ /* 8 */ "aa.........aa"
+ /* 9 */ "ac.........ca"
+ /* 10 */ "aa.........aa"
+ /* 11 */ "aaaca...acaaa"
+ /* 12 */ "aaaaa...aaaaa"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaa...aaaaa"
+ /* 1 */ "aaaca...acaaa"
+ /* 2 */ "aa.........aa"
+ /* 3 */ "ac.........ca"
+ /* 4 */ "aa.........aa"
+ /* 5 */ "ac.........ca"
+ /* 6 */ "aa.........aa"
+ /* 7 */ "ac.........ca"
+ /* 8 */ "aa.........aa"
+ /* 9 */ "ac.........ca"
+ /* 10 */ "aa.........aa"
+ /* 11 */ "aaaca...acaaa"
+ /* 12 */ "aaaaa...aaaaa"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "acacacccacaca"
+ /* 1 */ "caaaa...aaaac"
+ /* 2 */ "aa.........aa"
+ /* 3 */ "ca.........ac"
+ /* 4 */ "aa.........aa"
+ /* 5 */ "ca.........ac"
+ /* 6 */ "aa.........aa"
+ /* 7 */ "ca.........ac"
+ /* 8 */ "aa.........aa"
+ /* 9 */ "ca.........ac"
+ /* 10 */ "aa.........aa"
+ /* 11 */ "caaaa...aaaac"
+ /* 12 */ "acaca...acaca"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "acacaaaaacaca"
+ /* 1 */ "caaaaaaaaaaac"
+ /* 2 */ "aa.........aa"
+ /* 3 */ "ca.........ac"
+ /* 4 */ "aa.........aa"
+ /* 5 */ "ca.........ac"
+ /* 6 */ "aa.........aa"
+ /* 7 */ "ca.........ac"
+ /* 8 */ "aa.........aa"
+ /* 9 */ "ca.........ac"
+ /* 10 */ "aa.........aa"
+ /* 11 */ "caaaaaaaaaaac"
+ /* 12 */ "acacaaaaacaca"
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 7
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+ /* 12 */ "aaaaaaaaaaaaa"
+
+ // Level 8
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "cacacacacacac"
+ /* 1 */ "a...........a"
+ /* 2 */ "c...........c"
+ /* 3 */ "a...........a"
+ /* 4 */ "c...........c"
+ /* 5 */ "a...........a"
+ /* 6 */ "c...........c"
+ /* 7 */ "a...........a"
+ /* 8 */ "c...........c"
+ /* 9 */ "a...........a"
+ /* 10 */ "c...........c"
+ /* 11 */ "a...........a"
+ /* 12 */ "cacacacacacac",
+
+ // Connectors:
+ "0: 6, 1, 0: 2\n" /* Type 0, direction Z- */
+ "1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */
+ "-1: 6, 1, 12: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // CentralRoom
+};
+
+
+
+
+
+// The prefab counts:
+
+const size_t g_NetherFortPrefabsCount = ARRAYCOUNT(g_NetherFortPrefabs);
+
+const size_t g_NetherFortStartingPrefabsCount = ARRAYCOUNT(g_NetherFortStartingPrefabs);
+
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.h b/src/Generating/Prefabs/NetherFortPrefabs.h
new file mode 100644
index 000000000..04edc2953
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.h
@@ -0,0 +1,15 @@
+
+// NetherFortPrefabs.h
+
+// Declares the prefabs in the group NetherFort
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_NetherFortPrefabs[];
+extern const cPrefab::sDef g_NetherFortStartingPrefabs[];
+extern const size_t g_NetherFortPrefabsCount;
+extern const size_t g_NetherFortStartingPrefabsCount;
diff --git a/src/Generating/Prefabs/PlainsVillagePrefabs.cpp b/src/Generating/Prefabs/PlainsVillagePrefabs.cpp
new file mode 100644
index 000000000..f5c5b7a20
--- /dev/null
+++ b/src/Generating/Prefabs/PlainsVillagePrefabs.cpp
@@ -0,0 +1,6114 @@
+
+// PlainsVillagePrefabs.cpp
+
+// Defines the prefabs in the group PlainsVillage
+
+// NOTE: This file has been generated automatically by GalExport!
+// Any manual changes will be overwritten by the next automatic export!
+
+#include "Globals.h"
+#include "PlainsVillagePrefabs.h"
+
+
+
+
+
+const cPrefab::sDef g_PlainsVillagePrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BigPlantBed:
+ // The data has been exported from the gallery Plains, area index 26, ID 70, created by Taugrammaton
+ {
+ // Size:
+ 13, 8, 12, // SizeX = 13, SizeY = 8, SizeZ = 12
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 7, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 5: 0\n" /* wood */
+ "c: 13: 0\n" /* gravel */
+ "d: 17: 0\n" /* tree */
+ "e: 60: 7\n" /* tilleddirt */
+ "f: 8: 0\n" /* water */
+ "g: 85: 0\n" /* fence */
+ "h: 59: 7\n" /* crops */
+ "i: 50: 5\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaa"
+ /* 9 */ "aaaaaaaaaaaaa"
+ /* 10 */ "aaaaaaaaaaaaa"
+ /* 11 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "bbbbbbbbbbbbb"
+ /* 1 */ "bcccccccccccb"
+ /* 2 */ "bcccccccccccb"
+ /* 3 */ "bcccccccccccb"
+ /* 4 */ "bcccccccccccb"
+ /* 5 */ "bcccccccccccb"
+ /* 6 */ "bcccccccccccb"
+ /* 7 */ "bcccccccccccb"
+ /* 8 */ "bcccccccccccb"
+ /* 9 */ "bcccccccccccb"
+ /* 10 */ "bcccccccccccb"
+ /* 11 */ "bbbbbbbbbbbbb"
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "ddddddddddddd"
+ /* 1 */ "deefeefeefeed"
+ /* 2 */ "deefeefeefeed"
+ /* 3 */ "deefeefeefeed"
+ /* 4 */ "deefeefeefeed"
+ /* 5 */ "deefeefeefeed"
+ /* 6 */ "deefeefeefeed"
+ /* 7 */ "deefeefeefeed"
+ /* 8 */ "deefeefeefeed"
+ /* 9 */ "deefeefeefeed"
+ /* 10 */ "deefeefeefeed"
+ /* 11 */ "ddddddddddddd"
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "g..g..g..g..g"
+ /* 1 */ "ghh.h..hh.hhg"
+ /* 2 */ "ghh..h.hh.hhg"
+ /* 3 */ "ghh.h..h..hhg"
+ /* 4 */ "ghh.hh.h..hhg"
+ /* 5 */ "ghh.h..hh.hhg"
+ /* 6 */ "ghh.hh.hh.hhg"
+ /* 7 */ "ghh....h..hhg"
+ /* 8 */ "ghh..h....hhg"
+ /* 9 */ "ghh.....h.hhg"
+ /* 10 */ "ghh.hh.h..hhg"
+ /* 11 */ "g..g..g..g..g"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "i..i..i..i..i"
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "............."
+ /* 9 */ "............."
+ /* 10 */ "............."
+ /* 11 */ "i..i..i..i..i"
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "............."
+ /* 9 */ "............."
+ /* 10 */ "............."
+ /* 11 */ "............."
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "............."
+ /* 9 */ "............."
+ /* 10 */ "............."
+ /* 11 */ "............."
+
+ // Level 7
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "............."
+ /* 4 */ "............."
+ /* 5 */ "............."
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ "............."
+ /* 9 */ "............."
+ /* 10 */ "............."
+ /* 11 */ ".............",
+
+ // Connectors:
+ "-1: 7, 1, 11: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // BigPlantBed
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CobbleHouse10x5Library:
+ // The data has been exported from the gallery Plains, area index 23, ID 66, created by xoft
+ {
+ // Size:
+ 12, 7, 7, // SizeX = 12, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 12, 6, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f: 53: 3\n" /* woodstairs */
+ "g: 53: 1\n" /* woodstairs */
+ "h: 85: 0\n" /* fence */
+ "i: 53: 0\n" /* woodstairs */
+ "j: 53: 2\n" /* woodstairs */
+ "k:102: 0\n" /* glasspane */
+ "l: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 3\n" /* torch */
+ "o: 72: 0\n" /* woodplate */
+ "p: 50: 4\n" /* torch */
+ "q: 53: 7\n" /* woodstairs */
+ "r: 47: 0\n" /* bookshelf */
+ "s: 50: 1\n" /* torch */
+ "t: 50: 2\n" /* torch */
+ "u: 53: 6\n" /* woodstairs */
+ "v: 5: 0\n" /* wood */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "mmmmmmmaaamm"
+ /* 1 */ "maaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaam"
+ /* 6 */ "mmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ ".......bcd.."
+ /* 1 */ ".aaaaaaaaaa."
+ /* 2 */ ".aaaaaaaaaa."
+ /* 3 */ ".aaaaaaaaaa."
+ /* 4 */ ".aaaaaaaaaa."
+ /* 5 */ ".aaaaaaaaaa."
+ /* 6 */ "............"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".aaaaaaaeaa."
+ /* 2 */ ".af.ghi...a."
+ /* 3 */ ".ah.......a."
+ /* 4 */ ".aj.ghighia."
+ /* 5 */ ".aaaaaaaaaa."
+ /* 6 */ "............"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".akkakkalaa."
+ /* 2 */ ".k..no.n.nk."
+ /* 3 */ ".ko.......k."
+ /* 4 */ ".k..po.po.k."
+ /* 5 */ ".akkakkakka."
+ /* 6 */ "............"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "jjjjjjjjjjjj"
+ /* 1 */ "qaaaaaaaaaaq"
+ /* 2 */ ".arrrrrrrra."
+ /* 3 */ ".as......ta."
+ /* 4 */ ".arrrrrrrra."
+ /* 5 */ "uaaaaaaaaaau"
+ /* 6 */ "ffffffffffff"
+
+ // Level 5
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "jjjjjjjjjjjj"
+ /* 2 */ "qvvvvvvvvvvq"
+ /* 3 */ ".vvvvvvvvvv."
+ /* 4 */ "uvvvvvvvvvvu"
+ /* 5 */ "ffffffffffff"
+ /* 6 */ "............"
+
+ // Level 6
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "jjjjjjjjjjjj"
+ /* 3 */ "vvvvvvvvvvvv"
+ /* 4 */ "ffffffffffff"
+ /* 5 */ "............"
+ /* 6 */ "............",
+
+ // Connectors:
+ "-1: 8, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // CobbleHouse10x5Library
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // DoublePlantBed:
+ // The data has been exported from the gallery Plains, area index 5, ID 20, created by tonibm1999
+ {
+ // Size:
+ 15, 8, 9, // SizeX = 15, SizeY = 8, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 7, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 2: 0\n" /* grass */
+ "c: 17: 0\n" /* tree */
+ "d: 60: 7\n" /* tilleddirt */
+ "e: 8: 0\n" /* water */
+ "f: 50: 5\n" /* torch */
+ "g: 59: 7\n" /* crops */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaaaaaa"
+ /* 8 */ "aaaaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "aaaaaaabaaaaaaa"
+ /* 1 */ "aaaaaaabaaaaaaa"
+ /* 2 */ "aaaaaaabaaaaaaa"
+ /* 3 */ "aaaaaaabaaaaaaa"
+ /* 4 */ "aaaaaaabaaaaaaa"
+ /* 5 */ "aaaaaaabaaaaaaa"
+ /* 6 */ "aaaaaaabaaaaaaa"
+ /* 7 */ "aaaaaaabaaaaaaa"
+ /* 8 */ "aaaaaaabaaaaaaa"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "ccccccc.ccccccc"
+ /* 1 */ "cddeddc.cddeddc"
+ /* 2 */ "cddeddc.cddeddc"
+ /* 3 */ "cddeddc.cddeddc"
+ /* 4 */ "cddeddc.cddeddc"
+ /* 5 */ "cddeddc.cddeddc"
+ /* 6 */ "cddeddc.cddeddc"
+ /* 7 */ "cddeddc.cddeddc"
+ /* 8 */ "ccccccc.ccccccc"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "f.....f.f.....f"
+ /* 1 */ ".gg.gg...gg.gg."
+ /* 2 */ ".g...g...gg.gg."
+ /* 3 */ ".g.......gg.gg."
+ /* 4 */ ".gg..g...gg.gg."
+ /* 5 */ ".gg..g...gg.gg."
+ /* 6 */ "..g..g...gg.gg."
+ /* 7 */ "..g.g....gg.gg."
+ /* 8 */ "f.....f.f.....f"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "...............",
+
+ // Connectors:
+ "-1: 7, 2, 8: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // DoublePlantBed
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Forge:
+ // The data has been exported from the gallery Plains, area index 51, ID 102, created by Aloe_vera
+ {
+ // Size:
+ 12, 9, 11, // SizeX = 12, SizeY = 9, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 12, 8, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 6\n" /* wooddoorblock */
+ "h: 10: 0\n" /* lava */
+ "i: 54: 2\n" /* chest */
+ "j: 61: 2\n" /* furnace */
+ "k:102: 0\n" /* glasspane */
+ "l: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */
+ "n:139: 0\n" /* cobblestonewall */
+ "o:101: 0\n" /* ironbars */
+ "p: 53: 2\n" /* woodstairs */
+ "q: 53: 7\n" /* woodstairs */
+ "r: 50: 2\n" /* torch */
+ "s: 50: 1\n" /* torch */
+ "t: 53: 6\n" /* woodstairs */
+ "u: 53: 3\n" /* woodstairs */
+ "v: 43: 0\n" /* doubleslab */
+ "w: 44: 0\n" /* step */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "mmmmmaaaaamm"
+ /* 1 */ "maaaaaaaaamm"
+ /* 2 */ "maaaaaaaaamm"
+ /* 3 */ "maaaaaaaaaaa"
+ /* 4 */ "maaaaaaaaaaa"
+ /* 5 */ "maaaaaaaaaaa"
+ /* 6 */ "maaaaaaaaaaa"
+ /* 7 */ "maaaaaaaaaaa"
+ /* 8 */ "maaaaammmmmm"
+ /* 9 */ "maaaaammmmmm"
+ /* 10 */ "mmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ ".....bcccd.."
+ /* 1 */ ".aaaaaaaad.."
+ /* 2 */ ".aaaaaaaad.."
+ /* 3 */ ".aaaaaaaaaaa"
+ /* 4 */ ".aaaaaaaaaaa"
+ /* 5 */ ".aaaaaaaaaaa"
+ /* 6 */ ".aaaaaaaaaaa"
+ /* 7 */ ".aaaaaaaaaaa"
+ /* 8 */ ".aaaaa......"
+ /* 9 */ ".aaaaa......"
+ /* 10 */ "............"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".efffe......"
+ /* 2 */ ".f...g......"
+ /* 3 */ ".f...ea..aaa"
+ /* 4 */ ".f...f...aha"
+ /* 5 */ ".f...f...aha"
+ /* 6 */ ".f...fijjaha"
+ /* 7 */ ".f...eaaaaaa"
+ /* 8 */ ".f...f......"
+ /* 9 */ ".efffe......"
+ /* 10 */ "............"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".ekkke......"
+ /* 2 */ ".k...l......"
+ /* 3 */ ".k...en..n.a"
+ /* 4 */ ".k...k.....o"
+ /* 5 */ ".f...k.....o"
+ /* 6 */ ".k...k.....o"
+ /* 7 */ ".k...eaooooa"
+ /* 8 */ ".k...f......"
+ /* 9 */ ".ekkke......"
+ /* 10 */ "............"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "ppppppp....."
+ /* 1 */ "qfffffq....."
+ /* 2 */ ".f...f......"
+ /* 3 */ ".f..rfa..aoa"
+ /* 4 */ ".f...f...o.a"
+ /* 5 */ ".f...f...o.a"
+ /* 6 */ ".fs..f...o.a"
+ /* 7 */ ".f...faaaaaa"
+ /* 8 */ ".f...f......"
+ /* 9 */ "tffffft....."
+ /* 10 */ "uuuuuuu....."
+
+ // Level 5
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "ppppppp....."
+ /* 2 */ "qfffffq....."
+ /* 3 */ ".f...fvvvvvv"
+ /* 4 */ ".f...fvwwwwv"
+ /* 5 */ ".f...fvwwwwv"
+ /* 6 */ ".f...fvwwwwv"
+ /* 7 */ ".f...fvvvvvv"
+ /* 8 */ "tffffft....."
+ /* 9 */ "uuuuuuu....."
+ /* 10 */ "............"
+
+ // Level 6
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "ppppppp....."
+ /* 3 */ "qfffffq....."
+ /* 4 */ ".f...f......"
+ /* 5 */ ".f...f......"
+ /* 6 */ ".f...f......"
+ /* 7 */ "tffffft....."
+ /* 8 */ "uuuuuuu....."
+ /* 9 */ "............"
+ /* 10 */ "............"
+
+ // Level 7
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "ppppppp....."
+ /* 4 */ "qfffffq....."
+ /* 5 */ ".f...f......"
+ /* 6 */ "tffffft....."
+ /* 7 */ "uuuuuuu....."
+ /* 8 */ "............"
+ /* 9 */ "............"
+ /* 10 */ "............"
+
+ // Level 8
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "............"
+ /* 4 */ "ppppppp....."
+ /* 5 */ "fffffff....."
+ /* 6 */ "uuuuuuu....."
+ /* 7 */ "............"
+ /* 8 */ "............"
+ /* 9 */ "............"
+ /* 10 */ "............",
+
+ // Connectors:
+ "-1: 7, 1, -1: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Forge
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // LampPost:
+ // The data has been exported from the gallery Plains, area index 28, ID 73, created by STR_Warrior
+ {
+ // Size:
+ 3, 7, 3, // SizeX = 3, SizeY = 7, SizeZ = 3
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 2, 6, 2, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 43: 0\n" /* doubleslab */
+ "c:139: 0\n" /* cobblestonewall */
+ "d: 50: 4\n" /* torch */
+ "e: 50: 2\n" /* torch */
+ "f: 50: 1\n" /* torch */
+ "g: 50: 3\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012 */
+ /* 0 */ "mmm"
+ /* 1 */ "mam"
+ /* 2 */ "mmm"
+
+ // Level 1
+ /* z\x* 012 */
+ /* 0 */ "..."
+ /* 1 */ ".b."
+ /* 2 */ "..."
+
+ // Level 2
+ /* z\x* 012 */
+ /* 0 */ "..."
+ /* 1 */ ".c."
+ /* 2 */ "..."
+
+ // Level 3
+ /* z\x* 012 */
+ /* 0 */ "..."
+ /* 1 */ ".c."
+ /* 2 */ "..."
+
+ // Level 4
+ /* z\x* 012 */
+ /* 0 */ ".d."
+ /* 1 */ "ebf"
+ /* 2 */ ".g."
+
+ // Level 5
+ /* z\x* 012 */
+ /* 0 */ "..."
+ /* 1 */ "..."
+ /* 2 */ "..."
+
+ // Level 6
+ /* z\x* 012 */
+ /* 0 */ "..."
+ /* 1 */ "..."
+ /* 2 */ "...",
+
+ // Connectors:
+ "-1: 1, 1, 2: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // LampPost
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftCorridor:
+ // The data has been exported from the gallery Plains, area index 139, ID 447, created by STR_Warrior
+ {
+ // Size:
+ 10, 4, 3, // SizeX = 10, SizeY = 4, SizeZ = 3
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 9, 3, 2, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 85: 0\n" /* fence */
+ "c: 66: 1\n" /* tracks */
+ "d: 50: 2\n" /* torch */
+ "e: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "aaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaa"
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "..b....b.."
+ /* 1 */ "cccccccccc"
+ /* 2 */ "..b....b.."
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "..b....b.."
+ /* 1 */ ".........."
+ /* 2 */ "..b....b.."
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "..a....a.."
+ /* 1 */ ".dae..dae."
+ /* 2 */ "..a....a..",
+
+ // Connectors:
+ "-3: 0, 1, 1: 4\n" /* Type -3, direction X- */
+ "3: 9, 1, 1: 5\n" /* Type 3, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 200,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftCorridor
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftCrossing:
+ // The data has been exported from the gallery Plains, area index 171, ID 578, created by Aloe_vera
+ {
+ // Size:
+ 5, 4, 5, // SizeX = 5, SizeY = 4, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 3, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 66: 0\n" /* tracks */
+ "c: 66: 1\n" /* tracks */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "m.b.m"
+ /* 1 */ ".aba."
+ /* 2 */ "ccccc"
+ /* 3 */ ".aba."
+ /* 4 */ "m.b.m"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m",
+
+ // Connectors:
+ "3: 4, 1, 2: 5\n" /* Type 3, direction X+ */
+ "-3: 4, 1, 2: 5\n" /* Type -3, direction X+ */
+ "-3: 2, 1, 4: 3\n" /* Type -3, direction Z+ */
+ "3: 2, 1, 4: 3\n" /* Type 3, direction Z+ */
+ "3: 0, 1, 2: 4\n" /* Type 3, direction X- */
+ "-3: 0, 1, 2: 4\n" /* Type -3, direction X- */
+ "3: 2, 1, 0: 2\n" /* Type 3, direction Z- */
+ "-3: 2, 1, 0: 2\n" /* Type -3, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 1,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftCrossing:
+ // The data has been exported from the gallery Plains, area index 193, ID 657, created by Aloe_vera
+ {
+ // Size:
+ 11, 4, 11, // SizeX = 11, SizeY = 4, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 3, 10, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 66: 0\n" /* tracks */
+ "c: 85: 0\n" /* fence */
+ "d: 66: 1\n" /* tracks */
+ "e: 50: 4\n" /* torch */
+ "f: 50: 3\n" /* torch */
+ "g: 50: 2\n" /* torch */
+ "h: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "mmmmaaammmm"
+ /* 2 */ "mmmmaaammmm"
+ /* 3 */ "mmmmaaammmm"
+ /* 4 */ "aaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaa"
+ /* 7 */ "mmmmaaammmm"
+ /* 8 */ "mmmmaaammmm"
+ /* 9 */ "mmmmaaammmm"
+ /* 10 */ "mmmmaaammmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm.b.mmmm"
+ /* 1 */ "mmmm.b.mmmm"
+ /* 2 */ "mmmmcbcmmmm"
+ /* 3 */ "mmmm.b.mmmm"
+ /* 4 */ "..c..b..c.."
+ /* 5 */ "ddddddddddd"
+ /* 6 */ "..c..b..c.."
+ /* 7 */ "mmmm.b.mmmm"
+ /* 8 */ "mmmmcbcmmmm"
+ /* 9 */ "mmmm.b.mmmm"
+ /* 10 */ "mmmm.b.mmmm"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm...mmmm"
+ /* 1 */ "mmmm...mmmm"
+ /* 2 */ "mmmmc.cmmmm"
+ /* 3 */ "mmmm...mmmm"
+ /* 4 */ "..c.....c.."
+ /* 5 */ "..........."
+ /* 6 */ "..c.....c.."
+ /* 7 */ "mmmm...mmmm"
+ /* 8 */ "mmmmc.cmmmm"
+ /* 9 */ "mmmm...mmmm"
+ /* 10 */ "mmmm...mmmm"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm...mmmm"
+ /* 1 */ "mmmm.e.mmmm"
+ /* 2 */ "mmmmaaammmm"
+ /* 3 */ "mmmm.f.mmmm"
+ /* 4 */ "..a.....a.."
+ /* 5 */ ".gah...gah."
+ /* 6 */ "..a.....a.."
+ /* 7 */ "mmmm.e.mmmm"
+ /* 8 */ "mmmmaaammmm"
+ /* 9 */ "mmmm.f.mmmm"
+ /* 10 */ "mmmm...mmmm",
+
+ // Connectors:
+ "3: 5, 1, 0: 2\n" /* Type 3, direction Z- */
+ "-3: 5, 1, 0: 2\n" /* Type -3, direction Z- */
+ "3: 0, 1, 5: 4\n" /* Type 3, direction X- */
+ "-3: 0, 1, 5: 4\n" /* Type -3, direction X- */
+ "3: 5, 1, 10: 3\n" /* Type 3, direction Z+ */
+ "-3: 5, 1, 10: 3\n" /* Type -3, direction Z+ */
+ "3: 10, 1, 5: 5\n" /* Type 3, direction X+ */
+ "-3: 10, 1, 5: 5\n" /* Type -3, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftDoubleCrossing:
+ // The data has been exported from the gallery Plains, area index 172, ID 579, created by Aloe_vera
+ {
+ // Size:
+ 5, 8, 5, // SizeX = 5, SizeY = 8, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 7, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 66: 0\n" /* tracks */
+ "c: 66: 1\n" /* tracks */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "m.b.m"
+ /* 1 */ ".aba."
+ /* 2 */ "ccccc"
+ /* 3 */ ".aba."
+ /* 4 */ "m.b.m"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aa.aa"
+ /* 2 */ "a...a"
+ /* 3 */ "aa.aa"
+ /* 4 */ "aaaaa"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m"
+
+ // Level 6
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m"
+
+ // Level 7
+ /* z\x* 01234 */
+ /* 0 */ "m...m"
+ /* 1 */ ".a.a."
+ /* 2 */ "....."
+ /* 3 */ ".a.a."
+ /* 4 */ "m...m",
+
+ // Connectors:
+ "-3: 4, 5, 2: 5\n" /* Type -3, direction X+ */
+ "3: 4, 5, 2: 5\n" /* Type 3, direction X+ */
+ "-3: 2, 1, 4: 3\n" /* Type -3, direction Z+ */
+ "3: 2, 1, 4: 3\n" /* Type 3, direction Z+ */
+ "-3: 0, 1, 2: 4\n" /* Type -3, direction X- */
+ "3: 0, 1, 2: 4\n" /* Type 3, direction X- */
+ "-3: 2, 1, 0: 2\n" /* Type -3, direction Z- */
+ "3: 2, 1, 0: 2\n" /* Type 3, direction Z- */
+ "-3: 4, 1, 2: 5\n" /* Type -3, direction X+ */
+ "3: 4, 1, 2: 5\n" /* Type 3, direction X+ */
+ "-3: 2, 5, 4: 3\n" /* Type -3, direction Z+ */
+ "3: 2, 5, 4: 3\n" /* Type 3, direction Z+ */
+ "-3: 0, 5, 2: 4\n" /* Type -3, direction X- */
+ "3: 0, 5, 2: 4\n" /* Type 3, direction X- */
+ "-3: 2, 5, 0: 2\n" /* Type -3, direction Z- */
+ "3: 2, 5, 0: 2\n" /* Type 3, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 1,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftDoubleCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftSpiral:
+ // The data has been exported from the gallery Plains, area index 198, ID 662, created by Aloe_vera
+ {
+ // Size:
+ 7, 12, 7, // SizeX = 7, SizeY = 12, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 11, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 85: 0\n" /* fence */
+ "c: 66: 4\n" /* tracks */
+ "d: 66: 0\n" /* tracks */
+ "e: 66: 6\n" /* tracks */
+ "f: 66: 2\n" /* tracks */
+ "g: 50: 1\n" /* torch */
+ "h: 50: 3\n" /* torch */
+ "i: 66: 1\n" /* tracks */
+ "j: 66: 7\n" /* tracks */
+ "k: 66: 5\n" /* tracks */
+ "l: 50: 2\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 66: 3\n" /* tracks */
+ "o: 66: 8\n" /* tracks */
+ "p: 50: 4\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmmmmm"
+ /* 2 */ "mmmmmmm"
+ /* 3 */ "aaabmmm"
+ /* 4 */ "aaammmm"
+ /* 5 */ "aaammmm"
+ /* 6 */ "aaammmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmmmmm"
+ /* 2 */ "aaammmm"
+ /* 3 */ "aaabmmm"
+ /* 4 */ ".c.mmmm"
+ /* 5 */ ".d.mmmm"
+ /* 6 */ ".d.mmmm"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aaaammm"
+ /* 1 */ "aaaammm"
+ /* 2 */ "aaaammm"
+ /* 3 */ ".c.bmmm"
+ /* 4 */ "...mmmm"
+ /* 5 */ "...mmmm"
+ /* 6 */ "...mmmm"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "b..aamm"
+ /* 1 */ ".efaamm"
+ /* 2 */ ".d.aamm"
+ /* 3 */ "...bmmm"
+ /* 4 */ "...mmmm"
+ /* 5 */ "...mmmm"
+ /* 6 */ "...mmmm"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "b...aaa"
+ /* 1 */ "...faaa"
+ /* 2 */ "....aaa"
+ /* 3 */ "...baaa"
+ /* 4 */ "...mmmm"
+ /* 5 */ "mmmmmmm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "ag....b"
+ /* 1 */ "h...ij."
+ /* 2 */ ".....k."
+ /* 3 */ "...baaa"
+ /* 4 */ "mmmmaaa"
+ /* 5 */ "mmmmmmm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "mm....b"
+ /* 1 */ "mm....."
+ /* 2 */ "mm....."
+ /* 3 */ "mmmb.k."
+ /* 4 */ "mmmaaaa"
+ /* 5 */ "mmmaaaa"
+ /* 6 */ "mmmaaaa"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "mmm..la"
+ /* 1 */ "mmm...h"
+ /* 2 */ "mmm...."
+ /* 3 */ "mmmb..."
+ /* 4 */ "mmaa.d."
+ /* 5 */ "mmaano."
+ /* 6 */ "mmaa..b"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmmmmm"
+ /* 2 */ "mmmm..."
+ /* 3 */ "mmmb..."
+ /* 4 */ "aaa...."
+ /* 5 */ "aaan..."
+ /* 6 */ "aaa...b"
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmmmmm"
+ /* 2 */ "mmmmmmm"
+ /* 3 */ "mmmb..."
+ /* 4 */ "......."
+ /* 5 */ "iii...p"
+ /* 6 */ ".....la"
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmmmmm"
+ /* 2 */ "mmmmmmm"
+ /* 3 */ "mmmbmmm"
+ /* 4 */ ".....mm"
+ /* 5 */ ".....mm"
+ /* 6 */ ".....mm"
+
+ // Level 11
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmmmmm"
+ /* 2 */ "mmmmmmm"
+ /* 3 */ "mmmbmmm"
+ /* 4 */ "....mmm"
+ /* 5 */ "....mmm"
+ /* 6 */ "....mmm",
+
+ // Connectors:
+ "3: 1, 1, 6: 3\n" /* Type 3, direction Z+ */
+ "-3: 1, 1, 6: 3\n" /* Type -3, direction Z+ */
+ "3: 0, 9, 5: 4\n" /* Type 3, direction X- */
+ "-3: 0, 9, 5: 4\n" /* Type -3, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftSpiral
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftStairs:
+ // The data has been exported from the gallery Plains, area index 195, ID 659, created by Aloe_vera
+ {
+ // Size:
+ 7, 8, 3, // SizeX = 7, SizeY = 8, SizeZ = 3
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 7, 2, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 66: 1\n" /* tracks */
+ "c: 66: 2\n" /* tracks */
+ "d: 85: 0\n" /* fence */
+ "e: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaammmm"
+ /* 1 */ "aaammmm"
+ /* 2 */ "aaammmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "..aammm"
+ /* 1 */ "bcaammm"
+ /* 2 */ "..aammm"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "...aamm"
+ /* 1 */ "..caamm"
+ /* 2 */ "...aamm"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "...daam"
+ /* 1 */ "...caam"
+ /* 2 */ "...daam"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "m..d.aa"
+ /* 1 */ "m...caa"
+ /* 2 */ "m..d.aa"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "mm.d..."
+ /* 1 */ "mm...bb"
+ /* 2 */ "mm.d..."
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "mmmd..."
+ /* 1 */ "mmm...."
+ /* 2 */ "mmmd..."
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "mmma..."
+ /* 1 */ "mmmae.."
+ /* 2 */ "mmma...",
+
+ // Connectors:
+ "3: 0, 1, 1: 4\n" /* Type 3, direction X- */
+ "-3: 0, 1, 1: 4\n" /* Type -3, direction X- */
+ "3: 6, 5, 1: 5\n" /* Type 3, direction X+ */
+ "-3: 6, 5, 1: 5\n" /* Type -3, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftStairs
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftStairsCrossing:
+ // The data has been exported from the gallery Plains, area index 199, ID 663, created by Aloe_vera
+ {
+ // Size:
+ 11, 12, 12, // SizeX = 11, SizeY = 12, SizeZ = 12
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 11, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 66: 0\n" /* tracks */
+ "c: 66: 5\n" /* tracks */
+ "d: 85: 0\n" /* fence */
+ "e: 66: 1\n" /* tracks */
+ "f: 50: 3\n" /* torch */
+ "g: 50: 2\n" /* torch */
+ "h: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "mmmmaaammmm"
+ /* 2 */ "mmmmaaammmm"
+ /* 3 */ "mmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm.b.mmmm"
+ /* 1 */ "mmmm.c.mmmm"
+ /* 2 */ "mmmmaaammmm"
+ /* 3 */ "mmmmaaammmm"
+ /* 4 */ "mmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm...mmmm"
+ /* 1 */ "mmmm...mmmm"
+ /* 2 */ "mmmm.c.mmmm"
+ /* 3 */ "mmmmaaammmm"
+ /* 4 */ "mmmmaaammmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm...mmmm"
+ /* 1 */ "mmmm...mmmm"
+ /* 2 */ "mmmm...mmmm"
+ /* 3 */ "mmmmdcdmmmm"
+ /* 4 */ "mmmmaaammmm"
+ /* 5 */ "mmmmaaammmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmm"
+ /* 9 */ "mmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmm...mmmm"
+ /* 2 */ "mmmm...mmmm"
+ /* 3 */ "mmmmd.dmmmm"
+ /* 4 */ "mmmm.c.mmmm"
+ /* 5 */ "aaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaa"
+ /* 7 */ "aaaaaaaaaaa"
+ /* 8 */ "mmmmaaammmm"
+ /* 9 */ "mmmmmmmmmmm"
+ /* 10 */ "mmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmm...mmmm"
+ /* 3 */ "mmmmd.dmmmm"
+ /* 4 */ "mmmm...mmmm"
+ /* 5 */ "..d..b..d.."
+ /* 6 */ "eeeeeeeeeee"
+ /* 7 */ "..d..c..d.."
+ /* 8 */ "mmmmaaammmm"
+ /* 9 */ "mmmmaaammmm"
+ /* 10 */ "mmmmmmmmmmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmm"
+ /* 3 */ "mmmmd.dmmmm"
+ /* 4 */ "mmmm...mmmm"
+ /* 5 */ "..d.....d.."
+ /* 6 */ "..........."
+ /* 7 */ "..d.....d.."
+ /* 8 */ "mmmm.c.mmmm"
+ /* 9 */ "mmmmaaammmm"
+ /* 10 */ "mmmmaaammmm"
+ /* 11 */ "mmmmmmmmmmm"
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmm"
+ /* 3 */ "mmmmaaammmm"
+ /* 4 */ "mmmm.f.mmmm"
+ /* 5 */ "..a.....a.."
+ /* 6 */ ".gah...gah."
+ /* 7 */ "..a.....a.."
+ /* 8 */ "mmmm...mmmm"
+ /* 9 */ "mmmmdcdmmmm"
+ /* 10 */ "mmmmaaammmm"
+ /* 11 */ "mmmmaaammmm"
+
+ // Level 8
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmm...mmmm"
+ /* 8 */ "mmmm...mmmm"
+ /* 9 */ "mmmmd.dmmmm"
+ /* 10 */ "mmmm.c.mmmm"
+ /* 11 */ "mmmmaaammmm"
+
+ // Level 9
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmm...mmmm"
+ /* 9 */ "mmmmd.dmmmm"
+ /* 10 */ "mmmm...mmmm"
+ /* 11 */ "mmmm.b.mmmm"
+
+ // Level 10
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmm"
+ /* 9 */ "mmmmd.dmmmm"
+ /* 10 */ "mmmm...mmmm"
+ /* 11 */ "mmmm...mmmm"
+
+ // Level 11
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmmmmmmmm"
+ /* 1 */ "mmmmmmmmmmm"
+ /* 2 */ "mmmmmmmmmmm"
+ /* 3 */ "mmmmmmmmmmm"
+ /* 4 */ "mmmmmmmmmmm"
+ /* 5 */ "mmmmmmmmmmm"
+ /* 6 */ "mmmmmmmmmmm"
+ /* 7 */ "mmmmmmmmmmm"
+ /* 8 */ "mmmmmmmmmmm"
+ /* 9 */ "mmmmaaammmm"
+ /* 10 */ "mmmm.f.mmmm"
+ /* 11 */ "mmmm...mmmm",
+
+ // Connectors:
+ "3: 0, 5, 6: 4\n" /* Type 3, direction X- */
+ "-3: 0, 5, 6: 4\n" /* Type -3, direction X- */
+ "3: 10, 5, 6: 5\n" /* Type 3, direction X+ */
+ "-3: 10, 5, 6: 5\n" /* Type -3, direction X+ */
+ "3: 5, 9, 11: 3\n" /* Type 3, direction Z+ */
+ "-3: 5, 9, 11: 3\n" /* Type -3, direction Z+ */
+ "3: 5, 1, 1: 2\n" /* Type 3, direction Z- */
+ "-3: 5, 1, 1: 2\n" /* Type -3, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 30,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftStairsCrossing
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftTee:
+ // The data has been exported from the gallery Plains, area index 194, ID 658, created by Aloe_vera
+ {
+ // Size:
+ 11, 4, 7, // SizeX = 11, SizeY = 4, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 3, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 66: 0\n" /* tracks */
+ "c: 85: 0\n" /* fence */
+ "d: 66: 1\n" /* tracks */
+ "e: 50: 4\n" /* torch */
+ "f: 50: 3\n" /* torch */
+ "g: 50: 2\n" /* torch */
+ "h: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "mmmmaaammmm"
+ /* 2 */ "mmmmaaammmm"
+ /* 3 */ "mmmmaaammmm"
+ /* 4 */ "aaaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm.b.mmmm"
+ /* 1 */ "mmmm.b.mmmm"
+ /* 2 */ "mmmmcbcmmmm"
+ /* 3 */ "mmmm.b.mmmm"
+ /* 4 */ "..c..b..c.."
+ /* 5 */ "ddddddddddd"
+ /* 6 */ "..c.....c.."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm...mmmm"
+ /* 1 */ "mmmm...mmmm"
+ /* 2 */ "mmmmc.cmmmm"
+ /* 3 */ "mmmm...mmmm"
+ /* 4 */ "..c.....c.."
+ /* 5 */ "..........."
+ /* 6 */ "..c.....c.."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmm...mmmm"
+ /* 1 */ "mmmm.e.mmmm"
+ /* 2 */ "mmmmaaammmm"
+ /* 3 */ "mmmm.f.mmmm"
+ /* 4 */ "..a.....a.."
+ /* 5 */ ".gah...gah."
+ /* 6 */ "..a.....a..",
+
+ // Connectors:
+ "3: 0, 1, 5: 4\n" /* Type 3, direction X- */
+ "-3: 0, 1, 5: 4\n" /* Type -3, direction X- */
+ "3: 5, 1, 0: 2\n" /* Type 3, direction Z- */
+ "-3: 5, 1, 0: 2\n" /* Type -3, direction Z- */
+ "3: 10, 1, 5: 5\n" /* Type 3, direction X+ */
+ "-3: 10, 1, 5: 5\n" /* Type -3, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 20,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftTee
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineshaftsCorridor5:
+ // The data has been exported from the gallery Plains, area index 200, ID 664, created by Aloe_vera
+ {
+ // Size:
+ 11, 4, 3, // SizeX = 11, SizeY = 4, SizeZ = 3
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 3, 2, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 85: 0\n" /* fence */
+ "c: 66: 1\n" /* tracks */
+ "d: 50: 2\n" /* torch */
+ "e: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..b.....b.."
+ /* 1 */ "ccccccccccc"
+ /* 2 */ "..b.....b.."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..b.....b.."
+ /* 1 */ "..........."
+ /* 2 */ "..b.....b.."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..a.....a.."
+ /* 1 */ ".dae...dae."
+ /* 2 */ "..a.....a..",
+
+ // Connectors:
+ "3: 10, 1, 1: 5\n" /* Type 3, direction X+ */
+ "-3: 10, 1, 1: 5\n" /* Type -3, direction X+ */
+ "-3: 0, 1, 1: 4\n" /* Type -3, direction X- */
+ "3: 0, 1, 1: 4\n" /* Type 3, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ false,
+ }, // MineshaftsCorridor5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Scarecrow:
+ // The data has been exported from the gallery Plains, area index 150, ID 494, created by STR_Warrior
+ {
+ // Size:
+ 1, 6, 3, // SizeX = 1, SizeY = 6, SizeZ = 3
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 0, 5, 2, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:139: 0\n" /* cobblestonewall */
+ "b: 85: 0\n" /* fence */
+ "c:126: 4\n" /* woodenslab */
+ "d: 86: 1\n" /* pumpkin */
+ "e:139: 1\n" /* cobblestonewall */
+ "f:163: 4\n" /* acaciawoodenstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0 */
+ /* 0 */ "."
+ /* 1 */ "a"
+ /* 2 */ "."
+
+ // Level 1
+ /* z\x* 0 */
+ /* 0 */ "."
+ /* 1 */ "b"
+ /* 2 */ "."
+
+ // Level 2
+ /* z\x* 0 */
+ /* 0 */ "c"
+ /* 1 */ "d"
+ /* 2 */ "c"
+
+ // Level 3
+ /* z\x* 0 */
+ /* 0 */ "."
+ /* 1 */ "e"
+ /* 2 */ "."
+
+ // Level 4
+ /* z\x* 0 */
+ /* 0 */ "f"
+ /* 1 */ "d"
+ /* 2 */ "f"
+
+ // Level 5
+ /* z\x* 0 */
+ /* 0 */ "."
+ /* 1 */ "f"
+ /* 2 */ ".",
+
+ // Connectors:
+ "-1: -1, 0, 1: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 10,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Scarecrow
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // SinglePlantBed:
+ // The data has been exported from the gallery Plains, area index 17, ID 60, created by Aloe_vera
+ {
+ // Size:
+ 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 9, 6, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 3: 0\n" /* dirt */
+ "b: 17: 0\n" /* tree */
+ "c: 60: 7\n" /* tilleddirt */
+ "d: 8: 0\n" /* water */
+ "e: 59: 7\n" /* crops */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "aaaaaaaaaa"
+ /* 1 */ "aaaaaaaaaa"
+ /* 2 */ "aaaaaaaaaa"
+ /* 3 */ "aaaaaaaaaa"
+ /* 4 */ "aaaaaaaaaa"
+ /* 5 */ "aaaaaaaaaa"
+ /* 6 */ "aaaaaaaaaa"
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "bbbbbbbbbb"
+ /* 1 */ "bccccccccb"
+ /* 2 */ "bccccccccb"
+ /* 3 */ "bddddddddb"
+ /* 4 */ "bccccccccb"
+ /* 5 */ "bccccccccb"
+ /* 6 */ "bbbbbbbbbb"
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".eeeeeeee."
+ /* 2 */ ".eeeeeeee."
+ /* 3 */ ".........."
+ /* 4 */ ".eeeeeeee."
+ /* 5 */ ".eeeeeeee."
+ /* 6 */ ".........."
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".........."
+ /* 2 */ ".........."
+ /* 3 */ ".........."
+ /* 4 */ ".........."
+ /* 5 */ ".........."
+ /* 6 */ ".........."
+
+ // Level 4
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".........."
+ /* 2 */ ".........."
+ /* 3 */ ".........."
+ /* 4 */ ".........."
+ /* 5 */ ".........."
+ /* 6 */ ".........."
+
+ // Level 5
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".........."
+ /* 2 */ ".........."
+ /* 3 */ ".........."
+ /* 4 */ ".........."
+ /* 5 */ ".........."
+ /* 6 */ ".........."
+
+ // Level 6
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".........."
+ /* 2 */ ".........."
+ /* 3 */ ".........."
+ /* 4 */ ".........."
+ /* 5 */ ".........."
+ /* 6 */ "..........",
+
+ // Connectors:
+ "-1: 9, 1, 3: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // SinglePlantBed
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenChurchMid:
+ // The data has been exported from the gallery Plains, area index 58, ID 109, created by Aloe_vera
+ {
+ // Size:
+ 7, 15, 13, // SizeX = 7, SizeY = 15, SizeZ = 13
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 7, 14, 13, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A: 85: 0\n" /* fence */
+ "B:126: 8\n" /* woodenslab */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h: 65: 3\n" /* ladder */
+ "i: 53: 3\n" /* woodstairs */
+ "j: 53: 7\n" /* woodstairs */
+ "k: 64:12\n" /* wooddoorblock */
+ "l:102: 0\n" /* glasspane */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 1\n" /* torch */
+ "o: 50: 2\n" /* torch */
+ "p:171:14\n" /* carpet */
+ "q: 50: 3\n" /* torch */
+ "r: 53: 2\n" /* woodstairs */
+ "s: 53: 0\n" /* woodstairs */
+ "t: 53: 1\n" /* woodstairs */
+ "u: 53: 5\n" /* woodstairs */
+ "v: 53: 4\n" /* woodstairs */
+ "w: 17: 4\n" /* tree */
+ "x: 17: 8\n" /* tree */
+ "y: 54: 2\n" /* chest */
+ "z: 50: 4\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "mmaaamm"
+ /* 1 */ "maaaaam"
+ /* 2 */ "maaaaam"
+ /* 3 */ "maaaaam"
+ /* 4 */ "maaaaam"
+ /* 5 */ "maaaaam"
+ /* 6 */ "maaaaam"
+ /* 7 */ "maaaaam"
+ /* 8 */ "maaaaam"
+ /* 9 */ "maaaaam"
+ /* 10 */ "maaaaam"
+ /* 11 */ "maaaaam"
+ /* 12 */ "mmmmmmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "..bcd.."
+ /* 1 */ ".aaaaa."
+ /* 2 */ ".aaaaa."
+ /* 3 */ ".aaaaa."
+ /* 4 */ ".aaaaa."
+ /* 5 */ ".aaaaa."
+ /* 6 */ ".aaaaa."
+ /* 7 */ ".aaaaa."
+ /* 8 */ ".aaaaa."
+ /* 9 */ ".aaaaa."
+ /* 10 */ ".aaaaa."
+ /* 11 */ ".aaaaa."
+ /* 12 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".efgfe."
+ /* 2 */ ".f..hf."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ ".ei.ie."
+ /* 6 */ ".f...f."
+ /* 7 */ ".fi.if."
+ /* 8 */ ".f...f."
+ /* 9 */ ".f.j.f."
+ /* 10 */ ".f...f."
+ /* 11 */ ".efffe."
+ /* 12 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".efkfe."
+ /* 2 */ ".l..hl."
+ /* 3 */ ".l...l."
+ /* 4 */ ".l...l."
+ /* 5 */ ".e...e."
+ /* 6 */ ".l...l."
+ /* 7 */ ".l...l."
+ /* 8 */ ".fn.of."
+ /* 9 */ ".l.p.l."
+ /* 10 */ ".l...l."
+ /* 11 */ ".ellle."
+ /* 12 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".efffe."
+ /* 2 */ ".f.qhf."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ "re...er"
+ /* 6 */ "sf...ft"
+ /* 7 */ "sf...ft"
+ /* 8 */ "sf...ft"
+ /* 9 */ "sf...ft"
+ /* 10 */ "sf...ft"
+ /* 11 */ "sefffet"
+ /* 12 */ "su...vt"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ewwwe."
+ /* 2 */ ".xffhx."
+ /* 3 */ ".xfffx."
+ /* 4 */ ".xfffx."
+ /* 5 */ ".ewwwe."
+ /* 6 */ ".sf.ft."
+ /* 7 */ ".sf.ft."
+ /* 8 */ ".sf.ft."
+ /* 9 */ ".sf.ft."
+ /* 10 */ ".sf.ft."
+ /* 11 */ ".sffft."
+ /* 12 */ ".su.vt."
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".eflfe."
+ /* 2 */ ".f..hf."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f.y.f."
+ /* 5 */ ".efffe."
+ /* 6 */ "..sft.."
+ /* 7 */ "..sft.."
+ /* 8 */ "..sft.."
+ /* 9 */ "..sft.."
+ /* 10 */ "..sft.."
+ /* 11 */ "..sft.."
+ /* 12 */ "..sft.."
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".eflfe."
+ /* 2 */ ".f..hf."
+ /* 3 */ ".l...l."
+ /* 4 */ ".f...f."
+ /* 5 */ ".efffe."
+ /* 6 */ "......."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".eflfe."
+ /* 2 */ ".f..hf."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f.z.f."
+ /* 5 */ ".efffe."
+ /* 6 */ "......."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ewwwe."
+ /* 2 */ ".xffhx."
+ /* 3 */ ".xfffx."
+ /* 4 */ ".xfffx."
+ /* 5 */ ".ewwwe."
+ /* 6 */ "......."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".eAAAe."
+ /* 2 */ ".A...A."
+ /* 3 */ ".A...A."
+ /* 4 */ ".A...A."
+ /* 5 */ ".eAAAe."
+ /* 6 */ "......."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 11
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".e...e."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ ".e...e."
+ /* 6 */ "......."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 12
+ /* z\x* 0123456 */
+ /* 0 */ "su...vt"
+ /* 1 */ "sefffet"
+ /* 2 */ "sfBBBft"
+ /* 3 */ "sfBBBft"
+ /* 4 */ "sfBBBft"
+ /* 5 */ "sefffet"
+ /* 6 */ "su...vt"
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 13
+ /* z\x* 0123456 */
+ /* 0 */ ".su.vt."
+ /* 1 */ ".sffft."
+ /* 2 */ ".sffft."
+ /* 3 */ ".sffft."
+ /* 4 */ ".sffft."
+ /* 5 */ ".sffft."
+ /* 6 */ ".su.vt."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ "......."
+
+ // Level 14
+ /* z\x* 0123456 */
+ /* 0 */ "..sft.."
+ /* 1 */ "..sft.."
+ /* 2 */ "..sft.."
+ /* 3 */ "..sft.."
+ /* 4 */ "..sft.."
+ /* 5 */ "..sft.."
+ /* 6 */ "..sft.."
+ /* 7 */ "......."
+ /* 8 */ "......."
+ /* 9 */ "......."
+ /* 10 */ "......."
+ /* 11 */ "......."
+ /* 12 */ ".......",
+
+ // Connectors:
+ "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 20,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenChurchMid
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenGranary:
+ // The data has been exported from the gallery Plains, area index 54, ID 105, created by Aloe_vera
+ {
+ // Size:
+ 7, 7, 9, // SizeX = 7, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 7, 6, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b:170: 0\n" /* haybale */
+ "c: 67: 0\n" /* stairs */
+ "d: 67: 2\n" /* stairs */
+ "e: 67: 1\n" /* stairs */
+ "f: 17: 0\n" /* tree */
+ "g: 5: 0\n" /* wood */
+ "h:170: 4\n" /* haybale */
+ "i:170: 8\n" /* haybale */
+ "j: 54: 2\n" /* chest */
+ "k: 50: 4\n" /* torch */
+ "l: 53: 0\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 5\n" /* woodstairs */
+ "o: 53: 4\n" /* woodstairs */
+ "p: 53: 1\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "maaaaam"
+ /* 1 */ "maaaaam"
+ /* 2 */ "maaaaam"
+ /* 3 */ "maaaaam"
+ /* 4 */ "maaaaam"
+ /* 5 */ "maaaaam"
+ /* 6 */ "maaaaam"
+ /* 7 */ "maaaaam"
+ /* 8 */ "mmmmmmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "bcddde."
+ /* 1 */ ".aaaaa."
+ /* 2 */ ".aaaaa."
+ /* 3 */ ".aaaaa."
+ /* 4 */ ".aaaaa."
+ /* 5 */ ".aaaaa."
+ /* 6 */ ".aaaaa."
+ /* 7 */ ".aaaaa."
+ /* 8 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".f..bf."
+ /* 2 */ ".g...g."
+ /* 3 */ ".gb.hg."
+ /* 4 */ ".fihif."
+ /* 5 */ ".gbbbg."
+ /* 6 */ ".gijbg."
+ /* 7 */ ".fgfgf."
+ /* 8 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ ".k...k."
+ /* 1 */ ".f...f."
+ /* 2 */ ".g...g."
+ /* 3 */ ".g...g."
+ /* 4 */ ".fh..f."
+ /* 5 */ ".ghibg."
+ /* 6 */ ".ghiig."
+ /* 7 */ ".fgfgf."
+ /* 8 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "ln...op"
+ /* 1 */ "lgggggp"
+ /* 2 */ "lg...gp"
+ /* 3 */ "lg...gp"
+ /* 4 */ "lg...gp"
+ /* 5 */ "lgbb.gp"
+ /* 6 */ "lgibigp"
+ /* 7 */ "lgggggp"
+ /* 8 */ "ln...op"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ ".ln.op."
+ /* 1 */ ".lgggp."
+ /* 2 */ ".lg.gp."
+ /* 3 */ ".lg.gp."
+ /* 4 */ ".lg.gp."
+ /* 5 */ ".lg.gp."
+ /* 6 */ ".lg.gp."
+ /* 7 */ ".lgggp."
+ /* 8 */ ".ln.op."
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "..lgp.."
+ /* 1 */ "..lgp.."
+ /* 2 */ "..lgp.."
+ /* 3 */ "..lgp.."
+ /* 4 */ "..lgp.."
+ /* 5 */ "..lgp.."
+ /* 6 */ "..lgp.."
+ /* 7 */ "..lgp.."
+ /* 8 */ "..lgp..",
+
+ // Connectors:
+ "-1: 3, 1, -1: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenGranary
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse10x7Library:
+ // The data has been exported from the gallery Plains, area index 47, ID 98, created by Aloe_vera
+ {
+ // Size:
+ 12, 8, 9, // SizeX = 12, SizeY = 8, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 12, 7, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h: 64: 5\n" /* wooddoorblock */
+ "i: 53: 3\n" /* woodstairs */
+ "j: 85: 0\n" /* fence */
+ "k: 53: 2\n" /* woodstairs */
+ "l: 53: 1\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 0\n" /* woodstairs */
+ "o:102: 0\n" /* glasspane */
+ "p: 64:12\n" /* wooddoorblock */
+ "q: 50: 3\n" /* torch */
+ "r: 72: 0\n" /* woodplate */
+ "s: 53: 7\n" /* woodstairs */
+ "t: 47: 0\n" /* bookshelf */
+ "u: 50: 1\n" /* torch */
+ "v: 50: 2\n" /* torch */
+ "w: 53: 6\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "mmmmaaaammmm"
+ /* 1 */ "maaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaam"
+ /* 6 */ "maaaaaaaaaam"
+ /* 7 */ "maaaaaaaaaam"
+ /* 8 */ "mmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "....bccd...."
+ /* 1 */ ".aaaaaaaaaa."
+ /* 2 */ ".aaaaaaaaaa."
+ /* 3 */ ".aaaaaaaaaa."
+ /* 4 */ ".aaaaaaaaaa."
+ /* 5 */ ".aaaaaaaaaa."
+ /* 6 */ ".aaaaaaaaaa."
+ /* 7 */ ".aaaaaaaaaa."
+ /* 8 */ "............"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".efffghfffe."
+ /* 2 */ ".f........f."
+ /* 3 */ ".fi......if."
+ /* 4 */ ".fj......jf."
+ /* 5 */ ".fk......kf."
+ /* 6 */ ".f.ljnljn.f."
+ /* 7 */ ".effffffffe."
+ /* 8 */ "............"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".eoofppfooe."
+ /* 2 */ ".o..q..q..o."
+ /* 3 */ ".o........o."
+ /* 4 */ ".fr......rf."
+ /* 5 */ ".o........o."
+ /* 6 */ ".o..r..r..o."
+ /* 7 */ ".eoofoofooe."
+ /* 8 */ "............"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "kkkkkkkkkkkk"
+ /* 1 */ "sffffffffffs"
+ /* 2 */ ".fttttttttf."
+ /* 3 */ ".f........f."
+ /* 4 */ ".fu......vf."
+ /* 5 */ ".f........f."
+ /* 6 */ ".fttttttttf."
+ /* 7 */ "wffffffffffw"
+ /* 8 */ "iiiiiiiiiiii"
+
+ // Level 5
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "kkkkkkkkkkkk"
+ /* 2 */ "sffffffffffs"
+ /* 3 */ ".fttttttttf."
+ /* 4 */ ".f........f."
+ /* 5 */ ".fttttttttf."
+ /* 6 */ "wffffffffffw"
+ /* 7 */ "iiiiiiiiiiii"
+ /* 8 */ "............"
+
+ // Level 6
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "kkkkkkkkkkkk"
+ /* 3 */ "sffffffffffs"
+ /* 4 */ ".f........f."
+ /* 5 */ "wffffffffffw"
+ /* 6 */ "iiiiiiiiiiii"
+ /* 7 */ "............"
+ /* 8 */ "............"
+
+ // Level 7
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ "............"
+ /* 2 */ "............"
+ /* 3 */ "kkkkkkkkkkkk"
+ /* 4 */ "ffffffffffff"
+ /* 5 */ "iiiiiiiiiiii"
+ /* 6 */ "............"
+ /* 7 */ "............"
+ /* 8 */ "............",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse10x7Library
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse5x5:
+ // The data has been exported from the gallery Plains, area index 49, ID 100, created by Aloe_vera
+ {
+ // Size:
+ 7, 7, 7, // SizeX = 7, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 7, 6, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h: 64:12\n" /* wooddoorblock */
+ "i:102: 0\n" /* glasspane */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 7\n" /* woodstairs */
+ "l: 50: 3\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 6\n" /* woodstairs */
+ "o: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "mmaaamm"
+ /* 1 */ "maaaaam"
+ /* 2 */ "maaaaam"
+ /* 3 */ "maaaaam"
+ /* 4 */ "maaaaam"
+ /* 5 */ "maaaaam"
+ /* 6 */ "mmmmmmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "..bcd.."
+ /* 1 */ ".aaaaa."
+ /* 2 */ ".aaaaa."
+ /* 3 */ ".aaaaa."
+ /* 4 */ ".aaaaa."
+ /* 5 */ ".aaaaa."
+ /* 6 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".efgfe."
+ /* 2 */ ".f...f."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ ".efffe."
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".efhfe."
+ /* 2 */ ".i...i."
+ /* 3 */ ".i...i."
+ /* 4 */ ".i...i."
+ /* 5 */ ".eiiie."
+ /* 6 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "jjjjjjj"
+ /* 1 */ "kfffffk"
+ /* 2 */ ".fl.lf."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ "nfffffn"
+ /* 6 */ "ooooooo"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "jjjjjjj"
+ /* 2 */ "kfffffk"
+ /* 3 */ ".f...f."
+ /* 4 */ "nfffffn"
+ /* 5 */ "ooooooo"
+ /* 6 */ "......."
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "jjjjjjj"
+ /* 3 */ "fffffff"
+ /* 4 */ "ooooooo"
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse5x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse7x5:
+ // The data has been exported from the gallery Plains, area index 40, ID 91, created by xoft
+ {
+ // Size:
+ 9, 7, 7, // SizeX = 9, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 9, 6, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h:102: 0\n" /* glasspane */
+ "i: 64:12\n" /* wooddoorblock */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 7\n" /* woodstairs */
+ "l: 50: 3\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 6\n" /* woodstairs */
+ "o: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "mmmaaammm"
+ /* 1 */ "maaaaaaam"
+ /* 2 */ "maaaaaaam"
+ /* 3 */ "maaaaaaam"
+ /* 4 */ "maaaaaaam"
+ /* 5 */ "maaaaaaam"
+ /* 6 */ "mmmmmmmmm"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "...bcd..."
+ /* 1 */ ".aaaaaaa."
+ /* 2 */ ".aaaaaaa."
+ /* 3 */ ".aaaaaaa."
+ /* 4 */ ".aaaaaaa."
+ /* 5 */ ".aaaaaaa."
+ /* 6 */ "........."
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".effgffe."
+ /* 2 */ ".f.....f."
+ /* 3 */ ".f.....f."
+ /* 4 */ ".f.....f."
+ /* 5 */ ".efffffe."
+ /* 6 */ "........."
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".ehfifhe."
+ /* 2 */ ".h.....h."
+ /* 3 */ ".h.....h."
+ /* 4 */ ".h.....h."
+ /* 5 */ ".ehhfhhe."
+ /* 6 */ "........."
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "jjjjjjjjj"
+ /* 1 */ "kefffffek"
+ /* 2 */ ".f.l.l.f."
+ /* 3 */ ".f.....f."
+ /* 4 */ ".f.....f."
+ /* 5 */ "nefffffen"
+ /* 6 */ "ooooooooo"
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "jjjjjjjjj"
+ /* 2 */ "kfffffffk"
+ /* 3 */ ".f.....f."
+ /* 4 */ "nfffffffn"
+ /* 5 */ "ooooooooo"
+ /* 6 */ "........."
+
+ // Level 6
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "jjjjjjjjj"
+ /* 3 */ "fffffffff"
+ /* 4 */ "ooooooooo"
+ /* 5 */ "........."
+ /* 6 */ ".........",
+
+ // Connectors:
+ "-1: 4, 1, -1: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse7x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse9x5:
+ // The data has been exported from the gallery Plains, area index 41, ID 92, created by xoft
+ {
+ // Size:
+ 11, 7, 7, // SizeX = 11, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 11, 6, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h:102: 0\n" /* glasspane */
+ "i: 64:12\n" /* wooddoorblock */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 7\n" /* woodstairs */
+ "l: 50: 3\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 6\n" /* woodstairs */
+ "o: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....bcd...."
+ /* 1 */ ".aaaaaaaaa."
+ /* 2 */ ".aaaaaaaaa."
+ /* 3 */ ".aaaaaaaaa."
+ /* 4 */ ".aaaaaaaaa."
+ /* 5 */ ".aaaaaaaaa."
+ /* 6 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".efffgfffe."
+ /* 2 */ ".f.......f."
+ /* 3 */ ".f.......f."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".efffffffe."
+ /* 6 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ehhfifhhe."
+ /* 2 */ ".h.......h."
+ /* 3 */ ".h.......h."
+ /* 4 */ ".h.......h."
+ /* 5 */ ".ehhhfhhhe."
+ /* 6 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "jjjjjjjjjjj"
+ /* 1 */ "kfffffffffk"
+ /* 2 */ ".f..l.l.ff."
+ /* 3 */ ".f......ff."
+ /* 4 */ ".f......ff."
+ /* 5 */ "nfffffffffn"
+ /* 6 */ "ooooooooooo"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "jjjjjjjjjjj"
+ /* 2 */ "kfffffffffk"
+ /* 3 */ ".fffffffff."
+ /* 4 */ "nfffffffffn"
+ /* 5 */ "ooooooooooo"
+ /* 6 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "jjjjjjjjjjj"
+ /* 3 */ "fffffffffff"
+ /* 4 */ "ooooooooooo"
+ /* 5 */ "..........."
+ /* 6 */ "...........",
+
+ // Connectors:
+ "-1: 5, 1, -1: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse9x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse9x5Fence:
+ // The data has been exported from the gallery Plains, area index 9, ID 26, created by Aloe_vera
+ {
+ // Size:
+ 10, 7, 11, // SizeX = 10, SizeY = 7, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ 0, -1, -1, // MinX, MinY, MinZ
+ 10, 6, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 3: 0\n" /* dirt */
+ "c: 5: 0\n" /* wood */
+ "d: 2: 0\n" /* grass */
+ "e: 67: 2\n" /* stairs */
+ "f: 43: 0\n" /* doubleslab */
+ "g: 67: 0\n" /* stairs */
+ "h: 67: 3\n" /* stairs */
+ "i: 17: 0\n" /* tree */
+ "j: 53: 1\n" /* woodstairs */
+ "k: 85: 0\n" /* fence */
+ "l: 53: 0\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 64: 6\n" /* wooddoorblock */
+ "o: 64: 4\n" /* wooddoorblock */
+ "p:102: 0\n" /* glasspane */
+ "q: 72: 0\n" /* woodplate */
+ "r: 64:12\n" /* wooddoorblock */
+ "s: 53: 5\n" /* woodstairs */
+ "t: 53: 4\n" /* woodstairs */
+ "u: 50: 1\n" /* torch */
+ "v: 50: 2\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".aaaaa...."
+ /* 2 */ ".aaaaa...."
+ /* 3 */ ".aaaaabbbb"
+ /* 4 */ "aaaaaabbbb"
+ /* 5 */ "aaaaaabbbb"
+ /* 6 */ "aaaaaabbbb"
+ /* 7 */ ".aaaaabbbb"
+ /* 8 */ ".aaaaabbbb"
+ /* 9 */ ".aaaaa...."
+ /* 10 */ ".........."
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "......mmmm"
+ /* 1 */ ".aaaaammmm"
+ /* 2 */ ".acccammmm"
+ /* 3 */ ".acccadddd"
+ /* 4 */ "eafffadddd"
+ /* 5 */ "gaffffdddd"
+ /* 6 */ "hafffadddd"
+ /* 7 */ ".afffadddd"
+ /* 8 */ ".afffadddd"
+ /* 9 */ ".aaaaammmm"
+ /* 10 */ "......mmmm"
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "......mmmm"
+ /* 1 */ ".icccimmmm"
+ /* 2 */ ".cjklcmmmm"
+ /* 3 */ ".c...ckkkk"
+ /* 4 */ ".c...c...k"
+ /* 5 */ ".n...o...k"
+ /* 6 */ ".c...c...k"
+ /* 7 */ ".cff.c...k"
+ /* 8 */ ".c...ckkkk"
+ /* 9 */ ".icccimmmm"
+ /* 10 */ "......mmmm"
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "......mmmm"
+ /* 1 */ ".ipppimmmm"
+ /* 2 */ ".p.q.pmmmm"
+ /* 3 */ ".p...p...."
+ /* 4 */ ".c...c...."
+ /* 5 */ ".r...r...."
+ /* 6 */ ".c...c...."
+ /* 7 */ ".p...p...."
+ /* 8 */ ".p...p...."
+ /* 9 */ ".ipppimmmm"
+ /* 10 */ "......mmmm"
+
+ // Level 4
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "ls...tjmmm"
+ /* 1 */ "licccijmmm"
+ /* 2 */ "lc...cjmmm"
+ /* 3 */ "lc...cj..."
+ /* 4 */ "lcu.vcj..."
+ /* 5 */ "lc...cj..."
+ /* 6 */ "lcu.vcj..."
+ /* 7 */ "lc...cj..."
+ /* 8 */ "lc...cj..."
+ /* 9 */ "licccijmmm"
+ /* 10 */ "ls...tjmmm"
+
+ // Level 5
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mls.tjmmmm"
+ /* 1 */ "mlcccjmmmm"
+ /* 2 */ "mlc.cjmmmm"
+ /* 3 */ "mlc.cjm..."
+ /* 4 */ "mlc.cjm..."
+ /* 5 */ "mlc.cjm..."
+ /* 6 */ "mlc.cjm..."
+ /* 7 */ "mlc.cjm..."
+ /* 8 */ "mlc.cjm..."
+ /* 9 */ "mlcccjmmmm"
+ /* 10 */ "mls.tjmmmm"
+
+ // Level 6
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "mmlcjmmmmm"
+ /* 1 */ "mmlcjmmmmm"
+ /* 2 */ "mmlcjmmmmm"
+ /* 3 */ "mmlcjmm..."
+ /* 4 */ "mmlcjmm..."
+ /* 5 */ "mmlcjmm..."
+ /* 6 */ "mmlcjmm..."
+ /* 7 */ "mmlcjmm..."
+ /* 8 */ "mmlcjmm..."
+ /* 9 */ "mmlcjmmmmm"
+ /* 10 */ "mmlcjmmmmm",
+
+ // Connectors:
+ "-1: 0, 1, 5: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse9x5Fence
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse9x5Library:
+ // The data has been exported from the gallery Plains, area index 46, ID 97, created by Aloe_vera
+ {
+ // Size:
+ 11, 7, 7, // SizeX = 11, SizeY = 7, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 11, 6, 7, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h: 53: 3\n" /* woodstairs */
+ "i: 85: 0\n" /* fence */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 1\n" /* woodstairs */
+ "l: 53: 0\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n:102: 0\n" /* glasspane */
+ "o: 64:12\n" /* wooddoorblock */
+ "p: 50: 3\n" /* torch */
+ "q: 72: 0\n" /* woodplate */
+ "r: 53: 7\n" /* woodstairs */
+ "s: 47: 0\n" /* bookshelf */
+ "t: 50: 1\n" /* torch */
+ "u: 50: 2\n" /* torch */
+ "v: 53: 6\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....bcd...."
+ /* 1 */ ".aaaaaaaaa."
+ /* 2 */ ".aaaaaaaaa."
+ /* 3 */ ".aaaaaaaaa."
+ /* 4 */ ".aaaaaaaaa."
+ /* 5 */ ".aaaaaaaaa."
+ /* 6 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".efffgfffe."
+ /* 2 */ ".fh.....hf."
+ /* 3 */ ".fi.....if."
+ /* 4 */ ".fj.kil.jf."
+ /* 5 */ ".efffffffe."
+ /* 6 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ennfofnne."
+ /* 2 */ ".n..p.p..n."
+ /* 3 */ ".nq.....qn."
+ /* 4 */ ".n...q...n."
+ /* 5 */ ".ennnfnnne."
+ /* 6 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "jjjjjjjjjjj"
+ /* 1 */ "rfffffffffr"
+ /* 2 */ ".fsssssssf."
+ /* 3 */ ".ft.....uf."
+ /* 4 */ ".fsssssssf."
+ /* 5 */ "vfffffffffv"
+ /* 6 */ "hhhhhhhhhhh"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "jjjjjjjjjjj"
+ /* 2 */ "rfffffffffr"
+ /* 3 */ ".f.......f."
+ /* 4 */ "vfffffffffv"
+ /* 5 */ "hhhhhhhhhhh"
+ /* 6 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "jjjjjjjjjjj"
+ /* 3 */ "fffffffffff"
+ /* 4 */ "hhhhhhhhhhh"
+ /* 5 */ "..........."
+ /* 6 */ "...........",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse9x5Library
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse9x7:
+ // The data has been exported from the gallery Plains, area index 52, ID 103, created by Aloe_vera
+ {
+ // Size:
+ 11, 8, 9, // SizeX = 11, SizeY = 8, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 11, 7, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h:102: 0\n" /* glasspane */
+ "i: 64:12\n" /* wooddoorblock */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 7\n" /* woodstairs */
+ "l: 50: 3\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 4\n" /* torch */
+ "o: 53: 6\n" /* woodstairs */
+ "p: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "maaaaaaaaam"
+ /* 7 */ "maaaaaaaaam"
+ /* 8 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....bcd...."
+ /* 1 */ ".aaaaaaaaa."
+ /* 2 */ ".aaaaaaaaa."
+ /* 3 */ ".aaaaaaaaa."
+ /* 4 */ ".aaaaaaaaa."
+ /* 5 */ ".aaaaaaaaa."
+ /* 6 */ ".aaaaaaaaa."
+ /* 7 */ ".aaaaaaaaa."
+ /* 8 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".efffgfffe."
+ /* 2 */ ".f.......f."
+ /* 3 */ ".f.......f."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".f.......f."
+ /* 6 */ ".f.......f."
+ /* 7 */ ".efffffffe."
+ /* 8 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ehhfifhhe."
+ /* 2 */ ".h.......h."
+ /* 3 */ ".h.......h."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".h.......h."
+ /* 6 */ ".h.......h."
+ /* 7 */ ".ehhhfhhhe."
+ /* 8 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "jjjjjjjjjjj"
+ /* 1 */ "kfffffffffk"
+ /* 2 */ ".f..l.l..f."
+ /* 3 */ ".f.......f."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".f.......f."
+ /* 6 */ ".f...n...f."
+ /* 7 */ "offfffffffo"
+ /* 8 */ "ppppppppppp"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "jjjjjjjjjjj"
+ /* 2 */ "kfffffffffk"
+ /* 3 */ ".f.......f."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".f.......f."
+ /* 6 */ "offfffffffo"
+ /* 7 */ "ppppppppppp"
+ /* 8 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "jjjjjjjjjjj"
+ /* 3 */ "kfffffffffk"
+ /* 4 */ ".f.......f."
+ /* 5 */ "offfffffffo"
+ /* 6 */ "ppppppppppp"
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "jjjjjjjjjjj"
+ /* 4 */ "fffffffffff"
+ /* 5 */ "ppppppppppp"
+ /* 6 */ "..........."
+ /* 7 */ "..........."
+ /* 8 */ "...........",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse9x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse9x7Butcher:
+ // The data has been exported from the gallery Plains, area index 48, ID 99, created by Aloe_vera
+ {
+ // Size:
+ 11, 9, 13, // SizeX = 11, SizeY = 9, SizeZ = 13
+
+ // Hitbox (relative to bounding box):
+ -1, 0, 0, // MinX, MinY, MinZ
+ 11, 8, 13, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 2: 0\n" /* grass */
+ "b: 3: 0\n" /* dirt */
+ "c: 4: 0\n" /* cobblestone */
+ "d: 67: 0\n" /* stairs */
+ "e: 67: 2\n" /* stairs */
+ "f: 67: 1\n" /* stairs */
+ "g: 43: 0\n" /* doubleslab */
+ "h: 17: 0\n" /* tree */
+ "i: 5: 0\n" /* wood */
+ "j: 64: 7\n" /* wooddoorblock */
+ "k: 53: 3\n" /* woodstairs */
+ "l: 85: 0\n" /* fence */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 2\n" /* woodstairs */
+ "o:102: 0\n" /* glasspane */
+ "p: 64:12\n" /* wooddoorblock */
+ "q: 72: 0\n" /* woodplate */
+ "r: 53: 7\n" /* woodstairs */
+ "s: 50: 1\n" /* torch */
+ "t: 50: 2\n" /* torch */
+ "u: 53: 6\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "aaabbbbaaaa"
+ /* 1 */ "abbbbbbbbba"
+ /* 2 */ "abbbbbbbbba"
+ /* 3 */ "abbbbbbbbba"
+ /* 4 */ "abbbbbbbbba"
+ /* 5 */ "abbbbbbbbba"
+ /* 6 */ "abbbbbbbbba"
+ /* 7 */ "abbbbbbbbba"
+ /* 8 */ "aabbbbbbbaa"
+ /* 9 */ "aabbbbbbbaa"
+ /* 10 */ "aabbbbbbbaa"
+ /* 11 */ "aabbbbbbbaa"
+ /* 12 */ "aabbbbbbbaa"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmcccmmmm"
+ /* 1 */ "mcccccccccm"
+ /* 2 */ "mcccccccccm"
+ /* 3 */ "mcccccccccm"
+ /* 4 */ "mcccccccccm"
+ /* 5 */ "mcccccccccm"
+ /* 6 */ "mcccccccccm"
+ /* 7 */ "mcccccccccm"
+ /* 8 */ "mmbbbbbbbmm"
+ /* 9 */ "mmbbbbbbbmm"
+ /* 10 */ "mmbbbbbbbmm"
+ /* 11 */ "mmbbbbbbbmm"
+ /* 12 */ "mmbbbbbbbmm"
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....def...."
+ /* 1 */ ".ccccccccc."
+ /* 2 */ ".cggggcccc."
+ /* 3 */ ".cggggcccc."
+ /* 4 */ ".cggggcccc."
+ /* 5 */ ".cggggcccc."
+ /* 6 */ ".cggggcccc."
+ /* 7 */ ".ccccccccc."
+ /* 8 */ "..aaaaaaa.."
+ /* 9 */ "..aaaaaaa.."
+ /* 10 */ "..aaaaaaa.."
+ /* 11 */ "..aaaaaaa.."
+ /* 12 */ "..aaaaaaa.."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".hiiijiiih."
+ /* 2 */ ".i.g....ki."
+ /* 3 */ ".i.g....li."
+ /* 4 */ ".i.g....ni."
+ /* 5 */ ".i.......i."
+ /* 6 */ ".i.......i."
+ /* 7 */ ".hiiijiiih."
+ /* 8 */ "..l.....l.."
+ /* 9 */ "..l.....l.."
+ /* 10 */ "..l.....l.."
+ /* 11 */ "..l.....l.."
+ /* 12 */ "..lllllll.."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".hooipiooh."
+ /* 2 */ ".o.......o."
+ /* 3 */ ".o......qo."
+ /* 4 */ ".i.......i."
+ /* 5 */ ".o.......o."
+ /* 6 */ ".o.......o."
+ /* 7 */ ".hooipiooh."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+ /* 11 */ "..........."
+ /* 12 */ "..........."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "nnnnnnnnnnn"
+ /* 1 */ "riiiiiiiiir"
+ /* 2 */ ".i.......i."
+ /* 3 */ ".i.......i."
+ /* 4 */ ".is.....ti."
+ /* 5 */ ".i.......i."
+ /* 6 */ ".i.......i."
+ /* 7 */ "uiiiiiiiiiu"
+ /* 8 */ "kkkkkkkkkkk"
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+ /* 11 */ "..........."
+ /* 12 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "nnnnnnnnnnn"
+ /* 2 */ "riiiiiiiiir"
+ /* 3 */ ".i.......i."
+ /* 4 */ ".i.......i."
+ /* 5 */ ".i.......i."
+ /* 6 */ "uiiiiiiiiiu"
+ /* 7 */ "kkkkkkkkkkk"
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+ /* 11 */ "..........."
+ /* 12 */ "..........."
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "nnnnnnnnnnn"
+ /* 3 */ "riiiiiiiiir"
+ /* 4 */ ".i.......i."
+ /* 5 */ "uiiiiiiiiiu"
+ /* 6 */ "kkkkkkkkkkk"
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+ /* 11 */ "..........."
+ /* 12 */ "..........."
+
+ // Level 8
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "nnnnnnnnnnn"
+ /* 4 */ "iiiiiiiiiii"
+ /* 5 */ "kkkkkkkkkkk"
+ /* 6 */ "..........."
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+ /* 9 */ "..........."
+ /* 10 */ "..........."
+ /* 11 */ "..........."
+ /* 12 */ "...........",
+
+ // Connectors:
+ "-1: 5, 2, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse9x7Butcher
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouse9x7DoubleDoor:
+ // The data has been exported from the gallery Plains, area index 38, ID 87, created by Aloe_vera
+ {
+ // Size:
+ 11, 8, 9, // SizeX = 11, SizeY = 8, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 11, 7, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 67: 3\n" /* stairs */
+ "f: 17: 0\n" /* tree */
+ "g: 5: 0\n" /* wood */
+ "h: 64: 7\n" /* wooddoorblock */
+ "i:102: 0\n" /* glasspane */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 53: 2\n" /* woodstairs */
+ "l: 53: 7\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 17: 4\n" /* tree */
+ "o: 17: 8\n" /* tree */
+ "p: 50: 3\n" /* torch */
+ "q: 50: 4\n" /* torch */
+ "r: 53: 6\n" /* woodstairs */
+ "s: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "maaaaaaaaam"
+ /* 7 */ "maaaaaaaaam"
+ /* 8 */ "mmmmaaammmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....bcd...."
+ /* 1 */ ".aaaaaaaaa."
+ /* 2 */ ".aaaaaaaaa."
+ /* 3 */ ".aaaaaaaaa."
+ /* 4 */ ".aaaaaaaaa."
+ /* 5 */ ".aaaaaaaaa."
+ /* 6 */ ".aaaaaaaaa."
+ /* 7 */ ".aaaaaaaaa."
+ /* 8 */ "....bed...."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".fggfhfggf."
+ /* 2 */ ".g.......g."
+ /* 3 */ ".g.......g."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".g.......g."
+ /* 6 */ ".g.......g."
+ /* 7 */ ".fggfhfggf."
+ /* 8 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".fiifjfiif."
+ /* 2 */ ".i.......i."
+ /* 3 */ ".i.......i."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".i.......i."
+ /* 6 */ ".i.......i."
+ /* 7 */ ".fiifjfiif."
+ /* 8 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "kkkkkkkkkkk"
+ /* 1 */ "lfnnnnnnnfl"
+ /* 2 */ ".o..p.p..o."
+ /* 3 */ ".o.......o."
+ /* 4 */ ".o.......o."
+ /* 5 */ ".o.......o."
+ /* 6 */ ".o..q.q..o."
+ /* 7 */ "rfnnnnnnnfr"
+ /* 8 */ "sssssssssss"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "kkkkkkkkkkk"
+ /* 2 */ "lgggggggggl"
+ /* 3 */ ".g.......g."
+ /* 4 */ ".g.......g."
+ /* 5 */ ".g.......g."
+ /* 6 */ "rgggggggggr"
+ /* 7 */ "sssssssssss"
+ /* 8 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "kkkkkkkkkkk"
+ /* 3 */ "lgggggggggl"
+ /* 4 */ ".g.......g."
+ /* 5 */ "rgggggggggr"
+ /* 6 */ "sssssssssss"
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+
+ // Level 7
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "kkkkkkkkkkk"
+ /* 4 */ "ggggggggggg"
+ /* 5 */ "sssssssssss"
+ /* 6 */ "..........."
+ /* 7 */ "..........."
+ /* 8 */ "...........",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouse9x7DoubleDoor
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouseL13x14:
+ // The data has been exported from the gallery Plains, area index 39, ID 90, created by STR_Warrior
+ {
+ // Size:
+ 15, 9, 16, // SizeX = 15, SizeY = 9, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 15, 8, 16, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "A: 53: 7\n" /* woodstairs */
+ "B: 53: 4\n" /* woodstairs */
+ "C: 53: 5\n" /* woodstairs */
+ "D: 53: 6\n" /* woodstairs */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 43: 0\n" /* doubleslab */
+ "f: 17: 0\n" /* tree */
+ "g: 5: 0\n" /* wood */
+ "h: 64: 7\n" /* wooddoorblock */
+ "i: 96: 8\n" /* trapdoor */
+ "j: 61: 2\n" /* furnace */
+ "k: 53: 3\n" /* woodstairs */
+ "l: 85: 0\n" /* fence */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 2\n" /* woodstairs */
+ "o: 53: 1\n" /* woodstairs */
+ "p: 53: 0\n" /* woodstairs */
+ "q: 47: 0\n" /* bookshelf */
+ "r:102: 0\n" /* glasspane */
+ "s: 64:12\n" /* wooddoorblock */
+ "t: 72: 0\n" /* woodplate */
+ "u: 17: 4\n" /* tree */
+ "v: 17: 8\n" /* tree */
+ "w: 50: 3\n" /* torch */
+ "x: 50: 1\n" /* torch */
+ "y: 50: 4\n" /* torch */
+ "z: 50: 2\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "maaaaaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaaaaam"
+ /* 6 */ "maaaaaaaaaaaaam"
+ /* 7 */ "maaaaaaaaaaaaam"
+ /* 8 */ "mmmmmmmmaaaaaam"
+ /* 9 */ "mmmmmmmmaaaaaam"
+ /* 10 */ "mmmmmmmmaaaaaam"
+ /* 11 */ "mmmmmmmmaaaaaam"
+ /* 12 */ "mmmmmmmmaaaaaam"
+ /* 13 */ "mmmmmmmmaaaaaam"
+ /* 14 */ "mmmmmmmmaaaaaam"
+ /* 15 */ "mmmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "......bcd......"
+ /* 1 */ ".aaaaaaaaaaaaa."
+ /* 2 */ ".aeeeeaaaaaaaa."
+ /* 3 */ ".aeeeeaaaaaaaa."
+ /* 4 */ ".aaaaaaaaaaaaa."
+ /* 5 */ ".aaaaaaaaaaaaa."
+ /* 6 */ ".aaaaaaaaaaaaa."
+ /* 7 */ ".aaaaaaaaaaaaa."
+ /* 8 */ "........aaaaaa."
+ /* 9 */ "mmmmmmm.aaaaaa."
+ /* 10 */ "mmmmmmm.aaaaaa."
+ /* 11 */ "mmmmmmm.aaaaaa."
+ /* 12 */ "mmmmmmm.aaaaaa."
+ /* 13 */ "mmmmmmm.aaaaaa."
+ /* 14 */ "mmmmmmm.aaaaaa."
+ /* 15 */ "mmmmmmm........"
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".fggggfhfggggf."
+ /* 2 */ ".g...i.......g."
+ /* 3 */ ".gjeee......kg."
+ /* 4 */ ".f..........lg."
+ /* 5 */ ".g..........ng."
+ /* 6 */ ".g.olp..ol...g."
+ /* 7 */ ".fggggggfn...f."
+ /* 8 */ "........g....g."
+ /* 9 */ "mmmmmmm.gk...g."
+ /* 10 */ "mmmmmmm.gl..kg."
+ /* 11 */ "mmmmmmm.gn..lg."
+ /* 12 */ "mmmmmmm.g...ng."
+ /* 13 */ "mmmmmmm.gq..qg."
+ /* 14 */ "mmmmmmm.fggggf."
+ /* 15 */ "mmmmmmm........"
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".fgrrgfsfgrrgf."
+ /* 2 */ ".g...........g."
+ /* 3 */ ".g...........r."
+ /* 4 */ ".f..........tr."
+ /* 5 */ ".g...........r."
+ /* 6 */ ".g..t....t...g."
+ /* 7 */ ".fgrrrrgf....f."
+ /* 8 */ "........g....g."
+ /* 9 */ "mmmmmmm.r....r."
+ /* 10 */ "mmmmmmm.rt...r."
+ /* 11 */ "mmmmmmm.r...tr."
+ /* 12 */ "mmmmmmm.r....r."
+ /* 13 */ "mmmmmmm.gq..qg."
+ /* 14 */ "mmmmmmm.fgrrgf."
+ /* 15 */ "mmmmmmm........"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".fuuuuuuuuuuuf."
+ /* 2 */ ".v....w.w....v."
+ /* 3 */ ".v...........v."
+ /* 4 */ ".vx..........v."
+ /* 5 */ ".v...........v."
+ /* 6 */ ".v......y....v."
+ /* 7 */ ".fuuuuuufx..zv."
+ /* 8 */ "........v....v."
+ /* 9 */ "mmmmmmm.v....v."
+ /* 10 */ "mmmmmmm.v....v."
+ /* 11 */ "mmmmmmm.v....v."
+ /* 12 */ "mmmmmmm.v....v."
+ /* 13 */ "mmmmmmm.v.yy.v."
+ /* 14 */ "mmmmmmm.fuuuuf."
+ /* 15 */ "mmmmmmm........"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "nnnnnnnnnnnnnno"
+ /* 1 */ "pgggggggggggggo"
+ /* 2 */ "pgAAAAAAAAAABgo"
+ /* 3 */ "pgC.........Bgo"
+ /* 4 */ "pgC.........Bgo"
+ /* 5 */ "pgC.........Bgo"
+ /* 6 */ "pgCDDDDDDD..Bgo"
+ /* 7 */ "pggggggggC..Bgo"
+ /* 8 */ "pkkkkkkpgC..Bgo"
+ /* 9 */ "mmmmmmmpgC..Bgo"
+ /* 10 */ "mmmmmmmpgC..Bgo"
+ /* 11 */ "mmmmmmmpgC..Bgo"
+ /* 12 */ "mmmmmmmpgC..Bgo"
+ /* 13 */ "mmmmmmmpgCDDBgo"
+ /* 14 */ "mmmmmmmpggggggo"
+ /* 15 */ "mmmmmmmpkkkkkkk"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".pnnnnnnnnnnno."
+ /* 2 */ ".pgggggggggggo."
+ /* 3 */ ".pgggggggggggo."
+ /* 4 */ ".pgggggggggggo."
+ /* 5 */ ".pgggggggggggo."
+ /* 6 */ ".pgggggggggggo."
+ /* 7 */ ".pkkkkkkkggggo."
+ /* 8 */ "........pggggo."
+ /* 9 */ "mmmmmmm.pggggo."
+ /* 10 */ "mmmmmmm.pggggo."
+ /* 11 */ "mmmmmmm.pggggo."
+ /* 12 */ "mmmmmmm.pggggo."
+ /* 13 */ "mmmmmmm.pggggo."
+ /* 14 */ "mmmmmmm.kkkkko."
+ /* 15 */ "mmmmmmm........"
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..nnnnnnnnnnn.."
+ /* 3 */ "..pgggggggggo.."
+ /* 4 */ "..pgggggggggo.."
+ /* 5 */ "..pgggggggggo.."
+ /* 6 */ "..kkkkkkkkggo.."
+ /* 7 */ ".........pggo.."
+ /* 8 */ ".........pggo.."
+ /* 9 */ "mmmmmmm..pggo.."
+ /* 10 */ "mmmmmmm..pggo.."
+ /* 11 */ "mmmmmmm..pggo.."
+ /* 12 */ "mmmmmmm..pggo.."
+ /* 13 */ "mmmmmmm..kkko.."
+ /* 14 */ "mmmmmmm........"
+ /* 15 */ "mmmmmmm........"
+
+ // Level 8
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "...pnnnnnnno..."
+ /* 4 */ "...pgggggggo..."
+ /* 5 */ "...pkkkkkkpo..."
+ /* 6 */ "..........po..."
+ /* 7 */ "..........po..."
+ /* 8 */ "..........po..."
+ /* 9 */ "mmmmmmm...po..."
+ /* 10 */ "mmmmmmm...po..."
+ /* 11 */ "mmmmmmm...po..."
+ /* 12 */ "mmmmmmm...pk..."
+ /* 13 */ "mmmmmmm........"
+ /* 14 */ "mmmmmmm........"
+ /* 15 */ "mmmmmmm........",
+
+ // Connectors:
+ "-1: 7, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouseL13x14
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouseL14x14:
+ // The data has been exported from the gallery Plains, area index 0, ID 4, created by Aloe_vera
+ {
+ // Size:
+ 16, 8, 16, // SizeX = 16, SizeY = 8, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ -1, 1, 0, // MinX, MinY, MinZ
+ 16, 7, 16, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 2: 0\n" /* grass */
+ "c: 67: 0\n" /* stairs */
+ "d: 67: 2\n" /* stairs */
+ "e: 67: 1\n" /* stairs */
+ "f: 5: 0\n" /* wood */
+ "g: 67: 3\n" /* stairs */
+ "h: 17: 0\n" /* tree */
+ "i: 64: 7\n" /* wooddoorblock */
+ "j: 64: 5\n" /* wooddoorblock */
+ "k:102: 0\n" /* glasspane */
+ "l: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 2\n" /* woodstairs */
+ "o: 53: 1\n" /* woodstairs */
+ "p: 53: 7\n" /* woodstairs */
+ "q: 53: 6\n" /* woodstairs */
+ "r: 53: 3\n" /* woodstairs */
+ "s: 53: 0\n" /* woodstairs */
+ "t: 53: 5\n" /* woodstairs */
+ "u: 53: 4\n" /* woodstairs */
+ "v: 50: 3\n" /* torch */
+ "w: 50: 2\n" /* torch */
+ "x: 50: 4\n" /* torch */
+ "y: 50: 1\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "mmmmmmmmaaammmmm"
+ /* 1 */ "maaaaaaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaaaaaam"
+ /* 6 */ "maaaaaaaaaaaaaam"
+ /* 7 */ "maaaaaaaaaaaaaam"
+ /* 8 */ "bbbbbaaaaaaaaaam"
+ /* 9 */ "bbbbbbbbaaaaaaam"
+ /* 10 */ "bbbbbbbbaaaaaaam"
+ /* 11 */ "bbbbbbbbaaaaaaam"
+ /* 12 */ "bbbbbbbbaaaaaaam"
+ /* 13 */ "bbbbbbbbaaaaaaam"
+ /* 14 */ "bbbbbbbbaaaaaaam"
+ /* 15 */ "bbbbbbbbmmmmmmmm"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "........cde....."
+ /* 1 */ ".aaaaaaaaaaaaaa."
+ /* 2 */ ".affffffffffffa."
+ /* 3 */ ".affffffffffffa."
+ /* 4 */ ".affffffffffffa."
+ /* 5 */ ".affffffffffffa."
+ /* 6 */ ".affffffffffffa."
+ /* 7 */ ".aaaaaaaafffffa."
+ /* 8 */ ".....cgeafffffa."
+ /* 9 */ "........afffffa."
+ /* 10 */ "........afffffa."
+ /* 11 */ "........afffffa."
+ /* 12 */ "........afffffa."
+ /* 13 */ "........afffffa."
+ /* 14 */ "........aaaaaaa."
+ /* 15 */ "................"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".hffffffhihfffh."
+ /* 2 */ ".f............f."
+ /* 3 */ ".f............f."
+ /* 4 */ ".f............f."
+ /* 5 */ ".f............f."
+ /* 6 */ ".f............f."
+ /* 7 */ ".hffffjfh.....f."
+ /* 8 */ "........f.....f."
+ /* 9 */ "........f.....f."
+ /* 10 */ "........f.....f."
+ /* 11 */ "........f.....f."
+ /* 12 */ "........f.....f."
+ /* 13 */ "........f.....f."
+ /* 14 */ "........hfffffh."
+ /* 15 */ "................"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".hfkkfkkhlhkkfh."
+ /* 2 */ ".k............f."
+ /* 3 */ ".k............k."
+ /* 4 */ ".k............k."
+ /* 5 */ ".k............f."
+ /* 6 */ ".k............k."
+ /* 7 */ ".hfkkflfh.....k."
+ /* 8 */ "........f.....f."
+ /* 9 */ "........k.....k."
+ /* 10 */ "........k.....k."
+ /* 11 */ "........f.....f."
+ /* 12 */ "........k.....k."
+ /* 13 */ "........k.....k."
+ /* 14 */ "........hkkkkkh."
+ /* 15 */ "................"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "nnnnnnnnnnnnnnno"
+ /* 1 */ "phffffffhfhfffho"
+ /* 2 */ ".f............fo"
+ /* 3 */ ".f............fo"
+ /* 4 */ ".f............fo"
+ /* 5 */ ".f............fo"
+ /* 6 */ ".f............fo"
+ /* 7 */ "qhffffffh.....fo"
+ /* 8 */ "rrrrrrrsf.....fo"
+ /* 9 */ ".......sf.....fo"
+ /* 10 */ ".......sf.....fo"
+ /* 11 */ ".......sf.....fo"
+ /* 12 */ ".......sf.....fo"
+ /* 13 */ ".......sf.....fo"
+ /* 14 */ ".......shfffffho"
+ /* 15 */ ".......st.....uo"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "nnnnnnnnnnnnnnn."
+ /* 2 */ "pfffffffffffffo."
+ /* 3 */ ".f.........v.fo."
+ /* 4 */ ".f..........wfo."
+ /* 5 */ ".f......x....fo."
+ /* 6 */ "qfffffffff...fo."
+ /* 7 */ "rrrrrrrrsfy..fo."
+ /* 8 */ "........sf...fo."
+ /* 9 */ "........sf...fo."
+ /* 10 */ "........sf...fo."
+ /* 11 */ "........sf...fo."
+ /* 12 */ "........sf...fo."
+ /* 13 */ "........sf...fo."
+ /* 14 */ "........sfffffo."
+ /* 15 */ "........st...uo."
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "nnnnnnnnnnnnno.."
+ /* 3 */ "pffffffffffffo.."
+ /* 4 */ ".fy.........fo.."
+ /* 5 */ "qffffffffff.fo.."
+ /* 6 */ "rrrrrrrrrsf.fo.."
+ /* 7 */ ".........sf.fo.."
+ /* 8 */ ".........sf.fo.."
+ /* 9 */ ".........sf.fo.."
+ /* 10 */ ".........sf.fo.."
+ /* 11 */ ".........sf.fo.."
+ /* 12 */ ".........sf.fo.."
+ /* 13 */ ".........sfxfo.."
+ /* 14 */ ".........sfffo.."
+ /* 15 */ ".........st.uo.."
+
+ // Level 7
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "nnnnnnnnnnnnn..."
+ /* 4 */ "ffffffffffffo..."
+ /* 5 */ "rrrrrrrrrrsfo..."
+ /* 6 */ "..........sfo..."
+ /* 7 */ "..........sfo..."
+ /* 8 */ "..........sfo..."
+ /* 9 */ "..........sfo..."
+ /* 10 */ "..........sfo..."
+ /* 11 */ "..........sfo..."
+ /* 12 */ "..........sfo..."
+ /* 13 */ "..........sfo..."
+ /* 14 */ "..........sfo..."
+ /* 15 */ "..........sfo...",
+
+ // Connectors:
+ "-1: 9, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouseL14x14
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouseL9x9:
+ // The data has been exported from the gallery Plains, area index 42, ID 93, created by xoft
+ {
+ // Size:
+ 11, 7, 11, // SizeX = 11, SizeY = 7, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 11, 6, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h:102: 0\n" /* glasspane */
+ "i: 64:12\n" /* wooddoorblock */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 7\n" /* woodstairs */
+ "l: 53: 1\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 3\n" /* torch */
+ "o: 50: 4\n" /* torch */
+ "p: 53: 6\n" /* woodstairs */
+ "q: 50: 1\n" /* torch */
+ "r: 50: 2\n" /* torch */
+ "s: 53: 3\n" /* woodstairs */
+ "t: 53: 0\n" /* woodstairs */
+ "u: 53: 5\n" /* woodstairs */
+ "v: 53: 4\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "mmmmaaammmm"
+ /* 1 */ "maaaaaaaaam"
+ /* 2 */ "maaaaaaaaam"
+ /* 3 */ "maaaaaaaaam"
+ /* 4 */ "maaaaaaaaam"
+ /* 5 */ "maaaaaaaaam"
+ /* 6 */ "mmmmmaaaaam"
+ /* 7 */ "mmmmmaaaaam"
+ /* 8 */ "mmmmmaaaaam"
+ /* 9 */ "mmmmmaaaaam"
+ /* 10 */ "mmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....bcd...."
+ /* 1 */ ".aaaaaaaaa."
+ /* 2 */ ".aaaaaaaaa."
+ /* 3 */ ".aaaaaaaaa."
+ /* 4 */ ".aaaaaaaaa."
+ /* 5 */ ".aaaaaaaaa."
+ /* 6 */ ".....aaaaa."
+ /* 7 */ ".....aaaaa."
+ /* 8 */ ".....aaaaa."
+ /* 9 */ ".....aaaaa."
+ /* 10 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".efffgfffe."
+ /* 2 */ ".f.......f."
+ /* 3 */ ".f.......f."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".efffe...f."
+ /* 6 */ ".....f...f."
+ /* 7 */ ".....f...f."
+ /* 8 */ ".....f...f."
+ /* 9 */ ".....efffe."
+ /* 10 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ehhfifhhe."
+ /* 2 */ ".h.......h."
+ /* 3 */ ".h.......h."
+ /* 4 */ ".h.......h."
+ /* 5 */ ".ehhhe...f."
+ /* 6 */ ".....h...h."
+ /* 7 */ ".....h...h."
+ /* 8 */ ".....h...h."
+ /* 9 */ ".....ehhhe."
+ /* 10 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "jjjjjjjjjjj"
+ /* 1 */ "kfffffffffl"
+ /* 2 */ ".f..n.n..fl"
+ /* 3 */ ".f.......fl"
+ /* 4 */ ".f...o...fl"
+ /* 5 */ "pfffffq.rfl"
+ /* 6 */ "sssssf...fl"
+ /* 7 */ "....tf...fl"
+ /* 8 */ "....tf...fl"
+ /* 9 */ "....tfffffl"
+ /* 10 */ "....tu...vl"
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "jjjjjjjjjl."
+ /* 2 */ "kffffffffl."
+ /* 3 */ ".f......fl."
+ /* 4 */ "pffffff.fl."
+ /* 5 */ "ssssssf.fl."
+ /* 6 */ ".....tf.fl."
+ /* 7 */ ".....tf.fl."
+ /* 8 */ ".....tf.fl."
+ /* 9 */ ".....tfffl."
+ /* 10 */ ".....tu.vl."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "jjjjjjjjj.."
+ /* 3 */ "ffffffffl.."
+ /* 4 */ "sssssstfl.."
+ /* 5 */ "......tfl.."
+ /* 6 */ "......tfl.."
+ /* 7 */ "......tfl.."
+ /* 8 */ "......tfl.."
+ /* 9 */ "......tfl.."
+ /* 10 */ "......tfl..",
+
+ // Connectors:
+ "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouseL9x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenHouseU13x9:
+ // The data has been exported from the gallery Plains, area index 43, ID 94, created by xoft
+ {
+ // Size:
+ 15, 7, 11, // SizeX = 15, SizeY = 7, SizeZ = 11
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 15, 6, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 64: 7\n" /* wooddoorblock */
+ "h:102: 0\n" /* glasspane */
+ "i: 64:12\n" /* wooddoorblock */
+ "j: 53: 2\n" /* woodstairs */
+ "k: 53: 0\n" /* woodstairs */
+ "l: 53: 1\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 3\n" /* torch */
+ "o: 50: 4\n" /* torch */
+ "p: 50: 2\n" /* torch */
+ "q: 50: 1\n" /* torch */
+ "r: 53: 3\n" /* woodstairs */
+ "s: 53: 5\n" /* woodstairs */
+ "t: 53: 4\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "mmmmmmaaammmmmm"
+ /* 1 */ "maaaaaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaaaaam"
+ /* 6 */ "maaaaammmaaaaam"
+ /* 7 */ "maaaaammmaaaaam"
+ /* 8 */ "maaaaammmaaaaam"
+ /* 9 */ "maaaaammmaaaaam"
+ /* 10 */ "mmmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "......bcd......"
+ /* 1 */ ".aaaaaaaaaaaaa."
+ /* 2 */ ".aaaaaaaaaaaaa."
+ /* 3 */ ".aaaaaaaaaaaaa."
+ /* 4 */ ".aaaaaaaaaaaaa."
+ /* 5 */ ".aaaaaaaaaaaaa."
+ /* 6 */ ".aaaaa...aaaaa."
+ /* 7 */ ".aaaaa...aaaaa."
+ /* 8 */ ".aaaaa...aaaaa."
+ /* 9 */ ".aaaaa...aaaaa."
+ /* 10 */ "..............."
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".efffffgfffffe."
+ /* 2 */ ".f...........f."
+ /* 3 */ ".f...........f."
+ /* 4 */ ".f...........f."
+ /* 5 */ ".f...efffe...f."
+ /* 6 */ ".f...f...f...f."
+ /* 7 */ ".f...f...f...f."
+ /* 8 */ ".f...f...f...f."
+ /* 9 */ ".efffe...efffe."
+ /* 10 */ "..............."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".ehhhhfifhhhhe."
+ /* 2 */ ".h...........h."
+ /* 3 */ ".h...........h."
+ /* 4 */ ".h...........h."
+ /* 5 */ ".f...ehhhe...f."
+ /* 6 */ ".h...h...h...h."
+ /* 7 */ ".h...h...h...h."
+ /* 8 */ ".h...h...h...h."
+ /* 9 */ ".ehhhe...ehhhe."
+ /* 10 */ "..............."
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "jjjjjjjjjjjjjjj"
+ /* 1 */ "kfffffffffffffl"
+ /* 2 */ "kf....n.n....fl"
+ /* 3 */ "kf...........fl"
+ /* 4 */ "kf...o...o...fl"
+ /* 5 */ "kf..pfffffq..fl"
+ /* 6 */ "kf...frrrf...fl"
+ /* 7 */ "kf...fl.kf...fl"
+ /* 8 */ "kf...fl.kf...fl"
+ /* 9 */ "kfffffl.kfffffl"
+ /* 10 */ "ks...tl.ks...tl"
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".jjjjjjjjjjjjl."
+ /* 2 */ ".kfffffffffffl."
+ /* 3 */ ".kfffffffffffl."
+ /* 4 */ ".kfffffffffffl."
+ /* 5 */ ".kffflrrrrfffl."
+ /* 6 */ ".kfffl...kfffl."
+ /* 7 */ ".kfffl...kfffl."
+ /* 8 */ ".kfffl...kfffl."
+ /* 9 */ ".kfffl...kfffl."
+ /* 10 */ ".ks.tl...ks.tl."
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..kjjjjjjjjjj.."
+ /* 3 */ "..kfffffffffl.."
+ /* 4 */ "..kflrrrrrkfl.."
+ /* 5 */ "..kfl.....kfl.."
+ /* 6 */ "..kfl.....kfl.."
+ /* 7 */ "..kfl.....kfl.."
+ /* 8 */ "..kfl.....kfl.."
+ /* 9 */ "..kfl.....kfl.."
+ /* 10 */ "..kfl.....kfl..",
+
+ // Connectors:
+ "-1: 7, 1, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenHouseU13x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenMill5x5:
+ // The data has been exported from the gallery Plains, area index 60, ID 111, created by Aloe_vera
+ {
+ // Size:
+ 9, 17, 13, // SizeX = 9, SizeY = 17, SizeZ = 13
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 8, 16, 12, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 2\n" /* stairs */
+ "c: 67: 1\n" /* stairs */
+ "d: 67: 3\n" /* stairs */
+ "e: 17: 0\n" /* tree */
+ "f: 5: 0\n" /* wood */
+ "g: 54: 4\n" /* chest */
+ "h:154: 4\n" /* hopper */
+ "i: 64: 4\n" /* wooddoorblock */
+ "j:102: 0\n" /* glasspane */
+ "k: 85: 0\n" /* fence */
+ "l: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 2\n" /* torch */
+ "o: 35: 0\n" /* wool */
+ "p: 17: 4\n" /* tree */
+ "q: 17: 8\n" /* tree */
+ "r: 53: 2\n" /* woodstairs */
+ "s: 53: 7\n" /* woodstairs */
+ "t: 53: 6\n" /* woodstairs */
+ "u: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "mmmmmmmmm"
+ /* 1 */ "mmmmmmmmm"
+ /* 2 */ "mmmmmmmmm"
+ /* 3 */ "mmmmmmmmm"
+ /* 4 */ "maaaaammm"
+ /* 5 */ "maaaaaamm"
+ /* 6 */ "maaaaaamm"
+ /* 7 */ "maaaaaamm"
+ /* 8 */ "maaaaammm"
+ /* 9 */ "mmmmmmmmm"
+ /* 10 */ "mmmmmmmmm"
+ /* 11 */ "mmmmmmmmm"
+ /* 12 */ "mmmmmmmmm"
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".aaaaa..."
+ /* 5 */ ".aaaaab.."
+ /* 6 */ ".aaaaac.."
+ /* 7 */ ".aaaaad.."
+ /* 8 */ ".aaaaa..."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".efffe..."
+ /* 5 */ ".f...f..."
+ /* 6 */ ".fgh.i..."
+ /* 7 */ ".f...f..."
+ /* 8 */ ".efffe..."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".ejjje..."
+ /* 5 */ ".j...f..."
+ /* 6 */ ".j.k.l..."
+ /* 7 */ ".j...f..."
+ /* 8 */ ".ejjje..."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".efffe..."
+ /* 5 */ ".f..nf..."
+ /* 6 */ ".f.k.f..."
+ /* 7 */ ".f..nf..k"
+ /* 8 */ ".efffe..o"
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".epppe..."
+ /* 5 */ ".q...q..."
+ /* 6 */ ".q.k.q..."
+ /* 7 */ ".q...q..k"
+ /* 8 */ ".epppe..o"
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 6
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".efffe..."
+ /* 5 */ ".f...f..."
+ /* 6 */ ".f.k.f..k"
+ /* 7 */ ".f...f..o"
+ /* 8 */ ".efffe..o"
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 7
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ ".ejjje..."
+ /* 5 */ ".j...j..."
+ /* 6 */ ".j.k.j..k"
+ /* 7 */ ".j...j..o"
+ /* 8 */ ".ejjje..."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 8
+ /* z\x* 012345678 */
+ /* 0 */ "........o"
+ /* 1 */ "........o"
+ /* 2 */ "........o"
+ /* 3 */ "........."
+ /* 4 */ ".efffe..."
+ /* 5 */ ".f...f..k"
+ /* 6 */ ".f.k.f..o"
+ /* 7 */ ".f...f..o"
+ /* 8 */ ".efffe..."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 9
+ /* z\x* 012345678 */
+ /* 0 */ "........k"
+ /* 1 */ "........k"
+ /* 2 */ "........o"
+ /* 3 */ "........o"
+ /* 4 */ ".epppe..o"
+ /* 5 */ ".q...q..k"
+ /* 6 */ ".q.k.q..o"
+ /* 7 */ ".q...q..k"
+ /* 8 */ ".epppe..k"
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 10
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........k"
+ /* 3 */ "rrrrrrr.k"
+ /* 4 */ "sfffffs.o"
+ /* 5 */ ".f...f..o"
+ /* 6 */ ".f.kppppp"
+ /* 7 */ ".f...f..o"
+ /* 8 */ "tffffft.o"
+ /* 9 */ "uuuuuuu.k"
+ /* 10 */ "........k"
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 11
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ "rrrrrrr.k"
+ /* 5 */ "sfffffs.k"
+ /* 6 */ ".f...f..o"
+ /* 7 */ "tffffft.k"
+ /* 8 */ "uuuuuuu.o"
+ /* 9 */ "........o"
+ /* 10 */ "........o"
+ /* 11 */ "........k"
+ /* 12 */ "........k"
+
+ // Level 12
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ "........."
+ /* 5 */ "rrrrrrr.o"
+ /* 6 */ "fffffff.o"
+ /* 7 */ "uuuuuuu.k"
+ /* 8 */ "........."
+ /* 9 */ "........."
+ /* 10 */ "........o"
+ /* 11 */ "........o"
+ /* 12 */ "........o"
+
+ // Level 13
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ "........."
+ /* 5 */ "........o"
+ /* 6 */ "........k"
+ /* 7 */ "........."
+ /* 8 */ "........."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 14
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ "........o"
+ /* 5 */ "........o"
+ /* 6 */ "........k"
+ /* 7 */ "........."
+ /* 8 */ "........."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 15
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ "........o"
+ /* 5 */ "........k"
+ /* 6 */ "........."
+ /* 7 */ "........."
+ /* 8 */ "........."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ "........."
+
+ // Level 16
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "........."
+ /* 4 */ "........o"
+ /* 5 */ "........k"
+ /* 6 */ "........."
+ /* 7 */ "........."
+ /* 8 */ "........."
+ /* 9 */ "........."
+ /* 10 */ "........."
+ /* 11 */ "........."
+ /* 12 */ ".........",
+
+ // Connectors:
+ "-1: 8, 1, 6: 5\n" /* Type -1, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenMill5x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // WoodenStables:
+ // The data has been exported from the gallery Plains, area index 55, ID 106, created by Aloe_vera
+ {
+ // Size:
+ 15, 9, 9, // SizeX = 15, SizeY = 9, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ -1, -1, 0, // MinX, MinY, MinZ
+ 15, 8, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 4: 0\n" /* cobblestone */
+ "b: 67: 0\n" /* stairs */
+ "c: 67: 2\n" /* stairs */
+ "d: 67: 1\n" /* stairs */
+ "e: 3: 0\n" /* dirt */
+ "f: 17: 0\n" /* tree */
+ "g:107: 0\n" /* fencegate */
+ "h:107: 4\n" /* fencegate */
+ "i: 5: 0\n" /* wood */
+ "j:107: 6\n" /* fencegate */
+ "k: 85: 0\n" /* fence */
+ "l:170: 0\n" /* haybale */
+ "m: 19: 0\n" /* sponge */
+ "n:170: 4\n" /* haybale */
+ "o:170: 8\n" /* haybale */
+ "p: 50: 1\n" /* torch */
+ "q: 50: 2\n" /* torch */
+ "r: 53: 2\n" /* woodstairs */
+ "s: 53: 7\n" /* woodstairs */
+ "t: 53: 6\n" /* woodstairs */
+ "u: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "maaaaaaaaaaaaam"
+ /* 1 */ "maaaaaaaaaaaaam"
+ /* 2 */ "maaaaaaaaaaaaam"
+ /* 3 */ "maaaaaaaaaaaaam"
+ /* 4 */ "maaaaaaaaaaaaam"
+ /* 5 */ "maaaaaaaaaaaaam"
+ /* 6 */ "maaaaaaaaaaaaam"
+ /* 7 */ "maaaaaaaaaaaaam"
+ /* 8 */ "mmmmmmmmmmmmmmm"
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ ".bcccccccccccd."
+ /* 1 */ ".aaaaaaaaaaaaa."
+ /* 2 */ ".aeeeeeeeeeeea."
+ /* 3 */ ".aeeeeeeeeeeea."
+ /* 4 */ ".aeeeeeeeeeeea."
+ /* 5 */ ".aeeeeeeeeeeea."
+ /* 6 */ ".aeeeeeeeeeeea."
+ /* 7 */ ".aaaaaaaaaaaaa."
+ /* 8 */ "..............."
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".fghgighgigjgf."
+ /* 2 */ ".k...k...k...k."
+ /* 3 */ ".k...k...k...k."
+ /* 4 */ ".k...k...k...k."
+ /* 5 */ ".k...k...k...k."
+ /* 6 */ ".kl..k..nko..k."
+ /* 7 */ ".fkkkikkkikkkf."
+ /* 8 */ "..............."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".f...i...i...f."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ ".f...i...i...f."
+ /* 8 */ "..............."
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".fp.qip.qip.qf."
+ /* 2 */ "..............."
+ /* 3 */ "..............."
+ /* 4 */ "..............."
+ /* 5 */ "..............."
+ /* 6 */ "..............."
+ /* 7 */ ".f...i...i...f."
+ /* 8 */ "..............."
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "rrrrrrrrrrrrrrr"
+ /* 1 */ "siiiiiiiiiiiiis"
+ /* 2 */ ".i...........i."
+ /* 3 */ ".i...........i."
+ /* 4 */ ".i...........i."
+ /* 5 */ ".i...........i."
+ /* 6 */ ".i...........i."
+ /* 7 */ "tiiiiiiiiiiiiit"
+ /* 8 */ "uuuuuuuuuuuuuuu"
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "rrrrrrrrrrrrrrr"
+ /* 2 */ "siiiiiiiiiiiiis"
+ /* 3 */ ".i...........i."
+ /* 4 */ ".i...........i."
+ /* 5 */ ".i...........i."
+ /* 6 */ "tiiiiiiiiiiiiit"
+ /* 7 */ "uuuuuuuuuuuuuuu"
+ /* 8 */ "..............."
+
+ // Level 7
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "rrrrrrrrrrrrrrr"
+ /* 3 */ "siiiiiiiiiiiiis"
+ /* 4 */ ".i...........i."
+ /* 5 */ "tiiiiiiiiiiiiit"
+ /* 6 */ "uuuuuuuuuuuuuuu"
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+
+ // Level 8
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "rrrrrrrrrrrrrrr"
+ /* 4 */ "iiiiiiiiiiiiiii"
+ /* 5 */ "uuuuuuuuuuuuuuu"
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "...............",
+
+ // Connectors:
+ "-1: 7, 1, -1: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // WoodenStables
+}; // g_PlainsVillagePrefabs
+
+
+
+
+
+
+const cPrefab::sDef g_PlainsVillageStartingPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CobbleWell4x4:
+ // The data has been exported from the gallery Plains, area index 1, ID 5, created by Aloe_vera
+ {
+ // Size:
+ 4, 13, 4, // SizeX = 4, SizeY = 13, SizeZ = 4
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 3, 12, 3, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 4: 0\n" /* cobblestone */
+ "c: 8: 0\n" /* water */
+ "d: 85: 0\n" /* fence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123 */
+ /* 0 */ "aaaa"
+ /* 1 */ "aaaa"
+ /* 2 */ "aaaa"
+ /* 3 */ "aaaa"
+
+ // Level 1
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 2
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 3
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 4
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 5
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 6
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 7
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 8
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 9
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "b..b"
+ /* 2 */ "b..b"
+ /* 3 */ "bbbb"
+
+ // Level 10
+ /* z\x* 0123 */
+ /* 0 */ "d..d"
+ /* 1 */ "...."
+ /* 2 */ "...."
+ /* 3 */ "d..d"
+
+ // Level 11
+ /* z\x* 0123 */
+ /* 0 */ "d..d"
+ /* 1 */ "...."
+ /* 2 */ "...."
+ /* 3 */ "d..d"
+
+ // Level 12
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bbbb"
+ /* 2 */ "bbbb"
+ /* 3 */ "bbbb",
+
+ // Connectors:
+ "2: 1, 9, 3: 3\n" /* Type 2, direction Z+ */
+ "2: 2, 9, 0: 2\n" /* Type 2, direction Z- */
+ "2: 0, 9, 1: 4\n" /* Type 2, direction X- */
+ "2: 3, 9, 2: 5\n" /* Type 2, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // CobbleWell4x4
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MineEntrance:
+ // The data has been exported from the gallery Plains, area index 138, ID 446, created by STR_Warrior
+ {
+ // Size:
+ 7, 38, 7, // SizeX = 7, SizeY = 38, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 37, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 5: 0\n" /* wood */
+ "b: 77: 2\n" /* stonebutton */
+ "c: 66: 6\n" /* tracks */
+ "d: 27: 1\n" /* poweredrail */
+ "e: 66: 5\n" /* tracks */
+ "f: 66: 9\n" /* tracks */
+ "g: 66: 2\n" /* tracks */
+ "h: 50: 4\n" /* torch */
+ "i: 66: 4\n" /* tracks */
+ "j: 66: 8\n" /* tracks */
+ "k: 66: 3\n" /* tracks */
+ "l: 66: 7\n" /* tracks */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 2\n" /* torch */
+ "o: 2: 0\n" /* grass */
+ "p: 53: 2\n" /* woodstairs */
+ "q: 77: 1\n" /* stonebutton */
+ "r: 27: 0\n" /* poweredrail */
+ "s: 53: 7\n" /* woodstairs */
+ "t: 53: 6\n" /* woodstairs */
+ "u: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "maaaaam"
+ /* 1 */ "maaaaam"
+ /* 2 */ "maaaaam"
+ /* 3 */ "maaaaam"
+ /* 4 */ "maaaaam"
+ /* 5 */ "maaaaam"
+ /* 6 */ "mmmmmmm"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "mm...mm"
+ /* 1 */ "mm.abam"
+ /* 2 */ "mmcddam"
+ /* 3 */ "mae..am"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "mm...mm"
+ /* 1 */ "mm.a.mm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "mm.h.mm"
+ /* 1 */ "mm.a.mm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 11
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 12
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 13
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 14
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 15
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 16
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 17
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 18
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 19
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 20
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 21
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 22
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 23
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 24
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 25
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 26
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 27
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm.aamm"
+ /* 3 */ "ma..iam"
+ /* 4 */ "mm..jmm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 28
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmaklmm"
+ /* 3 */ "maa..am"
+ /* 4 */ "mm...mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 29
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mmc..mm"
+ /* 3 */ "mae.nam"
+ /* 4 */ "mmaa.mm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 30
+ /* z\x* 0123456 */
+ /* 0 */ "mmmmmmm"
+ /* 1 */ "mmmammm"
+ /* 2 */ "mm...mm"
+ /* 3 */ "ma..aam"
+ /* 4 */ "mmfgamm"
+ /* 5 */ "mmmammm"
+ /* 6 */ "mmmmmmm"
+
+ // Level 31
+ /* z\x* 0123456 */
+ /* 0 */ "ooomooo"
+ /* 1 */ "oaaaaao"
+ /* 2 */ "oa.aaao"
+ /* 3 */ "oa..iao"
+ /* 4 */ "oa..jao"
+ /* 5 */ "oaaaaao"
+ /* 6 */ "ooooooo"
+
+ // Level 32
+ /* z\x* 0123456 */
+ /* 0 */ "...p..."
+ /* 1 */ ".aqrba."
+ /* 2 */ "...fl.."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ ".a...a."
+ /* 6 */ "......."
+
+ // Level 33
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".a...a."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ ".a...a."
+ /* 6 */ "......."
+
+ // Level 34
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".a...a."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ ".a...a."
+ /* 6 */ "......."
+
+ // Level 35
+ /* z\x* 0123456 */
+ /* 0 */ "ppppppp"
+ /* 1 */ "saaaaas"
+ /* 2 */ ".a...a."
+ /* 3 */ ".a...a."
+ /* 4 */ ".a...a."
+ /* 5 */ "taaaaat"
+ /* 6 */ "uuuuuuu"
+
+ // Level 36
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "ppppppp"
+ /* 2 */ "saaaaas"
+ /* 3 */ ".aaaaa."
+ /* 4 */ "taaaaat"
+ /* 5 */ "uuuuuuu"
+ /* 6 */ "......."
+
+ // Level 37
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "ppppppp"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "uuuuuuu"
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "2: 6, 32, 3: 5\n" /* Type 2, direction X+ */
+ "2: 3, 32, 6: 3\n" /* Type 2, direction Z+ */
+ "2: 0, 32, 3: 4\n" /* Type 2, direction X- */
+ "2: 3, 32, 0: 2\n" /* Type 2, direction Z- */
+ "3: 3, 1, 0: 2\n" /* Type 3, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ false,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // MineEntrance
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // RoofedWell:
+ // The data has been exported from the gallery Plains, area index 119, ID 271, created by STR_Warrior
+ {
+ // Size:
+ 7, 15, 7, // SizeX = 7, SizeY = 15, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 14, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 4: 0\n" /* cobblestone */
+ "c: 8: 0\n" /* water */
+ "d: 3: 0\n" /* dirt */
+ "e: 2: 0\n" /* grass */
+ "f: 13: 0\n" /* gravel */
+ "g:118: 3\n" /* cauldronblock */
+ "h: 85: 0\n" /* fence */
+ "i: 53: 2\n" /* woodstairs */
+ "j: 53: 7\n" /* woodstairs */
+ "k: 5: 0\n" /* wood */
+ "l: 53: 4\n" /* woodstairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 53: 5\n" /* woodstairs */
+ "o: 53: 6\n" /* woodstairs */
+ "p: 53: 3\n" /* woodstairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "eefffee"
+ /* 1 */ "ebbbbbe"
+ /* 2 */ "fbcccbf"
+ /* 3 */ "fbcccbf"
+ /* 4 */ "fbcccbf"
+ /* 5 */ "ebbbbbe"
+ /* 6 */ "eefffee"
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".bbbbb."
+ /* 2 */ ".b...b."
+ /* 3 */ ".b.g.b."
+ /* 4 */ ".b...b."
+ /* 5 */ ".bbbbb."
+ /* 6 */ "......."
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".h...h."
+ /* 2 */ "......."
+ /* 3 */ "...h..."
+ /* 4 */ "......."
+ /* 5 */ ".h...h."
+ /* 6 */ "......."
+
+ // Level 11
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".h...h."
+ /* 2 */ "......."
+ /* 3 */ "...h..."
+ /* 4 */ "......."
+ /* 5 */ ".h...h."
+ /* 6 */ "......."
+
+ // Level 12
+ /* z\x* 0123456 */
+ /* 0 */ "iiiiiii"
+ /* 1 */ "jkjjjkj"
+ /* 2 */ ".l...n."
+ /* 3 */ ".l.h.n."
+ /* 4 */ ".l...n."
+ /* 5 */ "okoooko"
+ /* 6 */ "ppppppp"
+
+ // Level 13
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "iiiiiii"
+ /* 2 */ "jkjjjkj"
+ /* 3 */ ".k.h.k."
+ /* 4 */ "okoooko"
+ /* 5 */ "ppppppp"
+ /* 6 */ "......."
+
+ // Level 14
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "iiiiiii"
+ /* 3 */ "kkkkkkk"
+ /* 4 */ "ppppppp"
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "2: 0, 9, 3: 4\n" /* Type 2, direction X- */
+ "2: 3, 9, 6: 3\n" /* Type 2, direction Z+ */
+ "2: 6, 9, 3: 5\n" /* Type 2, direction X+ */
+ "2: 3, 9, 0: 2\n" /* Type 2, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // RoofedWell
+};
+
+
+
+
+
+// The prefab counts:
+
+const size_t g_PlainsVillagePrefabsCount = ARRAYCOUNT(g_PlainsVillagePrefabs);
+
+const size_t g_PlainsVillageStartingPrefabsCount = ARRAYCOUNT(g_PlainsVillageStartingPrefabs);
+
diff --git a/src/Generating/Prefabs/PlainsVillagePrefabs.h b/src/Generating/Prefabs/PlainsVillagePrefabs.h
new file mode 100644
index 000000000..087783b1e
--- /dev/null
+++ b/src/Generating/Prefabs/PlainsVillagePrefabs.h
@@ -0,0 +1,15 @@
+
+// PlainsVillagePrefabs.h
+
+// Declares the prefabs in the group PlainsVillage
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_PlainsVillagePrefabs[];
+extern const cPrefab::sDef g_PlainsVillageStartingPrefabs[];
+extern const size_t g_PlainsVillagePrefabsCount;
+extern const size_t g_PlainsVillageStartingPrefabsCount;
diff --git a/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp
new file mode 100644
index 000000000..4f0efdcc6
--- /dev/null
+++ b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp
@@ -0,0 +1,1558 @@
+
+// SandFlatRoofVillagePrefabs.cpp
+
+// Defines the prefabs in the group SandFlatRoofVillage
+
+// NOTE: This file has been generated automatically by GalExport!
+// Any manual changes will be overwritten by the next automatic export!
+
+#include "Globals.h"
+#include "SandFlatRoofVillagePrefabs.h"
+
+
+
+
+
+const cPrefab::sDef g_SandFlatRoofVillagePrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Forge:
+ // The data has been exported from the gallery Desert, area index 32, ID 173, created by Aloe_vera
+ {
+ // Size:
+ 12, 5, 10, // SizeX = 12, SizeY = 5, SizeZ = 10
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 11, 4, 9, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 2\n" /* sandstonestairs */
+ "b:128: 1\n" /* sandstonestairs */
+ "c:128: 0\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e:128: 3\n" /* sandstonestairs */
+ "f:171:15\n" /* carpet */
+ "g: 64: 6\n" /* wooddoorblock */
+ "h:171: 0\n" /* carpet */
+ "i:171:14\n" /* carpet */
+ "j: 61: 2\n" /* furnace */
+ "k: 10: 0\n" /* lava */
+ "l: 54: 2\n" /* chest */
+ "m: 19: 0\n" /* sponge */
+ "n: 24: 2\n" /* sandstone */
+ "o: 64:12\n" /* wooddoorblock */
+ "p: 50: 1\n" /* torch */
+ "q:101: 0\n" /* ironbars */
+ "r:128: 4\n" /* sandstonestairs */
+ "s:128: 6\n" /* sandstonestairs */
+ "t:128: 5\n" /* sandstonestairs */
+ "u:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "aaaaaab....."
+ /* 1 */ "cdddddddddd."
+ /* 2 */ "cdddddddddd."
+ /* 3 */ "cdddddddddd."
+ /* 4 */ "cdddddddddd."
+ /* 5 */ "edddddddddd."
+ /* 6 */ ".dddddddddd."
+ /* 7 */ ".dddddddddd."
+ /* 8 */ ".dddddddddd."
+ /* 9 */ "............"
+
+ // Level 1
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".d....ddddd."
+ /* 2 */ "......dfffd."
+ /* 3 */ "......ghfhd."
+ /* 4 */ "......diiid."
+ /* 5 */ ".d....dhfhd."
+ /* 6 */ ".djddjdfffd."
+ /* 7 */ ".ddkkddl..d."
+ /* 8 */ ".dddddddddd."
+ /* 9 */ "............"
+
+ // Level 2
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".n....nn.nn."
+ /* 2 */ "......n...n."
+ /* 3 */ "......o...n."
+ /* 4 */ "......n....."
+ /* 5 */ ".n....n...n."
+ /* 6 */ ".n....n...n."
+ /* 7 */ ".n....n...n."
+ /* 8 */ ".nnn.nnn.nn."
+ /* 9 */ "............"
+
+ // Level 3
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "............"
+ /* 1 */ ".d....ddddd."
+ /* 2 */ "......d...d."
+ /* 3 */ "......d...d."
+ /* 4 */ "......dp..d."
+ /* 5 */ ".d....d...d."
+ /* 6 */ ".dqqqqd...d."
+ /* 7 */ ".d....d...d."
+ /* 8 */ ".dddddddddd."
+ /* 9 */ "............"
+
+ // Level 4
+ /* z\x* 11 */
+ /* * 012345678901 */
+ /* 0 */ "rsssssssssss"
+ /* 1 */ "rddddddddddt"
+ /* 2 */ "rddddddddddt"
+ /* 3 */ "rddddddddddt"
+ /* 4 */ "rddddddddddt"
+ /* 5 */ "rddddddddddt"
+ /* 6 */ "rddddddddddt"
+ /* 7 */ "rddddddddddt"
+ /* 8 */ "rddddddddddt"
+ /* 9 */ "uuuuuuuuuuut",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Forge
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House11x7:
+ // The data has been exported from the gallery Desert, area index 31, ID 172, created by Aloe_vera
+ {
+ // Size:
+ 13, 5, 9, // SizeX = 13, SizeY = 5, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 4, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171: 0\n" /* carpet */
+ "g:171:15\n" /* carpet */
+ "h:171:14\n" /* carpet */
+ "i: 24: 2\n" /* sandstone */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 50: 3\n" /* torch */
+ "l: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 2\n" /* torch */
+ "o: 50: 4\n" /* torch */
+ "p:128: 4\n" /* sandstonestairs */
+ "q:128: 6\n" /* sandstonestairs */
+ "r:128: 5\n" /* sandstonestairs */
+ "s:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "..abc........"
+ /* 1 */ ".ddddddddddd."
+ /* 2 */ ".ddddddddddd."
+ /* 3 */ ".ddddddddddd."
+ /* 4 */ ".ddddddddddd."
+ /* 5 */ ".ddddddddddd."
+ /* 6 */ ".ddddddddddd."
+ /* 7 */ ".ddddddddddd."
+ /* 8 */ "............."
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".ddedddddddd."
+ /* 2 */ ".dffgggggffd."
+ /* 3 */ ".dfghhhhhgfd."
+ /* 4 */ ".dfghfffhgfd."
+ /* 5 */ ".dfghhhhhgfd."
+ /* 6 */ ".dffgggggffd."
+ /* 7 */ ".ddddddddddd."
+ /* 8 */ "............."
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".iiji.iii.ii."
+ /* 2 */ ".i.........i."
+ /* 3 */ ".i.........i."
+ /* 4 */ "............."
+ /* 5 */ ".i.........i."
+ /* 6 */ ".i.........i."
+ /* 7 */ ".ii.ii.ii.ii."
+ /* 8 */ "............."
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".ddddddddddd."
+ /* 2 */ ".d..k..k...d."
+ /* 3 */ ".d.........d."
+ /* 4 */ ".dl.......nd."
+ /* 5 */ ".d.........d."
+ /* 6 */ ".d....o....d."
+ /* 7 */ ".ddddddddddd."
+ /* 8 */ "............."
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "pqqqqqqqqqqqq"
+ /* 1 */ "pdddddddddddr"
+ /* 2 */ "pdddddddddddr"
+ /* 3 */ "pdddddddddddr"
+ /* 4 */ "pdddddddddddr"
+ /* 5 */ "pdddddddddddr"
+ /* 6 */ "pdddddddddddr"
+ /* 7 */ "pdddddddddddr"
+ /* 8 */ "ssssssssssssr",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House11x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House5x4:
+ // The data has been exported from the gallery Desert, area index 25, ID 166, created by Aloe_vera
+ {
+ // Size:
+ 7, 5, 6, // SizeX = 7, SizeY = 5, SizeZ = 6
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 4, 5, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171: 0\n" /* carpet */
+ "g:171:14\n" /* carpet */
+ "h: 24: 2\n" /* sandstone */
+ "i: 64:12\n" /* wooddoorblock */
+ "j: 50: 3\n" /* torch */
+ "k:128: 4\n" /* sandstonestairs */
+ "l:128: 6\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 5\n" /* sandstonestairs */
+ "o:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "..abc.."
+ /* 1 */ ".ddddd."
+ /* 2 */ ".ddddd."
+ /* 3 */ ".ddddd."
+ /* 4 */ ".ddddd."
+ /* 5 */ "......."
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ddedd."
+ /* 2 */ ".dfgfd."
+ /* 3 */ ".dfgfd."
+ /* 4 */ ".ddddd."
+ /* 5 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".hhihh."
+ /* 2 */ ".h...h."
+ /* 3 */ ".h...h."
+ /* 4 */ ".hh.hh."
+ /* 5 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ddddd."
+ /* 2 */ ".dj.jd."
+ /* 3 */ ".d...d."
+ /* 4 */ ".ddddd."
+ /* 5 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "kllllln"
+ /* 1 */ "kdddddn"
+ /* 2 */ "kdddddn"
+ /* 3 */ "kdddddn"
+ /* 4 */ "kdddddn"
+ /* 5 */ "oooooon",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House5x4
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House5x5:
+ // The data has been exported from the gallery Desert, area index 26, ID 167, created by Aloe_vera
+ {
+ // Size:
+ 7, 5, 7, // SizeX = 7, SizeY = 5, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 4, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171: 0\n" /* carpet */
+ "g:171:15\n" /* carpet */
+ "h:171:14\n" /* carpet */
+ "i: 24: 2\n" /* sandstone */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 50: 3\n" /* torch */
+ "l:128: 4\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 6\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "..abc.."
+ /* 1 */ ".ddddd."
+ /* 2 */ ".ddddd."
+ /* 3 */ ".ddddd."
+ /* 4 */ ".ddddd."
+ /* 5 */ ".ddddd."
+ /* 6 */ "......."
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ddedd."
+ /* 2 */ ".dfffd."
+ /* 3 */ ".dghgd."
+ /* 4 */ ".dfffd."
+ /* 5 */ ".ddddd."
+ /* 6 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".iijii."
+ /* 2 */ ".i...i."
+ /* 3 */ "......."
+ /* 4 */ ".i...i."
+ /* 5 */ ".ii.ii."
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ddddd."
+ /* 2 */ ".dk.kd."
+ /* 3 */ ".d...d."
+ /* 4 */ ".d...d."
+ /* 5 */ ".ddddd."
+ /* 6 */ "......."
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "lnnnnno"
+ /* 1 */ "ldddddo"
+ /* 2 */ "ldddddo"
+ /* 3 */ "ldddddo"
+ /* 4 */ "ldddddo"
+ /* 5 */ "ldddddo"
+ /* 6 */ "ppppppo",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House5x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House7x5:
+ // The data has been exported from the gallery Desert, area index 27, ID 168, created by Aloe_vera
+ {
+ // Size:
+ 9, 5, 7, // SizeX = 9, SizeY = 5, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 8, 4, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171:14\n" /* carpet */
+ "g:171: 0\n" /* carpet */
+ "h:171:15\n" /* carpet */
+ "i: 24: 2\n" /* sandstone */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 50: 3\n" /* torch */
+ "l:128: 4\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 6\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "..abc...."
+ /* 1 */ ".ddddddd."
+ /* 2 */ ".ddddddd."
+ /* 3 */ ".ddddddd."
+ /* 4 */ ".ddddddd."
+ /* 5 */ ".ddddddd."
+ /* 6 */ "........."
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".ddedddd."
+ /* 2 */ ".dfffffd."
+ /* 3 */ ".dghhhgd."
+ /* 4 */ ".dfffffd."
+ /* 5 */ ".ddddddd."
+ /* 6 */ "........."
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".iiji.ii."
+ /* 2 */ ".i.....i."
+ /* 3 */ "........."
+ /* 4 */ ".i.....i."
+ /* 5 */ ".iii.iii."
+ /* 6 */ "........."
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".ddddddd."
+ /* 2 */ ".dk.k..d."
+ /* 3 */ ".d.....d."
+ /* 4 */ ".d.....d."
+ /* 5 */ ".ddddddd."
+ /* 6 */ "........."
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "lnnnnnnnn"
+ /* 1 */ "ldddddddo"
+ /* 2 */ "ldddddddo"
+ /* 3 */ "ldddddddo"
+ /* 4 */ "ldddddddo"
+ /* 5 */ "ldddddddo"
+ /* 6 */ "ppppppppo",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House7x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House8x5:
+ // The data has been exported from the gallery Desert, area index 28, ID 169, created by Aloe_vera
+ {
+ // Size:
+ 10, 5, 7, // SizeX = 10, SizeY = 5, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171: 0\n" /* carpet */
+ "g:171:14\n" /* carpet */
+ "h:171:15\n" /* carpet */
+ "i: 24: 2\n" /* sandstone */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 50: 3\n" /* torch */
+ "l:128: 4\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 6\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "..abc....."
+ /* 1 */ ".dddddddd."
+ /* 2 */ ".dddddddd."
+ /* 3 */ ".dddddddd."
+ /* 4 */ ".dddddddd."
+ /* 5 */ ".dddddddd."
+ /* 6 */ ".........."
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".ddeddddd."
+ /* 2 */ ".dfghhgfd."
+ /* 3 */ ".dfhffhfd."
+ /* 4 */ ".dfghhgfd."
+ /* 5 */ ".dddddddd."
+ /* 6 */ ".........."
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".iijii.ii."
+ /* 2 */ ".i......i."
+ /* 3 */ ".........."
+ /* 4 */ ".i......i."
+ /* 5 */ ".ii.ii.ii."
+ /* 6 */ ".........."
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".dddddddd."
+ /* 2 */ ".dk.k...d."
+ /* 3 */ ".d......d."
+ /* 4 */ ".d......d."
+ /* 5 */ ".dddddddd."
+ /* 6 */ ".........."
+
+ // Level 4
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "lnnnnnnnnn"
+ /* 1 */ "lddddddddo"
+ /* 2 */ "lddddddddo"
+ /* 3 */ "lddddddddo"
+ /* 4 */ "lddddddddo"
+ /* 5 */ "lddddddddo"
+ /* 6 */ "pppppppppo",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House8x5
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House8x7:
+ // The data has been exported from the gallery Desert, area index 29, ID 170, created by Aloe_vera
+ {
+ // Size:
+ 10, 5, 9, // SizeX = 10, SizeY = 5, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 9, 4, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171: 0\n" /* carpet */
+ "g:171:14\n" /* carpet */
+ "h:171:15\n" /* carpet */
+ "i: 24: 2\n" /* sandstone */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 50: 3\n" /* torch */
+ "l: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 2\n" /* torch */
+ "o:128: 4\n" /* sandstonestairs */
+ "p:128: 6\n" /* sandstonestairs */
+ "q:128: 5\n" /* sandstonestairs */
+ "r:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "..abc....."
+ /* 1 */ ".dddddddd."
+ /* 2 */ ".dddddddd."
+ /* 3 */ ".dddddddd."
+ /* 4 */ ".dddddddd."
+ /* 5 */ ".dddddddd."
+ /* 6 */ ".dddddddd."
+ /* 7 */ ".dddddddd."
+ /* 8 */ ".........."
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".ddeddddd."
+ /* 2 */ ".dfghhgfd."
+ /* 3 */ ".dfhffhfd."
+ /* 4 */ ".dfhgghfd."
+ /* 5 */ ".dfhffhfd."
+ /* 6 */ ".dfghhgfd."
+ /* 7 */ ".dddddddd."
+ /* 8 */ ".........."
+
+ // Level 2
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".iijii.ii."
+ /* 2 */ ".i......i."
+ /* 3 */ ".i......i."
+ /* 4 */ ".........."
+ /* 5 */ ".i......i."
+ /* 6 */ ".i......i."
+ /* 7 */ ".ii.ii.ii."
+ /* 8 */ ".........."
+
+ // Level 3
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ ".........."
+ /* 1 */ ".dddddddd."
+ /* 2 */ ".d..k...d."
+ /* 3 */ ".d......d."
+ /* 4 */ ".dl....nd."
+ /* 5 */ ".d......d."
+ /* 6 */ ".d......d."
+ /* 7 */ ".dddddddd."
+ /* 8 */ ".........."
+
+ // Level 4
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "oppppppppp"
+ /* 1 */ "oddddddddq"
+ /* 2 */ "oddddddddq"
+ /* 3 */ "oddddddddq"
+ /* 4 */ "oddddddddq"
+ /* 5 */ "oddddddddq"
+ /* 6 */ "oddddddddq"
+ /* 7 */ "oddddddddq"
+ /* 8 */ "rrrrrrrrrq",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House8x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House9x7:
+ // The data has been exported from the gallery Desert, area index 30, ID 171, created by Aloe_vera
+ {
+ // Size:
+ 11, 5, 9, // SizeX = 11, SizeY = 5, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 4, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:171: 0\n" /* carpet */
+ "g:171:15\n" /* carpet */
+ "h:171:14\n" /* carpet */
+ "i: 24: 2\n" /* sandstone */
+ "j: 64:12\n" /* wooddoorblock */
+ "k: 50: 3\n" /* torch */
+ "l: 50: 1\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 2\n" /* torch */
+ "o: 50: 4\n" /* torch */
+ "p:128: 4\n" /* sandstonestairs */
+ "q:128: 6\n" /* sandstonestairs */
+ "r:128: 5\n" /* sandstonestairs */
+ "s:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..abc......"
+ /* 1 */ ".ddddddddd."
+ /* 2 */ ".ddddddddd."
+ /* 3 */ ".ddddddddd."
+ /* 4 */ ".ddddddddd."
+ /* 5 */ ".ddddddddd."
+ /* 6 */ ".ddddddddd."
+ /* 7 */ ".ddddddddd."
+ /* 8 */ "..........."
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ddedddddd."
+ /* 2 */ ".dffgggffd."
+ /* 3 */ ".dfghhhgfd."
+ /* 4 */ ".dfghfhgfd."
+ /* 5 */ ".dfghhhgfd."
+ /* 6 */ ".dffgggffd."
+ /* 7 */ ".ddddddddd."
+ /* 8 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".iijii.iii."
+ /* 2 */ ".i.......i."
+ /* 3 */ ".i.......i."
+ /* 4 */ "..........."
+ /* 5 */ ".i.......i."
+ /* 6 */ ".i.......i."
+ /* 7 */ ".ii.iii.ii."
+ /* 8 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ddddddddd."
+ /* 2 */ ".d..k....d."
+ /* 3 */ ".d.......d."
+ /* 4 */ ".dl.....nd."
+ /* 5 */ ".d.......d."
+ /* 6 */ ".d...o...d."
+ /* 7 */ ".ddddddddd."
+ /* 8 */ "..........."
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "pqqqqqqqqqq"
+ /* 1 */ "pdddddddddr"
+ /* 2 */ "pdddddddddr"
+ /* 3 */ "pdddddddddr"
+ /* 4 */ "pdddddddddr"
+ /* 5 */ "pdddddddddr"
+ /* 6 */ "pdddddddddr"
+ /* 7 */ "pdddddddddr"
+ /* 8 */ "ssssssssssr",
+
+ // Connectors:
+ "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House9x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseL13x12:
+ // The data has been exported from the gallery Desert, area index 53, ID 345, created by jakibaki
+ {
+ // Size:
+ 15, 5, 14, // SizeX = 15, SizeY = 5, SizeZ = 14
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 4, 13, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 43: 1\n" /* doubleslab */
+ "f: 64: 7\n" /* wooddoorblock */
+ "g:171: 0\n" /* carpet */
+ "h:171:15\n" /* carpet */
+ "i:171:14\n" /* carpet */
+ "j: 58: 0\n" /* workbench */
+ "k: 24: 2\n" /* sandstone */
+ "l: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 3\n" /* torch */
+ "o: 50: 1\n" /* torch */
+ "p: 50: 2\n" /* torch */
+ "q: 50: 4\n" /* torch */
+ "r:128: 6\n" /* sandstonestairs */
+ "s:128: 5\n" /* sandstonestairs */
+ "t:128: 4\n" /* sandstonestairs */
+ "u:128: 7\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "...abc........."
+ /* 1 */ ".ddddddddddddd."
+ /* 2 */ ".ddddddddddddd."
+ /* 3 */ ".ddddddddddddd."
+ /* 4 */ ".ddddddddddddd."
+ /* 5 */ ".ddddddddddded."
+ /* 6 */ ".ddddddddddddd."
+ /* 7 */ ".ddddddddddddd."
+ /* 8 */ ".......deddddd."
+ /* 9 */ "mmmmmm.ddddddd."
+ /* 10 */ "mmmmmm.ddddddd."
+ /* 11 */ "mmmmmm.ddddddd."
+ /* 12 */ "mmmmmm.ddddddd."
+ /* 13 */ "..............."
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".dddfddddddddd."
+ /* 2 */ ".dgghhhhhhhhgd."
+ /* 3 */ ".dghiiiiiiiihd."
+ /* 4 */ ".dghiggggggihd."
+ /* 5 */ ".dghiiiiiigihd."
+ /* 6 */ ".dgghhhhhigihd."
+ /* 7 */ ".dddddddhigihd."
+ /* 8 */ ".......dhigihd."
+ /* 9 */ "mmmmmm.dhiiihd."
+ /* 10 */ "mmmmmm.dghhhgd."
+ /* 11 */ "mmmmmm.dggggjd."
+ /* 12 */ "mmmmmm.ddddddd."
+ /* 13 */ "..............."
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".kkklkkkk.kkkk."
+ /* 2 */ ".k...........k."
+ /* 3 */ ".k...........k."
+ /* 4 */ "..............."
+ /* 5 */ ".k...........k."
+ /* 6 */ ".k...........k."
+ /* 7 */ ".kkk.kkk.....k."
+ /* 8 */ ".......k.....k."
+ /* 9 */ "mmmmmm.k......."
+ /* 10 */ "mmmmmm.......k."
+ /* 11 */ "mmmmmm.k.....k."
+ /* 12 */ "mmmmmm.kkk.kkk."
+ /* 13 */ "..............."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".ddddddddddddd."
+ /* 2 */ ".d......n....d."
+ /* 3 */ ".d...........d."
+ /* 4 */ ".do..........d."
+ /* 5 */ ".d...........d."
+ /* 6 */ ".d..........pd."
+ /* 7 */ ".ddddddd.....d."
+ /* 8 */ ".......d.....d."
+ /* 9 */ "mmmmmm.d.....d."
+ /* 10 */ "mmmmmm.d.....d."
+ /* 11 */ "mmmmmm.d..q..d."
+ /* 12 */ "mmmmmm.ddddddd."
+ /* 13 */ "..............."
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "rrrrrrrrrrrrrrs"
+ /* 1 */ "tddddddddddddds"
+ /* 2 */ "tddddddddddddds"
+ /* 3 */ "tddddddddddddds"
+ /* 4 */ "tddddddddddddds"
+ /* 5 */ "tddddddddddddds"
+ /* 6 */ "tddddddddddddds"
+ /* 7 */ "tddddddddddddds"
+ /* 8 */ "tuuuuutddddddds"
+ /* 9 */ "mmmmmmtddddddds"
+ /* 10 */ "mmmmmmtddddddds"
+ /* 11 */ "mmmmmmtddddddds"
+ /* 12 */ "mmmmmmtddddddds"
+ /* 13 */ "......tuuuuuuuu",
+
+ // Connectors:
+ "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseL13x12
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MarketStall:
+ // The data has been exported from the gallery Desert, area index 34, ID 175, created by Aloe_vera
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 5, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 12: 0\n" /* sand */
+ "b: 85: 0\n" /* fence */
+ "c:171:14\n" /* carpet */
+ "d:171:15\n" /* carpet */
+ "e:171: 0\n" /* carpet */
+ "f: 35:14\n" /* wool */
+ "g: 35: 0\n" /* wool */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "b.....b"
+ /* 1 */ "cddeddc"
+ /* 2 */ "cdeeedc"
+ /* 3 */ "cdeeedc"
+ /* 4 */ "cddeddc"
+ /* 5 */ "b.....b"
+ /* 6 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "b.....b"
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "b.....b"
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "b.....b"
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "b.....b"
+ /* 6 */ "fgfgfgf"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "fgfgfgf"
+ /* 1 */ "......."
+ /* 2 */ "......."
+ /* 3 */ "......."
+ /* 4 */ "......."
+ /* 5 */ "fgfgfgf"
+ /* 6 */ "......."
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "fgfgfgf"
+ /* 2 */ "fgfgfgf"
+ /* 3 */ "fgfgfgf"
+ /* 4 */ "fgfgfgf"
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "-1: 2, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 5,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // MarketStall
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Marketplace:
+ // The data has been exported from the gallery Desert, area index 38, ID 261, created by Aloe_vera
+ {
+ // Size:
+ 14, 4, 16, // SizeX = 14, SizeY = 4, SizeZ = 16
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 13, 3, 15, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 24: 0\n" /* sandstone */
+ "b: 12: 0\n" /* sand */
+ "c: 24: 2\n" /* sandstone */
+ "d: 12: 2\n" /* sand */
+ "e: 85: 0\n" /* fence */
+ "f: 5: 0\n" /* wood */
+ "g:128: 2\n" /* sandstonestairs */
+ "h:128: 0\n" /* sandstonestairs */
+ "i: 8: 0\n" /* water */
+ "j:128: 1\n" /* sandstonestairs */
+ "k:128: 3\n" /* sandstonestairs */
+ "l: 35: 0\n" /* wool */
+ "m: 19: 0\n" /* sponge */
+ "n: 35:14\n" /* wool */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "aaaabbbaaabbbb"
+ /* 1 */ "aaaabbaabbabbb"
+ /* 2 */ "aababbabcabbbb"
+ /* 3 */ "aaaaabaaaaabbb"
+ /* 4 */ "bbbbbbbbbbbbbb"
+ /* 5 */ "bbbbbbbbbbaabb"
+ /* 6 */ "bbbbccccbbabab"
+ /* 7 */ "ccbbccccbbaaab"
+ /* 8 */ "ccbbccccbbabbb"
+ /* 9 */ "dcbbccccbbabaa"
+ /* 10 */ "ccbbbbbbbbaaba"
+ /* 11 */ "ccbbbbbbbbabaa"
+ /* 12 */ "bbbbbbbbbbabaa"
+ /* 13 */ "bbbaababbbaaba"
+ /* 14 */ "bbbcaaaabbabbb"
+ /* 15 */ "bbbcccabbbabbb"
+
+ // Level 1
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "e...e.e...e..."
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ "fffff.fffff..."
+ /* 4 */ ".............."
+ /* 5 */ "..........f..e"
+ /* 6 */ "....gggg..f..."
+ /* 7 */ ".f..hiij..f..."
+ /* 8 */ ".f..hiij..f..."
+ /* 9 */ ".f..kkkk..f..e"
+ /* 10 */ ".f............"
+ /* 11 */ ".f........f..e"
+ /* 12 */ "...fffff..f..."
+ /* 13 */ "..........f..."
+ /* 14 */ "..........f..."
+ /* 15 */ "...e...e..f..e"
+
+ // Level 2
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "lnlnl.lnlnl..."
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ "e...e.e...e..."
+ /* 4 */ ".............."
+ /* 5 */ "..........e..l"
+ /* 6 */ ".............n"
+ /* 7 */ ".e...........l"
+ /* 8 */ ".............n"
+ /* 9 */ "..........e..l"
+ /* 10 */ ".............."
+ /* 11 */ ".e........e..l"
+ /* 12 */ "...e...e.....n"
+ /* 13 */ ".............l"
+ /* 14 */ ".............n"
+ /* 15 */ "...lnlnl..e..l"
+
+ // Level 3
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ "lnlnl.lnlnl..."
+ /* 2 */ "lnlnl.lnlnl..."
+ /* 3 */ "lnlnl.lnlnl..."
+ /* 4 */ ".............."
+ /* 5 */ "..........lll."
+ /* 6 */ "..........nnn."
+ /* 7 */ "ll........lll."
+ /* 8 */ "nn........nnn."
+ /* 9 */ "ll........lll."
+ /* 10 */ "nn............"
+ /* 11 */ "ll........lll."
+ /* 12 */ "...lnlnl..nnn."
+ /* 13 */ "...lnlnl..lll."
+ /* 14 */ "...lnlnl..nnn."
+ /* 15 */ "..........lll.",
+
+ // Connectors:
+ "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 20,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Marketplace
+}; // g_SandFlatRoofVillagePrefabs
+
+
+
+
+
+
+const cPrefab::sDef g_SandFlatRoofVillageStartingPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Well:
+ // The data has been exported from the gallery Desert, area index 44, ID 275, created by Aloe_vera
+ {
+ // Size:
+ 5, 16, 5, // SizeX = 5, SizeY = 16, SizeZ = 5
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 15, 4, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 24: 0\n" /* sandstone */
+ "c: 8: 0\n" /* water */
+ "d:128: 2\n" /* sandstonestairs */
+ "e:128: 0\n" /* sandstonestairs */
+ "f:128: 1\n" /* sandstonestairs */
+ "g:128: 3\n" /* sandstonestairs */
+ "h:128: 6\n" /* sandstonestairs */
+ "i:128: 4\n" /* sandstonestairs */
+ "j:128: 5\n" /* sandstonestairs */
+ "k:128: 7\n" /* sandstonestairs */
+ "l: 44: 1\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "abbba"
+ /* 2 */ "abbba"
+ /* 3 */ "abbba"
+ /* 4 */ "aaaaa"
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 5
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 6
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 7
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcccb"
+ /* 2 */ "bcccb"
+ /* 3 */ "bcccb"
+ /* 4 */ "bbbbb"
+
+ // Level 8
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcbcb"
+ /* 2 */ "bbcbb"
+ /* 3 */ "bcbcb"
+ /* 4 */ "bbbbb"
+
+ // Level 9
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcbcb"
+ /* 2 */ "bbbbb"
+ /* 3 */ "bcbcb"
+ /* 4 */ "bbbbb"
+
+ // Level 10
+ /* z\x* 01234 */
+ /* 0 */ "bbbbb"
+ /* 1 */ "bcbcb"
+ /* 2 */ "bbbbb"
+ /* 3 */ "bcbcb"
+ /* 4 */ "bbbbb"
+
+ // Level 11
+ /* z\x* 01234 */
+ /* 0 */ "ddddd"
+ /* 1 */ "ecccf"
+ /* 2 */ "ecbcf"
+ /* 3 */ "ecccf"
+ /* 4 */ "ggggf"
+
+ // Level 12
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "..b.."
+ /* 3 */ "....."
+ /* 4 */ "....."
+
+ // Level 13
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ "....."
+ /* 2 */ "..b.."
+ /* 3 */ "....."
+ /* 4 */ "....."
+
+ // Level 14
+ /* z\x* 01234 */
+ /* 0 */ "....."
+ /* 1 */ ".hhh."
+ /* 2 */ ".ibj."
+ /* 3 */ ".kkj."
+ /* 4 */ "....."
+
+ // Level 15
+ /* z\x* 01234 */
+ /* 0 */ "lllll"
+ /* 1 */ "lllll"
+ /* 2 */ "lllll"
+ /* 3 */ "lllll"
+ /* 4 */ "lllll",
+
+ // Connectors:
+ "2: 4, 11, 2: 5\n" /* Type 2, direction X+ */
+ "2: 2, 11, 4: 3\n" /* Type 2, direction Z+ */
+ "2: 0, 11, 2: 4\n" /* Type 2, direction X- */
+ "2: 2, 11, 0: 2\n" /* Type 2, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Well
+};
+
+
+
+
+
+// The prefab counts:
+
+const size_t g_SandFlatRoofVillagePrefabsCount = ARRAYCOUNT(g_SandFlatRoofVillagePrefabs);
+
+const size_t g_SandFlatRoofVillageStartingPrefabsCount = ARRAYCOUNT(g_SandFlatRoofVillageStartingPrefabs);
+
diff --git a/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h
new file mode 100644
index 000000000..ea06de5b5
--- /dev/null
+++ b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h
@@ -0,0 +1,15 @@
+
+// SandFlatRoofVillagePrefabs.h
+
+// Declares the prefabs in the group SandFlatRoofVillage
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_SandFlatRoofVillagePrefabs[];
+extern const cPrefab::sDef g_SandFlatRoofVillageStartingPrefabs[];
+extern const size_t g_SandFlatRoofVillagePrefabsCount;
+extern const size_t g_SandFlatRoofVillageStartingPrefabsCount;
diff --git a/src/Generating/Prefabs/SandVillagePrefabs.cpp b/src/Generating/Prefabs/SandVillagePrefabs.cpp
new file mode 100644
index 000000000..a062f8cd4
--- /dev/null
+++ b/src/Generating/Prefabs/SandVillagePrefabs.cpp
@@ -0,0 +1,2133 @@
+
+// SandVillagePrefabs.cpp
+
+// Defines the prefabs in the group SandVillage
+
+// NOTE: This file has been generated automatically by GalExport!
+// Any manual changes will be overwritten by the next automatic export!
+
+#include "Globals.h"
+#include "SandVillagePrefabs.h"
+
+
+
+
+
+const cPrefab::sDef g_SandVillagePrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // DoubleField:
+ // The data has been exported from the gallery Desert, area index 5, ID 75, created by tonibm1999
+ {
+ // Size:
+ 13, 2, 9, // SizeX = 13, SizeY = 2, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 1, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 24: 0\n" /* sandstone */
+ "b: 60: 7\n" /* tilleddirt */
+ "c: 8: 0\n" /* water */
+ "d: 50: 5\n" /* torch */
+ "e: 59: 7\n" /* crops */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "aaaaaaaaaaaaa"
+ /* 1 */ "abbcbbabbcbba"
+ /* 2 */ "abbcbbabbcbba"
+ /* 3 */ "abbcbbabbcbba"
+ /* 4 */ "abbcbbabbcbba"
+ /* 5 */ "abbcbbabbcbba"
+ /* 6 */ "abbcbbabbcbba"
+ /* 7 */ "abbcbbabbcbba"
+ /* 8 */ "aaaaaaaaaaaaa"
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "d.....d.....d"
+ /* 1 */ ".......ee.ee."
+ /* 2 */ ".......ee.ee."
+ /* 3 */ ".......ee.ee."
+ /* 4 */ ".......ee.ee."
+ /* 5 */ ".......ee.ee."
+ /* 6 */ ".......ee.ee."
+ /* 7 */ ".......ee.ee."
+ /* 8 */ "d.....d.....d",
+
+ // Connectors:
+ "-1: 6, 0, 8: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // DoubleField
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House11x7:
+ // The data has been exported from the gallery Desert, area index 6, ID 81, created by Aloe_vera
+ {
+ // Size:
+ 11, 6, 7, // SizeX = 11, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 5, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */
+ "n: 50: 1\n" /* torch */
+ "o: 50: 2\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....abc...."
+ /* 1 */ ".ddddddddd."
+ /* 2 */ ".ddddddddd."
+ /* 3 */ ".ddddddddd."
+ /* 4 */ ".ddddddddd."
+ /* 5 */ ".ddddddddd."
+ /* 6 */ "..........."
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ddddedddd."
+ /* 2 */ ".d.......d."
+ /* 3 */ ".d.......d."
+ /* 4 */ ".d.......d."
+ /* 5 */ ".ddddddddd."
+ /* 6 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".dffdgdffd."
+ /* 2 */ ".f.......f."
+ /* 3 */ ".f.......f."
+ /* 4 */ ".f.......f."
+ /* 5 */ ".dffdfdffd."
+ /* 6 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "bbbbbbbbbbb"
+ /* 1 */ "hdddddddddh"
+ /* 2 */ ".d..i.i..d."
+ /* 3 */ ".d.......d."
+ /* 4 */ ".d..j.j..d."
+ /* 5 */ "kdddddddddk"
+ /* 6 */ "lllllllllll"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "bbbbbbbbbbb"
+ /* 2 */ "hdddddddddh"
+ /* 3 */ ".dn.....od."
+ /* 4 */ "kdddddddddk"
+ /* 5 */ "lllllllllll"
+ /* 6 */ "..........."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "bbbbbbbbbbb"
+ /* 3 */ "ddddddddddd"
+ /* 4 */ "lllllllllll"
+ /* 5 */ "..........."
+ /* 6 */ "...........",
+
+ // Connectors:
+ "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House11x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House11x9:
+ // The data has been exported from the gallery Desert, area index 11, ID 115, created by xoft
+ {
+ // Size:
+ 11, 7, 9, // SizeX = 11, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 10, 6, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "....abc...."
+ /* 1 */ ".ddddddddd."
+ /* 2 */ ".ddddddddd."
+ /* 3 */ ".ddddddddd."
+ /* 4 */ ".ddddddddd."
+ /* 5 */ ".ddddddddd."
+ /* 6 */ ".ddddddddd."
+ /* 7 */ ".ddddddddd."
+ /* 8 */ "..........."
+
+ // Level 1
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".ddddedddd."
+ /* 2 */ ".d.......d."
+ /* 3 */ ".d.......d."
+ /* 4 */ ".d.......d."
+ /* 5 */ ".d.......d."
+ /* 6 */ ".d.......d."
+ /* 7 */ ".ddddddddd."
+ /* 8 */ "..........."
+
+ // Level 2
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ ".dffdgdffd."
+ /* 2 */ ".f.......f."
+ /* 3 */ ".f.......f."
+ /* 4 */ ".d.......d."
+ /* 5 */ ".f.......f."
+ /* 6 */ ".f.......f."
+ /* 7 */ ".dfffdfffd."
+ /* 8 */ "..........."
+
+ // Level 3
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "bbbbbbbbbbb"
+ /* 1 */ "hdddddddddh"
+ /* 2 */ ".d..i.i..d."
+ /* 3 */ ".d.......d."
+ /* 4 */ ".d.......d."
+ /* 5 */ ".d.......d."
+ /* 6 */ ".d...j...d."
+ /* 7 */ "kdddddddddk"
+ /* 8 */ "lllllllllll"
+
+ // Level 4
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "bbbbbbbbbbb"
+ /* 2 */ "hdddddddddh"
+ /* 3 */ ".d.......d."
+ /* 4 */ ".d.......d."
+ /* 5 */ ".d.......d."
+ /* 6 */ "kdddddddddk"
+ /* 7 */ "lllllllllll"
+ /* 8 */ "..........."
+
+ // Level 5
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "bbbbbbbbbbb"
+ /* 3 */ "hdddddddddh"
+ /* 4 */ ".d.......d."
+ /* 5 */ "kdddddddddk"
+ /* 6 */ "lllllllllll"
+ /* 7 */ "..........."
+ /* 8 */ "..........."
+
+ // Level 6
+ /* z\x* 1 */
+ /* * 01234567890 */
+ /* 0 */ "..........."
+ /* 1 */ "..........."
+ /* 2 */ "..........."
+ /* 3 */ "bbbbbbbbbbb"
+ /* 4 */ "ddddddddddd"
+ /* 5 */ "lllllllllll"
+ /* 6 */ "..........."
+ /* 7 */ "..........."
+ /* 8 */ "...........",
+
+ // Connectors:
+ "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House11x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House13x7:
+ // The data has been exported from the gallery Desert, area index 15, ID 125, created by Aloe_vera
+ {
+ // Size:
+ 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 5, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ ".....abc....."
+ /* 1 */ ".ddddddddddd."
+ /* 2 */ ".ddddddddddd."
+ /* 3 */ ".ddddddddddd."
+ /* 4 */ ".ddddddddddd."
+ /* 5 */ ".ddddddddddd."
+ /* 6 */ "............."
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".dddddeddddd."
+ /* 2 */ ".d.........d."
+ /* 3 */ ".d.........d."
+ /* 4 */ ".d.........d."
+ /* 5 */ ".ddddddddddd."
+ /* 6 */ "............."
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".dfffdgdfffd."
+ /* 2 */ ".f.........f."
+ /* 3 */ ".f.........f."
+ /* 4 */ ".f.........f."
+ /* 5 */ ".dffdfffdffd."
+ /* 6 */ "............."
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "bbbbbbbbbbbbb"
+ /* 1 */ "hdddddddddddh"
+ /* 2 */ ".d...i.i...d."
+ /* 3 */ ".d.........d."
+ /* 4 */ ".d..j...j..d."
+ /* 5 */ "kdddddddddddk"
+ /* 6 */ "lllllllllllll"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "bbbbbbbbbbbbb"
+ /* 2 */ "hdddddddddddh"
+ /* 3 */ ".d.........d."
+ /* 4 */ "kdddddddddddk"
+ /* 5 */ "lllllllllllll"
+ /* 6 */ "............."
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "bbbbbbbbbbbbb"
+ /* 3 */ "ddddddddddddd"
+ /* 4 */ "lllllllllllll"
+ /* 5 */ "............."
+ /* 6 */ ".............",
+
+ // Connectors:
+ "-1: 6, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House13x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House13x9:
+ // The data has been exported from the gallery Desert, area index 12, ID 116, created by xoft
+ {
+ // Size:
+ 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 12, 6, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ ".....abc....."
+ /* 1 */ ".ddddddddddd."
+ /* 2 */ ".ddddddddddd."
+ /* 3 */ ".ddddddddddd."
+ /* 4 */ ".ddddddddddd."
+ /* 5 */ ".ddddddddddd."
+ /* 6 */ ".ddddddddddd."
+ /* 7 */ ".ddddddddddd."
+ /* 8 */ "............."
+
+ // Level 1
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".dddddeddddd."
+ /* 2 */ ".d.........d."
+ /* 3 */ ".d.........d."
+ /* 4 */ ".d.........d."
+ /* 5 */ ".d.........d."
+ /* 6 */ ".d.........d."
+ /* 7 */ ".ddddddddddd."
+ /* 8 */ "............."
+
+ // Level 2
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ ".dfffdgdfffd."
+ /* 2 */ ".f.........f."
+ /* 3 */ ".f.........f."
+ /* 4 */ ".d.........d."
+ /* 5 */ ".f.........f."
+ /* 6 */ ".f.........f."
+ /* 7 */ ".dffdffdfffd."
+ /* 8 */ "............."
+
+ // Level 3
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "bbbbbbbbbbbbb"
+ /* 1 */ "hdddddddddddh"
+ /* 2 */ ".d...i.i...d."
+ /* 3 */ ".d.........d."
+ /* 4 */ ".d.........d."
+ /* 5 */ ".d.........d."
+ /* 6 */ ".d..j..j...d."
+ /* 7 */ "kdddddddddddk"
+ /* 8 */ "lllllllllllll"
+
+ // Level 4
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "bbbbbbbbbbbbb"
+ /* 2 */ "hdddddddddddh"
+ /* 3 */ ".d.........d."
+ /* 4 */ ".d.........d."
+ /* 5 */ ".d.........d."
+ /* 6 */ "kdddddddddddk"
+ /* 7 */ "lllllllllllll"
+ /* 8 */ "............."
+
+ // Level 5
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "bbbbbbbbbbbbb"
+ /* 3 */ "hdddddddddddh"
+ /* 4 */ ".d.........d."
+ /* 5 */ "kdddddddddddk"
+ /* 6 */ "lllllllllllll"
+ /* 7 */ "............."
+ /* 8 */ "............."
+
+ // Level 6
+ /* z\x* 111 */
+ /* * 0123456789012 */
+ /* 0 */ "............."
+ /* 1 */ "............."
+ /* 2 */ "............."
+ /* 3 */ "bbbbbbbbbbbbb"
+ /* 4 */ "ddddddddddddd"
+ /* 5 */ "lllllllllllll"
+ /* 6 */ "............."
+ /* 7 */ "............."
+ /* 8 */ ".............",
+
+ // Connectors:
+ "-1: 6, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House13x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House15x9:
+ // The data has been exported from the gallery Desert, area index 13, ID 118, created by xoft
+ {
+ // Size:
+ 15, 7, 9, // SizeX = 15, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 14, 6, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ ".....abc......."
+ /* 1 */ ".ddddddddddddd."
+ /* 2 */ ".ddddddddddddd."
+ /* 3 */ ".ddddddddddddd."
+ /* 4 */ ".ddddddddddddd."
+ /* 5 */ ".ddddddddddddd."
+ /* 6 */ ".ddddddddddddd."
+ /* 7 */ ".ddddddddddddd."
+ /* 8 */ "..............."
+
+ // Level 1
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".dddddeddddddd."
+ /* 2 */ ".d...........d."
+ /* 3 */ ".d...........d."
+ /* 4 */ ".d...........d."
+ /* 5 */ ".d...........d."
+ /* 6 */ ".d...........d."
+ /* 7 */ ".ddddddddddddd."
+ /* 8 */ "..............."
+
+ // Level 2
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ ".dfffdgdffdffd."
+ /* 2 */ ".f...........f."
+ /* 3 */ ".f...........f."
+ /* 4 */ ".d...........d."
+ /* 5 */ ".f...........f."
+ /* 6 */ ".f...........f."
+ /* 7 */ ".dffdffdffdffd."
+ /* 8 */ "..............."
+
+ // Level 3
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "bbbbbbbbbbbbbbb"
+ /* 1 */ "hdddddddddddddh"
+ /* 2 */ ".d...i.i..i..d."
+ /* 3 */ ".d...........d."
+ /* 4 */ ".d...........d."
+ /* 5 */ ".d...........d."
+ /* 6 */ ".d..j..j..j..d."
+ /* 7 */ "kdddddddddddddk"
+ /* 8 */ "lllllllllllllll"
+
+ // Level 4
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "bbbbbbbbbbbbbbb"
+ /* 2 */ "hdddddddddddddh"
+ /* 3 */ ".d...........d."
+ /* 4 */ ".d...........d."
+ /* 5 */ ".d...........d."
+ /* 6 */ "kdddddddddddddk"
+ /* 7 */ "lllllllllllllll"
+ /* 8 */ "..............."
+
+ // Level 5
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "bbbbbbbbbbbbbbb"
+ /* 3 */ "hdddddddddddddh"
+ /* 4 */ ".d...........d."
+ /* 5 */ "kdddddddddddddk"
+ /* 6 */ "lllllllllllllll"
+ /* 7 */ "..............."
+ /* 8 */ "..............."
+
+ // Level 6
+ /* z\x* 11111 */
+ /* * 012345678901234 */
+ /* 0 */ "..............."
+ /* 1 */ "..............."
+ /* 2 */ "..............."
+ /* 3 */ "bbbbbbbbbbbbbbb"
+ /* 4 */ "ddddddddddddddd"
+ /* 5 */ "lllllllllllllll"
+ /* 6 */ "..............."
+ /* 7 */ "..............."
+ /* 8 */ "...............",
+
+ // Connectors:
+ "-1: 6, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House15x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House16x9:
+ // The data has been exported from the gallery Desert, area index 16, ID 126, created by Aloe_vera
+ {
+ // Size:
+ 16, 7, 9, // SizeX = 16, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 15, 6, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "........abc....."
+ /* 1 */ ".dddddddddddddd."
+ /* 2 */ ".dddddddddddddd."
+ /* 3 */ ".dddddddddddddd."
+ /* 4 */ ".dddddddddddddd."
+ /* 5 */ ".dddddddddddddd."
+ /* 6 */ ".dddddddddddddd."
+ /* 7 */ ".dddddddddddddd."
+ /* 8 */ "................"
+
+ // Level 1
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".ddddddddeddddd."
+ /* 2 */ ".d............d."
+ /* 3 */ ".d............d."
+ /* 4 */ ".d............d."
+ /* 5 */ ".d............d."
+ /* 6 */ ".d............d."
+ /* 7 */ ".dddddddddddddd."
+ /* 8 */ "................"
+
+ // Level 2
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ ".dffdfffdgdfffd."
+ /* 2 */ ".f............f."
+ /* 3 */ ".f............f."
+ /* 4 */ ".d............d."
+ /* 5 */ ".f............f."
+ /* 6 */ ".f............f."
+ /* 7 */ ".dffdffdfffdffd."
+ /* 8 */ "................"
+
+ // Level 3
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "bbbbbbbbbbbbbbbb"
+ /* 1 */ "hddddddddddddddh"
+ /* 2 */ ".d..i...i.i...d."
+ /* 3 */ ".d............d."
+ /* 4 */ ".d............d."
+ /* 5 */ ".d............d."
+ /* 6 */ ".d..j..j...j..d."
+ /* 7 */ "kddddddddddddddk"
+ /* 8 */ "llllllllllllllll"
+
+ // Level 4
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "bbbbbbbbbbbbbbbb"
+ /* 2 */ "hddddddddddddddh"
+ /* 3 */ ".d............d."
+ /* 4 */ ".d............d."
+ /* 5 */ ".d............d."
+ /* 6 */ "kddddddddddddddk"
+ /* 7 */ "llllllllllllllll"
+ /* 8 */ "................"
+
+ // Level 5
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "bbbbbbbbbbbbbbbb"
+ /* 3 */ "hddddddddddddddh"
+ /* 4 */ ".d............d."
+ /* 5 */ "kddddddddddddddk"
+ /* 6 */ "llllllllllllllll"
+ /* 7 */ "................"
+ /* 8 */ "................"
+
+ // Level 6
+ /* z\x* 111111 */
+ /* * 0123456789012345 */
+ /* 0 */ "................"
+ /* 1 */ "................"
+ /* 2 */ "................"
+ /* 3 */ "bbbbbbbbbbbbbbbb"
+ /* 4 */ "dddddddddddddddd"
+ /* 5 */ "llllllllllllllll"
+ /* 6 */ "................"
+ /* 7 */ "................"
+ /* 8 */ "................",
+
+ // Connectors:
+ "-1: 9, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House16x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House7x7:
+ // The data has been exported from the gallery Desert, area index 8, ID 112, created by Aloe_vera
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 5, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j:128: 6\n" /* sandstonestairs */
+ "k:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "...abc."
+ /* 1 */ ".ddddd."
+ /* 2 */ ".ddddd."
+ /* 3 */ ".ddddd."
+ /* 4 */ ".ddddd."
+ /* 5 */ ".ddddd."
+ /* 6 */ "......."
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".ddded."
+ /* 2 */ ".d...d."
+ /* 3 */ ".d...d."
+ /* 4 */ ".d...d."
+ /* 5 */ ".ddddd."
+ /* 6 */ "......."
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".dfdgd."
+ /* 2 */ ".f...f."
+ /* 3 */ ".f...f."
+ /* 4 */ ".f...f."
+ /* 5 */ ".dfffd."
+ /* 6 */ "......."
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "bbbbbbb"
+ /* 1 */ "hdddddh"
+ /* 2 */ ".d.i.d."
+ /* 3 */ ".d...d."
+ /* 4 */ ".d...d."
+ /* 5 */ "jdddddj"
+ /* 6 */ "kkkkkkk"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "bbbbbbb"
+ /* 2 */ "hdddddh"
+ /* 3 */ ".d...d."
+ /* 4 */ "jdddddj"
+ /* 5 */ "kkkkkkk"
+ /* 6 */ "......."
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "bbbbbbb"
+ /* 3 */ "ddddddd"
+ /* 4 */ "kkkkkkk"
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House7x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House9x7:
+ // The data has been exported from the gallery Desert, area index 9, ID 113, created by xoft
+ {
+ // Size:
+ 9, 6, 7, // SizeX = 9, SizeY = 6, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 8, 5, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "...abc..."
+ /* 1 */ ".ddddddd."
+ /* 2 */ ".ddddddd."
+ /* 3 */ ".ddddddd."
+ /* 4 */ ".ddddddd."
+ /* 5 */ ".ddddddd."
+ /* 6 */ "........."
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".dddeddd."
+ /* 2 */ ".d.....d."
+ /* 3 */ ".d.....d."
+ /* 4 */ ".d.....d."
+ /* 5 */ ".ddddddd."
+ /* 6 */ "........."
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".dfdgdfd."
+ /* 2 */ ".f.....f."
+ /* 3 */ ".f.....f."
+ /* 4 */ ".f.....f."
+ /* 5 */ ".dffdffd."
+ /* 6 */ "........."
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "bbbbbbbbb"
+ /* 1 */ "hdddddddh"
+ /* 2 */ ".d.i.i.d."
+ /* 3 */ ".d.....d."
+ /* 4 */ ".d..j..d."
+ /* 5 */ "kdddddddk"
+ /* 6 */ "lllllllll"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "bbbbbbbbb"
+ /* 2 */ "hdddddddh"
+ /* 3 */ ".d.....d."
+ /* 4 */ "kdddddddk"
+ /* 5 */ "lllllllll"
+ /* 6 */ "........."
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "bbbbbbbbb"
+ /* 3 */ "ddddddddd"
+ /* 4 */ "lllllllll"
+ /* 5 */ "........."
+ /* 6 */ ".........",
+
+ // Connectors:
+ "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House9x7
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // House9x9:
+ // The data has been exported from the gallery Desert, area index 10, ID 114, created by xoft
+ {
+ // Size:
+ 9, 7, 9, // SizeX = 9, SizeY = 7, SizeZ = 9
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 8, 6, 8, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e: 64: 7\n" /* wooddoorblock */
+ "f:102: 0\n" /* glasspane */
+ "g: 64:12\n" /* wooddoorblock */
+ "h:128: 7\n" /* sandstonestairs */
+ "i: 50: 3\n" /* torch */
+ "j: 50: 4\n" /* torch */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 012345678 */
+ /* 0 */ "...abc..."
+ /* 1 */ ".ddddddd."
+ /* 2 */ ".ddddddd."
+ /* 3 */ ".ddddddd."
+ /* 4 */ ".ddddddd."
+ /* 5 */ ".ddddddd."
+ /* 6 */ ".ddddddd."
+ /* 7 */ ".ddddddd."
+ /* 8 */ "........."
+
+ // Level 1
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".dddeddd."
+ /* 2 */ ".d.....d."
+ /* 3 */ ".d.....d."
+ /* 4 */ ".d.....d."
+ /* 5 */ ".d.....d."
+ /* 6 */ ".d.....d."
+ /* 7 */ ".ddddddd."
+ /* 8 */ "........."
+
+ // Level 2
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ ".dfdgdfd."
+ /* 2 */ ".f.....f."
+ /* 3 */ ".f.....f."
+ /* 4 */ ".d.....d."
+ /* 5 */ ".f.....f."
+ /* 6 */ ".f.....f."
+ /* 7 */ ".dffdffd."
+ /* 8 */ "........."
+
+ // Level 3
+ /* z\x* 012345678 */
+ /* 0 */ "bbbbbbbbb"
+ /* 1 */ "hdddddddh"
+ /* 2 */ ".d.i.i.d."
+ /* 3 */ ".d.....d."
+ /* 4 */ ".d.....d."
+ /* 5 */ ".d.....d."
+ /* 6 */ ".d..j..d."
+ /* 7 */ "kdddddddk"
+ /* 8 */ "lllllllll"
+
+ // Level 4
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "bbbbbbbbb"
+ /* 2 */ "hdddddddh"
+ /* 3 */ ".d.....d."
+ /* 4 */ ".d.....d."
+ /* 5 */ ".d.....d."
+ /* 6 */ "kdddddddk"
+ /* 7 */ "lllllllll"
+ /* 8 */ "........."
+
+ // Level 5
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "bbbbbbbbb"
+ /* 3 */ "hdddddddh"
+ /* 4 */ ".d.....d."
+ /* 5 */ "kdddddddk"
+ /* 6 */ "lllllllll"
+ /* 7 */ "........."
+ /* 8 */ "........."
+
+ // Level 6
+ /* z\x* 012345678 */
+ /* 0 */ "........."
+ /* 1 */ "........."
+ /* 2 */ "........."
+ /* 3 */ "bbbbbbbbb"
+ /* 4 */ "ddddddddd"
+ /* 5 */ "lllllllll"
+ /* 6 */ "........."
+ /* 7 */ "........."
+ /* 8 */ ".........",
+
+ // Connectors:
+ "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // House9x9
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseL14x12:
+ // The data has been exported from the gallery Desert, area index 14, ID 124, created by Aloe_vera
+ {
+ // Size:
+ 14, 7, 12, // SizeX = 14, SizeY = 7, SizeZ = 12
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 13, 6, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e:128: 3\n" /* sandstonestairs */
+ "f: 64: 7\n" /* wooddoorblock */
+ "g:102: 0\n" /* glasspane */
+ "h: 64:12\n" /* wooddoorblock */
+ "i:128: 7\n" /* sandstonestairs */
+ "j: 50: 3\n" /* torch */
+ "k: 50: 2\n" /* torch */
+ "l: 50: 4\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 6\n" /* sandstonestairs */
+ "o: 50: 1\n" /* torch */
+ "p:128: 5\n" /* sandstonestairs */
+ "q:128: 4\n" /* sandstonestairs */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "....abc......."
+ /* 1 */ ".dddddddddddd."
+ /* 2 */ ".dddddddddddd."
+ /* 3 */ ".dddddddddddd."
+ /* 4 */ ".dddddddddddd."
+ /* 5 */ ".dddddddddddd."
+ /* 6 */ ".dddddddddddd."
+ /* 7 */ ".dddddddddddd."
+ /* 8 */ "....aeddddddd."
+ /* 9 */ "mmmmm.ddddddd."
+ /* 10 */ "mmmmm.ddddddd."
+ /* 11 */ "mmmmm........."
+
+ // Level 1
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".ddddfddddddd."
+ /* 2 */ ".d..........d."
+ /* 3 */ ".d..........d."
+ /* 4 */ ".d..........d."
+ /* 5 */ ".d..........d."
+ /* 6 */ ".d..........d."
+ /* 7 */ ".ddddfd.....d."
+ /* 8 */ "......d.....d."
+ /* 9 */ "mmmmm.d.....d."
+ /* 10 */ "mmmmm.ddddddd."
+ /* 11 */ "mmmmm........."
+
+ // Level 2
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".dggdhdggdggd."
+ /* 2 */ ".g..........g."
+ /* 3 */ ".g..........g."
+ /* 4 */ ".d..........d."
+ /* 5 */ ".g..........g."
+ /* 6 */ ".g..........g."
+ /* 7 */ ".dggdhd.....d."
+ /* 8 */ "......g.....g."
+ /* 9 */ "mmmmm.g.....g."
+ /* 10 */ "mmmmm.dggdggd."
+ /* 11 */ "mmmmm........."
+
+ // Level 3
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "bbbbbbbbbbbbbb"
+ /* 1 */ "iddddddddddddc"
+ /* 2 */ ".d..j.j.....dc"
+ /* 3 */ ".d..........dc"
+ /* 4 */ ".d.........kdc"
+ /* 5 */ ".d..........dc"
+ /* 6 */ ".d..l.l.....dc"
+ /* 7 */ "nddddddo...kdc"
+ /* 8 */ "eeeeead.....dc"
+ /* 9 */ "mmmmmad.....dc"
+ /* 10 */ "mmmmmadddddddc"
+ /* 11 */ "mmmmmap.....qc"
+
+ // Level 4
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ "bbbbbbbbbbbbc."
+ /* 2 */ "idddddddddddc."
+ /* 3 */ ".d.........dc."
+ /* 4 */ ".d.........dc."
+ /* 5 */ ".d.........dc."
+ /* 6 */ "nddddddd...dc."
+ /* 7 */ "eeeeeead...dc."
+ /* 8 */ "......ad...dc."
+ /* 9 */ "mmmmm.ad...dc."
+ /* 10 */ "mmmmm.adddddc."
+ /* 11 */ "mmmmm.ap...qc."
+
+ // Level 5
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".............."
+ /* 2 */ "bbbbbbbbbbbb.."
+ /* 3 */ "iddddddddddc.."
+ /* 4 */ ".d........dc.."
+ /* 5 */ "ndddddddd.dc.."
+ /* 6 */ "eeeeeeeed.dc.."
+ /* 7 */ ".......ad.dc.."
+ /* 8 */ ".......ad.dc.."
+ /* 9 */ "mmmmm..ad.dc.."
+ /* 10 */ "mmmmm..adddc.."
+ /* 11 */ "mmmmm..ap.qc.."
+
+ // Level 6
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".............."
+ /* 2 */ ".............."
+ /* 3 */ "bbbbbbbbbbb..."
+ /* 4 */ "ddddddddddc..."
+ /* 5 */ "eeeeeeeeadc..."
+ /* 6 */ "........adc..."
+ /* 7 */ "........adc..."
+ /* 8 */ "........adc..."
+ /* 9 */ "mmmmm...adc..."
+ /* 10 */ "mmmmm...adc..."
+ /* 11 */ "mmmmm...adc...",
+
+ // Connectors:
+ "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseL14x12
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HouseL14x12:
+ // The data has been exported from the gallery Desert, area index 7, ID 82, created by Aloe_vera
+ {
+ // Size:
+ 14, 6, 12, // SizeX = 14, SizeY = 6, SizeZ = 12
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 13, 5, 11, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:128: 0\n" /* sandstonestairs */
+ "b:128: 2\n" /* sandstonestairs */
+ "c:128: 1\n" /* sandstonestairs */
+ "d: 24: 0\n" /* sandstone */
+ "e:128: 3\n" /* sandstonestairs */
+ "f: 64: 7\n" /* wooddoorblock */
+ "g: 64: 5\n" /* wooddoorblock */
+ "h:102: 0\n" /* glasspane */
+ "i: 64:12\n" /* wooddoorblock */
+ "j:128: 7\n" /* sandstonestairs */
+ "k: 50: 3\n" /* torch */
+ "l: 50: 4\n" /* torch */
+ "m: 19: 0\n" /* sponge */
+ "n:128: 6\n" /* sandstonestairs */
+ "o:128: 5\n" /* sandstonestairs */
+ "p:128: 4\n" /* sandstonestairs */
+ "q: 50: 1\n" /* torch */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".......abc...."
+ /* 1 */ ".dddddddddddd."
+ /* 2 */ ".dddddddddddd."
+ /* 3 */ ".dddddddddddd."
+ /* 4 */ ".dddddddddddd."
+ /* 5 */ ".dddddddddddd."
+ /* 6 */ "....aec.ddddd."
+ /* 7 */ "mmmmmmm.ddddd."
+ /* 8 */ "mmmmmmm.ddddd."
+ /* 9 */ "mmmmmmm.ddddd."
+ /* 10 */ "mmmmmmm.ddddd."
+ /* 11 */ "mmmmmmm......."
+
+ // Level 1
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".dddddddfdddd."
+ /* 2 */ ".d..........d."
+ /* 3 */ ".d..........d."
+ /* 4 */ ".d..........d."
+ /* 5 */ ".ddddgddd...d."
+ /* 6 */ "........d...d."
+ /* 7 */ "mmmmmmm.d...d."
+ /* 8 */ "mmmmmmm.d...d."
+ /* 9 */ "mmmmmmm.d...d."
+ /* 10 */ "mmmmmmm.ddddd."
+ /* 11 */ "mmmmmmm......."
+
+ // Level 2
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".dhhdhhdidhhd."
+ /* 2 */ ".h..........h."
+ /* 3 */ ".h..........h."
+ /* 4 */ ".h..........d."
+ /* 5 */ ".dhhdidhh...h."
+ /* 6 */ "........h...h."
+ /* 7 */ "mmmmmmm.d...d."
+ /* 8 */ "mmmmmmm.h...h."
+ /* 9 */ "mmmmmmm.h...h."
+ /* 10 */ "mmmmmmm.dhhhd."
+ /* 11 */ "mmmmmmm......."
+
+ // Level 3
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ "bbbbbbbbbbbbbb"
+ /* 1 */ "jddddddddddddc"
+ /* 2 */ ".d.....k.k..dc"
+ /* 3 */ ".d..........dc"
+ /* 4 */ ".d..l.l.....dc"
+ /* 5 */ "ndddddddd...dc"
+ /* 6 */ "eeeeeeead...dc"
+ /* 7 */ "mmmmmmmad...dc"
+ /* 8 */ "mmmmmmmad...dc"
+ /* 9 */ "mmmmmmmad...dc"
+ /* 10 */ "mmmmmmmadddddc"
+ /* 11 */ "mmmmmmmao...pc"
+
+ // Level 4
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ "bbbbbbbbbbbbb."
+ /* 2 */ "jdddddddddddc."
+ /* 3 */ ".dq........dc."
+ /* 4 */ "nddddddddd.dc."
+ /* 5 */ "eeeeeeeead.dc."
+ /* 6 */ "........ad.dc."
+ /* 7 */ "mmmmmmm.ad.dc."
+ /* 8 */ "mmmmmmm.ad.dc."
+ /* 9 */ "mmmmmmm.adldc."
+ /* 10 */ "mmmmmmm.adddc."
+ /* 11 */ "mmmmmmm.ao.pc."
+
+ // Level 5
+ /* z\x* 1111 */
+ /* * 01234567890123 */
+ /* 0 */ ".............."
+ /* 1 */ ".............."
+ /* 2 */ "bbbbbbbbbbbb.."
+ /* 3 */ "dddddddddddc.."
+ /* 4 */ "eeeeeeeeeadc.."
+ /* 5 */ ".........adc.."
+ /* 6 */ ".........adc.."
+ /* 7 */ "mmmmmmm..adc.."
+ /* 8 */ "mmmmmmm..adc.."
+ /* 9 */ "mmmmmmm..adc.."
+ /* 10 */ "mmmmmmm..adc.."
+ /* 11 */ "mmmmmmm..adc..",
+
+ // Connectors:
+ "-1: 8, 0, 0: 2\n" /* Type -1, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // HouseL14x12
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // SingleField:
+ // The data has been exported from the gallery Desert, area index 17, ID 127, created by Aloe_vera
+ {
+ // Size:
+ 10, 2, 7, // SizeX = 10, SizeY = 2, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 9, 1, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 24: 0\n" /* sandstone */
+ "b: 60: 7\n" /* tilleddirt */
+ "c: 8: 0\n" /* water */
+ "d: 50: 5\n" /* torch */
+ "e: 59: 7\n" /* crops */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "aaaaaaaaaa"
+ /* 1 */ "abbbbbbbba"
+ /* 2 */ "abbbbbbbba"
+ /* 3 */ "acccccccca"
+ /* 4 */ "abbbbbbbba"
+ /* 5 */ "abbbbbbbba"
+ /* 6 */ "aaaaaaaaaa"
+
+ // Level 1
+ /* z\x* */
+ /* * 0123456789 */
+ /* 0 */ "d........d"
+ /* 1 */ ".eeeeeeee."
+ /* 2 */ ".eeeeeeee."
+ /* 3 */ ".........."
+ /* 4 */ ".eeeeeeee."
+ /* 5 */ ".eeeeeeee."
+ /* 6 */ "d........d",
+
+ // Connectors:
+ "-1: 0, 0, 3: 4\n" /* Type -1, direction X- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // SingleField
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // SmallHut:
+ // The data has been exported from the gallery Desert, area index 4, ID 68, created by tonibm1999
+ {
+ // Size:
+ 5, 5, 6, // SizeX = 5, SizeY = 5, SizeZ = 6
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 4, 4, 5, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 24: 0\n" /* sandstone */
+ "b:128: 3\n" /* sandstonestairs */
+ "c: 24: 2\n" /* sandstone */
+ "d: 50: 5\n" /* torch */
+ "e: 26:10\n" /* bedblock */
+ "f: 26: 2\n" /* bedblock */
+ "g: 64: 5\n" /* wooddoorblock */
+ "h: 64:12\n" /* wooddoorblock */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 01234 */
+ /* 0 */ "aaaaa"
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ "aaaaa"
+ /* 5 */ "..b.."
+
+ // Level 1
+ /* z\x* 01234 */
+ /* 0 */ "accca"
+ /* 1 */ "cdedc"
+ /* 2 */ "c.f.c"
+ /* 3 */ "c...c"
+ /* 4 */ "acgca"
+ /* 5 */ "....."
+
+ // Level 2
+ /* z\x* 01234 */
+ /* 0 */ "ac.ca"
+ /* 1 */ "c...c"
+ /* 2 */ "....."
+ /* 3 */ "c...c"
+ /* 4 */ "achca"
+ /* 5 */ "....."
+
+ // Level 3
+ /* z\x* 01234 */
+ /* 0 */ "accca"
+ /* 1 */ "c...c"
+ /* 2 */ "c...c"
+ /* 3 */ "c...c"
+ /* 4 */ "accca"
+ /* 5 */ "....."
+
+ // Level 4
+ /* z\x* 01234 */
+ /* 0 */ ".aaa."
+ /* 1 */ "aaaaa"
+ /* 2 */ "aaaaa"
+ /* 3 */ "aaaaa"
+ /* 4 */ ".aaa."
+ /* 5 */ ".....",
+
+ // Connectors:
+ "-1: 2, 0, 5: 3\n" /* Type -1, direction Z+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // SmallHut
+}; // g_SandVillagePrefabs
+
+
+
+
+
+
+const cPrefab::sDef g_SandVillageStartingPrefabs[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // RoofedWell:
+ // The data has been exported from the gallery Desert, area index 43, ID 274, created by Aloe_vera
+ {
+ // Size:
+ 7, 14, 7, // SizeX = 7, SizeY = 14, SizeZ = 7
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 6, 13, 6, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 24: 0\n" /* sandstone */
+ "c: 8: 0\n" /* water */
+ "d: 12: 0\n" /* sand */
+ "e:118: 3\n" /* cauldronblock */
+ "f: 85: 0\n" /* fence */
+ "g:128: 2\n" /* sandstonestairs */
+ "h:128: 7\n" /* sandstonestairs */
+ "i:128: 4\n" /* sandstonestairs */
+ "j:128: 5\n" /* sandstonestairs */
+ "k:128: 6\n" /* sandstonestairs */
+ "l:128: 3\n" /* sandstonestairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "aaaaaaa"
+ /* 2 */ "aaaaaaa"
+ /* 3 */ "aaaaaaa"
+ /* 4 */ "aaaaaaa"
+ /* 5 */ "aaaaaaa"
+ /* 6 */ "aaaaaaa"
+
+ // Level 1
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 2
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 3
+ /* z\x* 0123456 */
+ /* 0 */ "aaaaaaa"
+ /* 1 */ "abbbbba"
+ /* 2 */ "abcccba"
+ /* 3 */ "abcccba"
+ /* 4 */ "abcccba"
+ /* 5 */ "abbbbba"
+ /* 6 */ "aaaaaaa"
+
+ // Level 4
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 5
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 6
+ /* z\x* 0123456 */
+ /* 0 */ "ddddddd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "dbcccbd"
+ /* 3 */ "dbcccbd"
+ /* 4 */ "dbcccbd"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddddddd"
+
+ // Level 7
+ /* z\x* 0123456 */
+ /* 0 */ "ddbbbdd"
+ /* 1 */ "dbbbbbd"
+ /* 2 */ "bbcccbb"
+ /* 3 */ "bbcccbb"
+ /* 4 */ "bbcccbb"
+ /* 5 */ "dbbbbbd"
+ /* 6 */ "ddbbbdd"
+
+ // Level 8
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".bbbbb."
+ /* 2 */ ".b...b."
+ /* 3 */ ".b.e.b."
+ /* 4 */ ".b...b."
+ /* 5 */ ".bbbbb."
+ /* 6 */ "......."
+
+ // Level 9
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".f...f."
+ /* 2 */ "......."
+ /* 3 */ "...f..."
+ /* 4 */ "......."
+ /* 5 */ ".f...f."
+ /* 6 */ "......."
+
+ // Level 10
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ ".f...f."
+ /* 2 */ "......."
+ /* 3 */ "...f..."
+ /* 4 */ "......."
+ /* 5 */ ".f...f."
+ /* 6 */ "......."
+
+ // Level 11
+ /* z\x* 0123456 */
+ /* 0 */ "ggggggg"
+ /* 1 */ "hbhhhbh"
+ /* 2 */ ".i...j."
+ /* 3 */ ".i.f.j."
+ /* 4 */ ".i...j."
+ /* 5 */ "kbkkkbk"
+ /* 6 */ "lllllll"
+
+ // Level 12
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "ggggggg"
+ /* 2 */ "hb...bh"
+ /* 3 */ ".b.f.b."
+ /* 4 */ "kb...bk"
+ /* 5 */ "lllllll"
+ /* 6 */ "......."
+
+ // Level 13
+ /* z\x* 0123456 */
+ /* 0 */ "......."
+ /* 1 */ "......."
+ /* 2 */ "ggggggg"
+ /* 3 */ "bbbbbbb"
+ /* 4 */ "lllllll"
+ /* 5 */ "......."
+ /* 6 */ ".......",
+
+ // Connectors:
+ "2: 6, 8, 3: 5\n" /* Type 2, direction X+ */
+ "2: 3, 8, 6: 3\n" /* Type 2, direction Z+ */
+ "2: 0, 8, 3: 4\n" /* Type 2, direction X- */
+ "2: 3, 8, 0: 2\n" /* Type 2, direction Z- */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // RoofedWell
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Well:
+ // The data has been exported from the gallery Desert, area index 0, ID 1, created by Aloe_vera
+ {
+ // Size:
+ 4, 13, 4, // SizeX = 4, SizeY = 13, SizeZ = 4
+
+ // Hitbox (relative to bounding box):
+ 0, 0, 0, // MinX, MinY, MinZ
+ 3, 12, 3, // MaxX, MaxY, MaxZ
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a: 1: 0\n" /* stone */
+ "b: 24: 0\n" /* sandstone */
+ "c: 8: 0\n" /* water */
+ "d: 85: 0\n" /* fence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 0
+ /* z\x* 0123 */
+ /* 0 */ "aaaa"
+ /* 1 */ "aaaa"
+ /* 2 */ "aaaa"
+ /* 3 */ "aaaa"
+
+ // Level 1
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 2
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 3
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 4
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 5
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 6
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 7
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bccb"
+ /* 2 */ "bccb"
+ /* 3 */ "bbbb"
+
+ // Level 8
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "b..b"
+ /* 2 */ "b..b"
+ /* 3 */ "bbbb"
+
+ // Level 9
+ /* z\x* 0123 */
+ /* 0 */ "d..d"
+ /* 1 */ "...."
+ /* 2 */ "...."
+ /* 3 */ "d..d"
+
+ // Level 10
+ /* z\x* 0123 */
+ /* 0 */ "d..d"
+ /* 1 */ "...."
+ /* 2 */ "...."
+ /* 3 */ "d..d"
+
+ // Level 11
+ /* z\x* 0123 */
+ /* 0 */ "d..d"
+ /* 1 */ "...."
+ /* 2 */ "...."
+ /* 3 */ "d..d"
+
+ // Level 12
+ /* z\x* 0123 */
+ /* 0 */ "bbbb"
+ /* 1 */ "bbbb"
+ /* 2 */ "bbbb"
+ /* 3 */ "bbbb",
+
+ // Connectors:
+ "2: 2, 8, 0: 2\n" /* Type 2, direction Z- */
+ "2: 0, 8, 1: 4\n" /* Type 2, direction X- */
+ "2: 1, 8, 3: 3\n" /* Type 2, direction Z+ */
+ "2: 3, 8, 2: 5\n" /* Type 2, direction X+ */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotation allowed */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+
+ // ShouldExtendFloor:
+ true,
+
+ // DefaultWeight:
+ 100,
+
+ // DepthWeight:
+ "",
+
+ // AddWeightIfSame:
+ 0,
+
+ // MoveToGround:
+ true,
+ }, // Well
+};
+
+
+
+
+
+// The prefab counts:
+
+const size_t g_SandVillagePrefabsCount = ARRAYCOUNT(g_SandVillagePrefabs);
+
+const size_t g_SandVillageStartingPrefabsCount = ARRAYCOUNT(g_SandVillageStartingPrefabs);
+
diff --git a/src/Generating/Prefabs/SandVillagePrefabs.h b/src/Generating/Prefabs/SandVillagePrefabs.h
new file mode 100644
index 000000000..7b00db56f
--- /dev/null
+++ b/src/Generating/Prefabs/SandVillagePrefabs.h
@@ -0,0 +1,15 @@
+
+// SandVillagePrefabs.h
+
+// Declares the prefabs in the group SandVillage
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_SandVillagePrefabs[];
+extern const cPrefab::sDef g_SandVillageStartingPrefabs[];
+extern const size_t g_SandVillagePrefabsCount;
+extern const size_t g_SandVillageStartingPrefabsCount;
diff --git a/src/Generating/Ravines.cpp b/src/Generating/Ravines.cpp
index e64f55214..2722e4ca3 100644
--- a/src/Generating/Ravines.cpp
+++ b/src/Generating/Ravines.cpp
@@ -9,9 +9,6 @@
-/// How many ravines in each direction are generated for a given chunk. Must be an even number
-static const int NEIGHBORHOOD_SIZE = 8;
-
static const int NUM_RAVINE_POINTS = 4;
@@ -42,40 +39,38 @@ typedef std::vector<cRavDefPoint> cRavDefPoints;
-class cStructGenRavines::cRavine
+class cStructGenRavines::cRavine :
+ public cGridStructGen::cStructure
{
+ typedef cGridStructGen::cStructure super;
+
cRavDefPoints m_Points;
+
- /// Generates the shaping defpoints for the ravine, based on the ravine block coords and noise
+ /** Generates the shaping defpoints for the ravine, based on the ravine block coords and noise */
void GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise);
- /// Refines (adds and smooths) defpoints from a_Src into a_Dst
+ /** Refines (adds and smooths) defpoints from a_Src into a_Dst */
void RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst);
- /// Does one round of smoothing, two passes of RefineDefPoints()
+ /** Does one round of smoothing, two passes of RefineDefPoints() */
void Smooth(void);
- /// Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block
+ /** Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block */
void FinishLinear(void);
public:
- // Coords for which the ravine was generated (not necessarily the center)
- int m_BlockX;
- int m_BlockZ;
cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise);
- /// Carves the ravine into the chunk specified
- void ProcessChunk(
- int a_ChunkX, int a_ChunkZ,
- cChunkDef::BlockTypes & a_BlockTypes,
- cChunkDef::HeightMap & a_HeightMap
- );
-
#ifdef _DEBUG
/// Exports itself as a SVG line definition
AString ExportAsSVG(int a_Color, int a_OffsetX = 0, int a_OffsetZ = 0) const;
#endif // _DEBUG
+
+protected:
+ // cGridStructGen::cStructure overrides:
+ virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -86,6 +81,7 @@ public:
// cStructGenRavines:
cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) :
+ super(a_Seed, a_Size, a_Size, a_Size * 2, a_Size * 2, 100),
m_Noise(a_Seed),
m_Size(a_Size)
{
@@ -95,139 +91,9 @@ cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) :
-cStructGenRavines::~cStructGenRavines()
-{
- ClearCache();
-}
-
-
-
-
-
-void cStructGenRavines::ClearCache(void)
+cGridStructGen::cStructurePtr cStructGenRavines::CreateStructure(int a_OriginX, int a_OriginZ)
{
- for (cRavines::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
- {
- delete *itr;
- } // for itr - m_Cache[]
- m_Cache.clear();
-}
-
-
-
-
-
-void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc)
-{
- int ChunkX = a_ChunkDesc.GetChunkX();
- int ChunkZ = a_ChunkDesc.GetChunkZ();
- cRavines Ravines;
- GetRavinesForChunk(ChunkX, ChunkZ, Ravines);
- for (cRavines::const_iterator itr = Ravines.begin(), end = Ravines.end(); itr != end; ++itr)
- {
- (*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap());
- } // for itr - Ravines[]
-}
-
-
-
-
-
-void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenRavines::cRavines & a_Ravines)
-{
- int BaseX = a_ChunkX * cChunkDef::Width / m_Size;
- int BaseZ = a_ChunkZ * cChunkDef::Width / m_Size;
- if (BaseX < 0)
- {
- --BaseX;
- }
- if (BaseZ < 0)
- {
- --BaseZ;
- }
- BaseX -= 4;
- BaseZ -= 4;
-
- // Walk the cache, move each ravine that we want into a_Ravines:
- int StartX = BaseX * m_Size;
- int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Size;
- int StartZ = BaseZ * m_Size;
- int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Size;
- for (cRavines::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_Ravines.push_back(*itr);
- itr = m_Cache.erase(itr);
- }
- else
- {
- // don't want
- ++itr;
- }
- } // for itr - m_Cache[]
-
- for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
- {
- int RealX = (BaseX + x) * m_Size;
- for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
- {
- int RealZ = (BaseZ + z) * m_Size;
- bool Found = false;
- for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr)
- {
- if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
- {
- Found = true;
- break;
- }
- }
- if (!Found)
- {
- a_Ravines.push_back(new cRavine(RealX, RealZ, m_Size, m_Noise));
- }
- }
- }
-
- // Copy a_Ravines into m_Cache to the beginning:
- cRavines RavinesCopy(a_Ravines);
- m_Cache.splice(m_Cache.begin(), RavinesCopy, RavinesCopy.begin(), RavinesCopy.end());
-
- // Trim the cache if it's too long:
- if (m_Cache.size() > 100)
- {
- cRavines::iterator itr = m_Cache.begin();
- std::advance(itr, 100);
- for (cRavines::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());
- }
-
- /*
- #ifdef _DEBUG
- // DEBUG: Export as SVG into a file specific for the chunk, for visual verification:
- AString SVG;
- SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n");
- for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr)
- {
- SVG.append((*itr)->ExportAsSVG(0, 512, 512));
- }
- SVG.append("</svg>\n");
-
- AString fnam;
- Printf(fnam, "ravines\\%03d_%03d.svg", a_ChunkX, a_ChunkZ);
- cFile File(fnam, cFile::fmWrite);
- File.Write(SVG.c_str(), SVG.size());
- #endif // _DEBUG
- //*/
+ return cStructurePtr(new cRavine(a_OriginX, a_OriginZ, m_Size, m_Noise));
}
@@ -238,14 +104,13 @@ void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGe
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenRavines::cRavine
-cStructGenRavines::cRavine::cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise) :
- m_BlockX(a_BlockX),
- m_BlockZ(a_BlockZ)
+cStructGenRavines::cRavine::cRavine(int a_OriginX, int a_OriginZ, int a_Size, cNoise & a_Noise) :
+ super(a_OriginX, a_OriginZ)
{
// Calculate the ravine shape-defining points:
- GenerateBaseDefPoints(a_BlockX, a_BlockZ, a_Size, a_Noise);
+ GenerateBaseDefPoints(a_OriginX, a_OriginZ, a_Size, a_Noise);
- // Smooth the ravine. A two passes are needed:
+ // Smooth the ravine. Two passes are needed:
Smooth();
Smooth();
@@ -263,13 +128,13 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block
a_Size = (512 + ((a_Noise.IntNoise3DInt(19 * a_BlockX, 11 * a_BlockZ, a_BlockX + a_BlockZ) / 17) % 512)) * a_Size / 1024;
// The complete offset of the ravine from its cellpoint, up to 2 * a_Size in each direction
- int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2;
- int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2;
+ int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2;
+ int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2;
int CenterX = a_BlockX + OffsetX;
int CenterZ = a_BlockZ + OffsetZ;
// Get the base angle in which the ravine "axis" goes:
- float Angle = (float)(((float)((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * 3.141592653);
+ float Angle = (float)(((float)((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * M_PI);
float xc = sin(Angle);
float zc = cos(Angle);
@@ -306,18 +171,25 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block
void cStructGenRavines::cRavine::RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst)
{
+ if (a_Src.size() < 2)
+ {
+ // No midpoints, nothing to refine
+ return;
+ }
+
// Smoothing: for each line segment, add points on its 1/4 lengths
- int Num = a_Src.size() - 2; // this many intermediary points
+ size_t Num = a_Src.size() - 2; // this many intermediary points
a_Dst.clear();
a_Dst.reserve(Num * 2 + 2);
cRavDefPoints::const_iterator itr = a_Src.begin() + 1;
- a_Dst.push_back(a_Src.front());
- int PrevX = a_Src.front().m_BlockX;
- int PrevZ = a_Src.front().m_BlockZ;
- int PrevR = a_Src.front().m_Radius;
- int PrevT = a_Src.front().m_Top;
- int PrevB = a_Src.front().m_Bottom;
- for (int i = 0; i <= Num; ++i, ++itr)
+ const cRavDefPoint & Source = a_Src.front();
+ a_Dst.push_back(Source);
+ int PrevX = Source.m_BlockX;
+ int PrevZ = Source.m_BlockZ;
+ int PrevR = Source.m_Radius;
+ int PrevT = Source.m_Top;
+ int PrevB = Source.m_Bottom;
+ for (size_t i = 0; i <= Num; ++i, ++itr)
{
int dx = itr->m_BlockX - PrevX;
int dz = itr->m_BlockZ - PrevZ;
@@ -422,15 +294,15 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int
// Base point highlight:
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
- a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ
+ a_OffsetX + m_OriginX - 5, a_OffsetZ + m_OriginZ, a_OffsetX + m_OriginX + 5, a_OffsetZ + m_OriginZ
);
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
- a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5
+ a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ - 5, a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ + 5
);
// A gray line from the base point to the first point of the ravine, for identification:
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
- a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ
+ a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ
);
// Offset guides:
@@ -454,14 +326,10 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int
-void cStructGenRavines::cRavine::ProcessChunk(
- int a_ChunkX, int a_ChunkZ,
- cChunkDef::BlockTypes & a_BlockTypes,
- cChunkDef::HeightMap & a_HeightMap
-)
+void cStructGenRavines::cRavine::DrawIntoChunk(cChunkDesc & a_ChunkDesc)
{
- int BlockStartX = a_ChunkX * cChunkDef::Width;
- int BlockStartZ = a_ChunkZ * cChunkDef::Width;
+ int BlockStartX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockStartZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
int BlockEndX = BlockStartX + cChunkDef::Width;
int BlockEndZ = BlockStartZ + cChunkDef::Width;
for (cRavDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr)
@@ -487,7 +355,7 @@ void cStructGenRavines::cRavine::ProcessChunk(
// DEBUG: Make the ravine shapepoints visible on a single layer (so that we can see with Minutor what's going on)
if ((DifX + x == 0) && (DifZ + z == 0))
{
- cChunkDef::SetBlock(a_BlockTypes, x, 4, z, E_BLOCK_LAPIS_ORE);
+ a_ChunkDesc.SetBlockType(x, 4, z, E_BLOCK_LAPIS_ORE);
}
#endif // _DEBUG
@@ -497,7 +365,7 @@ void cStructGenRavines::cRavine::ProcessChunk(
int Top = std::min(itr->m_Top, (int)(cChunkDef::Height)); // Stupid gcc needs int cast
for (int y = std::max(itr->m_Bottom, 1); y <= Top; y++)
{
- switch (cChunkDef::GetBlock(a_BlockTypes, x, y, z))
+ switch (a_ChunkDesc.GetBlockType(x, y, z))
{
// Only carve out these specific block types
case E_BLOCK_DIRT:
@@ -515,7 +383,7 @@ void cStructGenRavines::cRavine::ProcessChunk(
case E_BLOCK_REDSTONE_ORE:
case E_BLOCK_REDSTONE_ORE_GLOWING:
{
- cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR);
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR);
break;
}
default: break;
diff --git a/src/Generating/Ravines.h b/src/Generating/Ravines.h
index c76b9f19f..30b47e9ec 100644
--- a/src/Generating/Ravines.h
+++ b/src/Generating/Ravines.h
@@ -9,7 +9,7 @@
#pragma once
-#include "ComposableGenerator.h"
+#include "GridStructGen.h"
#include "../Noise.h"
@@ -17,28 +17,22 @@
class cStructGenRavines :
- public cFinishGen
+ public cGridStructGen
{
+ typedef cGridStructGen super;
+
public:
cStructGenRavines(int a_Seed, int a_Size);
- ~cStructGenRavines();
protected:
class cRavine; // fwd: Ravines.cpp
- typedef std::list<cRavine *> cRavines;
-
- cNoise m_Noise;
- int m_Size; // Max size, in blocks, of the ravines generated
- cRavines m_Cache;
- /// Clears everything from the cache
- void ClearCache(void);
+ cNoise m_Noise;
+ int m_Size; // Max size, in blocks, of the ravines generated
- /// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function.
- void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines);
-
- // cFinishGen override:
- virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cGridStructGen overrides:
+ virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;
diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp
index db9d5578c..636364e17 100644
--- a/src/Generating/StructGen.cpp
+++ b/src/Generating/StructGen.cpp
@@ -596,24 +596,22 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
// Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
{
- switch (a_ChunkDesc.GetBiome(x, z))
+ EMCSBiome biome = a_ChunkDesc.GetBiome(x, z);
+
+ if ((biome == biExtremeHills) || (biome == biExtremeHillsEdge))
{
- case biExtremeHills:
- case biExtremeHillsEdge:
+ int Lo = FloorLo[x + 17 * z] / 256;
+ int Hi = FloorHi[x + 17 * z] / 256;
+ for (int y = 0; y < SEGMENT_HEIGHT; y++)
{
- int Lo = FloorLo[x + 17 * z] / 256;
- int Hi = FloorHi[x + 17 * z] / 256;
- for (int y = 0; y < SEGMENT_HEIGHT; y++)
+ int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT;
+ if (Val < 0)
{
- int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT;
- if (Val < 0)
- {
- a_ChunkDesc.SetBlockType(x, y + Segment, z, E_BLOCK_AIR);
- }
- } // for y
- break;
- }
- } // switch (biome)
+ a_ChunkDesc.SetBlockType(x, y + Segment, z, E_BLOCK_AIR);
+ }
+ } // for y
+ break;
+ } // if (biome)
} // for z, x
// Swap the floors:
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index 4909587b1..522f45148 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -136,7 +136,7 @@ inline void PushSomeColumns(int a_BlockX, int a_Height, int a_BlockZ, int a_Colu
{
int x = a_BlockX + a_Coords[i].x;
int z = a_BlockZ + a_Coords[i].z;
- if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height + i, z + 64 * a_Seq) <= a_Chance)
+ if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height + (int)i, z + 64 * a_Seq) <= a_Chance)
{
for (int j = 0; j < a_ColumnHeight; j++)
{
@@ -174,7 +174,7 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
{
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
}
- break;
+ return;
}
case biTaiga:
@@ -184,14 +184,14 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
{
// Conifers
GetConiferTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
- break;
+ return;
}
case biSwampland:
{
// Swamp trees:
GetSwampTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
- break;
+ return;
}
case biJungle:
@@ -207,21 +207,21 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
{
GetJungleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
}
- break;
+ return;
}
case biBirchForest:
case biBirchForestHills:
{
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
- break;
+ return;
}
case biBirchForestM:
case biBirchForestHillsM:
{
GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
- break;
+ return;
}
case biRoofedForest:
@@ -257,9 +257,29 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
{
// TODO: These need their special trees
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
- break;
+ return;
+ }
+
+ case biDesert:
+ case biDesertHills:
+ case biRiver:
+ case biBeach:
+ case biHell:
+ case biSky:
+ case biOcean:
+ case biFrozenOcean:
+ case biFrozenRiver:
+ case biVariant:
+ case biNumBiomes:
+ case biNumVariantBiomes:
+ case biInvalidBiome:
+ {
+ // These biomes have no trees, or are non-biome members of the enum.
+ return;
}
}
+
+ ASSERT(!"Invalid biome type!");
}
diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp
new file mode 100644
index 000000000..b9cb056ad
--- /dev/null
+++ b/src/Generating/VillageGen.cpp
@@ -0,0 +1,430 @@
+
+// VillageGen.cpp
+
+// Implements the cVillageGen class representing the village generator
+
+#include "Globals.h"
+#include "VillageGen.h"
+#include "Prefabs/AlchemistVillagePrefabs.h"
+#include "Prefabs/JapaneseVillagePrefabs.h"
+#include "Prefabs/PlainsVillagePrefabs.h"
+#include "Prefabs/SandVillagePrefabs.h"
+#include "Prefabs/SandFlatRoofVillagePrefabs.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+/*
+How village generating works:
+By descending from a cGridStructGen, a semi-random grid is generated. A village may be generated for each of
+the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all
+biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell
+is left village-less.
+
+A village is generated using the regular BFS piece generator. The well piece is used as the starting piece,
+the roads and houses are then used as the following pieces. Only the houses are read from the prefabs,
+though, the roads are generated by code and their content is ignored. A special subclass of the cPiecePool
+class is used, so that the roads connect to each other and to the well only in predefined manners.
+
+The well has connectors of type "2". The houses have connectors of type "-1". The roads have connectors of
+both types' opposites, type "-2" at the far ends and type "1" on the long edges. Additionally, there are
+type "2" connectors along the long edges of the roads as well, so that the roads create T junctions.
+
+When the village is about to be drawn into a chunk, it queries the heights for each piece intersecting the
+chunk. The pieces are shifted so that their pivot points lie on the surface, and the roads are drawn
+directly by turning the surface blocks into gravel / sandstone.
+
+The village prefabs are stored in global piecepools (one pool per village type). In order to support
+per-village density setting, the cVillage class itself implements the cPiecePool interface, relaying the
+calls to the underlying cVillagePiecePool, after processing the density check.
+*/
+
+class cVillagePiecePool :
+ public cPrefabPiecePool
+{
+ typedef cPrefabPiecePool super;
+public:
+ cVillagePiecePool(
+ const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
+ const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
+ ) :
+ super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs)
+ {
+ // Add the road pieces:
+ for (int len = 27; len < 60; len += 12)
+ {
+ cBlockArea BA;
+ BA.Create(len, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas);
+ BA.Fill(cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_GRAVEL, 0);
+ cPrefab * RoadPiece = new cPrefab(BA, 1);
+ RoadPiece->AddConnector(0, 0, 1, BLOCK_FACE_XM, -2);
+ RoadPiece->AddConnector(len - 1, 0, 1, BLOCK_FACE_XP, -2);
+ RoadPiece->SetDefaultWeight(100);
+
+ // Add the road connectors:
+ for (int x = 1; x < len; x += 12)
+ {
+ RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 2);
+ RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 2);
+ }
+
+ // Add the buildings connectors:
+ for (int x = 7; x < len; x += 12)
+ {
+ RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 1);
+ RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 1);
+ }
+ m_AllPieces.push_back(RoadPiece);
+ m_PiecesByConnector[-2].push_back(RoadPiece);
+ m_PiecesByConnector[1].push_back(RoadPiece);
+ m_PiecesByConnector[2].push_back(RoadPiece);
+ } // for len - roads of varying length
+ }
+
+
+ // cPrefabPiecePool overrides:
+ virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override
+ {
+ // Roads cannot branch T-wise (appending -2 connector to a +2 connector on a 1-high piece):
+ if ((a_ExistingConnector.m_Type == 2) && (a_PlacedPiece.GetDepth() > 0) && (a_PlacedPiece.GetPiece().GetSize().y == 1))
+ {
+ return 0;
+ }
+
+ return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
+ }
+} ;
+
+
+
+
+
+class cVillageGen::cVillage :
+ public cGridStructGen::cStructure,
+ protected cPiecePool
+{
+ typedef cGridStructGen::cStructure super;
+
+public:
+ cVillage(
+ int a_Seed,
+ int a_OriginX, int a_OriginZ,
+ int a_MaxRoadDepth,
+ int a_MaxSize,
+ int a_Density,
+ cPiecePool & a_Prefabs,
+ cTerrainHeightGen & a_HeightGen,
+ BLOCKTYPE a_RoadBlock
+ ) :
+ super(a_OriginX, a_OriginZ),
+ m_Seed(a_Seed),
+ m_Noise(a_Seed),
+ m_MaxSize(a_MaxSize),
+ m_Density(a_Density),
+ m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize),
+ m_Prefabs(a_Prefabs),
+ m_HeightGen(a_HeightGen),
+ m_RoadBlock(a_RoadBlock)
+ {
+ // Generate the pieces for this village; don't care about the Y coord:
+ cBFSPieceGenerator pg(*this, a_Seed);
+ pg.PlacePieces(a_OriginX, 0, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces);
+ if (m_Pieces.empty())
+ {
+ return;
+ }
+
+ // If the central piece should be moved to ground, move it, and
+ // check all of its dependents and move those that are strictly connector-driven based on its new Y coord:
+ if (((cPrefab &)m_Pieces[0]->GetPiece()).ShouldMoveToGround())
+ {
+ int OrigPosY = m_Pieces[0]->GetCoords().y;
+ PlacePieceOnGround(*m_Pieces[0]);
+ int NewPosY = m_Pieces[0]->GetCoords().y;
+ MoveAllDescendants(m_Pieces, 0, NewPosY - OrigPosY);
+ }
+ }
+
+ ~cVillage()
+ {
+ cPieceGenerator::FreePieces(m_Pieces);
+ }
+
+protected:
+ /** Seed for the random functions */
+ int m_Seed;
+
+ /** The noise used as a pseudo-random generator */
+ cNoise m_Noise;
+
+ /** Maximum size, in X/Z blocks, of the village (radius from the origin) */
+ int m_MaxSize;
+
+ /** The density for this village. Used to refrain from populating all house connectors. Range [0, 100] */
+ int m_Density;
+
+ /** Borders of the vilalge - no item may reach out of this cuboid. */
+ cCuboid m_Borders;
+
+ /** Prefabs to use for buildings */
+ cPiecePool & m_Prefabs;
+
+ /** The underlying height generator, used for placing the structures on top of the terrain. */
+ cTerrainHeightGen & m_HeightGen;
+
+ /** The village pieces, placed by the generator. */
+ cPlacedPieces m_Pieces;
+
+ /** The block to use for the roads. */
+ BLOCKTYPE m_RoadBlock;
+
+
+ // cGridStructGen::cStructure overrides:
+ virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override
+ {
+ // Iterate over all items
+ // Each intersecting prefab is placed on ground, then drawn
+ // Each intersecting road is drawn by replacing top soil blocks with gravel / sandstone blocks
+ cChunkDef::HeightMap HeightMap; // Heightmap for this chunk, used by roads
+ m_HeightGen.GenHeightMap(a_Chunk.GetChunkX(), a_Chunk.GetChunkZ(), HeightMap);
+ for (cPlacedPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ cPrefab & Prefab = (cPrefab &)((*itr)->GetPiece());
+ if ((*itr)->GetPiece().GetSize().y == 1)
+ {
+ // It's a road, special handling (change top terrain blocks to m_RoadBlock)
+ DrawRoad(a_Chunk, **itr, HeightMap);
+ continue;
+ }
+ if (Prefab.ShouldMoveToGround() && !(*itr)->HasBeenMovedToGround())
+ {
+ PlacePieceOnGround(**itr);
+ }
+ Prefab.Draw(a_Chunk, *itr);
+ } // for itr - m_PlacedPieces[]
+ }
+
+
+ /** Adjusts the Y coord of the given piece so that the piece is on the ground.
+ Ground level is assumed to be represented by the first connector in the piece. */
+ void PlacePieceOnGround(cPlacedPiece & a_Piece)
+ {
+ cPiece::cConnector FirstConnector = a_Piece.GetRotatedConnector(0);
+ int ChunkX, ChunkZ;
+ int BlockX = FirstConnector.m_Pos.x;
+ int BlockZ = FirstConnector.m_Pos.z;
+ int BlockY;
+ cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ cChunkDef::HeightMap HeightMap;
+ m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap);
+ int TerrainHeight = cChunkDef::GetHeight(HeightMap, BlockX, BlockZ);
+ a_Piece.MoveToGroundBy(TerrainHeight - FirstConnector.m_Pos.y + 1);
+ }
+
+
+ /** Draws the road into the chunk.
+ The heightmap is not queried from the heightgen, but is given via parameter, so that it may be queried just
+ once for all roads in a chunk. */
+ void DrawRoad(cChunkDesc & a_Chunk, cPlacedPiece & a_Road, cChunkDef::HeightMap & a_HeightMap)
+ {
+ cCuboid RoadCoords = a_Road.GetHitBox();
+ RoadCoords.Sort();
+ int MinX = std::max(RoadCoords.p1.x - a_Chunk.GetChunkX() * cChunkDef::Width, 0);
+ int MaxX = std::min(RoadCoords.p2.x - a_Chunk.GetChunkX() * cChunkDef::Width, cChunkDef::Width - 1);
+ int MinZ = std::max(RoadCoords.p1.z - a_Chunk.GetChunkZ() * cChunkDef::Width, 0);
+ int MaxZ = std::min(RoadCoords.p2.z - a_Chunk.GetChunkZ() * cChunkDef::Width, cChunkDef::Width - 1);
+ for (int z = MinZ; z <= MaxZ; z++)
+ {
+ for (int x = MinX; x <= MaxX; x++)
+ {
+ a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_RoadBlock);
+ }
+ }
+ }
+
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType)
+ {
+ return m_Prefabs.GetPiecesWithConnector(a_ConnectorType);
+ }
+
+
+ virtual cPieces GetStartingPieces(void)
+ {
+ return m_Prefabs.GetStartingPieces();
+ }
+
+
+ virtual int GetPieceWeight(
+ const cPlacedPiece & a_PlacedPiece,
+ const cPiece::cConnector & a_ExistingConnector,
+ const cPiece & a_NewPiece
+ ) override
+ {
+ // Check against the density:
+ if (a_ExistingConnector.m_Type == 1)
+ {
+ const Vector3i & Coords = a_PlacedPiece.GetRotatedConnector(a_ExistingConnector).m_Pos;
+ int rnd = (m_Noise.IntNoise3DInt(Coords.x, Coords.y, Coords.z) / 7) % 100;
+ if (rnd > m_Density)
+ {
+ return 0;
+ }
+ }
+
+ // Density check passed, relay to m_Prefabs:
+ return m_Prefabs.GetPieceWeight(a_PlacedPiece, a_ExistingConnector, a_NewPiece);
+ }
+
+
+ virtual int GetStartingPieceWeight(const cPiece & a_NewPiece) override
+ {
+ return m_Prefabs.GetStartingPieceWeight(a_NewPiece);
+ }
+
+
+ virtual void PiecePlaced(const cPiece & a_Piece) override
+ {
+ m_Prefabs.PiecePlaced(a_Piece);
+ }
+
+
+ virtual void Reset(void) override
+ {
+ m_Prefabs.Reset();
+ }
+
+
+ void MoveAllDescendants(cPlacedPieces & a_PlacedPieces, size_t a_Pivot, int a_HeightDifference)
+ {
+ size_t num = a_PlacedPieces.size();
+ cPlacedPiece * Pivot = a_PlacedPieces[a_Pivot];
+ for (size_t i = a_Pivot + 1; i < num; i++)
+ {
+ if (
+ (a_PlacedPieces[i]->GetParent() == Pivot) && // It is a direct dependant of the pivot
+ !((const cPrefab &)a_PlacedPieces[i]->GetPiece()).ShouldMoveToGround() // It attaches strictly by connectors
+ )
+ {
+ a_PlacedPieces[i]->MoveToGroundBy(a_HeightDifference);
+ MoveAllDescendants(a_PlacedPieces, i, a_HeightDifference);
+ }
+ } // for i - a_PlacedPieces[]
+ }
+} ;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cVillageGen:
+
+static cVillagePiecePool g_SandVillage(g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount);
+static cVillagePiecePool g_SandFlatRoofVillage(g_SandFlatRoofVillagePrefabs, g_SandFlatRoofVillagePrefabsCount, g_SandFlatRoofVillageStartingPrefabs, g_SandFlatRoofVillageStartingPrefabsCount);
+static cVillagePiecePool g_AlchemistVillage(g_AlchemistVillagePrefabs, g_AlchemistVillagePrefabsCount, g_AlchemistVillageStartingPrefabs, g_AlchemistVillageStartingPrefabsCount);
+static cVillagePiecePool g_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount);
+static cVillagePiecePool g_JapaneseVillage(g_JapaneseVillagePrefabs, g_JapaneseVillagePrefabsCount, g_JapaneseVillageStartingPrefabs, g_JapaneseVillageStartingPrefabsCount);
+
+static cVillagePiecePool * g_DesertVillagePools[] =
+{
+ &g_SandVillage,
+ &g_SandFlatRoofVillage,
+ &g_AlchemistVillage,
+} ;
+
+static cVillagePiecePool * g_PlainsVillagePools[] =
+{
+ &g_PlainsVillage,
+ &g_JapaneseVillage,
+} ;
+
+
+
+
+
+cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) :
+ super(a_Seed, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 100),
+ m_Noise(a_Seed + 1000),
+ m_MaxDepth(a_MaxDepth),
+ m_MaxSize(a_MaxSize),
+ m_MinDensity(a_MinDensity),
+ m_MaxDensity(a_MaxDensity),
+ m_BiomeGen(a_BiomeGen),
+ m_HeightGen(a_HeightGen)
+{
+}
+
+
+
+
+
+cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_OriginZ)
+{
+ // Generate the biomes for the chunk surrounding the origin:
+ int ChunkX, ChunkZ;
+ cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ);
+ cChunkDef::BiomeMap Biomes;
+ m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes);
+
+ // Check if all the biomes are village-friendly:
+ // If just one is not, no village is created, because it's likely that an unfriendly biome is too close
+ cVillagePiecePool * VillagePrefabs = NULL;
+ BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL;
+ int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11;
+ cVillagePiecePool * PlainsVillage = g_PlainsVillagePools[rnd % ARRAYCOUNT(g_PlainsVillagePools)];
+ cVillagePiecePool * DesertVillage = g_DesertVillagePools[rnd % ARRAYCOUNT(g_DesertVillagePools)];
+ for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++)
+ {
+ switch (Biomes[i])
+ {
+ case biDesert:
+ case biDesertM:
+ {
+ // These biomes allow sand villages
+ VillagePrefabs = DesertVillage;
+ // RoadBlock = E_BLOCK_SANDSTONE;
+ break;
+ }
+ case biPlains:
+ case biSavanna:
+ case biSavannaM:
+ case biSunflowerPlains:
+ {
+ // These biomes allow plains-style villages
+ VillagePrefabs = PlainsVillage;
+ break;
+ }
+ default:
+ {
+ // Village-unfriendly biome, bail out with zero structure:
+ return cStructurePtr();
+ }
+ } // switch (Biomes[i])
+ } // for i - Biomes[]
+
+ // Choose density for the village, random between m_MinDensity and m_MaxDensity:
+ int Density;
+ if (m_MaxDensity > m_MinDensity)
+ {
+ Density = m_MinDensity + rnd % (m_MaxDensity - m_MinDensity);
+ }
+ else
+ {
+ Density = m_MinDensity;
+ }
+
+ // Create a village based on the chosen prefabs:
+ if (VillagePrefabs == NULL)
+ {
+ return cStructurePtr();
+ }
+ return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *VillagePrefabs, m_HeightGen, RoadBlock));
+}
+
+
+
+
diff --git a/src/Generating/VillageGen.h b/src/Generating/VillageGen.h
new file mode 100644
index 000000000..5faaae8a6
--- /dev/null
+++ b/src/Generating/VillageGen.h
@@ -0,0 +1,57 @@
+
+// VillageGen.h
+
+// Declares the cVillageGen class representing the village generator
+
+
+
+
+
+#pragma once
+
+#include "GridStructGen.h"
+#include "PrefabPiecePool.h"
+
+
+
+
+
+class cVillageGen :
+ public cGridStructGen
+{
+ typedef cGridStructGen super;
+public:
+ cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen);
+
+protected:
+ class cVillage; // fwd: VillageGen.cpp
+
+ /** The noise used for generating random numbers */
+ cNoise m_Noise;
+
+ /** Maximum depth of the generator tree*/
+ int m_MaxDepth;
+
+ /** Maximum size, in X/Z blocks, of the village (radius from the origin) */
+ int m_MaxSize;
+
+ /** Minimum density - percentage of allowed house connections. Range [0, 100] */
+ int m_MinDensity;
+
+ /** Maximum density - percentage of allowed house connections. Range [0, 100] */
+ int m_MaxDensity;
+
+ /** The underlying biome generator that defines whether the village is created or not */
+ cBiomeGen & m_BiomeGen;
+
+ /** The underlying height generator, used to position the prefabs crossing chunk borders */
+ cTerrainHeightGen & m_HeightGen;
+
+
+ // cGridStructGen overrides:
+ virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
+} ;
+
+
+
+
diff --git a/src/Globals.h b/src/Globals.h
index a1cee5c2f..c5768facf 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
@@ -222,16 +225,28 @@ template class SizeChecker<UInt16, 2>;
+#ifndef TEST_GLOBALS
+ // Common headers (part 1, without macros):
+ #include "StringUtils.h"
+ #include "OSSupport/Sleep.h"
+ #include "OSSupport/CriticalSection.h"
+ #include "OSSupport/Semaphore.h"
+ #include "OSSupport/Event.h"
+ #include "OSSupport/Thread.h"
+ #include "OSSupport/File.h"
+ #include "MCLogger.h"
+#else
+ // Logging functions
+void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1,2);
-// Common headers (part 1, without macros):
-#include "StringUtils.h"
-#include "OSSupport/Sleep.h"
-#include "OSSupport/CriticalSection.h"
-#include "OSSupport/Semaphore.h"
-#include "OSSupport/Event.h"
-#include "OSSupport/Thread.h"
-#include "OSSupport/File.h"
-#include "MCLogger.h"
+void inline LOGERROR(const char* a_Format, ...)
+{
+ va_list argList;
+ va_start(argList, a_Format);
+ vprintf(a_Format, argList);
+ va_end(argList);
+}
+#endif
@@ -250,10 +265,44 @@ template class SizeChecker<UInt16, 2>;
#define FAST_FLOOR_DIV( x, div ) (((x) - (((x) < 0) ? ((div) - 1) : 0)) / (div))
// Own version of assert() that writes failed assertions to the log for review
-#ifdef _DEBUG
- #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) )
+#ifdef TEST_GLOBALS
+
+ class cAssertFailure
+ {
+ };
+
+ #ifdef _WIN32
+ #if (defined(_MSC_VER) && defined(_DEBUG))
+ #define DBG_BREAK _CrtDbgBreak()
+ #else
+ #define DBG_BREAK
+ #endif
+ #define REPORT_ERROR(FMT, ...) \
+ { \
+ AString msg = Printf(FMT, __VA_ARGS__); \
+ puts(msg.c_str()); \
+ fflush(stdout); \
+ OutputDebugStringA(msg.c_str()); \
+ DBG_BREAK; \
+ }
+ #else
+ #define REPORT_ERROR(FMT, ...) \
+ { \
+ AString msg = Printf(FMT, __VA_ARGS__); \
+ puts(msg.c_str()); \
+ fflush(stdout); \
+ }
+ #endif
+ #define ASSERT(x) do { if (!(x)) { throw cAssertFailure();} } while (0)
+ #define testassert(x) do { if(!(x)) { REPORT_ERROR("Test failure: %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } } while (0)
+ #define CheckAsserts(x) do { try {x} catch (cAssertFailure) { break; } REPORT_ERROR("Test failure: assert didn't fire for %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } while (0)
+
#else
- #define ASSERT(x) ((void)(x))
+ #ifdef _DEBUG
+ #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) )
+ #else
+ #define ASSERT(x) ((void)(x))
+ #endif
#endif
// Pretty much the same as ASSERT() but stays in Release builds
@@ -261,7 +310,21 @@ template class SizeChecker<UInt16, 2>;
// Same as assert but in all Self test builds
#ifdef SELF_TEST
-#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
+ #define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
+#endif
+
+// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
+// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
+#if (defined(_MSC_VER) && (_MSC_VER < 1600))
+ // MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
+ #define SharedPtr std::tr1::shared_ptr
+#elif (defined(_MSC_VER) || (__cplusplus >= 201103L))
+ // C++11 has std::shared_ptr in <memory>, included earlier
+ #define SharedPtr std::shared_ptr
+#else
+ // C++03 has std::tr1::shared_ptr in <tr1/memory>
+ #include <tr1/memory>
+ #define SharedPtr std::tr1::shared_ptr
#endif
@@ -293,7 +356,7 @@ T Clamp(T a_Value, T a_Min, T a_Max)
#ifndef TOLUA_TEMPLATE_BIND
-#define TOLUA_TEMPLATE_BIND(x)
+ #define TOLUA_TEMPLATE_BIND(x)
#endif
diff --git a/src/Group.cpp b/src/Group.cpp
index 5f1f25782..725740905 100644
--- a/src/Group.cpp
+++ b/src/Group.cpp
@@ -7,7 +7,7 @@
-void cGroup::AddCommand( AString a_Command )
+void cGroup::AddCommand( const AString & a_Command )
{
m_Commands[ a_Command ] = true;
}
@@ -16,7 +16,7 @@ void cGroup::AddCommand( AString a_Command )
-void cGroup::AddPermission( AString a_Permission )
+void cGroup::AddPermission( const AString & a_Permission )
{
m_Permissions[ a_Permission ] = true;
}
@@ -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/Group.h b/src/Group.h
index 8bee6f7ed..47088d50d 100644
--- a/src/Group.h
+++ b/src/Group.h
@@ -11,11 +11,11 @@ public: // tolua_export
cGroup() {}
~cGroup() {}
- void SetName( AString a_Name ) { m_Name = a_Name; } // tolua_export
+ void SetName( const AString & a_Name ) { m_Name = a_Name; } // tolua_export
const AString & GetName() const { return m_Name; } // tolua_export
- void SetColor( AString a_Color ) { m_Color = a_Color; } // tolua_export
- void AddCommand( AString a_Command ); // tolua_export
- void AddPermission( AString a_Permission ); // tolua_export
+ void SetColor( const AString & a_Color ) { m_Color = a_Color; } // tolua_export
+ void AddCommand( const AString & a_Command ); // tolua_export
+ void AddPermission( const AString & a_Permission ); // tolua_export
void InheritFrom( cGroup* a_Group ); // tolua_export
typedef std::map< AString, bool > PermissionMap;
diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp
index 33b601e82..523697b07 100644
--- a/src/GroupManager.cpp
+++ b/src/GroupManager.cpp
@@ -45,8 +45,14 @@ cGroupManager::cGroupManager()
{
LOGD("-- Loading Groups --");
- LoadGroups();
- CheckUsers();
+ if (!LoadGroups())
+ {
+ LOGWARNING("ERROR: Groups could not load!");
+ }
+ if (!CheckUsers())
+ {
+ LOGWARNING("ERROR: User file could not be found!");
+ }
LOGD("-- Groups Successfully Loaded --");
}
@@ -70,39 +76,42 @@ void cGroupManager::GenerateDefaultUsersIni(cIniFile & a_IniFile)
-void cGroupManager::CheckUsers(void)
+bool cGroupManager::CheckUsers()
{
cIniFile IniFile;
if (!IniFile.ReadFile("users.ini"))
{
GenerateDefaultUsersIni(IniFile);
- return;
+ return true;
}
- unsigned int NumKeys = IniFile.GetNumKeys();
- for (size_t i = 0; i < NumKeys; i++)
+ int NumKeys = IniFile.GetNumKeys();
+ for (int i = 0; i < NumKeys; i++)
{
- AString Player = IniFile.GetKeyName( i );
+ AString Player = IniFile.GetKeyName(i);
AString Groups = IniFile.GetValue(Player, "Groups", "");
- if (!Groups.empty())
+ if (Groups.empty())
{
- AStringVector Split = StringSplit( Groups, "," );
- for( unsigned int i = 0; i < Split.size(); i++ )
+ continue;
+ }
+ AStringVector Split = StringSplitAndTrim(Groups, ",");
+ for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
+ {
+ if (!ExistsGroup(*itr))
{
- if (!ExistsGroup(Split[i]))
- {
- LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str());
- }
+ LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str());
}
- }
- }
+ } // for itr - Split[]
+ } // for i - ini file keys
+ // Always return true for now, just but we can handle writefile fails later.
+ return true;
}
-void cGroupManager::LoadGroups()
+bool cGroupManager::LoadGroups()
{
cIniFile IniFile;
if (!IniFile.ReadFile("groups.ini"))
@@ -128,15 +137,15 @@ void cGroupManager::LoadGroups()
IniFile.WriteFile("groups.ini");
}
- unsigned int NumKeys = IniFile.GetNumKeys();
- for (size_t i = 0; i < NumKeys; i++)
+ int NumKeys = IniFile.GetNumKeys();
+ for (int i = 0; i < NumKeys; i++)
{
- AString KeyName = IniFile.GetKeyName( i );
- cGroup* Group = GetGroup( KeyName.c_str() );
+ AString KeyName = IniFile.GetKeyName(i);
+ cGroup * Group = GetGroup(KeyName.c_str());
Group->ClearPermission(); // Needed in case the groups are reloaded.
- LOGD("Loading group: %s", KeyName.c_str() );
+ LOGD("Loading group %s", KeyName.c_str());
Group->SetName(KeyName);
AString Color = IniFile.GetValue(KeyName, "Color", "-");
@@ -179,6 +188,8 @@ void cGroupManager::LoadGroups()
}
}
}
+ // Always return true, we can handle writefile fails later.
+ return true;
}
diff --git a/src/GroupManager.h b/src/GroupManager.h
index 9e1689a76..d42b55c4a 100644
--- a/src/GroupManager.h
+++ b/src/GroupManager.h
@@ -16,8 +16,8 @@ class cGroupManager
public:
bool ExistsGroup(const AString & a_Name);
cGroup * GetGroup(const AString & a_Name);
- void LoadGroups(void);
- void CheckUsers(void);
+ bool LoadGroups();
+ bool CheckUsers();
/** Writes the default header to the specified ini file, and saves it as "users.ini". */
static void GenerateDefaultUsersIni(cIniFile & a_IniFile);
diff --git a/src/HTTPServer/CMakeLists.txt b/src/HTTPServer/CMakeLists.txt
index 3badc669f..dc894368d 100644
--- a/src/HTTPServer/CMakeLists.txt
+++ b/src/HTTPServer/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(HTTPServer ${SOURCE})
diff --git a/src/HTTPServer/EnvelopeParser.cpp b/src/HTTPServer/EnvelopeParser.cpp
index 8dbe05f14..fd4f3836d 100644
--- a/src/HTTPServer/EnvelopeParser.cpp
+++ b/src/HTTPServer/EnvelopeParser.cpp
@@ -20,7 +20,7 @@ cEnvelopeParser::cEnvelopeParser(cCallbacks & a_Callbacks) :
-int cEnvelopeParser::Parse(const char * a_Data, int a_Size)
+size_t cEnvelopeParser::Parse(const char * a_Data, size_t a_Size)
{
if (!m_IsInHeaders)
{
@@ -55,7 +55,7 @@ int cEnvelopeParser::Parse(const char * a_Data, int a_Size)
{
// An error has occurred
m_IsInHeaders = false;
- return -1;
+ return AString::npos;
}
Last = idxCRLF + 2;
idxCRLF = m_IncomingData.find("\r\n", idxCRLF + 2);
diff --git a/src/HTTPServer/EnvelopeParser.h b/src/HTTPServer/EnvelopeParser.h
index 6430fbebf..e96d80abe 100644
--- a/src/HTTPServer/EnvelopeParser.h
+++ b/src/HTTPServer/EnvelopeParser.h
@@ -19,7 +19,10 @@ public:
class cCallbacks
{
public:
- /// Called when a full header line is parsed
+ // 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;
} ;
@@ -27,40 +30,41 @@ public:
cEnvelopeParser(cCallbacks & a_Callbacks);
/** Parses the incoming data.
- Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header
+ Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header.
+ Returns AString::npos on error
*/
- int Parse(const char * a_Data, int a_Size);
+ size_t Parse(const char * a_Data, size_t a_Size);
- /// Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream
+ /** Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream */
void Reset(void);
- /// Returns true if more input is expected for the envelope header
+ /** Returns true if more input is expected for the envelope header */
bool IsInHeaders(void) const { return m_IsInHeaders; }
- /// Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions
+ /** Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions */
void SetIsInHeaders(bool a_IsInHeaders) { m_IsInHeaders = a_IsInHeaders; }
public:
- /// Callbacks to call for the various events
+ /** Callbacks to call for the various events */
cCallbacks & m_Callbacks;
- /// Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data.
+ /** Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data. */
bool m_IsInHeaders;
- /// Buffer for the incoming data until it is parsed
+ /** Buffer for the incoming data until it is parsed */
AString m_IncomingData;
- /// Holds the last parsed key; used for line-wrapped values
+ /** Holds the last parsed key; used for line-wrapped values */
AString m_LastKey;
- /// Holds the last parsed value; used for line-wrapped values
+ /** Holds the last parsed value; used for line-wrapped values */
AString m_LastValue;
- /// Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them
+ /** Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them */
void NotifyLast(void);
- /// Parses one line of header data. Returns true if successful
+ /** Parses one line of header data. Returns true if successful */
bool ParseLine(const char * a_Data, size_t a_Size);
} ;
diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp
index 78b7ce4d9..b127e7091 100644
--- a/src/HTTPServer/HTTPConnection.cpp
+++ b/src/HTTPServer/HTTPConnection.cpp
@@ -26,6 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) :
cHTTPConnection::~cHTTPConnection()
{
+ // LOGD("HTTP: Connection deleting: %p", this);
delete m_CurrentRequest;
}
@@ -67,10 +68,10 @@ void cHTTPConnection::Send(const cHTTPResponse & a_Response)
-void cHTTPConnection::Send(const void * a_Data, int a_Size)
+void cHTTPConnection::Send(const void * a_Data, size_t a_Size)
{
ASSERT(m_State == wcsSendingResp);
- AppendPrintf(m_OutgoingData, "%x\r\n", a_Size);
+ AppendPrintf(m_OutgoingData, SIZE_T_FMT_HEX "\r\n", a_Size);
m_OutgoingData.append((const char *)a_Data, a_Size);
m_OutgoingData.append("\r\n");
m_HTTPServer.NotifyConnectionWrite(*this);
@@ -144,7 +145,7 @@ void cHTTPConnection::Terminate(void)
-void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
+bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
{
switch (m_State)
{
@@ -155,26 +156,26 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
m_CurrentRequest = new cHTTPRequest;
}
- int BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size);
- if (BytesConsumed < 0)
+ size_t BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size);
+ if (BytesConsumed == AString::npos)
{
delete m_CurrentRequest;
m_CurrentRequest = NULL;
m_State = wcsInvalid;
m_HTTPServer.CloseConnection(*this);
- return;
+ return true;
}
if (m_CurrentRequest->IsInHeaders())
{
// The request headers are not yet complete
- return;
+ return false;
}
// The request has finished parsing its headers successfully, notify of it:
m_State = wcsRecvBody;
m_HTTPServer.NewRequest(*this, *m_CurrentRequest);
m_CurrentRequestBodyRemaining = m_CurrentRequest->GetContentLength();
- if (m_CurrentRequestBodyRemaining < 0)
+ if (m_CurrentRequestBodyRemaining == AString::npos)
{
// The body length was not specified in the request, assume zero
m_CurrentRequestBodyRemaining = 0;
@@ -183,13 +184,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
// Process the rest of the incoming data into the request body:
if (a_Size > BytesConsumed)
{
- DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
+ return cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
}
else
{
- DataReceived("", 0); // If the request has zero body length, let it be processed right-away
+ return cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away
}
- break;
}
case wcsRecvBody:
@@ -197,7 +197,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
ASSERT(m_CurrentRequest != NULL);
if (m_CurrentRequestBodyRemaining > 0)
{
- int BytesToConsume = std::min(m_CurrentRequestBodyRemaining, a_Size);
+ size_t BytesToConsume = std::min(m_CurrentRequestBodyRemaining, (size_t)a_Size);
m_HTTPServer.RequestBody(*this, *m_CurrentRequest, a_Data, BytesToConsume);
m_CurrentRequestBodyRemaining -= BytesToConsume;
}
@@ -209,7 +209,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
{
m_State = wcsInvalid;
m_HTTPServer.CloseConnection(*this);
- return;
+ return true;
}
delete m_CurrentRequest;
m_CurrentRequest = NULL;
@@ -223,6 +223,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
break;
}
}
+ return false;
}
diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h
index 5b8103554..6ea8a1ae8 100644
--- a/src/HTTPServer/HTTPConnection.h
+++ b/src/HTTPServer/HTTPConnection.h
@@ -51,7 +51,7 @@ public:
void Send(const cHTTPResponse & a_Response);
/** Sends the data as the response (may be called multiple times) */
- void Send(const void * a_Data, int a_Size);
+ void Send(const void * a_Data, size_t a_Size);
/** Sends the data as the response (may be called multiple times) */
void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); }
@@ -87,13 +87,19 @@ protected:
/** Number of bytes that remain to read for the complete body of the message to be received.
Valid only in wcsRecvBody */
- int m_CurrentRequestBodyRemaining;
+ size_t m_CurrentRequestBodyRemaining;
// cSocketThreads::cCallback overrides:
- virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
- virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
- virtual void SocketClosed (void) override; // The socket has been closed for any reason
+ /** Data is received from the client.
+ Returns true if the connection has been closed as the result of parsing the data. */
+ virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
+
+ /** Data can be sent to client */
+ virtual void GetOutgoingData(AString & a_Data) override;
+
+ /** The socket has been closed for any reason */
+ virtual void SocketClosed(void) override;
} ;
typedef std::vector<cHTTPConnection *> cHTTPConnections;
diff --git a/src/HTTPServer/HTTPFormParser.cpp b/src/HTTPServer/HTTPFormParser.cpp
index e661ea6f9..9ddfb82f1 100644
--- a/src/HTTPServer/HTTPFormParser.cpp
+++ b/src/HTTPServer/HTTPFormParser.cpp
@@ -52,7 +52,7 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba
-cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks) :
+cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks) :
m_Callbacks(a_Callbacks),
m_Kind(a_Kind),
m_IsValid(true)
@@ -64,7 +64,7 @@ cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size,
-void cHTTPFormParser::Parse(const char * a_Data, int a_Size)
+void cHTTPFormParser::Parse(const char * a_Data, size_t a_Size)
{
if (!m_IsValid)
{
@@ -243,7 +243,7 @@ void cHTTPFormParser::OnPartHeader(const AString & a_Key, const AString & a_Valu
-void cHTTPFormParser::OnPartData(const char * a_Data, int a_Size)
+void cHTTPFormParser::OnPartData(const char * a_Data, size_t a_Size)
{
if (m_CurrentPartName.empty())
{
diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h
index a554ca5a4..edc6d2471 100644
--- a/src/HTTPServer/HTTPFormParser.h
+++ b/src/HTTPServer/HTTPFormParser.h
@@ -36,11 +36,14 @@ 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;
/// Called when more file data has come for the current file in the form data
- virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) = 0;
+ virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) = 0;
/// Called when the current file part has ended in the form data
virtual void OnFileEnd(cHTTPFormParser & a_Parser) = 0;
@@ -51,10 +54,10 @@ public:
cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callbacks);
/// Creates a parser with the specified content type that reads data from a string
- cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks);
+ cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks);
/// Adds more data into the parser, as the request body is received
- void Parse(const char * a_Data, int a_Size);
+ void Parse(const char * a_Data, size_t a_Size);
/** Notifies that there's no more data incoming and the parser should finish its parsing.
Returns true if parsing successful
@@ -103,7 +106,7 @@ protected:
// cMultipartParser::cCallbacks overrides:
virtual void OnPartStart (void) override;
virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) override;
- virtual void OnPartData (const char * a_Data, int a_Size) override;
+ virtual void OnPartData (const char * a_Data, size_t a_Size) override;
virtual void OnPartEnd (void) override;
} ;
diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp
index 98627eb8e..44feda469 100644
--- a/src/HTTPServer/HTTPMessage.cpp
+++ b/src/HTTPServer/HTTPMessage.cpp
@@ -25,7 +25,7 @@
cHTTPMessage::cHTTPMessage(eKind a_Kind) :
m_Kind(a_Kind),
- m_ContentLength(-1)
+ m_ContentLength(AString::npos)
{
}
@@ -81,23 +81,23 @@ cHTTPRequest::cHTTPRequest(void) :
-int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
+size_t cHTTPRequest::ParseHeaders(const char * a_Data, size_t a_Size)
{
if (!m_IsValid)
{
- return -1;
+ return AString::npos;
}
if (m_Method.empty())
{
// The first line hasn't been processed yet
- int res = ParseRequestLine(a_Data, a_Size);
- if ((res < 0) || (res == a_Size))
+ size_t res = ParseRequestLine(a_Data, a_Size);
+ if ((res == AString::npos) || (res == a_Size))
{
return res;
}
- int res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res);
- if (res2 < 0)
+ size_t res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res);
+ if (res2 == AString::npos)
{
m_IsValid = false;
return res2;
@@ -107,8 +107,8 @@ int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
if (m_EnvelopeParser.IsInHeaders())
{
- int res = m_EnvelopeParser.Parse(a_Data, a_Size);
- if (res < 0)
+ size_t res = m_EnvelopeParser.Parse(a_Data, a_Size);
+ if (res == AString::npos)
{
m_IsValid = false;
}
@@ -138,7 +138,7 @@ AString cHTTPRequest::GetBareURL(void) const
-int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
+size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size)
{
m_IncomingHeaderData.append(a_Data, a_Size);
size_t IdxEnd = m_IncomingHeaderData.size();
@@ -158,7 +158,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
if (LineStart >= IdxEnd)
{
m_IsValid = false;
- return -1;
+ return AString::npos;
}
int NumSpaces = 0;
@@ -186,7 +186,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
{
// Too many spaces in the request
m_IsValid = false;
- return -1;
+ return AString::npos;
}
}
NumSpaces += 1;
@@ -198,13 +198,13 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
{
// LF too early, without a CR, without two preceeding spaces or too soon after the second space
m_IsValid = false;
- return -1;
+ return AString::npos;
}
// Check that there's HTTP/version at the end
- if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0)
+ if (strncmp(m_IncomingHeaderData.c_str() + URLEnd + 1, "HTTP/1.", 7) != 0)
{
m_IsValid = false;
- return -1;
+ return AString::npos;
}
m_Method = m_IncomingHeaderData.substr(LineStart, MethodEnd - LineStart);
m_URL = m_IncomingHeaderData.substr(MethodEnd + 1, URLEnd - MethodEnd - 1);
diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h
index ab3338db7..dab942136 100644
--- a/src/HTTPServer/HTTPMessage.h
+++ b/src/HTTPServer/HTTPMessage.h
@@ -39,10 +39,10 @@ public:
void AddHeader(const AString & a_Key, const AString & a_Value);
void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; }
- void SetContentLength(int a_ContentLength) { m_ContentLength = a_ContentLength; }
+ void SetContentLength(size_t a_ContentLength) { m_ContentLength = a_ContentLength; }
const AString & GetContentType (void) const { return m_ContentType; }
- int GetContentLength(void) const { return m_ContentLength; }
+ size_t GetContentLength(void) const { return m_ContentLength; }
protected:
typedef std::map<AString, AString> cNameValueMap;
@@ -54,8 +54,10 @@ protected:
/** Type of the content; parsed by AddHeader(), set directly by SetContentLength() */
AString m_ContentType;
- /** Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() */
- int m_ContentLength;
+ /** Length of the content that is to be received.
+ AString::npos when the object is created.
+ Parsed by AddHeader() or set directly by SetContentLength() */
+ size_t m_ContentLength;
} ;
@@ -72,12 +74,12 @@ public:
cHTTPRequest(void);
/** Parses the request line and then headers from the received data.
- Returns the number of bytes consumed or a negative number for error
+ Returns the number of bytes consumed or AString::npos number for error
*/
- int ParseHeaders(const char * a_Data, int a_Size);
+ size_t ParseHeaders(const char * a_Data, size_t a_Size);
/** Returns true if the request did contain a Content-Length header */
- bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); }
+ bool HasReceivedContentLength(void) const { return (m_ContentLength != AString::npos); }
/** Returns the method used in the request */
const AString & GetMethod(void) const { return m_Method; }
@@ -145,7 +147,7 @@ protected:
/** Parses the incoming data for the first line (RequestLine)
Returns the number of bytes consumed, or -1 for an error
*/
- int ParseRequestLine(const char * a_Data, int a_Size);
+ size_t ParseRequestLine(const char * a_Data, size_t a_Size);
// cEnvelopeParser::cCallbacks overrides:
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override;
diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp
index 4e9195a00..d288c83c9 100644
--- a/src/HTTPServer/HTTPServer.cpp
+++ b/src/HTTPServer/HTTPServer.cpp
@@ -8,6 +8,7 @@
#include "HTTPMessage.h"
#include "HTTPConnection.h"
#include "HTTPFormParser.h"
+#include "SslHTTPConnection.h"
@@ -38,7 +39,7 @@ class cDebugCallbacks :
}
- virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override
+ virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override
{
UNUSED(a_Connection);
@@ -100,7 +101,7 @@ class cDebugCallbacks :
}
- virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override
+ virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) override
{
// TODO
}
@@ -142,6 +143,41 @@ cHTTPServer::~cHTTPServer()
bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6)
{
+ // Read the HTTPS cert + key:
+ AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt");
+ AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem");
+ if (!CertFile.empty() && !KeyFile.empty())
+ {
+ m_Cert.reset(new cX509Cert);
+ int res = m_Cert->Parse(CertFile.data(), CertFile.size());
+ if (res == 0)
+ {
+ m_CertPrivKey.reset(new cCryptoKey);
+ int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), "");
+ if (res2 != 0)
+ {
+ // Reading the private key failed, reset the cert:
+ LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2);
+ m_Cert.reset();
+ }
+ }
+ else
+ {
+ LOGWARNING("WebServer: Cannot read HTTPS certificate: -0x%x", -res);
+ }
+ }
+
+ // Notify the admin about the HTTPS / HTTP status
+ if (m_Cert.get() == NULL)
+ {
+ LOGWARNING("WebServer: The server is running in unsecure HTTP mode.");
+ }
+ else
+ {
+ LOGINFO("WebServer: The server is running in secure HTTPS mode.");
+ }
+
+ // Open up requested ports:
bool HasAnyPort;
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
@@ -195,7 +231,15 @@ void cHTTPServer::Stop(void)
void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket)
{
- cHTTPConnection * Connection = new cHTTPConnection(*this);
+ cHTTPConnection * Connection;
+ if (m_Cert.get() != NULL)
+ {
+ Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey);
+ }
+ else
+ {
+ Connection = new cHTTPConnection(*this);
+ }
m_SocketThreads.AddClient(a_Socket, Connection);
cCSLock Lock(m_CSConnections);
m_Connections.push_back(Connection);
@@ -242,7 +286,7 @@ void cHTTPServer::NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Re
-void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size)
+void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size)
{
m_Callbacks->OnRequestBody(a_Connection, a_Request, a_Data, a_Size);
}
diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h
index 383abb4b6..522b7da62 100644
--- a/src/HTTPServer/HTTPServer.h
+++ b/src/HTTPServer/HTTPServer.h
@@ -12,6 +12,9 @@
#include "../OSSupport/ListenThread.h"
#include "../OSSupport/SocketThreads.h"
#include "inifile/iniFile.h"
+#include "PolarSSL++/RsaPrivateKey.h"
+#include "PolarSSL++/CryptoKey.h"
+#include "PolarSSL++/X509Cert.h"
@@ -44,8 +47,9 @@ public:
*/
virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0;
- /// Called when another part of request body has arrived.
- virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) = 0;
+ /** Called when another part of request body has arrived.
+ May be called multiple times for a single request. */
+ virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) = 0;
/// Called when the request body has been fully received in previous calls to OnRequestBody()
virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0;
@@ -65,6 +69,7 @@ public:
protected:
friend class cHTTPConnection;
+ friend class cSslHTTPConnection;
cListenThread m_ListenThreadIPv4;
cListenThread m_ListenThreadIPv6;
@@ -77,6 +82,12 @@ protected:
/// The callbacks to call for various events
cCallbacks * m_Callbacks;
+ /** The server certificate to use for the SSL connections */
+ cX509CertPtr m_Cert;
+
+ /** The private key for m_Cert. */
+ cCryptoKeyPtr m_CertPrivKey;
+
// cListenThread::cCallback overrides:
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
@@ -90,8 +101,9 @@ protected:
/// Called by cHTTPConnection when it finishes parsing the request header
void NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
- /// Called by cHTTPConenction when it receives more data for the request body
- void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size);
+ /** Called by cHTTPConenction when it receives more data for the request body.
+ May be called multiple times for a single request. */
+ void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size);
/// Called by cHTTPConnection when it detects that the request has finished (all of its body has been received)
void RequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
diff --git a/src/HTTPServer/MultipartParser.cpp b/src/HTTPServer/MultipartParser.cpp
index 14c2c00fa..309495dd7 100644
--- a/src/HTTPServer/MultipartParser.cpp
+++ b/src/HTTPServer/MultipartParser.cpp
@@ -97,8 +97,6 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a
m_EnvelopeParser(*this),
m_HasHadData(false)
{
- static AString s_Multipart = "multipart/";
-
// Check that the content type is multipart:
AString ContentType(a_ContentType);
if (strncmp(ContentType.c_str(), "multipart/", 10) != 0)
@@ -146,7 +144,7 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a
-void cMultipartParser::Parse(const char * a_Data, int a_Size)
+void cMultipartParser::Parse(const char * a_Data, size_t a_Size)
{
// Skip parsing if invalid
if (!m_IsValid)
@@ -160,8 +158,8 @@ void cMultipartParser::Parse(const char * a_Data, int a_Size)
{
if (m_EnvelopeParser.IsInHeaders())
{
- int BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size());
- if (BytesConsumed < 0)
+ size_t BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size());
+ if (BytesConsumed == AString::npos)
{
m_IsValid = false;
return;
diff --git a/src/HTTPServer/MultipartParser.h b/src/HTTPServer/MultipartParser.h
index d853929ed..ad76ad650 100644
--- a/src/HTTPServer/MultipartParser.h
+++ b/src/HTTPServer/MultipartParser.h
@@ -22,50 +22,53 @@ public:
class cCallbacks
{
public:
- /// Called when a new part starts
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
+ /** Called when a new part starts */
virtual void OnPartStart(void) = 0;
- /// Called when a complete header line is received for a part
+ /** Called when a complete header line is received for a part */
virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) = 0;
- /// Called when body for a part is received
- virtual void OnPartData(const char * a_Data, int a_Size) = 0;
+ /** Called when body for a part is received */
+ virtual void OnPartData(const char * a_Data, size_t a_Size) = 0;
- /// Called when the current part ends
+ /** Called when the current part ends */
virtual void OnPartEnd(void) = 0;
} ;
- /// Creates the parser, expects to find the boundary in a_ContentType
+ /** Creates the parser, expects to find the boundary in a_ContentType */
cMultipartParser(const AString & a_ContentType, cCallbacks & a_Callbacks);
- /// Parses more incoming data
- void Parse(const char * a_Data, int a_Size);
+ /** Parses more incoming data */
+ void Parse(const char * a_Data, size_t a_Size);
protected:
- /// The callbacks to call for various parsing events
+ /** The callbacks to call for various parsing events */
cCallbacks & m_Callbacks;
- /// True if the data parsed so far is valid; if false, further parsing is skipped
+ /** True if the data parsed so far is valid; if false, further parsing is skipped */
bool m_IsValid;
- /// Parser for each part's envelope
+ /** Parser for each part's envelope */
cEnvelopeParser m_EnvelopeParser;
- /// Buffer for the incoming data until it is parsed
+ /** Buffer for the incoming data until it is parsed */
AString m_IncomingData;
- /// The boundary, excluding both the initial "--" and the terminating CRLF
+ /** The boundary, excluding both the initial "--" and the terminating CRLF */
AString m_Boundary;
- /// Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting.
+ /** Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting. */
bool m_HasHadData;
- /// Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size
- void ParseLine(const char * a_Data, int a_Size);
+ /** Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size */
+ void ParseLine(const char * a_Data, size_t a_Size);
- /// Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size
- void ParseHeaderLine(const char * a_Data, int a_Size);
+ /** Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size */
+ void ParseHeaderLine(const char * a_Data, size_t a_Size);
// cEnvelopeParser overrides:
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override;
diff --git a/src/HTTPServer/NameValueParser.cpp b/src/HTTPServer/NameValueParser.cpp
index 9ea8594ae..f16ea1915 100644
--- a/src/HTTPServer/NameValueParser.cpp
+++ b/src/HTTPServer/NameValueParser.cpp
@@ -24,7 +24,7 @@ public:
// Now try parsing char-by-char, to debug transitions across datachunk boundaries:
cNameValueParser Parser2;
- for (int i = 0; i < sizeof(Data) - 1; i++)
+ for (size_t i = 0; i < sizeof(Data) - 1; i++)
{
Parser2.Parse(Data + i, 1);
}
@@ -82,7 +82,7 @@ cNameValueParser::cNameValueParser(bool a_AllowsKeyOnly) :
-cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly) :
+cNameValueParser::cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly) :
m_State(psKeySpace),
m_AllowsKeyOnly(a_AllowsKeyOnly)
{
@@ -93,12 +93,12 @@ cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_Allow
-void cNameValueParser::Parse(const char * a_Data, int a_Size)
+void cNameValueParser::Parse(const char * a_Data, size_t a_Size)
{
ASSERT(m_State != psFinished); // Calling Parse() after Finish() is wrong!
- int Last = 0;
- for (int i = 0; i < a_Size;)
+ size_t Last = 0;
+ for (size_t i = 0; i < a_Size;)
{
switch (m_State)
{
diff --git a/src/HTTPServer/NameValueParser.h b/src/HTTPServer/NameValueParser.h
index 07dc0b942..9794614fa 100644
--- a/src/HTTPServer/NameValueParser.h
+++ b/src/HTTPServer/NameValueParser.h
@@ -21,10 +21,10 @@ public:
cNameValueParser(bool a_AllowsKeyOnly = true);
/// Creates an empty parser, then parses the data given. Doesn't call Finish(), so more data can be parsed later
- cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly = true);
+ cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly = true);
/// Parses the data given
- void Parse(const char * a_Data, int a_Size);
+ void Parse(const char * a_Data, size_t a_Size);
/// Notifies the parser that no more data will be coming. Returns true if the parser state is valid
bool Finish(void);
diff --git a/src/HTTPServer/SslHTTPConnection.cpp b/src/HTTPServer/SslHTTPConnection.cpp
new file mode 100644
index 000000000..d237089d9
--- /dev/null
+++ b/src/HTTPServer/SslHTTPConnection.cpp
@@ -0,0 +1,107 @@
+
+// SslHTTPConnection.cpp
+
+// Implements the cSslHTTPConnection class representing a HTTP connection made over a SSL link
+
+#include "Globals.h"
+#include "SslHTTPConnection.h"
+#include "HTTPServer.h"
+
+
+
+
+
+cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) :
+ super(a_HTTPServer),
+ m_Ssl(64000),
+ m_Cert(a_Cert),
+ m_PrivateKey(a_PrivateKey)
+{
+ m_Ssl.Initialize(false);
+ m_Ssl.SetOwnCert(a_Cert, a_PrivateKey);
+}
+
+
+
+
+
+bool cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
+{
+ // If there is outgoing data in the queue, notify the server that it should write it out:
+ if (!m_OutgoingData.empty())
+ {
+ m_HTTPServer.NotifyConnectionWrite(*this);
+ }
+
+ // Process the received data:
+ const char * Data = a_Data;
+ size_t Size = a_Size;
+ for (;;)
+ {
+ // Try to write as many bytes into Ssl's "incoming" buffer as possible:
+ size_t BytesWritten = 0;
+ if (Size > 0)
+ {
+ BytesWritten = m_Ssl.WriteIncoming(Data, Size);
+ Data += BytesWritten;
+ Size -= BytesWritten;
+ }
+
+ // Try to read as many bytes from SSL's decryption as possible:
+ char Buffer[32000];
+ int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer));
+ if (NumRead > 0)
+ {
+ if (super::DataReceived(Buffer, (size_t)NumRead))
+ {
+ // The socket has been closed, and the object is already deleted. Bail out.
+ return true;
+ }
+ }
+
+ // If both failed, bail out:
+ if ((BytesWritten == 0) && (NumRead <= 0))
+ {
+ return false;
+ }
+ }
+}
+
+
+
+
+
+void cSslHTTPConnection::GetOutgoingData(AString & a_Data)
+{
+ for (;;)
+ {
+ // Write as many bytes from our buffer to SSL's encryption as possible:
+ int NumWritten = 0;
+ if (!m_OutgoingData.empty())
+ {
+ NumWritten = m_Ssl.WritePlain(m_OutgoingData.data(), m_OutgoingData.size());
+ if (NumWritten > 0)
+ {
+ m_OutgoingData.erase(0, (size_t)NumWritten);
+ }
+ }
+
+ // Read as many bytes from SSL's "outgoing" buffer as possible:
+ char Buffer[32000];
+ size_t NumBytes = m_Ssl.ReadOutgoing(Buffer, sizeof(Buffer));
+ if (NumBytes > 0)
+ {
+ a_Data.append(Buffer, NumBytes);
+ }
+
+ // If both failed, bail out:
+ if ((NumWritten <= 0) && (NumBytes == 0))
+ {
+ return;
+ }
+ }
+}
+
+
+
+
diff --git a/src/HTTPServer/SslHTTPConnection.h b/src/HTTPServer/SslHTTPConnection.h
new file mode 100644
index 000000000..c2c1585cd
--- /dev/null
+++ b/src/HTTPServer/SslHTTPConnection.h
@@ -0,0 +1,45 @@
+
+// SslHTTPConnection.h
+
+// Declared the cSslHTTPConnection class representing a HTTP connection made over a SSL link
+
+
+
+
+
+#pragma once
+
+#include "HTTPConnection.h"
+#include "PolarSSL++/BufferedSslContext.h"
+
+
+
+
+
+class cSslHTTPConnection :
+ public cHTTPConnection
+{
+ typedef cHTTPConnection super;
+
+public:
+ /** Creates a new connection on the specified server.
+ Sends the specified cert as the server certificate, uses the private key for decryption. */
+ cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey);
+
+protected:
+ cBufferedSslContext m_Ssl;
+
+ /** The certificate to send to the client */
+ cX509CertPtr m_Cert;
+
+ /** The private key used for the certificate */
+ cCryptoKeyPtr m_PrivateKey;
+
+ // cHTTPConnection overrides:
+ virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
+ virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
+} ;
+
+
+
+
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index c7c089d5f..bce882c88 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -243,6 +243,16 @@ void cInventory::SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item)
+void cInventory::SendEquippedSlot()
+{
+ int EquippedSlotNum = cInventory::invArmorCount + cInventory::invInventoryCount + GetEquippedSlotNum();
+ SendSlot(EquippedSlotNum);
+}
+
+
+
+
+
const cItem & cInventory::GetSlot(int a_SlotNum) const
{
if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
@@ -376,6 +386,7 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount)
if (!Grid->DamageItem(GridSlotNum, a_Amount))
{
// The item has been damaged, but did not break yet
+ SendSlot(a_SlotNum);
return false;
}
diff --git a/src/Inventory.h b/src/Inventory.h
index 1ad7c4776..39aef1538 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -56,13 +56,13 @@ public:
// tolua_begin
- /// Removes all items from the entire inventory
+ /** Removes all items from the entire inventory */
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_ConsiderEmptySlots);
- /// Returns how many items of the specified type would fit into the slot range specified
+ /** Returns how many items of the specified type would fit into the slot range specified */
int HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots);
/** Adds as many items out of a_ItemStack as can fit.
@@ -86,33 +86,36 @@ public:
*/
int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst);
- /// Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed
+ /** Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed */
bool RemoveOneEquippedItem(void);
- /// 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);
+
+ /** Sends the equipped item slot to the client */
+ void SendEquippedSlot();
- /// Returns the cItemGrid object representing the armor slots
+ /** Returns the cItemGrid object representing the armor slots */
cItemGrid & GetArmorGrid(void) { return m_ArmorSlots; }
- /// Returns the cItemGrid object representing the main inventory slots
+ /** Returns the cItemGrid object representing the main inventory slots */
cItemGrid & GetInventoryGrid(void) { return m_InventorySlots; }
- /// Returns the cItemGrid object representing the hotbar slots
+ /** Returns the cItemGrid object representing the hotbar slots */
cItemGrid & GetHotbarGrid(void) { return m_HotbarSlots; }
- /// Returns the player associated with this inventory
+ /** Returns the player associated with this inventory */
cPlayer & GetOwner(void) { return m_Owner; }
- /// Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents
+ /** Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents */
void CopyToItems(cItems & a_Items);
// tolua_end
- /// Returns the player associated with this inventory (const version)
+ /** Returns the player associated with this inventory (const version) */
const cPlayer & GetOwner(void) const { return m_Owner; }
// tolua_begin
@@ -136,10 +139,10 @@ public:
*/
int ChangeSlotCount(int a_SlotNum, int a_AddToCount);
- /// Adds the specified damage to the specified item; deletes the item and returns true if the item broke.
+ /** Adds the specified damage to the specified item; deletes the item and returns true if the item broke. */
bool DamageItem(int a_SlotNum, short a_Amount);
- /// Adds the specified damage to the currently held item; deletes the item and returns true if the item broke.
+ /** Adds the specified damage to the currently held item; deletes the item and returns true if the item broke. */
bool DamageEquippedItem(short a_Amount = 1);
const cItem & GetEquippedHelmet (void) const { return m_ArmorSlots.GetSlot(0); }
@@ -149,13 +152,13 @@ public:
// tolua_end
- /// Sends the slot contents to the owner
+ /** Sends the slot contents to the owner */
void SendSlot(int a_SlotNum);
- /// Update items (e.g. Maps)
+ /** Update items (e.g. Maps) */
void UpdateItems(void);
- /// Converts an armor slot number into the ID for the EntityEquipment packet
+ /** Converts an armor slot number into the ID for the EntityEquipment packet */
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
void SaveToJson(Json::Value & a_Value);
@@ -172,10 +175,10 @@ protected:
cPlayer & m_Owner;
- /// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum
+ /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */
const cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const;
- /// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum
+ /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */
cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum);
// cItemGrid::cListener override:
diff --git a/src/Item.cpp b/src/Item.cpp
index 856b68be6..d6e8b224a 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -5,6 +5,8 @@
#include "json/json.h"
#include "Items/ItemHandler.h"
+#include "FastRandom.h"
+
@@ -149,6 +151,8 @@ void cItem::GetJson(Json::Value & a_OutValue) const
a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem);
a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem);
}
+
+ a_OutValue["RepairCost"] = m_RepairCost;
}
}
@@ -177,6 +181,8 @@ void cItem::FromJson(const Json::Value & a_Value)
m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem);
m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem);
}
+
+ m_RepairCost = a_Value.get("RepairCost", 0).asInt();
}
}
@@ -196,9 +202,6 @@ bool cItem::IsEnchantable(short item)
return true;
if ((item >= 298) && (item <= 317))
return true;
- if ((item >= 290) && (item <= 294))
- return true;
-
if ((item == 346) || (item == 359) || (item == 261))
return true;
@@ -209,6 +212,157 @@ bool cItem::IsEnchantable(short item)
+int cItem::GetEnchantability()
+{
+ int Enchantability = 0;
+
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_SWORD: Enchantability = 15; break;
+ case E_ITEM_WOODEN_PICKAXE: Enchantability = 15; break;
+ case E_ITEM_WOODEN_SHOVEL: Enchantability = 15; break;
+ case E_ITEM_WOODEN_AXE: Enchantability = 15; break;
+ case E_ITEM_WOODEN_HOE: Enchantability = 15; break;
+
+ case E_ITEM_LEATHER_CAP: Enchantability = 15; break;
+ case E_ITEM_LEATHER_TUNIC: Enchantability = 15; break;
+ case E_ITEM_LEATHER_PANTS: Enchantability = 15; break;
+ case E_ITEM_LEATHER_BOOTS: Enchantability = 15; break;
+
+ case E_ITEM_STONE_SWORD: Enchantability = 5; break;
+ case E_ITEM_STONE_PICKAXE: Enchantability = 5; break;
+ case E_ITEM_STONE_SHOVEL: Enchantability = 5; break;
+ case E_ITEM_STONE_AXE: Enchantability = 5; break;
+ case E_ITEM_STONE_HOE: Enchantability = 5; break;
+
+ case E_ITEM_IRON_HELMET: Enchantability = 9; break;
+ case E_ITEM_IRON_CHESTPLATE: Enchantability = 9; break;
+ case E_ITEM_IRON_LEGGINGS: Enchantability = 9; break;
+ case E_ITEM_IRON_BOOTS: Enchantability = 9; break;
+
+ case E_ITEM_IRON_SWORD: Enchantability = 14; break;
+ case E_ITEM_IRON_PICKAXE: Enchantability = 14; break;
+ case E_ITEM_IRON_SHOVEL: Enchantability = 14; break;
+ case E_ITEM_IRON_AXE: Enchantability = 14; break;
+ case E_ITEM_IRON_HOE: Enchantability = 14; break;
+
+ case E_ITEM_CHAIN_HELMET: Enchantability = 12; break;
+ case E_ITEM_CHAIN_CHESTPLATE: Enchantability = 12; break;
+ case E_ITEM_CHAIN_LEGGINGS: Enchantability = 12; break;
+ case E_ITEM_CHAIN_BOOTS: Enchantability = 12; break;
+
+ case E_ITEM_DIAMOND_HELMET: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_CHESTPLATE: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_LEGGINGS: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_BOOTS: Enchantability = 10; break;
+
+ case E_ITEM_DIAMOND_SWORD: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_PICKAXE: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_SHOVEL: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_AXE: Enchantability = 10; break;
+ case E_ITEM_DIAMOND_HOE: Enchantability = 10; break;
+
+ case E_ITEM_GOLD_HELMET: Enchantability = 25; break;
+ case E_ITEM_GOLD_CHESTPLATE: Enchantability = 25; break;
+ case E_ITEM_GOLD_LEGGINGS: Enchantability = 25; break;
+ case E_ITEM_GOLD_BOOTS: Enchantability = 25; break;
+
+ case E_ITEM_GOLD_SWORD: Enchantability = 22; break;
+ case E_ITEM_GOLD_PICKAXE: Enchantability = 22; break;
+ case E_ITEM_GOLD_SHOVEL: Enchantability = 22; break;
+ case E_ITEM_GOLD_AXE: Enchantability = 22; break;
+ case E_ITEM_GOLD_HOE: Enchantability = 22; break;
+
+ case E_ITEM_FISHING_ROD: Enchantability = 1; break;
+ case E_ITEM_BOW: Enchantability = 1; break;
+ case E_ITEM_BOOK: Enchantability = 1; break;
+ }
+
+ return Enchantability;
+}
+
+
+
+
+
+bool cItem::EnchantByXPLevels(int a_NumXPLevels)
+{
+ if (!cItem::IsEnchantable(m_ItemType) && (m_ItemType != E_ITEM_BOOK))
+ {
+ return false;
+ }
+
+ int Enchantability = GetEnchantability();
+
+ cFastRandom Random;
+ int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1;
+ float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F;
+ int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F);
+
+ cWeightedEnchantments enchantments;
+ cEnchantments::AddItemEnchantmentWeights(enchantments, m_ItemType, FinalEnchantmentLevel);
+
+ if (m_ItemType == E_ITEM_BOOK)
+ {
+ m_ItemType = E_ITEM_ENCHANTED_BOOK;
+ }
+
+ cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
+ m_Enchantments.AddFromString(Enchantment1.ToString());
+ cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment1);
+
+ // Checking for conflicting enchantments
+ cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment1);
+
+ float NewEnchantmentLevel = (float)a_NumXPLevels;
+
+ // Next Enchantment (Second)
+ NewEnchantmentLevel = NewEnchantmentLevel / 2;
+ float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
+ if (enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance))
+ {
+ return true;
+ }
+
+ cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
+ m_Enchantments.AddFromString(Enchantment2.ToString());
+ cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment2);
+
+ // Checking for conflicting enchantments
+ cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment2);
+
+ // Next Enchantment (Third)
+ NewEnchantmentLevel = NewEnchantmentLevel / 2;
+ float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
+ if (enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance))
+ {
+ return true;
+ }
+
+ cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
+ m_Enchantments.AddFromString(Enchantment3.ToString());
+ cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment3);
+
+ // Checking for conflicting enchantments
+ cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment3);
+
+ // Next Enchantment (Fourth)
+ NewEnchantmentLevel = NewEnchantmentLevel / 2;
+ float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
+ if (enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance))
+ {
+ return true;
+ }
+ cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
+ m_Enchantments.AddFromString(Enchantment4.ToString());
+
+ return true;
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cItems:
diff --git a/src/Item.h b/src/Item.h
index 4bdfb12dd..acbc880dc 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -40,6 +40,7 @@ public:
m_ItemDamage(0),
m_CustomName(""),
m_Lore(""),
+ m_RepairCost(0),
m_FireworkItem()
{
}
@@ -60,11 +61,12 @@ public:
m_Enchantments(a_Enchantments),
m_CustomName (a_CustomName),
m_Lore (a_Lore),
+ m_RepairCost (0),
m_FireworkItem()
{
if (!IsValidItem(m_ItemType))
{
- if (m_ItemType != E_BLOCK_AIR)
+ if ((m_ItemType != E_BLOCK_AIR) && (m_ItemType != E_ITEM_EMPTY))
{
LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType);
}
@@ -73,6 +75,10 @@ public:
}
+ // The constructor is disabled in code, because the compiler generates it anyway,
+ // but it needs to stay because ToLua needs to generate the binding for it
+ #if 0
+
/** Creates an exact copy of the item */
cItem(const cItem & a_CopyFrom) :
m_ItemType (a_CopyFrom.m_ItemType),
@@ -81,10 +87,13 @@ public:
m_Enchantments(a_CopyFrom.m_Enchantments),
m_CustomName (a_CopyFrom.m_CustomName),
m_Lore (a_CopyFrom.m_Lore),
+ m_RepairCost (a_CopyFrom.m_RepairCost),
m_FireworkItem(a_CopyFrom.m_FireworkItem)
{
}
+ #endif
+
void Empty(void)
{
@@ -94,6 +103,7 @@ public:
m_Enchantments.Clear();
m_CustomName = "";
m_Lore = "";
+ m_RepairCost = 0;
m_FireworkItem.EmptyData();
}
@@ -103,6 +113,7 @@ public:
m_ItemType = E_ITEM_EMPTY;
m_ItemCount = 0;
m_ItemDamage = 0;
+ m_RepairCost = 0;
}
@@ -175,16 +186,24 @@ public:
/** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */
static bool IsEnchantable(short a_ItemType); // tolua_export
+ /** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */
+ int GetEnchantability(); // tolua_export
+
+ /** Enchants the item using the specified number of XP levels.
+ Returns true if item enchanted, false if not. */
+ bool EnchantByXPLevels(int a_NumXPLevels); // tolua_export
+
// tolua_begin
- short m_ItemType;
- char m_ItemCount;
- short m_ItemDamage;
- cEnchantments m_Enchantments;
- AString m_CustomName;
- AString m_Lore;
-
- cFireworkItem m_FireworkItem;
+ short m_ItemType;
+ char m_ItemCount;
+ short m_ItemDamage;
+ cEnchantments m_Enchantments;
+ AString m_CustomName;
+ AString m_Lore;
+
+ int m_RepairCost;
+ cFireworkItem m_FireworkItem;
};
// tolua_end
@@ -209,7 +228,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) const { 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/Items/CMakeLists.txt b/src/Items/CMakeLists.txt
index 44a9f594f..a6fe6ea70 100644
--- a/src/Items/CMakeLists.txt
+++ b/src/Items/CMakeLists.txt
@@ -4,4 +4,9 @@ project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../")
-add_library(Items ItemHandler)
+file(GLOB SOURCE
+ "*.cpp"
+ "*.h"
+)
+
+add_library(Items ${SOURCE})
diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h
new file mode 100644
index 000000000..2436df5bd
--- /dev/null
+++ b/src/Items/ItemArmor.h
@@ -0,0 +1,110 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+
+
+
+
+
+class cItemArmorHandler :
+ public cItemHandler
+{
+public:
+ cItemArmorHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+ /** Move the armor to the armor slot of the player's inventory */
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
+ {
+ int SlotNum;
+ if (ItemCategory::IsHelmet(a_Item.m_ItemType))
+ {
+ SlotNum = 0;
+ }
+ else if (ItemCategory::IsChestPlate(a_Item.m_ItemType))
+ {
+ SlotNum = 1;
+ }
+ else if (ItemCategory::IsLeggings(a_Item.m_ItemType))
+ {
+ SlotNum = 2;
+ }
+ else if (ItemCategory::IsBoots(a_Item.m_ItemType))
+ {
+ SlotNum = 3;
+ }
+ else
+ {
+ LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType);
+ return false;
+ }
+
+ if (!a_Player->GetInventory().GetArmorSlot(SlotNum).IsEmpty())
+ {
+ return false;
+ }
+
+ a_Player->GetInventory().SetArmorSlot(SlotNum, a_Item.CopyOne());
+
+ cItem Item(a_Item);
+ Item.m_ItemCount--;
+ if (Item.m_ItemCount <= 0)
+ {
+ Item.Empty();
+ }
+ a_Player->GetInventory().SetHotbarSlot(a_Player->GetInventory().GetEquippedSlotNum(), Item);
+ return true;
+ }
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_CHAIN_BOOTS:
+ case E_ITEM_CHAIN_CHESTPLATE:
+ case E_ITEM_CHAIN_HELMET:
+ case E_ITEM_CHAIN_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_IRON);
+ }
+ case E_ITEM_DIAMOND_BOOTS:
+ case E_ITEM_DIAMOND_CHESTPLATE:
+ case E_ITEM_DIAMOND_HELMET:
+ case E_ITEM_DIAMOND_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ case E_ITEM_IRON_BOOTS:
+ case E_ITEM_IRON_CHESTPLATE:
+ case E_ITEM_IRON_HELMET:
+ case E_ITEM_IRON_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_IRON);
+ }
+ case E_ITEM_GOLD_BOOTS:
+ case E_ITEM_GOLD_CHESTPLATE:
+ case E_ITEM_GOLD_HELMET:
+ case E_ITEM_GOLD_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_GOLD);
+ }
+ case E_ITEM_LEATHER_BOOTS:
+ case E_ITEM_LEATHER_CAP:
+ case E_ITEM_LEATHER_PANTS:
+ case E_ITEM_LEATHER_TUNIC:
+ {
+ return (a_ItemType == E_ITEM_LEATHER);
+ }
+ }
+ return false;
+ }
+
+} ;
+
+
+
+
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/ItemBow.h b/src/Items/ItemBow.h
index 410c5f512..8c0b3a0a3 100644
--- a/src/Items/ItemBow.h
+++ b/src/Items/ItemBow.h
@@ -9,7 +9,7 @@
#pragma once
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
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/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
index f0b1e1424..953673382 100644
--- a/src/Items/ItemEmptyMap.h
+++ b/src/Items/ItemEmptyMap.h
@@ -55,7 +55,7 @@ public:
return true;
}
- a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, NewMap->GetID()), true, true);
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, (short)(NewMap->GetID() & 0x7fff)), true, true);
return true;
}
diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h
index 15acbd9fe..32c151db5 100644
--- a/src/Items/ItemFishingRod.h
+++ b/src/Items/ItemFishingRod.h
@@ -123,7 +123,7 @@ public:
}
case 2:
{
- Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, a_World->GetTickRandomNumber(50))); // Fishing rod with durability. TODO: Enchantments on it
+ Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, (short)a_World->GetTickRandomNumber(50))); // Fishing rod with durability. TODO: Enchantments on it
break;
}
case 3:
@@ -142,6 +142,8 @@ public:
break;
}
}
+
+ a_Player->GetStatManager().AddValue(statTreasureFished, 1);
}
else if (ItemCategory <= 14) // Junk 10%
{
@@ -152,7 +154,7 @@ public:
}
else if (Junk <= 4)
{
- Drops.Add(cItem(E_ITEM_BOW, 1, a_World->GetTickRandomNumber(64)));
+ Drops.Add(cItem(E_ITEM_BOW, 1, (short)a_World->GetTickRandomNumber(64)));
}
else if (Junk <= 9)
{
@@ -190,6 +192,8 @@ public:
{
Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK));
}
+
+ a_Player->GetStatManager().AddValue(statJunkFished, 1);
}
else // Fish
{
@@ -210,6 +214,8 @@ public:
{
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH));
}
+
+ a_Player->GetStatManager().AddValue(statFishCaught, 1);
}
if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops))
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 454fabdd7..d97f986ba 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -8,6 +8,7 @@
#include "../BlockInServerPluginInterface.h"
// Handlers:
+#include "ItemArmor.h"
#include "ItemBed.h"
#include "ItemBoat.h"
#include "ItemBow.h"
@@ -27,6 +28,7 @@
#include "ItemHoe.h"
#include "ItemLeaves.h"
#include "ItemLighter.h"
+#include "ItemLilypad.h"
#include "ItemMap.h"
#include "ItemMinecart.h"
#include "ItemNetherWart.h"
@@ -115,6 +117,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);
@@ -220,6 +223,31 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
{
return new cItemFoodHandler(a_ItemType);
}
+
+ // Armor:
+ case E_ITEM_LEATHER_CAP:
+ case E_ITEM_GOLD_HELMET:
+ case E_ITEM_CHAIN_HELMET:
+ case E_ITEM_IRON_HELMET:
+ case E_ITEM_DIAMOND_HELMET:
+ case E_ITEM_LEATHER_TUNIC:
+ case E_ITEM_GOLD_CHESTPLATE:
+ case E_ITEM_CHAIN_CHESTPLATE:
+ case E_ITEM_IRON_CHESTPLATE:
+ case E_ITEM_DIAMOND_CHESTPLATE:
+ case E_ITEM_LEATHER_PANTS:
+ case E_ITEM_GOLD_LEGGINGS:
+ case E_ITEM_CHAIN_LEGGINGS:
+ case E_ITEM_IRON_LEGGINGS:
+ case E_ITEM_DIAMOND_LEGGINGS:
+ case E_ITEM_LEATHER_BOOTS:
+ case E_ITEM_GOLD_BOOTS:
+ case E_ITEM_CHAIN_BOOTS:
+ case E_ITEM_IRON_BOOTS:
+ case E_ITEM_DIAMOND_BOOTS:
+ {
+ return new cItemArmorHandler(a_ItemType);
+ }
}
}
@@ -429,7 +457,6 @@ bool cItemHandler::IsTool()
|| (m_ItemType >= 267 && m_ItemType <= 279)
|| (m_ItemType >= 283 && m_ItemType <= 286)
|| (m_ItemType >= 290 && m_ItemType <= 294)
- || (m_ItemType >= 256 && m_ItemType <= 259)
|| (m_ItemType == 325)
|| (m_ItemType == 346);
}
@@ -484,6 +511,16 @@ bool cItemHandler::IsPlaceable(void)
+
+bool cItemHandler::CanRepairWithRawMaterial(short a_ItemType)
+{
+ return false;
+}
+
+
+
+
+
bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
{
UNUSED(a_BlockType);
@@ -504,13 +541,13 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
{
ASSERT(m_ItemType < 256); // Items with IDs above 255 should all be handled by specific handlers
- if (m_ItemType > 256)
+ if (m_ItemType >= 256)
{
- LOGERROR("%s: Item %d has no valid block!", __FUNCTION__, m_ItemType);
+ LOGERROR("%s: Item %d is not eligible for direct block placement!", __FUNCTION__, m_ItemType);
return false;
}
- cBlockHandler * BlockH = BlockHandler(m_ItemType);
+ cBlockHandler * BlockH = BlockHandler((BLOCKTYPE)m_ItemType);
cChunkInterface ChunkInterface(a_World->GetChunkMap());
return BlockH->GetPlacementBlockTypeMeta(
ChunkInterface, a_Player,
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index 5b6c239cc..e13198cd7 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -21,13 +21,13 @@ class cItemHandler
public:
cItemHandler(int a_ItemType);
- // Force virtual destructor
+ /** Force virtual destructor */
virtual ~cItemHandler() {}
- /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
+ /** Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False */
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir);
- /// Called when the client sends the SHOOT status in the lclk packet
+ /** Called when the client sends the SHOOT status in the lclk packet */
virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
{
UNUSED(a_BlockX);
@@ -36,7 +36,7 @@ public:
UNUSED(a_BlockFace);
}
- /// Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items
+ /** Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items */
virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
{
UNUSED(a_World);
@@ -44,48 +44,51 @@ public:
UNUSED(a_Item);
}
- /// Called while the player diggs a block using this item
+ /** Called while the player diggs a block using this item */
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
- /// Called when the player destroys a block using this item. This also calls the drop function for the destroyed block
+ /** Called when the player destroys a block using this item. This also calls the drop function for the destroyed block */
virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_X, int a_Y, int a_Z);
- /// Called after the player has eaten this item.
+ /** Called after the player has eaten this item. */
virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item);
- /// Returns the maximum stack size for a given item
+ /** Returns the maximum stack size for a given item */
virtual char GetMaxStackSize(void);
struct FoodInfo
{
- int FoodLevel;
double Saturation;
+ int FoodLevel;
int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning
FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
- FoodLevel(a_FoodLevel),
Saturation(a_Saturation),
+ FoodLevel(a_FoodLevel),
PoisonChance(a_PoisonChance)
{
}
} ;
- /// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance)
+ /** Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) */
virtual FoodInfo GetFoodInfo();
- /// Lets the player eat a selected item. Returns true if the player ate the item
+ /** Lets the player eat a selected item. Returns true if the player ate the item */
virtual bool EatItem(cPlayer *a_Player, cItem *a_Item);
- /// Indicates if this item is a tool
+ /** Indicates if this item is a tool */
virtual bool IsTool(void);
- /// Indicates if this item is food
+ /** Indicates if this item is food */
virtual bool IsFood(void);
- /// Blocks simply get placed
+ /** Blocks simply get placed */
virtual bool IsPlaceable(void);
- /** Called before a block is placed into a world.
+ /** Can the anvil repair this item, when a_Item is the second input? */
+ virtual bool CanRepairWithRawMaterial(short a_ItemType);
+
+ /** Called before a block is placed into a world.
The handler should return true to allow placement, false to refuse.
Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
*/
@@ -96,7 +99,7 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
);
- /// Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can´t) DEFAULT: False
+ /** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can�t) DEFAULT: False */
virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType);
static cItemHandler * GetItemHandler(int a_ItemType);
diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h
new file mode 100644
index 000000000..bc650cdbd
--- /dev/null
+++ b/src/Items/ItemLilypad.h
@@ -0,0 +1,108 @@
+#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(int a_ItemType):
+ super(a_ItemType)
+ {
+
+ }
+
+
+ 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(void) :
+ m_HasHitFluid(false)
+ {
+ }
+
+ virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override
+ {
+ if (IsBlockWater(a_CBBlockType))
+ {
+ if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged
+ {
+ return false;
+ }
+ AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, BLOCK_FACE_YP); // Always place pad at top of water block
+ if (
+ !IsBlockWater(a_CBBlockType) &&
+ cBlockInfo::FullyOccupiesVoxel(a_CBBlockType)
+ )
+ {
+ // Can't place lilypad on air/in another block!
+ return true;
+ }
+ m_HasHitFluid = true;
+ m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ);
+ return true;
+ }
+ return false;
+ }
+
+ Vector3i m_Pos;
+ bool m_HasHitFluid;
+
+ };
+
+ cCallbacks Callbacks;
+ 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/ItemMap.h b/src/Items/ItemMap.h
index e8ff9da88..056fe0fe7 100644
--- a/src/Items/ItemMap.h
+++ b/src/Items/ItemMap.h
@@ -29,7 +29,7 @@ public:
virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
{
- cMap * Map = a_World->GetMapManager().GetMapData(a_Item.m_ItemDamage);
+ cMap * Map = a_World->GetMapManager().GetMapData((unsigned)a_Item.m_ItemDamage);
if (Map == NULL)
{
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
index bcaa5635a..4e7d8fcff 100644
--- a/src/Items/ItemMinecart.h
+++ b/src/Items/ItemMinecart.h
@@ -1,4 +1,3 @@
-
// ItemMinecart.h
// Declares the various minecart ItemHandlers
@@ -72,9 +71,14 @@ public:
}
} // switch (m_ItemType)
Minecart->Initialize(a_World);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
return true;
}
-
+
} ;
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
index 2a8e40daa..82bec52d4 100644
--- a/src/Items/ItemPickaxe.h
+++ b/src/Items/ItemPickaxe.h
@@ -76,6 +76,7 @@ public:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_BRICK:
case E_BLOCK_COBBLESTONE_STAIRS:
+ case E_BLOCK_COBBLESTONE_WALL:
case E_BLOCK_STONE_BRICK_STAIRS:
case E_BLOCK_NETHER_BRICK_STAIRS:
case E_BLOCK_CAULDRON:
@@ -85,6 +86,19 @@ public:
}
return false;
}
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_PICKAXE: return (a_ItemType == E_BLOCK_PLANKS);
+ case E_ITEM_STONE_PICKAXE: return (a_ItemType == E_BLOCK_COBBLESTONE);
+ case E_ITEM_IRON_PICKAXE: return (a_ItemType == E_ITEM_IRON);
+ case E_ITEM_GOLD_PICKAXE: return (a_ItemType == E_ITEM_GOLD);
+ case E_ITEM_DIAMOND_PICKAXE: return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ return false;
+ }
} ;
diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h
index 873d5ae25..333ba46e8 100644
--- a/src/Items/ItemShovel.h
+++ b/src/Items/ItemShovel.h
@@ -41,4 +41,18 @@ public:
{
return (a_BlockType == E_BLOCK_SNOW);
}
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_SHOVEL: return (a_ItemType == E_BLOCK_PLANKS);
+ case E_ITEM_STONE_SHOVEL: return (a_ItemType == E_BLOCK_COBBLESTONE);
+ case E_ITEM_IRON_SHOVEL: return (a_ItemType == E_ITEM_IRON);
+ case E_ITEM_GOLD_SHOVEL: return (a_ItemType == E_ITEM_GOLD);
+ case E_ITEM_DIAMOND_SHOVEL: return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ return false;
+ }
+
};
diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h
index 0d6019398..bba97afa1 100644
--- a/src/Items/ItemSpawnEgg.h
+++ b/src/Items/ItemSpawnEgg.h
@@ -33,7 +33,10 @@ public:
a_BlockY--;
}
- if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0)
+ cMonster::eType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage);
+ if (
+ (MonsterType != cMonster::mtInvalidType) && // Valid monster type
+ (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded
{
if (!a_Player->IsGameModeCreative())
{
@@ -45,6 +48,41 @@ public:
return false;
}
+
+
+ /** Converts the Spawn egg item damage to the monster type to spawn.
+ Returns mtInvalidType for invalid damage values. */
+ static cMonster::eType ItemDamageToMonsterType(short a_ItemDamage)
+ {
+ switch (a_ItemDamage)
+ {
+ case E_META_SPAWN_EGG_BAT: return cMonster::mtBat;
+ case E_META_SPAWN_EGG_BLAZE: return cMonster::mtBlaze;
+ case E_META_SPAWN_EGG_CAVE_SPIDER: return cMonster::mtCaveSpider;
+ case E_META_SPAWN_EGG_CHICKEN: return cMonster::mtChicken;
+ case E_META_SPAWN_EGG_COW: return cMonster::mtCow;
+ case E_META_SPAWN_EGG_CREEPER: return cMonster::mtCreeper;
+ case E_META_SPAWN_EGG_ENDERMAN: return cMonster::mtEnderman;
+ case E_META_SPAWN_EGG_GHAST: return cMonster::mtGhast;
+ case E_META_SPAWN_EGG_HORSE: return cMonster::mtHorse;
+ case E_META_SPAWN_EGG_MAGMA_CUBE: return cMonster::mtMagmaCube;
+ case E_META_SPAWN_EGG_MOOSHROOM: return cMonster::mtMooshroom;
+ case E_META_SPAWN_EGG_OCELOT: return cMonster::mtOcelot;
+ case E_META_SPAWN_EGG_PIG: return cMonster::mtPig;
+ case E_META_SPAWN_EGG_SHEEP: return cMonster::mtSheep;
+ case E_META_SPAWN_EGG_SILVERFISH: return cMonster::mtSilverfish;
+ case E_META_SPAWN_EGG_SKELETON: return cMonster::mtSkeleton;
+ case E_META_SPAWN_EGG_SLIME: return cMonster::mtSlime;
+ case E_META_SPAWN_EGG_SPIDER: return cMonster::mtSpider;
+ case E_META_SPAWN_EGG_SQUID: return cMonster::mtSquid;
+ case E_META_SPAWN_EGG_VILLAGER: return cMonster::mtVillager;
+ case E_META_SPAWN_EGG_WITCH: return cMonster::mtWitch;
+ case E_META_SPAWN_EGG_WOLF: return cMonster::mtWolf;
+ case E_META_SPAWN_EGG_ZOMBIE: return cMonster::mtZombie;
+ case E_META_SPAWN_EGG_ZOMBIE_PIGMAN: return cMonster::mtZombiePigman;
+ }
+ return cMonster::mtInvalidType;
+ }
} ;
diff --git a/src/Items/ItemSword.h b/src/Items/ItemSword.h
index a7c1d2432..44feb2d83 100644
--- a/src/Items/ItemSword.h
+++ b/src/Items/ItemSword.h
@@ -23,6 +23,19 @@ public:
{
return (a_BlockType == E_BLOCK_COBWEB);
}
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_SWORD: return (a_ItemType == E_BLOCK_PLANKS);
+ case E_ITEM_STONE_SWORD: return (a_ItemType == E_BLOCK_COBBLESTONE);
+ case E_ITEM_IRON_SWORD: return (a_ItemType == E_ITEM_IRON);
+ case E_ITEM_GOLD_SWORD: return (a_ItemType == E_ITEM_GOLD);
+ case E_ITEM_DIAMOND_SWORD: return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ return false;
+ }
} ;
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index c6a4e714e..35c2b8731 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -28,15 +28,19 @@ public:
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
+ Vector3d Pos = a_Player->GetThrowStartPos();
+ Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
+
+ if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0)
+ {
+ return false;
+ }
+
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
- Vector3d Pos = a_Player->GetThrowStartPos();
- Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
- a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed);
-
return true;
}
@@ -127,7 +131,10 @@ public:
return false;
}
- a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem());
+ if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()) < 0)
+ {
+ return false;
+ }
if (!a_Player->IsGameModeCreative())
{
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index 302473d71..dc19bf500 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -18,20 +18,17 @@
class cReader :
public cChunkDataCallback
{
- virtual void BlockTypes(const BLOCKTYPE * a_Type) override
+ virtual void ChunkData(const cChunkData & a_ChunkBuffer) override
{
- // ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that)
- // C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :)
- typedef struct {BLOCKTYPE m_Row[16]; } ROW;
- ROW * InputRows = (ROW *)a_Type;
- ROW * OutputRows = (ROW *)m_BlockTypes;
+ BLOCKTYPE * OutputRows = m_BlockTypes;
int InputIdx = 0;
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
for (int y = 0; y < cChunkDef::Height; y++)
{
for (int z = 0; z < cChunkDef::Width; z++)
{
- OutputRows[OutputIdx] = InputRows[InputIdx++];
+ a_ChunkBuffer.CopyBlockTypes(OutputRows + OutputIdx * 16, InputIdx * 16, 16);
+ InputIdx++;
OutputIdx += 3;
} // for z
// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
@@ -106,11 +103,13 @@ void cLightingThread::Stop(void)
cCSLock Lock(m_CS);
for (cChunkStays::iterator itr = m_PendingQueue.begin(), end = m_PendingQueue.end(); itr != end; ++itr)
{
+ (*itr)->Disable();
delete *itr;
}
m_PendingQueue.clear();
for (cChunkStays::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr)
{
+ (*itr)->Disable();
delete *itr;
}
m_Queue.clear();
@@ -286,6 +285,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
{
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ);
}
+ a_Item.Disable();
delete &a_Item;
}
diff --git a/src/LightingThread.h b/src/LightingThread.h
index 198f27248..770ae809f 100644
--- a/src/LightingThread.h
+++ b/src/LightingThread.h
@@ -160,14 +160,12 @@ 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_DstIdx >= 0);
- ASSERT(a_DstIdx < (int)ARRAYCOUNT(m_BlockTypes));
+ ASSERT(a_SrcIdx < ARRAYCOUNT(m_SkyLight));
+ 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/LineBlockTracer.cpp b/src/LineBlockTracer.cpp
index f4f29e833..b03652bab 100644
--- a/src/LineBlockTracer.cpp
+++ b/src/LineBlockTracer.cpp
@@ -171,7 +171,6 @@ bool cLineBlockTracer::MoveToNextBlock(void)
double CoeffZ = (DestZ - m_StartZ) / m_DiffZ;
if (CoeffZ < Coeff)
{
- Coeff = CoeffZ;
Direction = dirZ;
}
}
diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp
index 4f3e5dc0f..583438d65 100644
--- a/src/MCLogger.cpp
+++ b/src/MCLogger.cpp
@@ -9,7 +9,6 @@
cMCLogger * cMCLogger::s_MCLogger = NULL;
-bool g_ShouldColorOutput = false;
#ifdef _WIN32
#include <io.h> // Needed for _isatty(), not available on Linux
@@ -33,7 +32,8 @@ cMCLogger * cMCLogger::GetInstance(void)
-cMCLogger::cMCLogger(void)
+cMCLogger::cMCLogger(void):
+ m_ShouldColorOutput(false)
{
AString FileName;
Printf(FileName, "LOG_%d.txt", (int)time(NULL));
@@ -76,15 +76,15 @@ void cMCLogger::InitLog(const AString & a_FileName)
#ifdef _WIN32
// See whether we are writing to a console the default console attrib:
- g_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0);
- if (g_ShouldColorOutput)
+ m_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0);
+ if (m_ShouldColorOutput)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
GetConsoleScreenBufferInfo(g_Console, &sbi);
g_DefaultConsoleAttrib = sbi.wAttributes;
}
#elif defined (__linux) && !defined(ANDROID_NDK)
- g_ShouldColorOutput = isatty(fileno(stdout));
+ m_ShouldColorOutput = isatty(fileno(stdout));
// TODO: Check if the terminal supports colors, somehow?
#endif
}
@@ -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;
+ }
}
}
@@ -173,7 +178,7 @@ void cMCLogger::Error(const char * a_Format, va_list a_ArgList)
void cMCLogger::SetColor(eColorScheme a_Scheme)
{
- if (!g_ShouldColorOutput)
+ if (!m_ShouldColorOutput)
{
return;
}
@@ -206,7 +211,7 @@ void cMCLogger::SetColor(eColorScheme a_Scheme)
void cMCLogger::ResetColor(void)
{
- if (!g_ShouldColorOutput)
+ if (!m_ShouldColorOutput)
{
return;
}
diff --git a/src/MCLogger.h b/src/MCLogger.h
index 996e60329..114210f63 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
{
@@ -41,6 +52,7 @@ private:
cCriticalSection m_CriticalSection;
cLog * m_Log;
static cMCLogger * s_MCLogger;
+ bool m_ShouldColorOutput;
/// Sets the specified color scheme in the terminal (TODO: if coloring available)
diff --git a/src/Map.cpp b/src/Map.cpp
index 79370b097..7721baa70 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -614,7 +614,7 @@ unsigned int cMap::GetNumPixels(void) const
-unsigned int cMap::GetNumDecorators(void) const
+size_t cMap::GetNumDecorators(void) const
{
return m_Decorators.size();
}
diff --git a/src/Map.h b/src/Map.h
index ee7c537b1..e23ca2c92 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -181,7 +181,7 @@ public:
// tolua_end
- unsigned int GetNumDecorators(void) const;
+ size_t GetNumDecorators(void) const;
const cColorList & GetData(void) const { return m_Data; }
diff --git a/src/MapManager.cpp b/src/MapManager.cpp
index 9d02eafb4..e7df75118 100644
--- a/src/MapManager.cpp
+++ b/src/MapManager.cpp
@@ -86,7 +86,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale)
return NULL;
}
- cMap Map(m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale);
+ cMap Map((unsigned)m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale);
m_MapData.push_back(Map);
@@ -97,7 +97,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale)
-unsigned int cMapManager::GetNumMaps(void) const
+size_t cMapManager::GetNumMaps(void) const
{
return m_MapData.size();
}
@@ -151,7 +151,7 @@ void cMapManager::SaveMapData(void)
cIDCountSerializer IDSerializer(m_World->GetName());
- IDSerializer.SetMapCount(m_MapData.size());
+ IDSerializer.SetMapCount((unsigned)m_MapData.size());
if (!IDSerializer.Save())
{
diff --git a/src/MapManager.h b/src/MapManager.h
index 80e6d16d1..ceab8f126 100644
--- a/src/MapManager.h
+++ b/src/MapManager.h
@@ -53,7 +53,7 @@ public:
*/
bool ForEachMap(cMapCallback & a_Callback);
- unsigned int GetNumMaps(void) const; // tolua_export
+ size_t GetNumMaps(void) const; // tolua_export
/** Loads the map data from the disk */
void LoadMapData(void);
diff --git a/src/MobCensus.cpp b/src/MobCensus.cpp
index 9c32bf695..23f74b59e 100644
--- a/src/MobCensus.cpp
+++ b/src/MobCensus.cpp
@@ -64,7 +64,7 @@ void cMobCensus::CollectSpawnableChunk(cChunk & a_Chunk)
int cMobCensus::GetNumChunks(void)
{
- return m_EligibleForSpawnChunks.size();
+ return (int)m_EligibleForSpawnChunks.size();
}
diff --git a/src/MobFamilyCollecter.cpp b/src/MobFamilyCollecter.cpp
index e9c69e078..6da330c83 100644
--- a/src/MobFamilyCollecter.cpp
+++ b/src/MobFamilyCollecter.cpp
@@ -18,7 +18,7 @@ void cMobFamilyCollecter::CollectMob(cMonster & a_Monster)
int cMobFamilyCollecter::GetNumberOfCollectedMobs(cMonster::eFamily a_Family)
{
- return m_Mobs[a_Family].size();
+ return (int)m_Mobs[a_Family].size();
}
diff --git a/src/MobProximityCounter.cpp b/src/MobProximityCounter.cpp
index 6c44ea458..ce20bf56b 100644
--- a/src/MobProximityCounter.cpp
+++ b/src/MobProximityCounter.cpp
@@ -24,7 +24,7 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl
if (a_Distance < it->second.m_Distance)
{
it->second.m_Distance = a_Distance;
- it->second.m_Chunk = a_Chunk;
+ it->second.m_Chunk = &a_Chunk;
}
}
@@ -34,9 +34,9 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl
void cMobProximityCounter::convertMaps()
{
- for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); itr++)
+ for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); ++itr)
{
- m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk)));
+ m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,*itr->second.m_Chunk)));
}
}
@@ -55,7 +55,7 @@ cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDist
convertMaps();
}
- for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); itr++)
+ for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); ++itr)
{
if (toReturn.m_Begin == m_DistanceToMonster.end())
{
diff --git a/src/MobProximityCounter.h b/src/MobProximityCounter.h
index 8a67139aa..79429eb60 100644
--- a/src/MobProximityCounter.h
+++ b/src/MobProximityCounter.h
@@ -16,9 +16,9 @@ protected :
// structs used for later maps (see m_MonsterToDistance and m_DistanceToMonster)
struct sDistanceAndChunk
{
- sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(a_Chunk) {}
+ sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(&a_Chunk) {}
double m_Distance;
- cChunk& m_Chunk;
+ cChunk* m_Chunk;
};
struct sMonsterAndChunk
{
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index a0d0f5c54..de8e01b8a 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -13,7 +13,7 @@ cMobSpawner::cMobSpawner(cMonster::eFamily a_MonsterFamily,const std::set<cMonst
m_NewPack(true),
m_MobType(cMonster::mtInvalidType)
{
- for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); itr++)
+ for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); ++itr)
{
if (cMonster::FamilyFromType(*itr) == a_MonsterFamily)
{
@@ -104,15 +104,15 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
}
}
- int allowedMobsSize = allowedMobs.size();
+ size_t allowedMobsSize = allowedMobs.size();
if (allowedMobsSize > 0)
{
std::set<cMonster::eType>::iterator itr = allowedMobs.begin();
- int iRandom = m_Random.NextInt(allowedMobsSize,a_Biome);
+ int iRandom = m_Random.NextInt((int)allowedMobsSize, a_Biome);
- for(int i = 0; i < iRandom; i++)
+ for (int i = 0; i < iRandom; i++)
{
- itr++;
+ ++itr;
}
return *itr;
@@ -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/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 0901f85a9..85b122034 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -37,7 +37,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt)
}
}
- if (((float)m_FinalDestination.x != (float)m_Target->GetPosX()) || ((float)m_FinalDestination.z != (float)m_Target->GetPosZ()))
+ if (!IsMovingToTargetPosition())
{
MoveToPosition(m_Target->GetPosition());
}
@@ -106,3 +106,17 @@ void cAggressiveMonster::Attack(float a_Dt)
+bool cAggressiveMonster::IsMovingToTargetPosition()
+{
+ // Difference between destination x and target x is negligible (to 10^-12 precision)
+ if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon())
+ {
+ return false;
+ }
+ // Difference between destination z and target z is negligible (to 10^-12 precision)
+ else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon())
+ {
+ return false;
+ }
+ return true;
+}
diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h
index 152260f95..d70ff04a3 100644
--- a/src/Mobs/AggressiveMonster.h
+++ b/src/Mobs/AggressiveMonster.h
@@ -22,6 +22,10 @@ public:
virtual void EventSeePlayer(cEntity *) override;
virtual void Attack(float a_Dt);
+protected:
+ /** Whether this mob's destination is the same as its target's position. */
+ bool IsMovingToTargetPosition();
+
} ;
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index ac42cf40b..326b42f07 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -3,6 +3,7 @@
#include "Blaze.h"
#include "../World.h"
+#include "../Entities/FireChargeEntity.h"
@@ -53,4 +54,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/CMakeLists.txt b/src/Mobs/CMakeLists.txt
index 87fbfd2fc..53c265803 100644
--- a/src/Mobs/CMakeLists.txt
+++ b/src/Mobs/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Mobs ${SOURCE})
diff --git a/src/Mobs/Cavespider.cpp b/src/Mobs/CaveSpider.cpp
index 94e93283d..56ecd2d28 100644
--- a/src/Mobs/Cavespider.cpp
+++ b/src/Mobs/CaveSpider.cpp
@@ -1,15 +1,14 @@
-
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-#include "Cavespider.h"
+#include "CaveSpider.h"
#include "../World.h"
-cCavespider::cCavespider(void) :
- super("Cavespider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5)
+cCaveSpider::cCaveSpider(void) :
+ super("CaveSpider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5)
{
}
@@ -17,7 +16,7 @@ cCavespider::cCavespider(void) :
-void cCavespider::Tick(float a_Dt, cChunk & a_Chunk)
+void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
@@ -29,7 +28,7 @@ void cCavespider::Tick(float a_Dt, cChunk & a_Chunk)
-void cCavespider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
int LootingLevel = 0;
if (a_Killer != NULL)
diff --git a/src/Mobs/Cavespider.h b/src/Mobs/CaveSpider.h
index 10ea03f7b..be9f174f9 100644
--- a/src/Mobs/Cavespider.h
+++ b/src/Mobs/CaveSpider.h
@@ -1,4 +1,3 @@
-
#pragma once
#include "AggressiveMonster.h"
@@ -7,13 +6,13 @@
-class cCavespider :
+class cCaveSpider :
public cAggressiveMonster
{
typedef cAggressiveMonster super;
public:
- cCavespider(void);
+ cCaveSpider(void);
CLASS_PROTODEF(cCaveSpider);
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index 3471b4cf1..9cf539427 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -75,9 +75,12 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- super::DoTakeDamage(a_TDI);
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
if (a_TDI.DamageType == dtLightning)
{
@@ -85,6 +88,7 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
}
m_World->BroadcastEntityMetadata(*this);
+ return true;
}
diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h
index 9abca369b..fc7db6716 100644
--- a/src/Mobs/Creeper.h
+++ b/src/Mobs/Creeper.h
@@ -18,7 +18,7 @@ public:
CLASS_PROTODEF(cCreeper);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Attack(float a_Dt) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp
index fe18f5e76..d8a7663f8 100644
--- a/src/Mobs/Ghast.cpp
+++ b/src/Mobs/Ghast.cpp
@@ -3,6 +3,7 @@
#include "Ghast.h"
#include "../World.h"
+#include "../Entities/GhastFireballEntity.h"
diff --git a/src/Mobs/IncludeAllMonsters.h b/src/Mobs/IncludeAllMonsters.h
index 1b436a11f..3460db993 100644
--- a/src/Mobs/IncludeAllMonsters.h
+++ b/src/Mobs/IncludeAllMonsters.h
@@ -1,6 +1,6 @@
#include "Bat.h"
#include "Blaze.h"
-#include "Cavespider.h"
+#include "CaveSpider.h"
#include "Chicken.h"
#include "Cow.h"
#include "Creeper.h"
@@ -10,7 +10,7 @@
#include "Giant.h"
#include "Horse.h"
#include "IronGolem.h"
-#include "Magmacube.h"
+#include "MagmaCube.h"
#include "Mooshroom.h"
#include "Ocelot.h"
#include "Pig.h"
@@ -26,4 +26,4 @@
#include "Wither.h"
#include "Wolf.h"
#include "Zombie.h"
-#include "Zombiepigman.h"
+#include "ZombiePigman.h"
diff --git a/src/Mobs/Magmacube.cpp b/src/Mobs/MagmaCube.cpp
index 05405f082..3e9abc108 100644
--- a/src/Mobs/Magmacube.cpp
+++ b/src/Mobs/MagmaCube.cpp
@@ -1,7 +1,6 @@
-
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-#include "Magmacube.h"
+#include "MagmaCube.h"
diff --git a/src/Mobs/Magmacube.h b/src/Mobs/MagmaCube.h
index 130952970..43065cae5 100644
--- a/src/Mobs/Magmacube.h
+++ b/src/Mobs/MagmaCube.h
@@ -1,4 +1,3 @@
-
#pragma once
#include "AggressiveMonster.h"
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index d3e0f1c26..a9ca7a2fa 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 = POSX_TOINT;
+ const int PosY = POSY_TOINT;
+ const int PosZ = POSZ_TOINT;
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;
@@ -146,13 +148,27 @@ void cMonster::TickPathFinding()
BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ);
BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
- BLOCKTYPE BlockAtYM = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY - 1, gCrossCoords[i].z + PosZ);
-
- if ((!cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
+ int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
+
+ if (
+ (!cBlockInfo::IsSolid(BlockAtY)) &&
+ (!cBlockInfo::IsSolid(BlockAtYP)) &&
+ (!IsBlockLava(BlockAtLowestY)) &&
+ (BlockAtLowestY != E_BLOCK_CACTUS) &&
+ (PosY - LowestY < FALL_DAMAGE_HEIGHT)
+ )
{
m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
}
- else if ((cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!cBlockInfo::IsSolid(BlockAtYPP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
+ else if (
+ (cBlockInfo::IsSolid(BlockAtY)) &&
+ (BlockAtY != E_BLOCK_CACTUS) &&
+ (!cBlockInfo::IsSolid(BlockAtYP)) &&
+ (!cBlockInfo::IsSolid(BlockAtYPP)) &&
+ (BlockAtY != E_BLOCK_FENCE) &&
+ (BlockAtY != E_BLOCK_FENCE_GATE)
+ )
{
m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
}
@@ -339,6 +355,8 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
InStateEscaping(a_Dt);
break;
}
+
+ case ATTACKING: break;
} // switch (m_EMState)
BroadcastMovementUpdate();
@@ -400,7 +418,7 @@ void cMonster::HandleFalling()
GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
}
- m_LastGroundHeight = (int)floor(GetPosY());
+ m_LastGroundHeight = POSY_TOINT;
}
}
@@ -409,7 +427,7 @@ void cMonster::HandleFalling()
int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
{
- int PosY = (int)floor(GetPosY());
+ int PosY = POSY_TOINT;
if (PosY < 0)
PosY = 0;
@@ -441,17 +459,23 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
-void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- super::DoTakeDamage(a_TDI);
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
- if((m_SoundHurt != "") && (m_Health > 0))
+ if (!m_SoundHurt.empty() && (m_Health > 0))
+ {
m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+ }
if (a_TDI.Attacker != NULL)
{
m_Target = a_TDI.Attacker;
}
+ return true;
}
@@ -524,7 +548,10 @@ void cMonster::KilledBy(cEntity * a_Killer)
break;
}
}
- m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
+ if ((a_Killer != NULL) && (!IsBaby()))
+ {
+ m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
+ }
m_DestroyTimer = 0;
}
@@ -742,8 +769,10 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
case mtChicken: return mfPassive;
case mtCow: return mfPassive;
case mtCreeper: return mfHostile;
+ case mtEnderDragon: return mfNoSpawn;
case mtEnderman: return mfHostile;
case mtGhast: return mfHostile;
+ case mtGiant: return mfNoSpawn;
case mtHorse: return mfPassive;
case mtIronGolem: return mfPassive;
case mtMagmaCube: return mfHostile;
@@ -754,17 +783,20 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
case mtSilverfish: return mfHostile;
case mtSkeleton: return mfHostile;
case mtSlime: return mfHostile;
+ case mtSnowGolem: return mfNoSpawn;
case mtSpider: return mfHostile;
case mtSquid: return mfWater;
case mtVillager: return mfPassive;
case mtWitch: return mfHostile;
- case mtWither: return mfHostile;
+ case mtWither: return mfNoSpawn;
case mtWolf: return mfHostile;
case mtZombie: return mfHostile;
case mtZombiePigman: return mfHostile;
- } ;
+
+ case mtInvalidType: break;
+ }
ASSERT(!"Unhandled mob type");
- return mfMaxplusone;
+ return mfUnhandled;
}
@@ -775,10 +807,12 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
{
switch (a_MobFamily)
{
- case mfHostile: return 40;
- case mfPassive: return 40;
- case mfAmbient: return 40;
- case mfWater: return 400;
+ case mfHostile: return 40;
+ case mfPassive: return 40;
+ case mfAmbient: return 40;
+ case mfWater: return 400;
+ case mfNoSpawn: return -1;
+ case mfUnhandled: break;
}
ASSERT(!"Unhandled mob family");
return -1;
@@ -797,6 +831,10 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
switch (a_MobType)
{
case mtMagmaCube:
+ {
+ toReturn = new cMagmaCube(Random.NextInt(2) + 1);
+ break;
+ }
case mtSlime:
{
toReturn = new cSlime(Random.NextInt(2) + 1);
@@ -840,13 +878,14 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtBat: toReturn = new cBat(); break;
case mtBlaze: toReturn = new cBlaze(); break;
- case mtCaveSpider: toReturn = new cCavespider(); break;
+ case mtCaveSpider: toReturn = new cCaveSpider(); break;
case mtChicken: toReturn = new cChicken(); break;
case mtCow: toReturn = new cCow(); break;
case mtCreeper: toReturn = new cCreeper(); break;
case mtEnderDragon: toReturn = new cEnderDragon(); break;
case mtEnderman: toReturn = new cEnderman(); break;
case mtGhast: toReturn = new cGhast(); break;
+ case mtGiant: toReturn = new cGiant(); break;
case mtIronGolem: toReturn = new cIronGolem(); break;
case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break;
@@ -964,15 +1003,15 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
return;
}
- int RelY = (int)floor(GetPosY());
+ int RelY = POSY_TOINT;
if ((RelY < 0) || (RelY >= cChunkDef::Height))
{
// Outside the world
return;
}
- int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width;
- int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width;
+ int RelX = POSX_TOINT - GetChunkX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - GetChunkZ() * cChunkDef::Width;
if (!a_Chunk.IsLightValid())
{
@@ -984,7 +1023,8 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
(a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight
(a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
- !IsOnFire() // Not already burning
+ !IsOnFire() && // Not already burning
+ (GetWorld()->GetWeather() != eWeather_Rain) // Not raining
)
{
// Burn for 100 ticks, then decide again
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 776426a0d..7d7e90eb2 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -66,7 +66,8 @@ public:
mfAmbient = 2, // Bats
mfWater = 3, // Squid
- mfMaxplusone, // Nothing. Be sure this is the last and the others are in order
+ mfNoSpawn,
+ mfUnhandled, // Nothing. Be sure this is the last and the others are in order
} ;
// tolua_end
@@ -87,7 +88,7 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void KilledBy(cEntity * a_Killer) override;
@@ -185,14 +186,14 @@ protected:
inline bool IsNextYPosReachable(int a_PosY)
{
return (
- (a_PosY <= (int)floor(GetPosY())) ||
+ (a_PosY <= POSY_TOINT) ||
DoesPosYRequireJump(a_PosY)
);
}
/** Returns if a monster can reach a given height by jumping */
inline bool DoesPosYRequireJump(int a_PosY)
{
- return ((a_PosY > (int)floor(GetPosY())) && (a_PosY == (int)floor(GetPosY()) + 1));
+ return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1));
}
/** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp
index 4b45f9a2a..24501b1ba 100644
--- a/src/Mobs/PassiveAggressiveMonster.cpp
+++ b/src/Mobs/PassiveAggressiveMonster.cpp
@@ -19,9 +19,12 @@ cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigNam
-void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- super::DoTakeDamage(a_TDI);
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
if ((m_Target != NULL) && (m_Target->IsPlayer()))
{
@@ -30,6 +33,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
m_EMState = CHASING;
}
}
+ return true;
}
diff --git a/src/Mobs/PassiveAggressiveMonster.h b/src/Mobs/PassiveAggressiveMonster.h
index 2c5ef30b1..a0da50e8e 100644
--- a/src/Mobs/PassiveAggressiveMonster.h
+++ b/src/Mobs/PassiveAggressiveMonster.h
@@ -15,7 +15,7 @@ class cPassiveAggressiveMonster :
public:
cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
} ;
diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp
index 904cd63cc..2861d7314 100644
--- a/src/Mobs/PassiveMonster.cpp
+++ b/src/Mobs/PassiveMonster.cpp
@@ -18,13 +18,17 @@ cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType,
-void cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- super::DoTakeDamage(a_TDI);
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL))
{
m_EMState = ESCAPING;
}
+ return true;
}
diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h
index 0b3c155da..70574585a 100644
--- a/src/Mobs/PassiveMonster.h
+++ b/src/Mobs/PassiveMonster.h
@@ -18,7 +18,7 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
/// When hit by someone, run away
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
/** Returns the item that the animal of this class follows when a player holds it in hand
Return an empty item not to follow (default). */
virtual const cItem GetFollowedItem(void) const { return cItem(); }
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index c64360153..5a6b760af 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -36,7 +36,8 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
- if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
+ const cItem & EquippedItem = a_Player.GetEquippedItem();
+ if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
{
m_IsSheared = true;
m_World->BroadcastEntityMetadata(*this);
@@ -51,9 +52,9 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
}
- if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - a_Player.GetEquippedItem().m_ItemDamage))
+ else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage))
{
- m_WoolColor = 15 - a_Player.GetEquippedItem().m_ItemDamage;
+ m_WoolColor = 15 - EquippedItem.m_ItemDamage;
if (!a_Player.IsGameModeCreative())
{
a_Player.GetInventory().RemoveOneEquippedItem();
@@ -101,7 +102,7 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
{
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
+ m_World->BroadcastEntityStatus(*this, esSheepEating);
m_TimeToStopEating = 40;
}
}
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index 47fcdbb26..1e62d7987 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -3,6 +3,7 @@
#include "Skeleton.h"
#include "../World.h"
+#include "../Entities/ArrowEntity.h"
@@ -88,4 +89,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.cpp b/src/Mobs/Villager.cpp
index bbd8d6aaa..41283acf4 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -23,16 +23,21 @@ cVillager::cVillager(eVillagerType VillagerType) :
-void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- super::DoTakeDamage(a_TDI);
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer())
{
if (m_World->GetTickRandomNumber(5) == 3)
{
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY);
+ m_World->BroadcastEntityStatus(*this, esVillagerAngry);
}
}
+ return true;
}
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index 5bba4d4ba..abde48407 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -30,7 +30,7 @@ public:
CLASS_PROTODEF(cVillager);
// cEntity overrides
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
// cVillager functions
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index 0e42194ac..170f4fdc0 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -2,7 +2,9 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Wither.h"
+
#include "../World.h"
+#include "../Entities/Player.h"
@@ -10,30 +12,54 @@
cWither::cWither(void) :
super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
- m_InvulnerableTicks(220)
+ m_WitherInvulnerableTicks(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)
+bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (a_TDI.DamageType == dtDrowning)
{
- return;
+ return false;
+ }
+
+ if (m_WitherInvulnerableTicks > 0)
+ {
+ return false;
}
- if (m_InvulnerableTicks > 0)
+ if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
{
- return;
+ return false;
}
- super::DoTakeDamage(a_TDI);
+ return super::DoTakeDamage(a_TDI);
}
@@ -44,22 +70,24 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- if (m_InvulnerableTicks > 0)
+ if (m_WitherInvulnerableTicks > 0)
{
- unsigned int NewTicks = m_InvulnerableTicks - 1;
+ unsigned int NewTicks = m_WitherInvulnerableTicks - 1;
if (NewTicks == 0)
{
m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
}
- m_InvulnerableTicks = NewTicks;
+ m_WitherInvulnerableTicks = NewTicks;
if ((NewTicks % 10) == 0)
{
Heal(10);
}
}
+
+ m_World->BroadcastEntityMetadata(*this);
}
@@ -74,3 +102,35 @@ void cWither::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+
+void cWither::KilledBy(cEntity * a_Killer)
+{
+ super::KilledBy(a_Killer);
+
+ class cPlayerCallback : public cPlayerListCallback
+ {
+ Vector3f m_Pos;
+
+ virtual bool Item(cPlayer * a_Player)
+ {
+ // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
+ double Dist = (a_Player->GetPosition() - m_Pos).Length();
+ if (Dist < 50.0)
+ {
+ // If player is close, award achievement
+ a_Player->AwardAchievement(achKillWither);
+ }
+ return false;
+ }
+
+ public:
+ cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
+
+ } PlayerCallback(GetPosition());
+
+ m_World->ForEachPlayer(PlayerCallback);
+}
+
+
+
+
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index d09e3607a..93b4f8bfc 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -17,19 +17,24 @@ public:
CLASS_PROTODEF(cWither);
- unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; }
+ unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; }
- void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
+ void SetWitherInvulnerableTicks(unsigned int a_Ticks) { m_WitherInvulnerableTicks = 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 bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void KilledBy(cEntity * a_Killer) override;
private:
/** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
- unsigned int m_InvulnerableTicks;
+ unsigned int m_WitherInvulnerableTicks;
} ;
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index 0d3619166..e6268abc7 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -25,14 +25,19 @@ cWolf::cWolf(void) :
-void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
+bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- super::DoTakeDamage(a_TDI);
+ if (super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
if (!m_IsTame)
{
m_IsAngry = true;
}
m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
+ return true;
}
@@ -75,12 +80,12 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
SetMaxHealth(20);
SetIsTame(true);
SetOwner(a_Player.GetName());
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED);
+ m_World->BroadcastEntityStatus(*this, esWolfTamed);
m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
}
else
{
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMING);
+ m_World->BroadcastEntityStatus(*this, esWolfTaming);
m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
}
}
diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h
index 9e5ad03c7..fb8a7c995 100644
--- a/src/Mobs/Wolf.h
+++ b/src/Mobs/Wolf.h
@@ -18,7 +18,7 @@ public:
CLASS_PROTODEF(cWolf);
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void TickFollowPlayer();
@@ -37,7 +37,7 @@ public:
void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; }
void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; }
void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; }
- void SetOwner (AString a_NewOwner) { m_OwnerName = a_NewOwner; }
+ void SetOwner (const AString & a_NewOwner) { m_OwnerName = a_NewOwner; }
void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; }
protected:
diff --git a/src/Mobs/Zombiepigman.cpp b/src/Mobs/ZombiePigman.cpp
index a0142b566..c9d94face 100644
--- a/src/Mobs/Zombiepigman.cpp
+++ b/src/Mobs/ZombiePigman.cpp
@@ -1,7 +1,6 @@
-
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-#include "Zombiepigman.h"
+#include "ZombiePigman.h"
#include "../World.h"
diff --git a/src/Mobs/Zombiepigman.h b/src/Mobs/ZombiePigman.h
index 67991d56a..ab3cebf6d 100644
--- a/src/Mobs/Zombiepigman.h
+++ b/src/Mobs/ZombiePigman.h
@@ -1,4 +1,3 @@
-
#pragma once
#include "PassiveAggressiveMonster.h"
diff --git a/src/MonsterConfig.cpp b/src/MonsterConfig.cpp
index c06bd6b6f..72a3a3245 100644
--- a/src/MonsterConfig.cpp
+++ b/src/MonsterConfig.cpp
@@ -17,6 +17,7 @@ struct cMonsterConfig::sAttributesStruct
int m_AttackRange;
double m_AttackRate;
int m_MaxHealth;
+ bool m_IsFireproof;
};
@@ -72,6 +73,7 @@ void cMonsterConfig::Initialize()
Attributes.m_SightDistance = MonstersIniFile.GetValueI(Name, "SightDistance", 0);
Attributes.m_AttackRate = MonstersIniFile.GetValueF(Name, "AttackRate", 0);
Attributes.m_MaxHealth = MonstersIniFile.GetValueI(Name, "MaxHealth", 1);
+ Attributes.m_IsFireproof = MonstersIniFile.GetValueB(Name, "IsFireproof", false);
m_pState->AttributesList.push_front(Attributes);
} // for i - SplitList[]
}
@@ -92,6 +94,7 @@ void cMonsterConfig::AssignAttributes(cMonster * a_Monster, const AString & a_Na
a_Monster->SetSightDistance(itr->m_SightDistance);
a_Monster->SetAttackRate ((float)itr->m_AttackRate);
a_Monster->SetMaxHealth (itr->m_MaxHealth);
+ a_Monster->SetIsFireproof (itr->m_IsFireproof);
return;
}
} // for itr - m_pState->AttributesList[]
diff --git a/src/Noise.cpp b/src/Noise.cpp
index a97ea70c6..89115d992 100644
--- a/src/Noise.cpp
+++ b/src/Noise.cpp
@@ -425,7 +425,7 @@ void cCubicCell3D::Move(int a_NewFloorX, int a_NewFloorY, int a_NewFloorZ)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cNoise:
-cNoise::cNoise(unsigned int a_Seed) :
+cNoise::cNoise(int a_Seed) :
m_Seed(a_Seed)
{
}
@@ -608,6 +608,8 @@ void cCubicNoise::Generate2D(
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction
) const
{
+ ASSERT(a_SizeX > 0);
+ ASSERT(a_SizeY > 0);
ASSERT(a_SizeX < MAX_SIZE);
ASSERT(a_SizeY < MAX_SIZE);
ASSERT(a_StartX < a_EndX);
@@ -744,6 +746,8 @@ void cCubicNoise::CalcFloorFrac(
int * a_Same, int & a_NumSame
) const
{
+ ASSERT(a_Size > 0);
+
NOISE_DATATYPE val = a_Start;
NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1);
for (int i = 0; i < a_Size; i++)
@@ -810,7 +814,7 @@ void cPerlinNoise::SetSeed(int a_Seed)
void cPerlinNoise::AddOctave(float a_Frequency, float a_Amplitude)
{
- m_Octaves.push_back(cOctave(m_Seed * (m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude));
+ m_Octaves.push_back(cOctave(m_Seed * ((int)m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude));
}
@@ -840,12 +844,14 @@ void cPerlinNoise::Generate2D(
}
// Generate the first octave directly into array:
- m_Octaves.front().m_Noise.Generate2D(
+ const cOctave & FirstOctave = m_Octaves.front();
+
+ FirstOctave.m_Noise.Generate2D(
a_Workspace, a_SizeX, a_SizeY,
- a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency,
- a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency
+ a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
+ a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency
);
- NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude;
+ NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
for (int i = 0; i < ArrayCount; i++)
{
a_Array[i] *= Amplitude;
@@ -902,13 +908,15 @@ void cPerlinNoise::Generate3D(
}
// Generate the first octave directly into array:
- m_Octaves.front().m_Noise.Generate3D(
+ const cOctave & FirstOctave = m_Octaves.front();
+
+ FirstOctave.m_Noise.Generate3D(
a_Workspace, a_SizeX, a_SizeY, a_SizeZ,
- a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency,
- a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency,
- a_StartZ * m_Octaves.front().m_Frequency, a_EndZ * m_Octaves.front().m_Frequency
+ a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
+ a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency,
+ a_StartZ * FirstOctave.m_Frequency, a_EndZ * FirstOctave.m_Frequency
);
- NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude;
+ NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
for (int i = 0; i < ArrayCount; i++)
{
a_Array[i] = a_Workspace[i] * Amplitude;
diff --git a/src/Noise.h b/src/Noise.h
index ea72c64e9..e605051b5 100644
--- a/src/Noise.h
+++ b/src/Noise.h
@@ -25,7 +25,7 @@
class cNoise
{
public:
- cNoise(unsigned int a_Seed);
+ cNoise(int a_Seed);
cNoise(const cNoise & a_Noise);
// The following functions, if not marked INLINE, are about 20 % slower
@@ -47,14 +47,14 @@ public:
NOISE_DATATYPE CubicNoise3D (NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z) const;
- void SetSeed(unsigned int a_Seed) { m_Seed = a_Seed; }
+ void SetSeed(int a_Seed) { m_Seed = a_Seed; }
INLINE static NOISE_DATATYPE CubicInterpolate (NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_C, NOISE_DATATYPE a_D, NOISE_DATATYPE a_Pct);
INLINE static NOISE_DATATYPE CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct);
INLINE static NOISE_DATATYPE LinearInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct);
private:
- unsigned int m_Seed;
+ int m_Seed;
} ;
@@ -280,7 +280,7 @@ NOISE_DATATYPE cNoise::CubicInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B,
NOISE_DATATYPE cNoise::CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct)
{
const NOISE_DATATYPE ft = a_Pct * (NOISE_DATATYPE)3.1415927;
- const NOISE_DATATYPE f = (1 - cos(ft)) * (NOISE_DATATYPE)0.5;
+ const NOISE_DATATYPE f = (NOISE_DATATYPE)((NOISE_DATATYPE)(1 - cos(ft)) * (NOISE_DATATYPE)0.5);
return a_A * (1 - f) + a_B * f;
}
diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp
deleted file mode 100644
index 07f48b955..000000000
--- a/src/OSSupport/BlockingTCPLink.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "BlockingTCPLink.h"
-#include "Errors.h"
-
-
-
-
-cBlockingTCPLink::cBlockingTCPLink(void)
-{
-}
-
-
-
-
-
-cBlockingTCPLink::~cBlockingTCPLink()
-{
- CloseSocket();
-}
-
-
-
-
-
-void cBlockingTCPLink::CloseSocket()
-{
- if (!m_Socket.IsValid())
- {
- m_Socket.CloseSocket();
- }
-}
-
-
-
-
-
-bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
-{
- ASSERT(!m_Socket.IsValid());
- if (m_Socket.IsValid())
- {
- LOGWARN("WARNING: cTCPLink Connect() called while still connected.");
- m_Socket.CloseSocket();
- }
-
- struct hostent *hp;
- unsigned int addr;
- struct sockaddr_in server;
-
- m_Socket = socket(AF_INET, SOCK_STREAM, 0);
- if (!m_Socket.IsValid())
- {
- LOGERROR("cTCPLink: Cannot create a socket");
- return false;
- }
-
- addr = inet_addr(iAddress);
- hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
- if (hp == NULL)
- {
- //LOGWARN("cTCPLink: gethostbyaddr returned NULL");
- hp = gethostbyname(iAddress);
- if (hp == NULL)
- {
- LOGWARN("cTCPLink: Could not resolve %s", iAddress);
- CloseSocket();
- return false;
- }
- }
-
- memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length);
- server.sin_family = AF_INET;
- server.sin_port = htons( (unsigned short)iPort);
- if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server)))
- {
- LOGWARN("cTCPLink: Connection to \"%s:%d\" failed (%s)", iAddress, iPort,GetOSErrorString( cSocket::GetLastError() ).c_str() );
- CloseSocket();
- return false;
- }
-
- return true;
-}
-
-
-
-
-
-int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
-{
- UNUSED(a_Flags);
-
- ASSERT(m_Socket.IsValid());
- if (!m_Socket.IsValid())
- {
- LOGERROR("cBlockingTCPLink: Trying to send data without a valid connection!");
- return -1;
- }
- return m_Socket.Send(a_Data, a_Size);
-}
-
-
-
-
-
-int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
-{
- UNUSED(a_Flags);
-
- ASSERT(m_Socket.IsValid());
- if (!m_Socket.IsValid())
- {
- LOGWARN("cBlockingTCPLink: Trying to send message without a valid connection!");
- return -1;
- }
- return m_Socket.Send(a_Message, strlen(a_Message));
-}
-
-
-
-
-
-void cBlockingTCPLink::ReceiveData(AString & oData)
-{
- ASSERT(m_Socket.IsValid());
- if (!m_Socket.IsValid())
- {
- return;
- }
-
- int Received = 0;
- char Buffer[256];
- while ((Received = recv(m_Socket, Buffer, sizeof(Buffer), 0)) > 0)
- {
- oData.append(Buffer, Received);
- }
-}
-
-
-
-
diff --git a/src/OSSupport/BlockingTCPLink.h b/src/OSSupport/BlockingTCPLink.h
deleted file mode 100644
index cb5f9e3f4..000000000
--- a/src/OSSupport/BlockingTCPLink.h
+++ /dev/null
@@ -1,28 +0,0 @@
-
-#pragma once
-
-#include "Socket.h"
-
-
-
-
-
-class cBlockingTCPLink // tolua_export
-{ // tolua_export
-public: // tolua_export
- cBlockingTCPLink(void); // tolua_export
- ~cBlockingTCPLink(); // tolua_export
-
- bool Connect( const char* a_Address, unsigned int a_Port ); // tolua_export
- int Send( char* a_Data, unsigned int a_Size, int a_Flags = 0 ); // tolua_export
- int SendMessage( const char* a_Message, int a_Flags = 0 ); // tolua_export
- void CloseSocket(); // tolua_export
- void ReceiveData(AString & oData); // tolua_export
-protected:
-
- cSocket m_Socket;
-}; // tolua_export
-
-
-
-
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index 497cd0ba3..dee60b450 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -5,6 +5,7 @@ project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(OSSupport ${SOURCE})
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..8c24fa541 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -67,15 +67,15 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
case fmRead: Mode = "rb"; break;
case fmWrite: Mode = "wb"; break;
case fmReadWrite: Mode = "rb+"; break;
- default:
- {
- ASSERT(!"Unhandled file mode");
- return false;
- }
+ }
+ if (Mode == NULL)
+ {
+ ASSERT(!"Unhandled file mode");
+ return false;
}
#ifdef _WIN32
- fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), Mode);
+ m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR);
#else
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode);
#endif // _WIN32
@@ -88,7 +88,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
// Simply re-open for read-writing, erasing existing contents:
#ifdef _WIN32
- fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), "wb+");
+ m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+", _SH_DENYWR);
#else
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+");
#endif // _WIN32
@@ -143,7 +143,7 @@ bool cFile::IsEOF(void) const
-int cFile::Read (void * iBuffer, int iNumBytes)
+int cFile::Read (void * iBuffer, size_t iNumBytes)
{
ASSERT(IsOpen());
@@ -152,14 +152,14 @@ 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
}
-int cFile::Write(const void * iBuffer, int iNumBytes)
+int cFile::Write(const void * iBuffer, size_t iNumBytes)
{
ASSERT(IsOpen());
@@ -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/File.h b/src/OSSupport/File.h
index b394c5cb9..2a7ecf0ed 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -80,10 +80,10 @@ public:
bool IsEOF(void) const;
/** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */
- int Read (void * iBuffer, int iNumBytes);
+ int Read (void * iBuffer, size_t iNumBytes);
/** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */
- int Write(const void * iBuffer, int iNumBytes);
+ int Write(const void * iBuffer, size_t iNumBytes);
/** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */
int Seek (int iPosition);
diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp
index b13e519e0..22d887783 100644
--- a/src/OSSupport/GZipFile.cpp
+++ b/src/OSSupport/GZipFile.cpp
@@ -11,7 +11,7 @@
cGZipFile::cGZipFile(void) :
- m_File(NULL)
+ m_File(NULL), m_Mode(fmRead)
{
}
@@ -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/IsThread.cpp b/src/OSSupport/IsThread.cpp
index 36205bcf1..04fc818e4 100644
--- a/src/OSSupport/IsThread.cpp
+++ b/src/OSSupport/IsThread.cpp
@@ -18,26 +18,33 @@
// Usage: SetThreadName (-1, "MainThread");
//
-static void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
+// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push, 8)
+typedef struct tagTHREADNAME_INFO
{
- struct
- {
- DWORD dwType; // must be 0x1000
- LPCSTR szName; // pointer to name (in user addr space)
- DWORD dwThreadID; // thread ID (-1=caller thread)
- DWORD dwFlags; // reserved for future use, must be zero
- } info;
-
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1 = caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+static void SetThreadName(DWORD dwThreadID, const char * threadName)
+{
+ THREADNAME_INFO info;
info.dwType = 0x1000;
- info.szName = szThreadName;
+ info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
- RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (DWORD *)&info);
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
}
- __except(EXCEPTION_CONTINUE_EXECUTION)
+ __except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h
index 42b8bfdda..57651a490 100644
--- a/src/OSSupport/IsThread.h
+++ b/src/OSSupport/IsThread.h
@@ -62,7 +62,7 @@ protected:
HANDLE m_Handle;
- static DWORD_PTR __stdcall thrExecute(LPVOID a_Param)
+ static DWORD __stdcall thrExecute(LPVOID a_Param)
{
// Create a window so that the thread can be identified by 3rd party tools:
HWND IdentificationWnd = CreateWindow("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
diff --git a/src/OSSupport/ListenThread.cpp b/src/OSSupport/ListenThread.cpp
index ba3198764..02e98acfc 100644
--- a/src/OSSupport/ListenThread.cpp
+++ b/src/OSSupport/ListenThread.cpp
@@ -214,7 +214,7 @@ void cListenThread::Execute(void)
timeval tv; // On Linux select() doesn't seem to wake up when socket is closed, so let's kinda busy-wait:
tv.tv_sec = 1;
tv.tv_usec = 0;
- if (select(Highest + 1, &fdRead, NULL, NULL, &tv) == -1)
+ if (select((int)Highest + 1, &fdRead, NULL, NULL, &tv) == -1)
{
LOG("select(R) call failed in cListenThread: \"%s\"", cSocket::GetLastErrorString().c_str());
continue;
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/Socket.cpp b/src/OSSupport/Socket.cpp
index c29e495c3..56835b518 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -295,7 +295,7 @@ bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port)
bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port)
{
- // First try IP Address string to hostent conversion, because it's faster
+ // First try IP Address string to hostent conversion, because it's faster and local:
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
if (addr == INADDR_NONE)
{
@@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
CloseSocket();
return false;
}
- // Should be optimised to a single word copy
memcpy(&addr, hp->h_addr, hp->h_length);
}
+ // If the socket is not created yet, create one:
+ if (!IsValid())
+ {
+ m_Socket = socket((int)IPv4, SOCK_STREAM, 0);
+ }
+
+ // Connect the socket:
sockaddr_in server;
server.sin_addr.s_addr = addr;
server.sin_family = AF_INET;
@@ -322,18 +328,18 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
-int cSocket::Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags)
+int cSocket::Receive(char * a_Buffer, size_t a_Length, unsigned int a_Flags)
{
- return recv(m_Socket, a_Buffer, a_Length, a_Flags);
+ return recv(m_Socket, a_Buffer, (int)a_Length, a_Flags);
}
-int cSocket::Send(const char * a_Buffer, unsigned int a_Length)
+int cSocket::Send(const char * a_Buffer, size_t a_Length)
{
- return send(m_Socket, a_Buffer, a_Length, MSG_NOSIGNAL);
+ return send(m_Socket, a_Buffer, (int)a_Length, MSG_NOSIGNAL);
}
diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h
index bdc2babf5..35ecadfa0 100644
--- a/src/OSSupport/Socket.h
+++ b/src/OSSupport/Socket.h
@@ -110,8 +110,8 @@ public:
/// Connects to the specified host or string IP address and port, using IPv4. Returns true if successful.
bool ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port);
- int Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags);
- int Send (const char * a_Buffer, unsigned int a_Length);
+ int Receive(char * a_Buffer, size_t a_Length, unsigned int a_Flags);
+ int Send (const char * a_Buffer, size_t a_Length);
unsigned short GetPort(void) const; // Returns 0 on failure
diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp
index 0bc1d6b55..0ab5b6298 100644
--- a/src/OSSupport/SocketThreads.cpp
+++ b/src/OSSupport/SocketThreads.cpp
@@ -406,7 +406,7 @@ void cSocketThreads::cSocketThread::Execute(void)
timeval Timeout;
Timeout.tv_sec = 5;
Timeout.tv_usec = 0;
- if (select(Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1)
+ if (select((int)Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1)
{
LOG("select() call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
continue;
diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h
index b2eb5950f..944f5f3bc 100644
--- a/src/OSSupport/SocketThreads.h
+++ b/src/OSSupport/SocketThreads.h
@@ -63,8 +63,10 @@ public:
// Force a virtual destructor in all subclasses:
virtual ~cCallback() {}
- /** Called when data is received from the remote party */
- virtual void DataReceived(const char * a_Data, int a_Size) = 0;
+ /** Called when data is received from the remote party.
+ SocketThreads does not care about the return value, others can use it for their specific purpose -
+ for example HTTPServer uses it to signal if the connection was terminated as a result of the data received. */
+ virtual bool DataReceived(const char * a_Data, size_t a_Size) = 0;
/** Called when data can be sent to remote party
The function is supposed to *set* outgoing data to a_Data (overwrite) */
diff --git a/src/OSSupport/Thread.cpp b/src/OSSupport/Thread.cpp
index 3df75f0e7..7a10ef8d2 100644
--- a/src/OSSupport/Thread.cpp
+++ b/src/OSSupport/Thread.cpp
@@ -10,27 +10,34 @@
//
// Usage: SetThreadName (-1, "MainThread");
//
+
+// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push, 8)
typedef struct tagTHREADNAME_INFO
{
- DWORD dwType; // must be 0x1000
- LPCSTR szName; // pointer to name (in user addr space)
- DWORD dwThreadID; // thread ID (-1=caller thread)
- DWORD dwFlags; // reserved for future use, must be zero
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1 = caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
+#pragma pack(pop)
-void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
+static void SetThreadName(DWORD dwThreadID, const char * threadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
- info.szName = szThreadName;
+ info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
}
- __except(EXCEPTION_CONTINUE_EXECUTION)
+ __except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
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/PolarSSL++/AesCfb128Decryptor.cpp b/src/PolarSSL++/AesCfb128Decryptor.cpp
new file mode 100644
index 000000000..af0d5106e
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Decryptor.cpp
@@ -0,0 +1,67 @@
+
+// AesCfb128Decryptor.cpp
+
+// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128
+
+#include "Globals.h"
+#include "AesCfb128Decryptor.h"
+
+
+
+
+
+cAesCfb128Decryptor::cAesCfb128Decryptor(void) :
+ m_IVOffset(0),
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+cAesCfb128Decryptor::~cAesCfb128Decryptor()
+{
+ // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
+ memset(&m_Aes, 0, sizeof(m_Aes));
+}
+
+
+
+
+
+void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
+{
+ ASSERT(!IsValid()); // Cannot Init twice
+
+ memcpy(m_IV, a_IV, 16);
+ aes_setkey_enc(&m_Aes, a_Key, 128);
+ m_IsValid = true;
+}
+
+
+
+
+
+void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
+{
+ ASSERT(IsValid()); // Must Init() first
+
+ // PolarSSL doesn't support AES-CFB8, need to implement it manually:
+ for (size_t i = 0; i < a_Length; i++)
+ {
+ Byte Buffer[sizeof(m_IV)];
+ aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
+ for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
+ {
+ m_IV[idx] = m_IV[idx + 1];
+ }
+ m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
+ a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
+ }
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/AesCfb128Decryptor.h b/src/PolarSSL++/AesCfb128Decryptor.h
new file mode 100644
index 000000000..68c203d70
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Decryptor.h
@@ -0,0 +1,52 @@
+
+// AesCfb128Decryptor.h
+
+// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128
+
+
+
+
+
+#pragma once
+
+#include "polarssl/aes.h"
+
+
+
+
+
+/** Decrypts data using the AES / CFB 128 algorithm */
+class cAesCfb128Decryptor
+{
+public:
+ Byte test;
+
+ cAesCfb128Decryptor(void);
+ ~cAesCfb128Decryptor();
+
+ /** Initializes the decryptor with the specified Key / IV */
+ void Init(const Byte a_Key[16], const Byte a_IV[16]);
+
+ /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
+ void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
+
+ /** Returns true if the object has been initialized with the Key / IV */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ aes_context m_Aes;
+
+ /** The InitialVector, used by the CFB mode decryption */
+ Byte m_IV[16];
+
+ /** Current offset in the m_IV, used by the CFB mode decryption */
+ size_t m_IVOffset;
+
+ /** Indicates whether the object has been initialized with the Key / IV */
+ bool m_IsValid;
+} ;
+
+
+
+
+
diff --git a/src/PolarSSL++/AesCfb128Encryptor.cpp b/src/PolarSSL++/AesCfb128Encryptor.cpp
new file mode 100644
index 000000000..a641ad48e
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Encryptor.cpp
@@ -0,0 +1,68 @@
+
+// AesCfb128Encryptor.cpp
+
+// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128
+
+#include "Globals.h"
+#include "AesCfb128Encryptor.h"
+
+
+
+
+
+cAesCfb128Encryptor::cAesCfb128Encryptor(void) :
+ m_IVOffset(0),
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+cAesCfb128Encryptor::~cAesCfb128Encryptor()
+{
+ // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
+ memset(&m_Aes, 0, sizeof(m_Aes));
+}
+
+
+
+
+
+void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
+{
+ ASSERT(!IsValid()); // Cannot Init twice
+ ASSERT(m_IVOffset == 0);
+
+ memcpy(m_IV, a_IV, 16);
+ aes_setkey_enc(&m_Aes, a_Key, 128);
+ m_IsValid = true;
+}
+
+
+
+
+
+void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
+{
+ ASSERT(IsValid()); // Must Init() first
+
+ // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
+ for (size_t i = 0; i < a_Length; i++)
+ {
+ Byte Buffer[sizeof(m_IV)];
+ aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
+ for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
+ {
+ m_IV[idx] = m_IV[idx + 1];
+ }
+ a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
+ m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
+ }
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/AesCfb128Encryptor.h b/src/PolarSSL++/AesCfb128Encryptor.h
new file mode 100644
index 000000000..9dbb5d2c3
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Encryptor.h
@@ -0,0 +1,50 @@
+
+// AesCfb128Encryptor.h
+
+// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128
+
+
+
+
+
+#pragma once
+
+#include "polarssl/aes.h"
+
+
+
+
+
+/** Encrypts data using the AES / CFB (128) algorithm */
+class cAesCfb128Encryptor
+{
+public:
+ cAesCfb128Encryptor(void);
+ ~cAesCfb128Encryptor();
+
+ /** Initializes the decryptor with the specified Key / IV */
+ void Init(const Byte a_Key[16], const Byte a_IV[16]);
+
+ /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
+ void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
+
+ /** Returns true if the object has been initialized with the Key / IV */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ aes_context m_Aes;
+
+ /** The InitialVector, used by the CFB mode encryption */
+ Byte m_IV[16];
+
+ /** Current offset in the m_IV, used by the CFB mode encryption */
+ size_t m_IVOffset;
+
+ /** Indicates whether the object has been initialized with the Key / IV */
+ bool m_IsValid;
+} ;
+
+
+
+
+
diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp
new file mode 100644
index 000000000..699bc57ee
--- /dev/null
+++ b/src/PolarSSL++/BlockingSslClientSocket.cpp
@@ -0,0 +1,195 @@
+
+// BlockingSslClientSocket.cpp
+
+// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
+
+#include "Globals.h"
+#include "BlockingSslClientSocket.h"
+
+
+
+
+
+cBlockingSslClientSocket::cBlockingSslClientSocket(void) :
+ m_Ssl(*this),
+ m_IsConnected(false)
+{
+ // Nothing needed yet
+}
+
+
+
+
+
+bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port)
+{
+ // If already connected, report an error:
+ if (m_IsConnected)
+ {
+ // TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success
+ m_LastErrorText = "Already connected";
+ return false;
+ }
+
+ // Connect the underlying socket:
+ m_Socket.CreateSocket(cSocket::IPv4);
+ if (!m_Socket.ConnectIPv4(a_ServerName.c_str(), a_Port))
+ {
+ Printf(m_LastErrorText, "Socket connect failed: %s", m_Socket.GetLastErrorString().c_str());
+ return false;
+ }
+
+ // Initialize the SSL:
+ int ret = m_Ssl.Initialize(true);
+ if (ret != 0)
+ {
+ Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret);
+ return false;
+ }
+
+ // If we have been assigned a trusted CA root cert store, push it into the SSL context:
+ if (m_CACerts.get() != NULL)
+ {
+ m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName);
+ }
+
+ ret = m_Ssl.Handshake();
+ if (ret != 0)
+ {
+ Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret);
+ return false;
+ }
+
+ m_IsConnected = true;
+ return true;
+}
+
+
+
+
+
+
+bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName)
+{
+ // Warn if used multiple times, but don't signal an error:
+ if (m_CACerts.get() != NULL)
+ {
+ LOGWARNING(
+ "SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s",
+ a_ExpectedPeerName.c_str()
+ );
+ }
+
+ // Parse the cert:
+ m_CACerts.reset(new cX509Cert);
+ int ret = m_CACerts->Parse(a_CACerts.data(), a_CACerts.size());
+ if (ret < 0)
+ {
+ Printf(m_LastErrorText, "CA cert parsing failed: -0x%x", -ret);
+ return false;
+ }
+ m_ExpectedPeerName = a_ExpectedPeerName;
+
+ return true;
+}
+
+
+
+
+
+bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes)
+{
+ ASSERT(m_IsConnected);
+
+ // Keep sending the data until all of it is sent:
+ const char * Data = (const char *)a_Data;
+ size_t NumBytes = a_NumBytes;
+ for (;;)
+ {
+ int res = m_Ssl.WritePlain(a_Data, a_NumBytes);
+ if (res < 0)
+ {
+ ASSERT(res != POLARSSL_ERR_NET_WANT_READ); // This should never happen with callback-based SSL
+ ASSERT(res != POLARSSL_ERR_NET_WANT_WRITE); // This should never happen with callback-based SSL
+ Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res);
+ return false;
+ }
+ else
+ {
+ Data += res;
+ NumBytes -= res;
+ if (NumBytes == 0)
+ {
+ return true;
+ }
+ }
+ }
+}
+
+
+
+
+
+
+int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes)
+{
+ ASSERT(m_IsConnected);
+
+ int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes);
+ if (res < 0)
+ {
+ Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res);
+ }
+ return res;
+}
+
+
+
+
+
+void cBlockingSslClientSocket::Disconnect(void)
+{
+ // Ignore if not connected
+ if (!m_IsConnected)
+ {
+ return;
+ }
+
+ m_Ssl.NotifyClose();
+ m_Socket.CloseSocket();
+ m_IsConnected = false;
+}
+
+
+
+
+
+int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
+{
+ int res = m_Socket.Receive((char *)a_Buffer, a_NumBytes, 0);
+ if (res < 0)
+ {
+ // PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
+ return POLARSSL_ERR_NET_RECV_FAILED;
+ }
+ return res;
+}
+
+
+
+
+
+int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
+{
+ int res = m_Socket.Send((const char *)a_Buffer, a_NumBytes);
+ if (res < 0)
+ {
+ // PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
+ return POLARSSL_ERR_NET_SEND_FAILED;
+ }
+ return res;
+}
+
+
+
+
diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h
new file mode 100644
index 000000000..7af897582
--- /dev/null
+++ b/src/PolarSSL++/BlockingSslClientSocket.h
@@ -0,0 +1,80 @@
+
+// BlockingSslClientSocket.h
+
+// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
+
+
+
+
+
+#pragma once
+
+#include "CallbackSslContext.h"
+#include "../OSSupport/Socket.h"
+
+
+
+
+
+class cBlockingSslClientSocket :
+ protected cCallbackSslContext::cDataCallbacks
+{
+public:
+ cBlockingSslClientSocket(void);
+
+ /** Connects to the specified server and performs SSL handshake.
+ Returns true if successful, false on failure. Sets internal error text on failure. */
+ bool Connect(const AString & a_ServerName, UInt16 a_Port);
+
+ /** Sends the specified data over the connection.
+ Returns true if successful, false on failure. Sets the internal error text on failure. */
+ bool Send(const void * a_Data, size_t a_NumBytes);
+
+ /** Receives data from the connection.
+ Blocks until there is any data available, then returns as much as possible.
+ Returns the number of bytes actually received, negative number on failure.
+ Sets the internal error text on failure. */
+ int Receive(void * a_Data, size_t a_MaxBytes);
+
+ /** Disconnects the connection gracefully, if possible.
+ Note that this also frees the internal SSL context, so all the certificates etc. are lost. */
+ void Disconnect(void);
+
+ /** Sets the root certificates that are to be trusted. Forces the connection to use strict cert
+ verification. Needs to be used before calling Connect().
+ a_ExpectedPeerName is the name that we expect to receive in the SSL peer's cert; verification will fail if
+ the presented name is different (possible MITM).
+ Returns true on success, false on failure. Sets internal error text on failure. */
+ bool SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName);
+
+ /** Returns the text of the last error that has occurred in this instance. */
+ const AString & GetLastErrorText(void) const { return m_LastErrorText; }
+
+protected:
+ /** The SSL context used for the socket */
+ cCallbackSslContext m_Ssl;
+
+ /** The underlying socket to the SSL server */
+ cSocket m_Socket;
+
+ /** The trusted CA root cert store, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
+ cX509CertPtr m_CACerts;
+
+ /** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
+ AString m_ExpectedPeerName;
+
+ /** Text of the last error that has occurred. */
+ AString m_LastErrorText;
+
+ /** Set to true if the connection established successfully. */
+ bool m_IsConnected;
+
+
+ // cCallbackSslContext::cDataCallbacks overrides:
+ virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
+ virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp
new file mode 100644
index 000000000..9f7caeb8a
--- /dev/null
+++ b/src/PolarSSL++/BufferedSslContext.cpp
@@ -0,0 +1,93 @@
+
+// BufferedSslContext.cpp
+
+// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
+
+#include "Globals.h"
+#include "BufferedSslContext.h"
+
+
+
+
+
+cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize):
+ m_OutgoingData(a_BufferSize),
+ m_IncomingData(a_BufferSize)
+{
+}
+
+
+
+
+
+size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes)
+{
+ size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes);
+ if (NumBytes > 0)
+ {
+ m_IncomingData.Write(a_Data, NumBytes);
+ return NumBytes;
+ }
+ return 0;
+}
+
+
+
+
+
+size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize)
+{
+ size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize);
+ if (NumBytes > 0)
+ {
+ m_OutgoingData.ReadBuf(a_Data, NumBytes);
+ m_OutgoingData.CommitRead();
+ return NumBytes;
+ }
+ return 0;
+}
+
+
+
+
+
+int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
+{
+ // Called when PolarSSL wants to read encrypted data from the SSL peer
+ // Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming():
+ size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace());
+ if (NumBytes == 0)
+ {
+ return POLARSSL_ERR_NET_WANT_READ;
+ }
+ if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes))
+ {
+ m_IncomingData.ResetRead();
+ return POLARSSL_ERR_NET_RECV_FAILED;
+ }
+ m_IncomingData.CommitRead();
+ return (int)NumBytes;
+}
+
+
+
+
+
+int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
+{
+ // Called when PolarSSL wants to write encrypted data to the SSL peer
+ // Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing():
+ if (!m_OutgoingData.CanWriteBytes(a_NumBytes))
+ {
+ return POLARSSL_ERR_NET_WANT_WRITE;
+ }
+ if (!m_OutgoingData.Write((const char *)a_Buffer, a_NumBytes))
+ {
+ return POLARSSL_ERR_NET_SEND_FAILED;
+ }
+ return (int)a_NumBytes;
+}
+
+
+
+
diff --git a/src/PolarSSL++/BufferedSslContext.h b/src/PolarSSL++/BufferedSslContext.h
new file mode 100644
index 000000000..1b7e1af46
--- /dev/null
+++ b/src/PolarSSL++/BufferedSslContext.h
@@ -0,0 +1,52 @@
+
+// BufferedSslContext.h
+
+// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
+
+
+
+
+
+#pragma once
+
+#include "SslContext.h"
+
+
+
+
+
+class cBufferedSslContext :
+ public cSslContext
+{
+ typedef cSslContext super;
+
+public:
+ /** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */
+ cBufferedSslContext(size_t a_BufferSize = 64000);
+
+ /** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor.
+ This is the data received from the SSL peer.
+ Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */
+ size_t WriteIncoming(const void * a_Data, size_t a_NumBytes);
+
+ /** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor.
+ This is the data to be sent to the SSL peer.
+ Returns the number of bytes actually retrieved. */
+ size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize);
+
+protected:
+ /** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */
+ cByteBuffer m_OutgoingData;
+
+ /** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */
+ cByteBuffer m_IncomingData;
+
+
+ // cSslContext overrides:
+ virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
+ virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt
new file mode 100644
index 000000000..9a59cdb2c
--- /dev/null
+++ b/src/PolarSSL++/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required (VERSION 2.6)
+project (MCServer)
+
+include_directories ("${PROJECT_SOURCE_DIR}/../")
+
+set(SOURCES
+ AesCfb128Decryptor.cpp
+ AesCfb128Encryptor.cpp
+ BlockingSslClientSocket.cpp
+ BufferedSslContext.cpp
+ CallbackSslContext.cpp
+ CtrDrbgContext.cpp
+ CryptoKey.cpp
+ EntropyContext.cpp
+ RsaPrivateKey.cpp
+ Sha1Checksum.cpp
+ SslContext.cpp
+ X509Cert.cpp
+)
+
+set(HEADERS
+ AesCfb128Decryptor.h
+ AesCfb128Encryptor.h
+ BlockingSslClientSocket.h
+ BufferedSslContext.h
+ CallbackSslContext.h
+ CtrDrbgContext.h
+ CryptoKey.h
+ EntropyContext.h
+ RsaPrivateKey.h
+ SslContext.h
+ Sha1Checksum.h
+ X509Cert.h
+)
+
+add_library(PolarSSL++ ${SOURCES} ${HEADERS})
+
+if (UNIX)
+ target_link_libraries(PolarSSL++ polarssl)
+endif()
diff --git a/src/PolarSSL++/CallbackSslContext.cpp b/src/PolarSSL++/CallbackSslContext.cpp
new file mode 100644
index 000000000..0cc88a14a
--- /dev/null
+++ b/src/PolarSSL++/CallbackSslContext.cpp
@@ -0,0 +1,59 @@
+
+// CallbackSslContext.cpp
+
+// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
+
+#include "Globals.h"
+#include "CallbackSslContext.h"
+
+
+
+
+
+
+cCallbackSslContext::cCallbackSslContext(void)
+{
+ // Nothing needed, but the constructor needs to exist so
+}
+
+
+
+
+
+cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) :
+ m_Callbacks(&a_Callbacks)
+{
+}
+
+
+
+
+
+int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
+{
+ if (m_Callbacks == NULL)
+ {
+ LOGWARNING("SSL: Trying to receive data with no callbacks, aborting.");
+ return POLARSSL_ERR_NET_RECV_FAILED;
+ }
+ return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes);
+}
+
+
+
+
+
+int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
+{
+ if (m_Callbacks == NULL)
+ {
+ LOGWARNING("SSL: Trying to send data with no callbacks, aborting.");
+ return POLARSSL_ERR_NET_SEND_FAILED;
+ }
+ return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes);
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/CallbackSslContext.h b/src/PolarSSL++/CallbackSslContext.h
new file mode 100644
index 000000000..3e6edc5f4
--- /dev/null
+++ b/src/PolarSSL++/CallbackSslContext.h
@@ -0,0 +1,64 @@
+
+// CallbackSslContext.h
+
+// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
+
+
+
+
+
+#pragma once
+
+#include "SslContext.h"
+
+
+
+
+
+class cCallbackSslContext :
+ public cSslContext
+{
+public:
+ /** Interface used as a data sink for the SSL peer data. */
+ class cDataCallbacks
+ {
+ public:
+ // Force a virtual destructor in descendants:
+ virtual ~cDataCallbacks() {}
+
+ /** Called when PolarSSL wants to read encrypted data from the SSL peer.
+ The returned value is the number of bytes received, or a PolarSSL error on failure.
+ The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
+ that there's currently no more data and that there might be more data in the future. In such cases the
+ SSL operation that invoked this call will terminate with the same return value, so that the owner is
+ notified of this condition and can potentially restart the operation later on. */
+ virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
+
+ /** Called when PolarSSL wants to write encrypted data to the SSL peer.
+ The returned value is the number of bytes sent, or a PolarSSL error on failure.
+ The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
+ that there's currently no more data and that there might be more data in the future. In such cases the
+ SSL operation that invoked this call will terminate with the same return value, so that the owner is
+ notified of this condition and can potentially restart the operation later on. */
+ virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
+ } ;
+
+
+ /** Creates a new SSL context with no callbacks assigned */
+ cCallbackSslContext(void);
+
+ /** Creates a new SSL context with the specified callbacks */
+ cCallbackSslContext(cDataCallbacks & a_Callbacks);
+
+protected:
+ /** The callbacks to use to send and receive SSL peer data */
+ cDataCallbacks * m_Callbacks;
+
+ // cSslContext overrides:
+ virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
+ virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
+};
+
+
+
+
diff --git a/src/PolarSSL++/CryptoKey.cpp b/src/PolarSSL++/CryptoKey.cpp
new file mode 100644
index 000000000..0763c387b
--- /dev/null
+++ b/src/PolarSSL++/CryptoKey.cpp
@@ -0,0 +1,149 @@
+
+// CryptoKey.cpp
+
+// Implements the cCryptoKey class representing a RSA public key in PolarSSL
+
+#include "Globals.h"
+#include "CryptoKey.h"
+
+
+
+
+
+cCryptoKey::cCryptoKey(void)
+{
+ pk_init(&m_Pk);
+ m_CtrDrbg.Initialize("rsa_pubkey", 10);
+}
+
+
+
+
+
+cCryptoKey::cCryptoKey(const AString & a_PublicKeyData)
+{
+ pk_init(&m_Pk);
+ m_CtrDrbg.Initialize("rsa_pubkey", 10);
+ int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size());
+ if (res != 0)
+ {
+ LOGWARNING("Failed to parse public key: -0x%x", res);
+ ASSERT(!"Cannot parse PubKey");
+ return;
+ }
+}
+
+
+
+
+
+cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password)
+{
+ pk_init(&m_Pk);
+ m_CtrDrbg.Initialize("rsa_privkey", 11);
+ int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password);
+ if (res != 0)
+ {
+ LOGWARNING("Failed to parse private key: -0x%x", res);
+ ASSERT(!"Cannot parse PubKey");
+ return;
+ }
+}
+
+
+
+
+
+cCryptoKey::~cCryptoKey()
+{
+ pk_free(&m_Pk);
+}
+
+
+
+
+
+int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
+{
+ ASSERT(IsValid());
+
+ size_t DecryptedLen = a_DecryptedMaxLength;
+ int res = pk_decrypt(&m_Pk,
+ a_EncryptedData, a_EncryptedLength,
+ a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
+ ctr_drbg_random, m_CtrDrbg.GetInternal()
+ );
+ if (res != 0)
+ {
+ return res;
+ }
+ return (int)DecryptedLen;
+}
+
+
+
+
+
+int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
+{
+ ASSERT(IsValid());
+
+ size_t EncryptedLength = a_EncryptedMaxLength;
+ int res = pk_encrypt(&m_Pk,
+ a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
+ ctr_drbg_random, m_CtrDrbg.GetInternal()
+ );
+ if (res != 0)
+ {
+ return res;
+ }
+ return (int)EncryptedLength;
+}
+
+
+
+
+
+
+int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes)
+{
+ ASSERT(!IsValid()); // Cannot parse a second key
+
+ return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes);
+}
+
+
+
+
+
+
+int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password)
+{
+ ASSERT(!IsValid()); // Cannot parse a second key
+
+ if (a_Password.empty())
+ {
+ return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0);
+ }
+ else
+ {
+ return pk_parse_key(
+ &m_Pk,
+ (const unsigned char *)a_Data, a_NumBytes,
+ (const unsigned char *)a_Password.c_str(), a_Password.size()
+ );
+ }
+}
+
+
+
+
+
+bool cCryptoKey::IsValid(void) const
+{
+ return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE);
+}
+
+
+
+
diff --git a/src/PolarSSL++/CryptoKey.h b/src/PolarSSL++/CryptoKey.h
new file mode 100644
index 000000000..9c298e501
--- /dev/null
+++ b/src/PolarSSL++/CryptoKey.h
@@ -0,0 +1,76 @@
+
+// CryptoKey.h
+
+// Declares the cCryptoKey class representing a RSA public key in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "CtrDrbgContext.h"
+#include "polarssl/pk.h"
+
+
+
+
+
+class cCryptoKey
+{
+ friend class cSslContext;
+
+public:
+ /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */
+ cCryptoKey(void);
+
+ /** Constructs the public key out of the DER- or PEM-encoded pubkey data */
+ cCryptoKey(const AString & a_PublicKeyData);
+
+ /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password.
+ If a_Password is empty, no password is assumed. */
+ cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password);
+
+ ~cCryptoKey();
+
+ /** Decrypts the data using the stored public key
+ Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
+ Returns the number of bytes decrypted, or negative number for error. */
+ int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
+
+ /** Encrypts the data using the stored public key
+ Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
+ Returns the number of bytes decrypted, or negative number for error. */
+ int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
+
+ /** Parses the specified data into a public key representation.
+ The key can be DER- or PEM-encoded.
+ Returns 0 on success, PolarSSL error code on failure. */
+ int ParsePublic(const void * a_Data, size_t a_NumBytes);
+
+ /** Parses the specified data into a private key representation.
+ If a_Password is empty, no password is assumed.
+ The key can be DER- or PEM-encoded.
+ Returns 0 on success, PolarSSL error code on failure. */
+ int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password);
+
+ /** Returns true if the contained key is valid. */
+ bool IsValid(void) const;
+
+protected:
+ /** The PolarSSL representation of the key data */
+ pk_context m_Pk;
+
+ /** The random generator used in encryption and decryption */
+ cCtrDrbgContext m_CtrDrbg;
+
+
+ /** Returns the internal context ptr. Only use in PolarSSL API calls. */
+ pk_context * GetInternal(void) { return &m_Pk; }
+} ;
+
+typedef SharedPtr<cCryptoKey> cCryptoKeyPtr;
+
+
+
+
diff --git a/src/PolarSSL++/CtrDrbgContext.cpp b/src/PolarSSL++/CtrDrbgContext.cpp
new file mode 100644
index 000000000..86e6d1ca5
--- /dev/null
+++ b/src/PolarSSL++/CtrDrbgContext.cpp
@@ -0,0 +1,49 @@
+
+// CtrDrbgContext.cpp
+
+// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
+
+#include "Globals.h"
+#include "CtrDrbgContext.h"
+#include "EntropyContext.h"
+
+
+
+
+
+cCtrDrbgContext::cCtrDrbgContext(void) :
+ m_EntropyContext(new cEntropyContext),
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+cCtrDrbgContext::cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext) :
+ m_EntropyContext(a_EntropyContext),
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize)
+{
+ if (m_IsValid)
+ {
+ // Already initialized
+ return 0;
+ }
+
+ int res = ctr_drbg_init(&m_CtrDrbg, entropy_func, &(m_EntropyContext->m_Entropy), (const unsigned char *)a_Custom, a_CustomSize);
+ m_IsValid = (res == 0);
+ return res;
+}
+
+
+
+
diff --git a/src/PolarSSL++/CtrDrbgContext.h b/src/PolarSSL++/CtrDrbgContext.h
new file mode 100644
index 000000000..230db8753
--- /dev/null
+++ b/src/PolarSSL++/CtrDrbgContext.h
@@ -0,0 +1,63 @@
+
+// CtrDrbgContext.h
+
+// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "polarssl/ctr_drbg.h"
+
+
+
+
+
+// fwd: EntropyContext.h
+class cEntropyContext;
+
+
+
+
+
+class cCtrDrbgContext
+{
+ friend class cSslContext;
+ friend class cRsaPrivateKey;
+ friend class cCryptoKey;
+
+public:
+ /** Constructs the context with a new entropy context. */
+ cCtrDrbgContext(void);
+
+ /** Constructs the context with the specified entropy context. */
+ cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext);
+
+ /** Initializes the context.
+ a_Custom is optional additional data to use for entropy, nullptr is accepted.
+ Returns 0 if successful, PolarSSL error code on failure. */
+ int Initialize(const void * a_Custom, size_t a_CustomSize);
+
+ /** Returns true if the object is valid (has been initialized properly) */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ /** The entropy source used for generating the random */
+ SharedPtr<cEntropyContext> m_EntropyContext;
+
+ /** The random generator context */
+ ctr_drbg_context m_CtrDrbg;
+
+ /** Set to true if the object is valid (has been initialized properly) */
+ bool m_IsValid;
+
+
+ /** Returns the internal context ptr. Only use in PolarSSL API calls. */
+ ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; }
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/EntropyContext.cpp b/src/PolarSSL++/EntropyContext.cpp
new file mode 100644
index 000000000..9c59b3f11
--- /dev/null
+++ b/src/PolarSSL++/EntropyContext.cpp
@@ -0,0 +1,29 @@
+
+// EntropyContext.cpp
+
+// Implements the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
+
+#include "Globals.h"
+#include "EntropyContext.h"
+
+
+
+
+
+cEntropyContext::cEntropyContext(void)
+{
+ entropy_init(&m_Entropy);
+}
+
+
+
+
+
+cEntropyContext::~cEntropyContext()
+{
+ entropy_free(&m_Entropy);
+}
+
+
+
+
diff --git a/src/PolarSSL++/EntropyContext.h b/src/PolarSSL++/EntropyContext.h
new file mode 100644
index 000000000..bc7fff066
--- /dev/null
+++ b/src/PolarSSL++/EntropyContext.h
@@ -0,0 +1,31 @@
+
+// EntropyContext.h
+
+// Declares the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "polarssl/entropy.h"
+
+
+
+
+
+class cEntropyContext
+{
+ friend class cCtrDrbgContext;
+public:
+ cEntropyContext(void);
+ ~cEntropyContext();
+
+protected:
+ entropy_context m_Entropy;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/RsaPrivateKey.cpp b/src/PolarSSL++/RsaPrivateKey.cpp
new file mode 100644
index 000000000..2d5a2a4b1
--- /dev/null
+++ b/src/PolarSSL++/RsaPrivateKey.cpp
@@ -0,0 +1,176 @@
+
+// RsaPrivateKey.cpp
+
+#include "Globals.h"
+#include "RsaPrivateKey.h"
+#include "CtrDrbgContext.h"
+#include "polarssl/pk.h"
+
+
+
+
+
+
+cRsaPrivateKey::cRsaPrivateKey(void)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ m_CtrDrbg.Initialize("RSA", 3);
+}
+
+
+
+
+
+cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ rsa_copy(&m_Rsa, &a_Other.m_Rsa);
+ m_CtrDrbg.Initialize("RSA", 3);
+}
+
+
+
+
+
+cRsaPrivateKey::~cRsaPrivateKey()
+{
+ rsa_free(&m_Rsa);
+}
+
+
+
+
+
+bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits)
+{
+ int res = rsa_gen_key(&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537);
+ if (res != 0)
+ {
+ LOG("RSA key generation failed: -0x%x", -res);
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+
+AString cRsaPrivateKey::GetPubKeyDER(void)
+{
+ class cPubKey
+ {
+ public:
+ cPubKey(rsa_context * a_Rsa) :
+ m_IsValid(false)
+ {
+ pk_init(&m_Key);
+ if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
+ {
+ ASSERT(!"Cannot init PrivKey context");
+ return;
+ }
+ if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
+ {
+ ASSERT(!"Cannot copy PrivKey to PK context");
+ return;
+ }
+ m_IsValid = true;
+ }
+
+ ~cPubKey()
+ {
+ if (m_IsValid)
+ {
+ pk_free(&m_Key);
+ }
+ }
+
+ operator pk_context * (void) { return &m_Key; }
+
+ protected:
+ bool m_IsValid;
+ pk_context m_Key;
+ } PkCtx(&m_Rsa);
+
+ unsigned char buf[3000];
+ int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
+ if (res < 0)
+ {
+ return AString();
+ }
+ return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
+}
+
+
+
+
+
+int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
+{
+ if (a_EncryptedLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ if (a_DecryptedMaxLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ size_t DecryptedLength;
+ int res = rsa_pkcs1_decrypt(
+ &m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, &DecryptedLength,
+ a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)DecryptedLength;
+}
+
+
+
+
+
+int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
+{
+ if (a_EncryptedMaxLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ if (a_PlainLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_PlainLength!");
+ return -1;
+ }
+ int res = rsa_pkcs1_encrypt(
+ &m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE,
+ a_PlainLength, a_PlainData, a_EncryptedData
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)m_Rsa.len;
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/RsaPrivateKey.h b/src/PolarSSL++/RsaPrivateKey.h
new file mode 100644
index 000000000..4d03f27df
--- /dev/null
+++ b/src/PolarSSL++/RsaPrivateKey.h
@@ -0,0 +1,67 @@
+
+// RsaPrivateKey.h
+
+// Declares the cRsaPrivateKey class representing a private key for RSA operations.
+
+
+
+
+
+#pragma once
+
+#include "CtrDrbgContext.h"
+#include "polarssl/rsa.h"
+
+
+
+
+
+/** Encapsulates an RSA private key used in PKI cryptography */
+class cRsaPrivateKey
+{
+ friend class cSslContext;
+
+public:
+ /** Creates a new empty object, the key is not assigned */
+ cRsaPrivateKey(void);
+
+ /** Deep-copies the key from a_Other */
+ cRsaPrivateKey(const cRsaPrivateKey & a_Other);
+
+ ~cRsaPrivateKey();
+
+ /** Generates a new key within this object, with the specified size in bits.
+ Returns true on success, false on failure. */
+ bool Generate(unsigned a_KeySizeBits = 1024);
+
+ /** Returns the public key part encoded in ASN1 DER encoding */
+ AString GetPubKeyDER(void);
+
+ /** Decrypts the data using RSAES-PKCS#1 algorithm.
+ Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
+ Returns the number of bytes decrypted, or negative number for error. */
+ int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
+
+ /** Encrypts the data using RSAES-PKCS#1 algorithm.
+ Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
+ Returns the number of bytes decrypted, or negative number for error. */
+ int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
+
+protected:
+ /** The PolarSSL key context */
+ rsa_context m_Rsa;
+
+ /** The random generator used for generating the key and encryption / decryption */
+ cCtrDrbgContext m_CtrDrbg;
+
+
+ /** Returns the internal context ptr. Only use in PolarSSL API calls. */
+ rsa_context * GetInternal(void) { return &m_Rsa; }
+} ;
+
+typedef SharedPtr<cRsaPrivateKey> cRsaPrivateKeyPtr;
+
+
+
+
+
diff --git a/src/PolarSSL++/Sha1Checksum.cpp b/src/PolarSSL++/Sha1Checksum.cpp
new file mode 100644
index 000000000..a1ee9d7b9
--- /dev/null
+++ b/src/PolarSSL++/Sha1Checksum.cpp
@@ -0,0 +1,138 @@
+
+// Sha1Checksum.cpp
+
+// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
+
+#include "Globals.h"
+#include "Sha1Checksum.h"
+
+
+
+
+
+/*
+// Self-test the hash formatting for known values:
+// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
+// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
+// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
+
+static class Test
+{
+public:
+ Test(void)
+ {
+ AString DigestNotch, DigestJeb, DigestSimon;
+ Byte Digest[20];
+ cSha1Checksum Checksum;
+ Checksum.Update((const Byte *)"Notch", 5);
+ Checksum.Finalize(Digest);
+ cSha1Checksum::DigestToJava(Digest, DigestNotch);
+ Checksum.Restart();
+ Checksum.Update((const Byte *)"jeb_", 4);
+ Checksum.Finalize(Digest);
+ cSha1Checksum::DigestToJava(Digest, DigestJeb);
+ Checksum.Restart();
+ Checksum.Update((const Byte *)"simon", 5);
+ Checksum.Finalize(Digest);
+ cSha1Checksum::DigestToJava(Digest, DigestSimon);
+ printf("Notch: \"%s\"\n", DigestNotch.c_str());
+ printf("jeb_: \"%s\"\n", DigestJeb.c_str());
+ printf("simon: \"%s\"\n", DigestSimon.c_str());
+ assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
+ assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
+ assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
+ }
+} test;
+*/
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSha1Checksum:
+
+cSha1Checksum::cSha1Checksum(void) :
+ m_DoesAcceptInput(true)
+{
+ sha1_starts(&m_Sha1);
+}
+
+
+
+
+
+void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_update(&m_Sha1, a_Data, a_Length);
+}
+
+
+
+
+
+void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_finish(&m_Sha1, a_Output);
+ m_DoesAcceptInput = false;
+}
+
+
+
+
+
+void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
+{
+ Checksum Digest;
+ memcpy(Digest, a_Digest, sizeof(Digest));
+
+ bool IsNegative = (Digest[0] >= 0x80);
+ if (IsNegative)
+ {
+ // Two's complement:
+ bool carry = true; // Add one to the whole number
+ for (int i = 19; i >= 0; i--)
+ {
+ Digest[i] = ~Digest[i];
+ if (carry)
+ {
+ carry = (Digest[i] == 0xff);
+ Digest[i]++;
+ }
+ }
+ }
+ a_Out.clear();
+ a_Out.reserve(40);
+ for (int i = 0; i < 20; i++)
+ {
+ AppendPrintf(a_Out, "%02x", Digest[i]);
+ }
+ while ((a_Out.length() > 0) && (a_Out[0] == '0'))
+ {
+ a_Out.erase(0, 1);
+ }
+ if (IsNegative)
+ {
+ a_Out.insert(0, "-");
+ }
+}
+
+
+
+
+
+
+void cSha1Checksum::Restart(void)
+{
+ sha1_starts(&m_Sha1);
+ m_DoesAcceptInput = true;
+}
+
+
+
+
diff --git a/src/PolarSSL++/Sha1Checksum.h b/src/PolarSSL++/Sha1Checksum.h
new file mode 100644
index 000000000..68fdbcf1b
--- /dev/null
+++ b/src/PolarSSL++/Sha1Checksum.h
@@ -0,0 +1,52 @@
+
+// Sha1Checksum.h
+
+// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
+
+
+
+
+
+#pragma once
+
+#include "polarssl/sha1.h"
+
+
+
+
+
+/** Calculates a SHA1 checksum for data stream */
+class cSha1Checksum
+{
+public:
+ typedef Byte Checksum[20]; // The type used for storing the checksum
+
+ cSha1Checksum(void);
+
+ /** Adds the specified data to the checksum */
+ void Update(const Byte * a_Data, size_t a_Length);
+
+ /** Calculates and returns the final checksum */
+ void Finalize(Checksum & a_Output);
+
+ /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
+
+ /** Converts a raw 160-bit SHA1 digest into a Java Hex representation
+ According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
+ */
+ static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
+
+ /** Clears the current context and start a new checksum calculation */
+ void Restart(void);
+
+protected:
+ /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool m_DoesAcceptInput;
+
+ sha1_context m_Sha1;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp
new file mode 100644
index 000000000..c3074f197
--- /dev/null
+++ b/src/PolarSSL++/SslContext.cpp
@@ -0,0 +1,303 @@
+
+// SslContext.cpp
+
+// Implements the cSslContext class that holds everything a single SSL context needs to function
+
+#include "Globals.h"
+#include "SslContext.h"
+#include "EntropyContext.h"
+#include "CtrDrbgContext.h"
+
+
+
+
+
+cSslContext::cSslContext(void) :
+ m_IsValid(false),
+ m_HasHandshaken(false)
+{
+}
+
+
+
+
+
+cSslContext::~cSslContext()
+{
+ if (m_IsValid)
+ {
+ ssl_free(&m_Ssl);
+ }
+}
+
+
+
+
+
+int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg)
+{
+ // Check double-initialization:
+ if (m_IsValid)
+ {
+ LOGWARNING("SSL: Double initialization is not supported.");
+ return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one.
+ }
+
+ // Set the CtrDrbg context, create a new one if needed:
+ m_CtrDrbg = a_CtrDrbg;
+ if (m_CtrDrbg.get() == NULL)
+ {
+ m_CtrDrbg.reset(new cCtrDrbgContext);
+ m_CtrDrbg->Initialize("MCServer", 8);
+ }
+
+ // Initialize PolarSSL's structures:
+ memset(&m_Ssl, 0, sizeof(m_Ssl));
+ int res = ssl_init(&m_Ssl);
+ if (res != 0)
+ {
+ return res;
+ }
+ ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
+ ssl_set_authmode(&m_Ssl, a_IsClient ? SSL_VERIFY_OPTIONAL : SSL_VERIFY_NONE); // Clients ask for server's cert but don't verify strictly; servers don't ask clients for certs by default
+ ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
+ ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
+
+ #ifdef _DEBUG
+ /*
+ // These functions allow us to debug SSL and certificate problems, but produce way too much output,
+ // so they're disabled until someone needs them
+ ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
+ ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
+ */
+
+ /*
+ // Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded:
+ static const int CipherSuites[] =
+ {
+ TLS_RSA_WITH_RC4_128_MD5,
+ TLS_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ 0, // Must be 0-terminated!
+ };
+ ssl_set_ciphersuites(&m_Ssl, CipherSuites);
+ */
+ #endif
+
+ m_IsValid = true;
+ return 0;
+}
+
+
+
+
+
+void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey)
+{
+ ASSERT(m_IsValid); // Call Initialize() first
+
+ // Check that both the cert and the key is valid:
+ if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL))
+ {
+ LOGWARNING("SSL: Own certificate is not valid, skipping the set.");
+ return;
+ }
+
+ // Make sure we have the cert stored for later, PolarSSL only uses the cert later on
+ m_OwnCert = a_OwnCert;
+ m_OwnCertPrivKey = a_OwnCertPrivKey;
+
+ // Set into the context:
+ ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal());
+}
+
+
+
+
+
+void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey)
+{
+ ASSERT(m_IsValid); // Call Initialize() first
+
+ // Check that both the cert and the key is valid:
+ if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL))
+ {
+ LOGWARNING("SSL: Own certificate is not valid, skipping the set.");
+ return;
+ }
+
+ // Make sure we have the cert stored for later, PolarSSL only uses the cert later on
+ m_OwnCert = a_OwnCert;
+ m_OwnCertPrivKey2 = a_OwnCertPrivKey;
+
+ // Set into the context:
+ ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal());
+}
+
+
+
+
+
+void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
+{
+ ASSERT(m_IsValid); // Call Initialize() first
+
+ // Store the data in our internal buffers, to avoid losing the pointers later on
+ // PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
+ m_ExpectedPeerName = a_ExpectedPeerName;
+ m_CACerts = a_CACert;
+
+ // Set the trusted CA root cert store:
+ ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED);
+ ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), NULL, m_ExpectedPeerName.empty() ? NULL : m_ExpectedPeerName.c_str());
+}
+
+
+
+
+
+int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes)
+{
+ ASSERT(m_IsValid); // Need to call Initialize() first
+ if (!m_HasHandshaken)
+ {
+ int res = Handshake();
+ if (res != 0)
+ {
+ return res;
+ }
+ }
+
+ return ssl_write(&m_Ssl, (const unsigned char *)a_Data, a_NumBytes);
+}
+
+
+
+
+
+int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes)
+{
+ ASSERT(m_IsValid); // Need to call Initialize() first
+ if (!m_HasHandshaken)
+ {
+ int res = Handshake();
+ if (res != 0)
+ {
+ return res;
+ }
+ }
+
+ return ssl_read(&m_Ssl, (unsigned char *)a_Data, a_MaxBytes);
+}
+
+
+
+
+
+int cSslContext::Handshake(void)
+{
+ ASSERT(m_IsValid); // Need to call Initialize() first
+ ASSERT(!m_HasHandshaken); // Must not call twice
+
+ int res = ssl_handshake(&m_Ssl);
+ if (res == 0)
+ {
+ m_HasHandshaken = true;
+ }
+ return res;
+}
+
+
+
+
+
+int cSslContext::NotifyClose(void)
+{
+ return ssl_close_notify(&m_Ssl);
+}
+
+
+
+
+
+#ifdef _DEBUG
+ void cSslContext::SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text)
+ {
+ if (a_Level > 3)
+ {
+ // Don't want the trace messages
+ return;
+ }
+
+ // Remove the terminating LF:
+ size_t len = strlen(a_Text) - 1;
+ while ((len > 0) && (a_Text[len] <= 32))
+ {
+ len--;
+ }
+ AString Text(a_Text, len + 1);
+
+ LOGD("SSL (%d): %s", a_Level, Text.c_str());
+ }
+
+
+
+
+
+ int cSslContext::SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags)
+ {
+ char buf[1024];
+ UNUSED(a_This);
+
+ LOG("Verify requested for (Depth %d):", a_Depth);
+ x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt);
+ LOG("%s", buf);
+
+ int Flags = *a_Flags;
+ if ((Flags & BADCERT_EXPIRED) != 0)
+ {
+ LOG(" ! server certificate has expired");
+ }
+
+ if ((Flags & BADCERT_REVOKED) != 0)
+ {
+ LOG(" ! server certificate has been revoked");
+ }
+
+ if ((Flags & BADCERT_CN_MISMATCH) != 0)
+ {
+ LOG(" ! CN mismatch");
+ }
+
+ if ((Flags & BADCERT_NOT_TRUSTED) != 0)
+ {
+ LOG(" ! self-signed or not signed by a trusted CA");
+ }
+
+ if ((Flags & BADCRL_NOT_TRUSTED) != 0)
+ {
+ LOG(" ! CRL not trusted");
+ }
+
+ if ((Flags & BADCRL_EXPIRED) != 0)
+ {
+ LOG(" ! CRL expired");
+ }
+
+ if ((Flags & BADCERT_OTHER) != 0)
+ {
+ LOG(" ! other (unknown) flag");
+ }
+
+ if (Flags == 0)
+ {
+ LOG(" This certificate has no flags");
+ }
+
+ return 0;
+ }
+#endif // _DEBUG
+
+
+
+
diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h
new file mode 100644
index 000000000..6b4f2c1e7
--- /dev/null
+++ b/src/PolarSSL++/SslContext.h
@@ -0,0 +1,156 @@
+
+// SslContext.h
+
+// Declares the cSslContext class that holds everything a single SSL context needs to function
+
+
+
+
+
+#pragma once
+
+#include "polarssl/ssl.h"
+#include "../ByteBuffer.h"
+#include "CryptoKey.h"
+#include "RsaPrivateKey.h"
+#include "X509Cert.h"
+
+
+
+
+
+// fwd:
+class cCtrDrbgContext;
+
+
+
+
+
+/**
+Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected
+to create it, initialize it and then provide the means of reading and writing data through the SSL link.
+This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer
+data comes into the system:
+ - cBufferedSslContext uses a cByteBuffer to read and write the data
+ - cCallbackSslContext uses callbacks to provide the data
+*/
+class cSslContext abstract
+{
+public:
+ /** Creates a new uninitialized context */
+ cSslContext(void);
+
+ virtual ~cSslContext();
+
+ /** Initializes the context for use as a server or client.
+ Returns 0 on success, PolarSSL error on failure. */
+ int Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg = SharedPtr<cCtrDrbgContext>());
+
+ /** Returns true if the object has been initialized properly. */
+ bool IsValid(void) const { return m_IsValid; }
+
+ /** Sets the certificate to use as our own. Must be used when representing a server, optional when client.
+ Must be called after Initialize(). */
+ void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey);
+
+ /** Sets the certificate to use as our own. Must be used when representing a server, optional when client.
+ Must be called after Initialize(). */
+ void SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey);
+
+ /** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize().
+ Calling this will switch the context into strict cert verification mode.
+ a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
+ if it is different, the verification will fail. An empty string will disable the CN check. */
+ void SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName);
+
+ /** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed.
+ Returns the number of bytes actually written, or PolarSSL error code.
+ If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
+ cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
+ this function again with the same parameters. Note that this may repeat a few times before the data is
+ actually written, mainly due to initial handshake. */
+ int WritePlain(const void * a_Data, size_t a_NumBytes);
+
+ /** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed.
+ Returns the number of bytes actually read, or PolarSSL error code.
+ If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
+ cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
+ this function again with the same parameters. Note that this may repeat a few times before the data is
+ actually read, mainly due to initial handshake. */
+ int ReadPlain(void * a_Data, size_t a_MaxBytes);
+
+ /** Performs the SSL handshake.
+ Returns zero on success, PoladSSL error code on failure.
+ If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
+ cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
+ this function again. Note that this may repeat a few times before the handshake is completed. */
+ int Handshake(void);
+
+ /** Returns true if the SSL handshake has been completed. */
+ bool HasHandshaken(void) const { return m_HasHandshaken; }
+
+ /** Notifies the SSL peer that the connection is being closed.
+ Returns 0 on success, PolarSSL error code on failure. */
+ int NotifyClose(void);
+
+protected:
+ /** True if the object has been initialized properly. */
+ bool m_IsValid;
+
+ /** The random generator to use */
+ SharedPtr<cCtrDrbgContext> m_CtrDrbg;
+
+ /** The SSL context that PolarSSL uses. */
+ ssl_context m_Ssl;
+
+ /** The certificate that we present to the peer. */
+ cX509CertPtr m_OwnCert;
+
+ /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey. */
+ cRsaPrivateKeyPtr m_OwnCertPrivKey;
+
+ /** Private key for m_OwnCert, if initialized from a cCryptoKey. */
+ cCryptoKeyPtr m_OwnCertPrivKey2;
+
+ /** True if the SSL handshake has been completed. */
+ bool m_HasHandshaken;
+
+ /** A copy of the trusted CA root cert store that is passed to us in SetCACerts(), so that the pointer
+ stays valid even after the call, when PolarSSL finally uses it. */
+ cX509CertPtr m_CACerts;
+
+ /** Buffer for the expected peer name. We need to buffer it because the caller may free the string they
+ give us before PolarSSL consumes the raw pointer it gets to the CN. */
+ AString m_ExpectedPeerName;
+
+
+ /** The callback used by PolarSSL when it wants to read encrypted data. */
+ static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes)
+ {
+ return ((cSslContext *)a_This)->ReceiveEncrypted(a_Buffer, a_NumBytes);
+ }
+
+ /** The callback used by PolarSSL when it wants to write encrypted data. */
+ static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes)
+ {
+ return ((cSslContext *)a_This)->SendEncrypted(a_Buffer, a_NumBytes);
+ }
+
+ #ifdef _DEBUG
+ /** The callback used by PolarSSL to output debug messages */
+ static void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text);
+
+ /** The callback used by PolarSSL to log information on the cert chain */
+ static int SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags);
+ #endif // _DEBUG
+
+ /** Called when PolarSSL wants to read encrypted data. */
+ virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
+
+ /** Called when PolarSSL wants to write encrypted data. */
+ virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/X509Cert.cpp b/src/PolarSSL++/X509Cert.cpp
new file mode 100644
index 000000000..ecf664855
--- /dev/null
+++ b/src/PolarSSL++/X509Cert.cpp
@@ -0,0 +1,38 @@
+
+// X509Cert.cpp
+
+// Implements the cX509Cert class representing a wrapper over X509 certs in PolarSSL
+
+#include "Globals.h"
+#include "X509Cert.h"
+
+
+
+
+
+cX509Cert::cX509Cert(void)
+{
+ x509_crt_init(&m_Cert);
+}
+
+
+
+
+
+cX509Cert::~cX509Cert()
+{
+ x509_crt_free(&m_Cert);
+}
+
+
+
+
+
+int cX509Cert::Parse(const void * a_CertContents, size_t a_Size)
+{
+ return x509_crt_parse(&m_Cert, (const unsigned char *)a_CertContents, a_Size);
+}
+
+
+
+
diff --git a/src/PolarSSL++/X509Cert.h b/src/PolarSSL++/X509Cert.h
new file mode 100644
index 000000000..991617d24
--- /dev/null
+++ b/src/PolarSSL++/X509Cert.h
@@ -0,0 +1,41 @@
+
+// X509Cert.h
+
+// Declares the cX509Cert class representing a wrapper over X509 certs in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "polarssl/x509_crt.h"
+
+
+
+
+
+class cX509Cert
+{
+ friend class cSslContext;
+
+public:
+ cX509Cert(void);
+ ~cX509Cert(void);
+
+ /** Parses the certificate chain data into the context.
+ Returns 0 on succes, or PolarSSL error code on failure. */
+ int Parse(const void * a_CertContents, size_t a_Size);
+
+protected:
+ x509_crt m_Cert;
+
+ /** Returns the internal cert ptr. Only use in PolarSSL API calls. */
+ x509_crt * GetInternal(void) { return &m_Cert; }
+} ;
+
+typedef SharedPtr<cX509Cert> cX509CertPtr;
+
+
+
+
diff --git a/src/ProbabDistrib.cpp b/src/ProbabDistrib.cpp
index 5fa17c276..7a5869dcc 100644
--- a/src/ProbabDistrib.cpp
+++ b/src/ProbabDistrib.cpp
@@ -118,7 +118,7 @@ int cProbabDistrib::MapValue(int a_OrigValue) const
size_t Hi = m_Cumulative.size() - 1;
while (Hi - Lo > 1)
{
- int Mid = (Lo + Hi) / 2;
+ size_t Mid = (Lo + Hi) / 2;
int MidProbab = m_Cumulative[Mid].m_Probability;
if (MidProbab < a_OrigValue)
{
diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp
new file mode 100644
index 000000000..2050393c2
--- /dev/null
+++ b/src/Protocol/Authenticator.cpp
@@ -0,0 +1,309 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Authenticator.h"
+#include "../Root.h"
+#include "../Server.h"
+#include "../ClientHandle.h"
+
+#include "inifile/iniFile.h"
+#include "json/json.h"
+
+#include "PolarSSL++/BlockingSslClientSocket.h"
+
+#include <sstream>
+#include <iomanip>
+
+
+
+
+
+#define DEFAULT_AUTH_SERVER "sessionserver.mojang.com"
+#define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%"
+
+
+
+
+
+cAuthenticator::cAuthenticator(void) :
+ super("cAuthenticator"),
+ m_Server(DEFAULT_AUTH_SERVER),
+ m_Address(DEFAULT_AUTH_ADDRESS),
+ m_ShouldAuthenticate(true)
+{
+}
+
+
+
+
+
+cAuthenticator::~cAuthenticator()
+{
+ Stop();
+}
+
+
+
+
+
+void cAuthenticator::ReadINI(cIniFile & IniFile)
+{
+ m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER);
+ m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
+ m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true);
+}
+
+
+
+
+
+void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash)
+{
+ if (!m_ShouldAuthenticate)
+ {
+ cRoot::Get()->AuthenticateUser(a_ClientID, a_UserName, cClientHandle::GenerateOfflineUUID(a_UserName));
+ return;
+ }
+
+ cCSLock LOCK(m_CS);
+ m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash));
+ m_QueueNonempty.Set();
+}
+
+
+
+
+
+void cAuthenticator::Start(cIniFile & IniFile)
+{
+ ReadINI(IniFile);
+ m_ShouldTerminate = false;
+ super::Start();
+}
+
+
+
+
+
+void cAuthenticator::Stop(void)
+{
+ m_ShouldTerminate = true;
+ m_QueueNonempty.Set();
+ Wait();
+}
+
+
+
+
+
+void cAuthenticator::Execute(void)
+{
+ for (;;)
+ {
+ cCSLock Lock(m_CS);
+ while (!m_ShouldTerminate && (m_Queue.size() == 0))
+ {
+ cCSUnlock Unlock(Lock);
+ m_QueueNonempty.Wait();
+ }
+ if (m_ShouldTerminate)
+ {
+ return;
+ }
+ ASSERT(!m_Queue.empty());
+
+ cAuthenticator::cUser & User = m_Queue.front();
+ int ClientID = User.m_ClientID;
+ AString UserName = User.m_Name;
+ AString ServerID = User.m_ServerID;
+ m_Queue.pop_front();
+ Lock.Unlock();
+
+ AString NewUserName = UserName;
+ AString UUID;
+ if (AuthWithYggdrasil(NewUserName, ServerID, UUID))
+ {
+ LOGINFO("User %s authenticated with UUID '%s'", NewUserName.c_str(), UUID.c_str());
+ cRoot::Get()->AuthenticateUser(ClientID, NewUserName, UUID);
+ }
+ else
+ {
+ cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!");
+ }
+ } // for (-ever)
+}
+
+
+
+
+
+bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID)
+{
+ LOGD("Trying to auth user %s", a_UserName.c_str());
+
+ int ret;
+ unsigned char buf[1024];
+
+ /* Initialize certificates */
+ // This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert:
+ // Downloaded from http://certs.starfieldtech.com/repository/
+ static const AString StarfieldCACert(
+ // G2 cert
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n"
+ "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n"
+ "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n"
+ "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n"
+ "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n"
+ "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n"
+ "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n"
+ "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+ "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n"
+ "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n"
+ "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n"
+ "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n"
+ "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n"
+ "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n"
+ "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n"
+ "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n"
+ "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n"
+ "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n"
+ "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n"
+ "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n"
+ "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n"
+ "-----END CERTIFICATE-----\n\n"
+ // Original (G1) cert:
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"
+ "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"
+ "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"
+ "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"
+ "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"
+ "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"
+ "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"
+ "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"
+ "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"
+ "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"
+ "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"
+ "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"
+ "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"
+ "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"
+ "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"
+ "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"
+ "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"
+ "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"
+ "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"
+ "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"
+ "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"
+ "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"
+ "-----END CERTIFICATE-----\n"
+ );
+
+ // Connect the socket:
+ cBlockingSslClientSocket Socket;
+ Socket.SetTrustedRootCertsFromString(StarfieldCACert, m_Server);
+ if (!Socket.Connect(m_Server, 443))
+ {
+ LOGWARNING("cAuthenticator: Can't connect to %s: %s", m_Server.c_str(), Socket.GetLastErrorText().c_str());
+ return false;
+ }
+
+ // Create the GET request:
+ AString ActualAddress = m_Address;
+ ReplaceString(ActualAddress, "%USERNAME%", a_UserName);
+ ReplaceString(ActualAddress, "%SERVERID%", a_ServerId);
+
+ AString Request;
+ Request += "GET " + ActualAddress + " HTTP/1.0\r\n";
+ Request += "Host: " + m_Server + "\r\n";
+ Request += "User-Agent: MCServer\r\n";
+ Request += "Connection: close\r\n";
+ Request += "\r\n";
+
+ if (!Socket.Send(Request.c_str(), Request.size()))
+ {
+ LOGWARNING("cAuthenticator: Writing SSL data failed: %s", Socket.GetLastErrorText().c_str());
+ return false;
+ }
+
+ // Read the HTTP response:
+ std::string Response;
+ for (;;)
+ {
+ ret = Socket.Receive(buf, sizeof(buf));
+
+ if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE))
+ {
+ // This value should never be returned, it is handled internally by cBlockingSslClientSocket
+ LOGWARNING("cAuthenticator: SSL reading failed internally.");
+ return false;
+ }
+ if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
+ {
+ break;
+ }
+ if (ret < 0)
+ {
+ LOGWARNING("cAuthenticator: SSL reading failed: -0x%x", -ret);
+ return false;
+ }
+ if (ret == 0)
+ {
+ break;
+ }
+
+ Response.append((const char *)buf, (size_t)ret);
+ }
+
+ Socket.Disconnect();
+
+ // Check the HTTP status line:
+ AString prefix("HTTP/1.1 200 OK");
+ AString HexDump;
+ if (Response.compare(0, prefix.size(), prefix))
+ {
+ LOGINFO("User \"%s\" failed to auth, bad http status line received", a_UserName.c_str());
+ LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
+ return false;
+ }
+
+ // Erase the HTTP headers from the response:
+ size_t idxHeadersEnd = Response.find("\r\n\r\n");
+ if (idxHeadersEnd == AString::npos)
+ {
+ LOGINFO("User \"%s\" failed to authenticate, bad http response header received", a_UserName.c_str());
+ LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
+ return false;
+ }
+ Response.erase(0, idxHeadersEnd + 4);
+
+ // Parse the Json response:
+ if (Response.empty())
+ {
+ return false;
+ }
+ Json::Value root;
+ Json::Reader reader;
+ if (!reader.parse(Response, root, false))
+ {
+ LOGWARNING("cAuthenticator: Cannot parse Received Data to json!");
+ return false;
+ }
+ a_UserName = root.get("name", "Unknown").asString();
+ a_UUID = root.get("id", "").asString();
+
+ // If the UUID doesn't contain the hashes, insert them at the proper places:
+ if (a_UUID.size() == 32)
+ {
+ a_UUID.insert(8, "-");
+ a_UUID.insert(13, "-");
+ a_UUID.insert(18, "-");
+ a_UUID.insert(23, "-");
+ }
+ return true;
+}
+
+
+
+
+
diff --git a/src/Authenticator.h b/src/Protocol/Authenticator.h
index 02cd6f4c5..211f51394 100644
--- a/src/Authenticator.h
+++ b/src/Protocol/Authenticator.h
@@ -14,7 +14,7 @@
#ifndef CAUTHENTICATOR_H_INCLUDED
#define CAUTHENTICATOR_H_INCLUDED
-#include "OSSupport/IsThread.h"
+#include "../OSSupport/IsThread.h"
@@ -31,23 +31,23 @@ class cAuthenticator :
public cIsThread
{
typedef cIsThread super;
-
+
public:
cAuthenticator(void);
~cAuthenticator();
- /// (Re-)read server and address from INI:
+ /** (Re-)read server and address from INI: */
void ReadINI(cIniFile & IniFile);
- /// Queues a request for authenticating a user. If the auth fails, the user is kicked
+ /** Queues a request for authenticating a user. If the auth fails, the user will be kicked */
void Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash);
- /// Starts the authenticator thread. The thread may be started and stopped repeatedly
+ /** Starts the authenticator thread. The thread may be started and stopped repeatedly */
void Start(cIniFile & IniFile);
-
- /// Stops the authenticator thread. The thread may be started and stopped repeatedly
+
+ /** Stops the authenticator thread. The thread may be started and stopped repeatedly */
void Stop(void);
-
+
private:
class cUser
@@ -56,30 +56,30 @@ private:
int m_ClientID;
AString m_Name;
AString m_ServerID;
-
+
cUser(int a_ClientID, const AString & a_Name, const AString & a_ServerID) :
m_ClientID(a_ClientID),
m_Name(a_Name),
m_ServerID(a_ServerID)
{
}
- } ;
-
+ };
+
typedef std::deque<cUser> cUserList;
-
+
cCriticalSection m_CS;
cUserList m_Queue;
cEvent m_QueueNonempty;
-
+
AString m_Server;
AString m_Address;
bool m_ShouldAuthenticate;
-
- // cIsThread override:
+
+ /** cIsThread override: */
virtual void Execute(void) override;
-
- // Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep)
- bool AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level = 1);
+
+ /** Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep) */
+ bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID);
};
diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt
index 107b79627..849ec27ca 100644
--- a/src/Protocol/CMakeLists.txt
+++ b/src/Protocol/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Protocol ${SOURCE})
diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp
index 78318a5ee..ebe61631b 100644
--- a/src/Protocol/ChunkDataSerializer.cpp
+++ b/src/Protocol/ChunkDataSerializer.cpp
@@ -105,7 +105,7 @@ void cChunkDataSerializer::Serialize29(AString & a_Data)
a_Data.append((const char *)&BitMap1, sizeof(short));
a_Data.append((const char *)&BitMap2, sizeof(short));
- Int32 CompressedSizeBE = htonl(CompressedSize);
+ UInt32 CompressedSizeBE = htonl((UInt32)CompressedSize);
a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE));
Int32 UnusedInt32 = 0;
@@ -163,7 +163,7 @@ void cChunkDataSerializer::Serialize39(AString & a_Data)
a_Data.append((const char *)&BitMap1, sizeof(short));
a_Data.append((const char *)&BitMap2, sizeof(short));
- Int32 CompressedSizeBE = htonl(CompressedSize);
+ UInt32 CompressedSizeBE = htonl((UInt32)CompressedSize);
a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE));
// Unlike 29, 39 doesn't have the "unused" int
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index d3383bf0d..a543c6361 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -31,6 +31,7 @@ class cMonster;
class cChunkDataSerializer;
class cFallingBlock;
class cCompositeChat;
+class cStatManager;
@@ -83,6 +84,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
virtual void SendKeepAlive (int a_PingID) = 0;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
+ virtual void SendLoginSuccess (void) = 0;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) = 0;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0;
@@ -110,6 +112,7 @@ public:
virtual void SendSpawnMob (const cMonster & a_Mob) = 0;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0;
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) = 0;
+ virtual void SendStatistics (const cStatManager & a_Manager) = 0;
virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0;
virtual void SendTeleportEntity (const cEntity & a_Entity) = 0;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
@@ -122,7 +125,7 @@ public:
virtual void SendWholeInventory (const cWindow & a_Window) = 0;
virtual void SendWindowClose (const cWindow & a_Window) = 0;
virtual void SendWindowOpen (const cWindow & a_Window) = 0;
- virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) = 0;
+ virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) = 0;
/// Returns the ServerID used for authentication through session.minecraft.net
virtual AString GetAuthServerID(void) = 0;
@@ -132,7 +135,7 @@ protected:
cCriticalSection m_CSPacket; //< Each SendXYZ() function must acquire this CS in order to send the whole packet at once
/// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it
- virtual void SendData(const char * a_Data, int a_Size) = 0;
+ virtual void SendData(const char * a_Data, size_t a_Size) = 0;
/// Called after writing each packet, enables descendants to flush their buffers
virtual void Flush(void) {};
@@ -143,10 +146,15 @@ protected:
SendData((const char *)&a_Value, 1);
}
+ void WriteChar(char a_Value)
+ {
+ SendData(&a_Value, 1);
+ }
+
void WriteShort(short a_Value)
{
- a_Value = htons(a_Value);
- SendData((const char *)&a_Value, 2);
+ u_short Value = htons((u_short)a_Value);
+ SendData((const char *)&Value, 2);
}
/*
@@ -159,8 +167,8 @@ protected:
void WriteInt(int a_Value)
{
- a_Value = htonl(a_Value);
- SendData((const char *)&a_Value, 4);
+ u_long Value = htonl((u_long)a_Value);
+ SendData((const char *)&Value, 4);
}
void WriteUInt(unsigned int a_Value)
@@ -171,19 +179,19 @@ protected:
void WriteInt64 (Int64 a_Value)
{
- a_Value = HostToNetwork8(&a_Value);
- SendData((const char *)&a_Value, 8);
+ UInt64 Value = HostToNetwork8(&a_Value);
+ SendData((const char *)&Value, 8);
}
void WriteFloat (float a_Value)
{
- unsigned int val = HostToNetwork4(&a_Value);
+ UInt32 val = HostToNetwork4(&a_Value);
SendData((const char *)&val, 4);
}
void WriteDouble(double a_Value)
{
- unsigned long long val = HostToNetwork8(&a_Value);
+ UInt64 val = HostToNetwork8(&a_Value);
SendData((const char *)&val, 8);
}
@@ -191,7 +199,7 @@ protected:
{
AString UTF16;
UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16);
- WriteShort((unsigned short)(UTF16.size() / 2));
+ WriteShort((short)(UTF16.size() / 2));
SendData(UTF16.data(), UTF16.size());
}
@@ -211,7 +219,7 @@ protected:
{
// A 32-bit integer can be encoded by at most 5 bytes:
unsigned char b[5];
- int idx = 0;
+ size_t idx = 0;
do
{
b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
@@ -224,7 +232,7 @@ protected:
void WriteVarUTF8String(const AString & a_String)
{
- WriteVarInt(a_String.size());
+ WriteVarInt((UInt32)a_String.size());
SendData(a_String.data(), a_String.size());
}
} ;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 69f4934d8..f3bdae3ac 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -26,7 +26,7 @@ Documentation:
#include "../Root.h"
#include "../Server.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"
@@ -96,8 +96,10 @@ enum
PACKET_INVENTORY_WHOLE = 0x68,
PACKET_WINDOW_PROPERTY = 0x69,
PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
+ PACKET_ENCHANT_ITEM = 0x6C,
PACKET_UPDATE_SIGN = 0x82,
PACKET_ITEM_DATA = 0x83,
+ PACKET_INCREMENT_STATISTIC = 0xC8,
PACKET_PLAYER_LIST_ITEM = 0xC9,
PACKET_PLAYER_ABILITIES = 0xca,
PACKET_PLUGIN_MESSAGE = 0xfa,
@@ -161,8 +163,8 @@ void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
WriteInt (a_BlockX);
WriteShort((short)a_BlockY);
WriteInt (a_BlockZ);
- WriteByte (a_Byte1);
- WriteByte (a_Byte2);
+ WriteChar (a_Byte1);
+ WriteChar (a_Byte2);
Flush();
}
@@ -209,12 +211,12 @@ void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
WriteByte (PACKET_MULTI_BLOCK);
WriteInt (a_ChunkX);
WriteInt (a_ChunkZ);
- WriteShort((unsigned short)a_Changes.size());
- WriteUInt (sizeof(int) * a_Changes.size());
+ WriteShort((short)a_Changes.size());
+ WriteUInt ((UInt32)(4 * a_Changes.size()));
for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr)
{
- unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12);
- unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4);
+ UInt32 Coords = ((UInt32)itr->y) | ((UInt32)(itr->z << 8)) | ((UInt32)(itr->x << 12));
+ UInt32 Blocks = ((UInt32)itr->BlockMeta) | ((UInt32)(itr->BlockType << 4));
WriteUInt(Coords << 16 | Blocks);
}
Flush();
@@ -239,32 +241,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();
}
@@ -346,8 +327,8 @@ void cProtocol125::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_ENTITY_EFFECT);
WriteInt (a_Entity.GetUniqueID());
- WriteByte (a_EffectID);
- WriteByte (a_Amplifier);
+ WriteByte ((Byte)a_EffectID);
+ WriteByte ((Byte)a_Amplifier);
WriteShort(a_Duration);
Flush();
}
@@ -378,7 +359,7 @@ void cProtocol125::SendEntityHeadLook(const cEntity & a_Entity)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_HEAD_LOOK);
WriteInt (a_Entity.GetUniqueID());
- WriteByte((char)((a_Entity.GetHeadYaw() / 360.f) * 256));
+ WriteChar((char)((a_Entity.GetHeadYaw() / 360.f) * 256));
Flush();
}
@@ -393,8 +374,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_LOOK);
WriteInt (a_Entity.GetUniqueID());
- WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -442,9 +423,9 @@ void cProtocol125::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_REL_MOVE);
WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_RelX);
- WriteByte(a_RelY);
- WriteByte(a_RelZ);
+ WriteChar(a_RelX);
+ WriteChar(a_RelY);
+ WriteChar(a_RelZ);
Flush();
}
@@ -459,11 +440,11 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_REL_MOVE_LOOK);
WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_RelX);
- WriteByte(a_RelY);
- WriteByte(a_RelZ);
- WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteChar(a_RelX);
+ WriteChar(a_RelY);
+ WriteChar(a_RelZ);
+ WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -476,7 +457,7 @@ void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_STATUS);
WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_Status);
+ WriteChar(a_Status);
Flush();
}
@@ -509,7 +490,7 @@ void cProtocol125::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc
WriteDouble (a_BlockY);
WriteDouble (a_BlockZ);
WriteFloat (a_Radius);
- WriteInt (a_BlocksAffected.size());
+ WriteInt ((Int32)a_BlocksAffected.size());
int BlockX = (int)a_BlockX;
int BlockY = (int)a_BlockY;
int BlockZ = (int)a_BlockZ;
@@ -534,7 +515,7 @@ void cProtocol125::SendGameMode(eGameMode a_GameMode)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_CHANGE_GAME_STATE);
WriteByte(3);
- WriteByte((char)a_GameMode);
+ WriteChar((char)a_GameMode);
Flush();
}
@@ -558,9 +539,10 @@ void cProtocol125::SendHealth(void)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_UPDATE_HEALTH);
- WriteShort((short)m_Client->GetPlayer()->GetHealth());
- WriteShort(m_Client->GetPlayer()->GetFoodLevel());
- WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
+ cPlayer * Player = m_Client->GetPlayer();
+ WriteShort((short)Player->GetHealth());
+ WriteShort((short)Player->GetFoodLevel());
+ WriteFloat((float)Player->GetFoodSaturationLevel());
Flush();
}
@@ -572,7 +554,7 @@ void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_INVENTORY_SLOT);
- WriteByte (a_WindowID);
+ WriteChar (a_WindowID);
WriteShort(a_SlotNum);
WriteItem (a_Item);
Flush();
@@ -615,23 +597,29 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+void cProtocol125::SendLoginSuccess(void)
+{
+ // Not supported in this protocol version
+}
+
+
+
+
+
void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_ITEM_DATA);
WriteShort(E_ITEM_MAP);
- WriteShort(a_ID);
- WriteShort(3 + a_Length);
+ WriteShort((short)a_ID);
+ WriteShort((short)(3 + a_Length));
WriteByte(0);
- WriteByte(a_X);
- WriteByte(a_Y);
+ WriteChar((char)a_X);
+ WriteChar((char)a_Y);
- for (unsigned int i = 0; i < a_Length; ++i)
- {
- WriteByte(a_Colors[i]);
- }
+ SendData((const char *)a_Colors, a_Length);
Flush();
}
@@ -646,16 +634,16 @@ void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
WriteByte (PACKET_ITEM_DATA);
WriteShort(E_ITEM_MAP);
- WriteShort(a_ID);
- WriteShort(1 + (3 * a_Decorators.size()));
+ WriteShort((short)a_ID);
+ WriteShort((short)(1 + (3 * a_Decorators.size())));
WriteByte(1);
for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it)
{
- WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf));
- WriteByte(it->GetPixelX());
- WriteByte(it->GetPixelZ());
+ WriteByte((Byte)(it->GetType() << 4) | (it->GetRot() & 0xf));
+ WriteByte((Byte)it->GetPixelX());
+ WriteByte((Byte)it->GetPixelZ());
}
Flush();
@@ -666,18 +654,30 @@ void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
+void cProtocol125::SendMapInfo(int a_ID, unsigned int a_Scale)
+{
+ // This protocol doesn't support such message
+ UNUSED(a_ID);
+ UNUSED(a_Scale);
+}
+
+
+
+
+
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PICKUP_SPAWN);
WriteInt (a_Pickup.GetUniqueID());
- WriteShort (a_Pickup.GetItem().m_ItemType);
- WriteByte (a_Pickup.GetItem().m_ItemCount);
- WriteShort (a_Pickup.GetItem().m_ItemDamage);
+ const cItem & Item = a_Pickup.GetItem();
+ WriteShort (Item.m_ItemType);
+ WriteChar (Item.m_ItemCount);
+ WriteShort (Item.m_ItemDamage);
WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
- WriteByte ((char)(a_Pickup.GetSpeed().x * 8));
- WriteByte ((char)(a_Pickup.GetSpeed().y * 8));
- WriteByte ((char)(a_Pickup.GetSpeed().z * 8));
+ WriteByte ((char)(a_Pickup.GetSpeedX() * 8));
+ WriteByte ((char)(a_Pickup.GetSpeedY() * 8));
+ WriteByte ((char)(a_Pickup.GetSpeedZ() * 8));
Flush();
}
@@ -690,7 +690,7 @@ void cProtocol125::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ANIMATION);
WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_Animation);
+ WriteChar(a_Animation);
Flush();
}
@@ -707,6 +707,16 @@ void cProtocol125::SendParticleEffect(const AString & a_ParticleName, float a_Sr
+void cProtocol125::SendPaintingSpawn(const cPainting & a_Painting)
+{
+ // Not implemented in this protocol version
+ UNUSED(a_Painting);
+}
+
+
+
+
+
void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
{
cCSLock Lock(m_CSPacket);
@@ -784,8 +794,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
- WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
+ WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256));
+ WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
Flush();
}
@@ -811,9 +821,9 @@ void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString &
void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_REMOVE_ENTITY_EFFECT);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte (a_EffectID);
+ WriteByte(PACKET_REMOVE_ENTITY_EFFECT);
+ WriteInt (a_Entity.GetUniqueID());
+ WriteChar((char)a_EffectID);
Flush();
}
@@ -824,10 +834,11 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
void cProtocol125::SendRespawn(void)
{
cCSLock Lock(m_CSPacket);
+ cPlayer * Player = m_Client->GetPlayer();
WriteByte (PACKET_RESPAWN);
- WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension()));
+ WriteInt ((int)(Player->GetWorld()->GetDimension()));
WriteByte (2); // TODO: Difficulty; 2 = Normal
- WriteByte ((char)m_Client->GetPlayer()->GetGameMode());
+ WriteChar ((char)Player->GetGameMode());
WriteShort (256); // Current world height
WriteString("default");
}
@@ -839,10 +850,11 @@ void cProtocol125::SendRespawn(void)
void cProtocol125::SendExperience(void)
{
cCSLock Lock(m_CSPacket);
+ cPlayer * Player = m_Client->GetPlayer();
WriteByte (PACKET_EXPERIENCE);
- WriteFloat (m_Client->GetPlayer()->GetXpPercentage());
- WriteShort (m_Client->GetPlayer()->GetXpLevel());
- WriteShort (m_Client->GetPlayer()->GetCurrentXp());
+ WriteFloat (Player->GetXpPercentage());
+ WriteShort (Player->GetXpLevel());
+ WriteShort (Player->GetCurrentXp());
Flush();
}
@@ -858,7 +870,7 @@ void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb)
WriteInt((int) a_ExpOrb.GetPosX());
WriteInt((int) a_ExpOrb.GetPosY());
WriteInt((int) a_ExpOrb.GetPosZ());
- WriteShort(a_ExpOrb.GetReward());
+ WriteShort((short)a_ExpOrb.GetReward());
Flush();
}
@@ -866,6 +878,18 @@ void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb)
+void cProtocol125::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
+{
+ // This protocol version doesn't support such message
+ UNUSED(a_Name);
+ UNUSED(a_DisplayName);
+ UNUSED(a_Mode);
+}
+
+
+
+
+
void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
{
// Not needed in this protocol version
@@ -899,7 +923,7 @@ void cProtocol125::SendSpawnMob(const cMonster & a_Mob)
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_SPAWN_MOB);
WriteInt (a_Mob.GetUniqueID());
- WriteByte (a_Mob.GetMobType());
+ WriteByte ((Byte)a_Mob.GetMobType());
WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
WriteByte (0);
WriteByte (0);
@@ -924,7 +948,7 @@ void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType,
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_SPAWN_OBJECT);
WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_ObjectType);
+ WriteChar(a_ObjectType);
WriteInt ((int)(a_Entity.GetPosX() * 32));
WriteInt ((int)(a_Entity.GetPosY() * 32));
WriteInt ((int)(a_Entity.GetPosZ() * 32));
@@ -949,7 +973,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_SPAWN_OBJECT);
WriteInt (a_Vehicle.GetUniqueID());
- WriteByte (a_VehicleType);
+ WriteChar (a_VehicleType);
WriteInt ((int)(a_Vehicle.GetPosX() * 32));
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
@@ -969,6 +993,33 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
+void cProtocol125::SendStatistics(const cStatManager & a_Manager)
+{
+ /* NOTE:
+ * Versions prior to minecraft 1.7 use an incremental statistic sync
+ * method. The current setup does not allow us to implement that, because
+ * of performance considerations.
+ */
+#if 0
+ for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
+ {
+ StatValue Value = m_Manager->GetValue((eStatistic) i);
+
+ unsigned int StatID = cStatInfo::GetID((eStatistic) i);
+
+ cCSLock Lock(m_CSPacket);
+ WriteByte(PACKET_INCREMENT_STATISTIC);
+ WriteInt(StatID);
+ WriteByte(Value); /* Can overflow! */
+ Flush();
+ }
+#endif
+}
+
+
+
+
+
void cProtocol125::SendTabCompletionResults(const AStringVector & a_Results)
{
// This protocol version doesn't support tab completion
@@ -987,8 +1038,8 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity)
WriteInt ((int)(floor(a_Entity.GetPosX() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosY() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosZ() * 32)));
- WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256));
- WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteChar ((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteChar ((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -1063,7 +1114,7 @@ void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc
WriteInt (a_Entity.GetUniqueID());
WriteByte(0); // Unknown byte only 0 has been observed
WriteInt (a_BlockX);
- WriteByte(a_BlockY);
+ WriteByte((Byte)a_BlockY);
WriteInt (a_BlockZ);
Flush();
}
@@ -1107,7 +1158,7 @@ void cProtocol125::SendWholeInventory(const cWindow & a_Window)
cCSLock Lock(m_CSPacket);
cItems Slots;
a_Window.GetSlots(*(m_Client->GetPlayer()), Slots);
- SendWindowSlots(a_Window.GetWindowID(), Slots.size(), &(Slots[0]));
+ SendWindowSlots(a_Window.GetWindowID(), (int)Slots.size(), &(Slots[0]));
}
@@ -1124,7 +1175,7 @@ void cProtocol125::SendWindowClose(const cWindow & a_Window)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_WINDOW_CLOSE);
- WriteByte(a_Window.GetWindowID());
+ WriteChar(a_Window.GetWindowID());
Flush();
}
@@ -1141,10 +1192,10 @@ void cProtocol125::SendWindowOpen(const cWindow & a_Window)
}
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_WINDOW_OPEN);
- WriteByte (a_Window.GetWindowID());
- WriteByte (a_Window.GetWindowType());
+ WriteChar (a_Window.GetWindowID());
+ WriteByte ((Byte)a_Window.GetWindowType());
WriteString(a_Window.GetWindowTitle());
- WriteByte (a_Window.GetNumNonInventorySlots());
+ WriteByte ((Byte)a_Window.GetNumNonInventorySlots());
Flush();
}
@@ -1152,11 +1203,11 @@ void cProtocol125::SendWindowOpen(const cWindow & a_Window)
-void cProtocol125::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
+void cProtocol125::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_WINDOW_PROPERTY);
- WriteByte (a_Window.GetWindowID());
+ WriteChar (a_Window.GetWindowID());
WriteShort(a_Property);
WriteShort(a_Value);
Flush();
@@ -1177,7 +1228,7 @@ AString cProtocol125::GetAuthServerID(void)
-void cProtocol125::SendData(const char * a_Data, int a_Size)
+void cProtocol125::SendData(const char * a_Data, size_t a_Size)
{
m_Client->SendData(a_Data, a_Size);
}
@@ -1260,6 +1311,7 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType)
case PACKET_SLOT_SELECTED: return ParseSlotSelected();
case PACKET_UPDATE_SIGN: return ParseUpdateSign();
case PACKET_USE_ENTITY: return ParseUseEntity();
+ case PACKET_ENCHANT_ITEM: return ParseEnchantItem();
case PACKET_WINDOW_CLICK: return ParseWindowClick();
case PACKET_WINDOW_CLOSE: return ParseWindowClose();
}
@@ -1548,7 +1600,7 @@ int cProtocol125::ParsePluginMessage(void)
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ChannelName);
HANDLE_PACKET_READ(ReadBEShort, short, Length);
AString Data;
- if (!m_ReceivedData.ReadString(Data, Length))
+ if (!m_ReceivedData.ReadString(Data, (size_t)Length))
{
m_ReceivedData.CheckValid();
return PARSE_INCOMPLETE;
@@ -1621,6 +1673,20 @@ int cProtocol125::ParseUseEntity(void)
+int cProtocol125::ParseEnchantItem(void)
+{
+ HANDLE_PACKET_READ(ReadByte, Byte, WindowID);
+ HANDLE_PACKET_READ(ReadByte, Byte, Enchantment);
+
+ m_Client->HandleEnchantItem(WindowID, Enchantment);
+
+ return PARSE_OK;
+}
+
+
+
+
+
int cProtocol125::ParseWindowClick(void)
{
HANDLE_PACKET_READ(ReadChar, char, WindowID);
@@ -1709,7 +1775,7 @@ void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad)
void cProtocol125::SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items)
{
WriteByte (PACKET_INVENTORY_WHOLE);
- WriteByte (a_WindowID);
+ WriteChar (a_WindowID);
WriteShort((short)a_NumItems);
for (int j = 0; j < a_NumItems; j++)
@@ -1739,7 +1805,7 @@ void cProtocol125::WriteItem(const cItem & a_Item)
return;
}
- WriteByte (a_Item.m_ItemCount);
+ WriteChar (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
if (cItem::IsEnchantable(a_Item.m_ItemType))
@@ -1786,7 +1852,7 @@ int cProtocol125::ParseItem(cItem & a_Item)
}
// TODO: Enchantment not implemented yet!
- if (!m_ReceivedData.SkipRead(EnchantNumBytes))
+ if (!m_ReceivedData.SkipRead((size_t)EnchantNumBytes))
{
return PARSE_INCOMPLETE;
}
@@ -1871,7 +1937,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
case cMonster::mtCreeper:
{
WriteByte(0x10);
- WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up?
+ WriteChar(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up?
WriteByte(0x11);
WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0); // Lightning-charged?
break;
@@ -1941,9 +2007,9 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
WriteByte(0x10);
Byte SheepMetadata = 0;
- SheepMetadata = ((const cSheep &)a_Mob).GetFurColor(); // Fur colour
+ SheepMetadata = (Byte)((const cSheep &)a_Mob).GetFurColor();
- if (((const cSheep &)a_Mob).IsSheared()) // Is sheared?
+ if (((const cSheep &)a_Mob).IsSheared())
{
SheepMetadata |= 0x16;
}
@@ -1972,17 +2038,25 @@ 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((Int32)((const cWither &)a_Mob).GetWitherInvulnerableTicks());
+ WriteByte(0x66); // Float at index 6
+ WriteFloat((float)(a_Mob.GetHealth()));
+ break;
+ }
case cMonster::mtSlime:
case cMonster::mtMagmaCube:
{
WriteByte(0x10);
if (a_Mob.GetMobType() == cMonster::mtSlime)
{
- WriteByte(((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME
+ WriteByte((Byte)((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME
}
else
{
- WriteByte(((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME
+ WriteByte((Byte)((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME
}
break;
}
@@ -2021,7 +2095,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
WriteInt(Flags);
WriteByte(0x13);
- WriteByte(((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.)
+ WriteByte((Byte)((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.)
WriteByte(0x54);
int Appearance = 0;
@@ -2033,6 +2107,10 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
WriteInt(((const cHorse &)a_Mob).GetHorseArmour()); // Horshey armour
break;
}
+ default:
+ {
+ break;
+ }
}
}
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index aca24c03a..18a626a2d 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -56,19 +56,12 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
+ virtual void SendLoginSuccess (void) override;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
- virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override
- {
- // This protocol doesn't support such message
- UNUSED(a_ID);
- UNUSED(a_Scale);
- }
+ virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
- virtual void SendPaintingSpawn (const cPainting & a_Painting) override
- {
- UNUSED(a_Painting);
- };
+ virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
@@ -82,12 +75,7 @@ public:
virtual void SendRespawn (void) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
- virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override
- {
- UNUSED(a_Name);
- UNUSED(a_DisplayName);
- UNUSED(a_Mode);
- } // This protocol doesn't support such message
+ virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
@@ -96,6 +84,7 @@ public:
virtual void SendSpawnMob (const cMonster & a_Mob) override;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
+ virtual void SendStatistics (const cStatManager & a_Manager) override;
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
@@ -108,7 +97,7 @@ public:
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
virtual void SendWindowOpen (const cWindow & a_Window) override;
- virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override;
+ virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override;
virtual AString GetAuthServerID(void) override;
@@ -125,7 +114,7 @@ protected:
AString m_Username; ///< Stored in ParseHandshake(), compared to Login username
- virtual void SendData(const char * a_Data, int a_Size) override;
+ virtual void SendData(const char * a_Data, size_t a_Size) override;
/// Sends the Handshake packet
void SendHandshake(const AString & a_ConnectionHash);
@@ -155,6 +144,7 @@ protected:
virtual int ParseSlotSelected (void);
virtual int ParseUpdateSign (void);
virtual int ParseUseEntity (void);
+ virtual int ParseEnchantItem (void);
virtual int ParseWindowClick (void);
virtual int ParseWindowClose (void);
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index be9c503ed..f4717f592 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -18,19 +18,7 @@
#include "../WorldStorage/FastNBT.h"
#include "../WorldStorage/EnchantmentSerializer.h"
#include "../StringCompression.h"
-
-#ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable:4127)
- #pragma warning(disable:4244)
- #pragma warning(disable:4231)
- #pragma warning(disable:4189)
- #pragma warning(disable:4702)
-#endif
-
-#ifdef _MSC_VER
- #pragma warning(pop)
-#endif
+#include "PolarSSL++/Sha1Checksum.h"
@@ -115,7 +103,7 @@ void cProtocol132::DataReceived(const char * a_Data, size_t a_Size)
Byte Decrypted[512];
while (a_Size > 0)
{
- int NumBytes = (a_Size > (int)sizeof(Decrypted)) ? (int)sizeof(Decrypted) : a_Size;
+ size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
super::DataReceived((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
@@ -139,8 +127,8 @@ void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
WriteInt (a_BlockX);
WriteShort((short)a_BlockY);
WriteInt (a_BlockZ);
- WriteByte (a_Byte1);
- WriteByte (a_Byte2);
+ WriteChar (a_Byte1);
+ WriteChar (a_Byte2);
WriteShort(a_BlockType);
Flush();
}
@@ -157,7 +145,7 @@ void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY
WriteInt (a_BlockX);
WriteInt (a_BlockY);
WriteInt (a_BlockZ);
- WriteByte (stage);
+ WriteChar (stage);
Flush();
}
@@ -259,7 +247,7 @@ void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
WriteByte (PACKET_LOGIN);
WriteInt (a_Player.GetUniqueID()); // EntityID of the player
WriteString("default"); // Level type
- WriteByte ((int)a_Player.GetGameMode());
+ WriteByte ((Byte)a_Player.GetGameMode());
WriteByte ((Byte)(a_World.GetDimension()));
WriteByte (2); // TODO: Difficulty
WriteByte (0); // Unused, used to be world height
@@ -283,8 +271,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
- WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
+ WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256));
+ WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
// Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata:
WriteByte (0); // Index 0, byte (flags)
@@ -306,7 +294,7 @@ void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int
WriteInt (a_SrcY);
WriteInt (a_SrcZ);
WriteFloat (a_Volume);
- WriteByte ((char)(a_Pitch * 63.0f));
+ WriteChar ((char)(a_Pitch * 63.0f));
Flush();
}
@@ -320,7 +308,7 @@ void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
WriteInt (a_EffectID);
WriteInt (a_SrcX);
- WriteByte(a_SrcY);
+ WriteByte((Byte)a_SrcY);
WriteInt (a_SrcZ);
WriteInt (a_Data);
Flush();
@@ -335,7 +323,7 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_SPAWN_MOB);
WriteInt (a_Mob.GetUniqueID());
- WriteByte (a_Mob.GetMobType());
+ WriteByte ((Byte)a_Mob.GetMobType());
WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
@@ -408,21 +396,22 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window)
super::SendWholeInventory(a_Window);
// Send the player inventory and hotbar:
- const cInventory & Inventory = m_Client->GetPlayer()->GetInventory();
+ cPlayer * Player = m_Client->GetPlayer();
+ const cInventory & Inventory = Player->GetInventory();
int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots
char WindowID = a_Window.GetWindowID();
- for (int i = 0; i < cInventory::invInventoryCount; i++)
+ for (short i = 0; i < cInventory::invInventoryCount; i++)
{
SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i));
} // for i - Inventory[]
BaseOffset += cInventory::invInventoryCount;
- for (int i = 0; i < cInventory::invHotbarCount; i++)
+ for (short i = 0; i < cInventory::invHotbarCount; i++)
{
SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i));
} // for i - Hotbar[]
// Send even the item being dragged:
- SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem());
+ SendInventorySlot(-1, -1, Player->GetDraggingItem());
}
@@ -527,21 +516,30 @@ int cProtocol132::ParseClientStatuses(void)
int cProtocol132::ParseEncryptionKeyResponse(void)
{
+ // Read the encryption key:
HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength);
+ if (EncKeyLength > MAX_ENC_LEN)
+ {
+ LOGD("Too long encryption key");
+ m_Client->Kick("Hacked client");
+ return PARSE_OK;
+ }
AString EncKey;
- if (!m_ReceivedData.ReadString(EncKey, EncKeyLength))
+ if (!m_ReceivedData.ReadString(EncKey, (size_t)EncKeyLength))
{
return PARSE_INCOMPLETE;
}
+
+ // Read the encryption nonce:
HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength);
AString EncNonce;
- if (!m_ReceivedData.ReadString(EncNonce, EncNonceLength))
+ if (!m_ReceivedData.ReadString(EncNonce, (size_t)EncNonceLength))
{
return PARSE_INCOMPLETE;
}
- if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
+ if (EncNonceLength > MAX_ENC_LEN)
{
- LOGD("Too long encryption");
+ LOGD("Too long encryption nonce");
m_Client->Kick("Hacked client");
return PARSE_OK;
}
@@ -605,7 +603,7 @@ int cProtocol132::ParseTabCompletion(void)
-void cProtocol132::SendData(const char * a_Data, int a_Size)
+void cProtocol132::SendData(const char * a_Data, size_t a_Size)
{
m_DataToSend.append(a_Data, a_Size);
}
@@ -623,23 +621,23 @@ void cProtocol132::Flush(void)
LOGD("Flushing empty");
return;
}
- const char * a_Data = m_DataToSend.data();
- int a_Size = m_DataToSend.size();
+ const char * Data = m_DataToSend.data();
+ size_t Size = m_DataToSend.size();
if (m_IsEncrypted)
{
Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
- while (a_Size > 0)
+ while (Size > 0)
{
- int NumBytes = (a_Size > (int)sizeof(Encrypted)) ? (int)sizeof(Encrypted) : a_Size;
- m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
+ size_t NumBytes = (Size > sizeof(Encrypted)) ? sizeof(Encrypted) : Size;
+ m_Encryptor.ProcessData(Encrypted, (Byte *)Data, NumBytes);
super::SendData((const char *)Encrypted, NumBytes);
- a_Size -= NumBytes;
- a_Data += NumBytes;
+ Size -= NumBytes;
+ Data += NumBytes;
}
}
else
{
- super::SendData(a_Data, a_Size);
+ super::SendData(Data, Size);
}
m_DataToSend.clear();
}
@@ -665,7 +663,7 @@ void cProtocol132::WriteItem(const cItem & a_Item)
}
WriteShort(ItemType);
- WriteByte (a_Item.m_ItemCount);
+ WriteChar (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
if (a_Item.m_Enchantments.IsEmpty())
@@ -681,7 +679,7 @@ void cProtocol132::WriteItem(const cItem & a_Item)
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
- WriteShort(Compressed.size());
+ WriteShort((short)Compressed.size());
SendData(Compressed.data(), Compressed.size());
}
@@ -717,8 +715,8 @@ int cProtocol132::ParseItem(cItem & a_Item)
// Read the metadata
AString Metadata;
- Metadata.resize(MetadataLength);
- if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), MetadataLength))
+ Metadata.resize((size_t)MetadataLength);
+ if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), (size_t)MetadataLength))
{
return PARSE_INCOMPLETE;
}
@@ -791,10 +789,12 @@ void cProtocol132::SendCompass(const cWorld & a_World)
void cProtocol132::SendEncryptionKeyRequest(void)
{
cCSLock Lock(m_CSPacket);
+ cServer * Server = cRoot::Get()->GetServer();
WriteByte(0xfd);
- WriteString(cRoot::Get()->GetServer()->GetServerID());
- WriteShort((short)(cRoot::Get()->GetServer()->GetPublicKeyDER().size()));
- SendData(cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
+ WriteString(Server->GetServerID());
+ const AString & PublicKeyDER = Server->GetPublicKeyDER();
+ WriteShort((short)(PublicKeyDER.size()));
+ SendData(PublicKeyDER.data(), PublicKeyDER.size());
WriteShort(4);
WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
Flush();
@@ -807,7 +807,7 @@ void cProtocol132::SendEncryptionKeyRequest(void)
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
{
// Decrypt EncNonce using privkey
- cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
+ cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
@@ -864,14 +864,15 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
- cSHA1Checksum Checksum;
- AString ServerID = cRoot::Get()->GetServer()->GetServerID();
+ cSha1Checksum Checksum;
+ cServer * Server = cRoot::Get()->GetServer();
+ AString ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
Checksum.Update(a_Key, 16);
- Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
+ Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
+ cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
}
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index 0702fbf5a..32bc7d581 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -24,7 +24,8 @@
#pragma warning(pop)
#endif
-#include "../Crypto.h"
+#include "PolarSSL++/AesCfb128Decryptor.h"
+#include "PolarSSL++/AesCfb128Encryptor.h"
@@ -79,15 +80,15 @@ public:
protected:
bool m_IsEncrypted;
- cAESCFBDecryptor m_Decryptor;
- cAESCFBEncryptor m_Encryptor;
+ cAesCfb128Decryptor m_Decryptor;
+ cAesCfb128Encryptor m_Encryptor;
AString m_DataToSend;
/// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID()
AString m_AuthServerID;
- virtual void SendData(const char * a_Data, int a_Size) override;
+ virtual void SendData(const char * a_Data, size_t a_Size) override;
// DEBUG:
virtual void Flush(void) override;
diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp
index 232b2718e..f60e756fd 100644
--- a/src/Protocol/Protocol14x.cpp
+++ b/src/Protocol/Protocol14x.cpp
@@ -103,9 +103,9 @@ void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup)
WriteInt (a_Pickup.GetUniqueID());
WriteItem (a_Pickup.GetItem());
WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
- WriteByte ((char)(a_Pickup.GetSpeed().x * 8));
- WriteByte ((char)(a_Pickup.GetSpeed().y * 8));
- WriteByte ((char)(a_Pickup.GetSpeed().z * 8));
+ WriteChar((char)(a_Pickup.GetSpeedX() * 8));
+ WriteChar((char)(a_Pickup.GetSpeedY() * 8));
+ WriteChar((char)(a_Pickup.GetSpeedZ() * 8));
Flush();
}
@@ -119,7 +119,7 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
WriteInt (a_EffectID);
WriteInt (a_SrcX);
- WriteByte(a_SrcY);
+ WriteByte((Byte)a_SrcY);
WriteInt (a_SrcZ);
WriteInt (a_Data);
WriteBool(0);
@@ -170,9 +170,9 @@ void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup)
WriteInt ((int)(a_Pickup.GetPosY() * 32));
WriteInt ((int)(a_Pickup.GetPosZ() * 32));
WriteInt (1);
- WriteShort((short)(a_Pickup.GetSpeed().x * 32));
- WriteShort((short)(a_Pickup.GetSpeed().y * 32));
- WriteShort((short)(a_Pickup.GetSpeed().z * 32));
+ WriteShort((short)(a_Pickup.GetSpeedX() * 32));
+ WriteShort((short)(a_Pickup.GetSpeedY() * 32));
+ WriteShort((short)(a_Pickup.GetSpeedZ() * 32));
WriteByte(0);
WriteByte(0);
@@ -218,7 +218,7 @@ void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType,
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_SPAWN_OBJECT);
WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_ObjectType);
+ WriteChar(a_ObjectType);
WriteInt ((int)(a_Entity.GetPosX() * 32));
WriteInt ((int)(a_Entity.GetPosY() * 32));
WriteInt ((int)(a_Entity.GetPosZ() * 32));
@@ -243,7 +243,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_SPAWN_OBJECT);
WriteInt (a_Vehicle.GetUniqueID());
- WriteByte (a_VehicleType);
+ WriteChar (a_VehicleType);
WriteInt ((int)(a_Vehicle.GetPosX() * 32));
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp
index ecb24254f..714bf5e46 100644
--- a/src/Protocol/Protocol16x.cpp
+++ b/src/Protocol/Protocol16x.cpp
@@ -18,6 +18,7 @@ Implements the 1.6.x protocol classes:
#include "../Entities/Entity.h"
#include "../Entities/Player.h"
#include "../UI/Window.h"
+#include "../CompositeChat.h"
@@ -89,6 +90,18 @@ void cProtocol161::SendChat(const AString & a_Message)
+void cProtocol161::SendChat(const cCompositeChat & a_Message)
+{
+ // This protocol version doesn't support composite messages to the full
+ // Just extract each part's text and use it:
+
+ super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message.ExtractText()).c_str()));
+}
+
+
+
+
+
void cProtocol161::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
{
cCSLock Lock(m_CSPacket);
@@ -118,9 +131,10 @@ void cProtocol161::SendHealth(void)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_UPDATE_HEALTH);
- WriteFloat((float)m_Client->GetPlayer()->GetHealth());
- WriteShort(m_Client->GetPlayer()->GetFoodLevel());
- WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
+ cPlayer * Player = m_Client->GetPlayer();
+ WriteFloat((float)Player->GetHealth());
+ WriteShort((short)Player->GetFoodLevel());
+ WriteFloat((float)Player->GetFoodSaturationLevel());
Flush();
}
@@ -131,11 +145,12 @@ void cProtocol161::SendHealth(void)
void cProtocol161::SendPlayerMaxSpeed(void)
{
cCSLock Lock(m_CSPacket);
+ cPlayer * Player = m_Client->GetPlayer();
WriteByte(PACKET_ENTITY_PROPERTIES);
- WriteInt(m_Client->GetPlayer()->GetUniqueID());
+ WriteInt(Player->GetUniqueID());
WriteInt(1);
WriteString("generic.movementSpeed");
- WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
+ WriteDouble(0.1 * Player->GetMaxSpeed());
Flush();
}
@@ -163,10 +178,10 @@ void cProtocol161::SendWindowOpen(const cWindow & a_Window)
}
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_WINDOW_OPEN);
- WriteByte (a_Window.GetWindowID());
- WriteByte (a_Window.GetWindowType());
+ WriteChar (a_Window.GetWindowID());
+ WriteByte ((Byte)a_Window.GetWindowType());
WriteString(a_Window.GetWindowTitle());
- WriteByte (a_Window.GetNumNonInventorySlots());
+ WriteByte ((Byte)a_Window.GetNumNonInventorySlots());
WriteByte (1); // Use title
if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
{
@@ -201,6 +216,25 @@ int cProtocol161::ParseEntityAction(void)
+int cProtocol161::ParseLogin(void)
+{
+ // The login packet is sent by Forge clients only
+ // Only parse the packet, do no extra processing
+ // Note that the types and the names have been only guessed and are not verified at all!
+ HANDLE_PACKET_READ(ReadBEInt, int, Int1);
+ HANDLE_PACKET_READ(ReadBEUTF16String16, AString, String1);
+ HANDLE_PACKET_READ(ReadChar, char, Char1);
+ HANDLE_PACKET_READ(ReadChar, char, Char2);
+ HANDLE_PACKET_READ(ReadChar, char, Char3);
+ HANDLE_PACKET_READ(ReadByte, Byte, Byte1);
+ HANDLE_PACKET_READ(ReadByte, Byte, Byte2);
+ return PARSE_OK;
+}
+
+
+
+
+
int cProtocol161::ParsePlayerAbilities(void)
{
HANDLE_PACKET_READ(ReadByte, Byte, Flags);
@@ -263,11 +297,12 @@ cProtocol162::cProtocol162(cClientHandle * a_Client) :
void cProtocol162::SendPlayerMaxSpeed(void)
{
cCSLock Lock(m_CSPacket);
+ cPlayer * Player = m_Client->GetPlayer();
WriteByte(PACKET_ENTITY_PROPERTIES);
- WriteInt(m_Client->GetPlayer()->GetUniqueID());
+ WriteInt(Player->GetUniqueID());
WriteInt(1);
WriteString("generic.movementSpeed");
- WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
+ WriteDouble(0.1 * Player->GetMaxSpeed());
WriteShort(0);
Flush();
}
diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h
index 325e41c5a..8eedce8d5 100644
--- a/src/Protocol/Protocol16x.h
+++ b/src/Protocol/Protocol16x.h
@@ -37,6 +37,7 @@ protected:
// cProtocol150 overrides:
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
virtual void SendChat (const AString & a_Message) override;
+ virtual void SendChat (const cCompositeChat & a_Message) override;
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
virtual void SendGameMode (eGameMode a_GameMode) override;
virtual void SendHealth (void) override;
@@ -45,6 +46,7 @@ protected:
virtual void SendWindowOpen (const cWindow & a_Window) override;
virtual int ParseEntityAction (void) override;
+ virtual int ParseLogin (void) override;
virtual int ParsePlayerAbilities(void) override;
// New packets:
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 721ed349e..f7564fe6d 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -11,13 +11,19 @@ Implements the 1.7.x protocol classes:
#include "json/json.h"
#include "Protocol17x.h"
#include "ChunkDataSerializer.h"
+#include "PolarSSL++/Sha1Checksum.h"
+
#include "../ClientHandle.h"
#include "../Root.h"
#include "../Server.h"
#include "../World.h"
+#include "../StringCompression.h"
+#include "../CompositeChat.h"
+#include "../Statistics.h"
+
#include "../WorldStorage/FastNBT.h"
#include "../WorldStorage/EnchantmentSerializer.h"
-#include "../StringCompression.h"
+
#include "../Entities/ExpOrb.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"
@@ -25,12 +31,15 @@ Implements the 1.7.x protocol classes:
#include "../Entities/Pickup.h"
#include "../Entities/Player.h"
#include "../Entities/ItemFrame.h"
+#include "../Entities/ArrowEntity.h"
+#include "../Entities/FireworkEntity.h"
+
#include "../Mobs/IncludeAllMonsters.h"
#include "../UI/Window.h"
+
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
-#include "../CompositeChat.h"
@@ -88,8 +97,9 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
// Create the comm log file, if so requested:
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
{
+ static int sCounter = 0;
cFile::CreateFolder("CommLogs");
- AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
+ AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(NULL), sCounter++, a_Client->GetIPString().c_str());
m_CommLogFile.Open(FileName, cFile::fmWrite);
}
}
@@ -124,6 +134,8 @@ void cProtocol172::DataReceived(const char * a_Data, size_t a_Size)
void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x1b); // Attach Entity packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0);
@@ -136,6 +148,8 @@ void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_
void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x24); // Block Action packet
Pkt.WriteInt(a_BlockX);
Pkt.WriteShort(a_BlockY);
@@ -151,6 +165,8 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
Pkt.WriteVarInt(a_EntityID);
Pkt.WriteInt(a_BlockX);
@@ -165,6 +181,8 @@ void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY
void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x23); // Block Change packet
Pkt.WriteInt(a_BlockX);
Pkt.WriteByte(a_BlockY);
@@ -179,11 +197,13 @@ void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x22); // Multi Block Change packet
Pkt.WriteInt(a_ChunkX);
Pkt.WriteInt(a_ChunkZ);
Pkt.WriteShort((short)a_Changes.size());
- Pkt.WriteInt(a_Changes.size() * 4);
+ Pkt.WriteInt((int)a_Changes.size() * 4);
for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr)
{
unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12);
@@ -198,6 +218,8 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
void cProtocol172::SendChat(const AString & a_Message)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x02); // Chat Message packet
Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()));
}
@@ -208,9 +230,12 @@ void cProtocol172::SendChat(const AString & a_Message)
void cProtocol172::SendChat(const cCompositeChat & a_Message)
{
+ ASSERT(m_State == 3); // In game mode?
+
// Compose the complete Json string to send:
Json::Value msg;
- msg["text"] = ""; // The client crashes without this
+ cWorld * World = m_Client->GetPlayer()->GetWorld();
+ msg["text"] = cClientHandle::FormatMessageType((World == NULL) ? false : World->ShouldUseChatPrefixes(), a_Message.GetMessageType(), a_Message.GetAdditionalMessageTypeData()); // The client crashes without this field being present
const cCompositeChat::cParts & Parts = a_Message.GetParts();
for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr)
{
@@ -265,6 +290,35 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message)
AddChatPartStyle(Part, p.m_Style);
break;
}
+
+ case cCompositeChat::ptShowAchievement:
+ {
+ const cCompositeChat::cShowAchievementPart & p = (const cCompositeChat::cShowAchievementPart &)**itr;
+ Part["translate"] = "chat.type.achievement";
+
+ Json::Value Ach;
+ Ach["action"] = "show_achievement";
+ Ach["value"] = p.m_Text;
+
+ Json::Value AchColourAndName;
+ AchColourAndName["color"] = "green";
+ AchColourAndName["translate"] = p.m_Text;
+ AchColourAndName["hoverEvent"] = Ach;
+
+ Json::Value Extra;
+ Extra.append(AchColourAndName);
+
+ Json::Value Name;
+ Name["text"] = p.m_PlayerName;
+
+ Json::Value With;
+ With.append(Name);
+ With.append(Extra);
+
+ Part["with"] = With;
+ AddChatPartStyle(Part, p.m_Style);
+ break;
+ }
}
msg["extra"].append(Part);
} // for itr - Parts[]
@@ -280,6 +334,8 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message)
void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{
+ ASSERT(m_State == 3); // In game mode?
+
// Serialize first, before creating the Packetizer (the packetizer locks a CS)
// This contains the flags and bitmasks, too
const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2);
@@ -296,6 +352,8 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x0d); // Collect Item packet
Pkt.WriteInt(a_Pickup.GetUniqueID());
Pkt.WriteInt(a_Player.GetUniqueID());
@@ -307,6 +365,8 @@ void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a
void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x13); // Destroy Entities packet
Pkt.WriteByte(1);
Pkt.WriteInt(a_Entity.GetUniqueID());
@@ -343,6 +403,8 @@ void cProtocol172::SendDisconnect(const AString & a_Reason)
void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet
Pkt.WriteInt(a_BlockX);
Pkt.WriteInt(a_BlockY);
@@ -355,6 +417,8 @@ void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x1D); // Entity Effect packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_EffectID);
@@ -368,6 +432,8 @@ void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in
void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x04); // Entity Equipment packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteShort(a_SlotNum);
@@ -380,6 +446,8 @@ void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum
void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x19); // Entity Head Look packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
@@ -391,6 +459,8 @@ void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
void cProtocol172::SendEntityLook(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x16); // Entity Look packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetYaw());
@@ -403,6 +473,8 @@ void cProtocol172::SendEntityLook(const cEntity & a_Entity)
void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteEntityMetadata(a_Entity);
@@ -415,6 +487,8 @@ void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
void cProtocol172::SendEntityProperties(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x20); // Entity Properties packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteEntityProperties(a_Entity);
@@ -426,6 +500,8 @@ void cProtocol172::SendEntityProperties(const cEntity & a_Entity)
void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_RelX);
@@ -439,6 +515,8 @@ void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char
void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_RelX);
@@ -454,6 +532,8 @@ void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x1a); // Entity Status packet
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteChar(a_Status);
@@ -465,6 +545,8 @@ void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x12); // Entity Velocity packet
Pkt.WriteInt(a_Entity.GetUniqueID());
// 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick
@@ -479,12 +561,14 @@ void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x27); // Explosion packet
Pkt.WriteFloat((float)a_BlockX);
Pkt.WriteFloat((float)a_BlockY);
Pkt.WriteFloat((float)a_BlockZ);
Pkt.WriteFloat((float)a_Radius);
- Pkt.WriteInt(a_BlocksAffected.size());
+ Pkt.WriteInt((int)a_BlocksAffected.size());
for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr)
{
Pkt.WriteChar((char)itr->x);
@@ -502,6 +586,8 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc
void cProtocol172::SendGameMode(eGameMode a_GameMode)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
Pkt.WriteByte(3); // Reason: Change game mode
Pkt.WriteFloat((float)a_GameMode);
@@ -513,10 +599,13 @@ void cProtocol172::SendGameMode(eGameMode a_GameMode)
void cProtocol172::SendHealth(void)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x06); // Update Health packet
- Pkt.WriteFloat((float)m_Client->GetPlayer()->GetHealth());
- Pkt.WriteShort(m_Client->GetPlayer()->GetFoodLevel());
- Pkt.WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
+ cPlayer * Player = m_Client->GetPlayer();
+ Pkt.WriteFloat((float)Player->GetHealth());
+ Pkt.WriteShort(Player->GetFoodLevel());
+ Pkt.WriteFloat((float)Player->GetFoodSaturationLevel());
}
@@ -525,6 +614,8 @@ void cProtocol172::SendHealth(void)
void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x2f); // Set Slot packet
Pkt.WriteChar(a_WindowID);
Pkt.WriteShort(a_SlotNum);
@@ -537,6 +628,13 @@ void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt
void cProtocol172::SendKeepAlive(int a_PingID)
{
+ // Drop the packet if the protocol is not in the Game state yet (caused a client crash):
+ if (m_State != 3)
+ {
+ LOGWARNING("Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet.", m_State);
+ return;
+ }
+
cPacketizer Pkt(*this, 0x00); // Keep Alive packet
Pkt.WriteInt(a_PingID);
}
@@ -549,12 +647,13 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
// Send the Join Game packet:
{
+ cServer * Server = cRoot::Get()->GetServer();
cPacketizer Pkt(*this, 0x01); // Join Game packet
Pkt.WriteInt(a_Player.GetUniqueID());
- Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (cRoot::Get()->GetServer()->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
+ Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
Pkt.WriteChar((char)a_World.GetDimension());
Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
- Pkt.WriteByte(std::min(cRoot::Get()->GetServer()->GetMaxPlayers(), 60));
+ Pkt.WriteByte(std::min(Server->GetMaxPlayers(), 60));
Pkt.WriteString("default"); // Level type - wtf?
}
@@ -573,8 +672,27 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+void cProtocol172::SendLoginSuccess(void)
+{
+ ASSERT(m_State == 2); // State: login?
+
+ {
+ cPacketizer Pkt(*this, 0x02); // Login success packet
+ Pkt.WriteString(m_Client->GetUUID());
+ Pkt.WriteString(m_Client->GetUsername());
+ }
+
+ m_State = 3; // State = Game
+}
+
+
+
+
+
void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
Pkt.WriteVarInt(a_Painting.GetUniqueID());
Pkt.WriteString(a_Painting.GetName().c_str());
@@ -590,6 +708,8 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x34);
Pkt.WriteVarInt(a_ID);
Pkt.WriteShort (3 + a_Length);
@@ -610,9 +730,11 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo
void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x34);
Pkt.WriteVarInt(a_ID);
- Pkt.WriteShort (1 + (3 * a_Decorators.size()));
+ Pkt.WriteShort ((short)(1 + (3 * a_Decorators.size())));
Pkt.WriteByte(1);
@@ -630,6 +752,8 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x34);
Pkt.WriteVarInt(a_ID);
Pkt.WriteShort (2);
@@ -645,6 +769,8 @@ void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
{
+ ASSERT(m_State == 3); // In game mode?
+
{
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
Pkt.WriteVarInt(a_Pickup.GetUniqueID());
@@ -671,24 +797,27 @@ void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
void cProtocol172::SendPlayerAbilities(void)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x39); // Player Abilities packet
Byte Flags = 0;
- if (m_Client->GetPlayer()->IsGameModeCreative())
+ cPlayer * Player = m_Client->GetPlayer();
+ if (Player->IsGameModeCreative())
{
Flags |= 0x01;
Flags |= 0x08; // Godmode, used for creative
}
- if (m_Client->GetPlayer()->IsFlying())
+ if (Player->IsFlying())
{
Flags |= 0x02;
}
- if (m_Client->GetPlayer()->CanFly())
+ if (Player->CanFly())
{
Flags |= 0x04;
}
Pkt.WriteByte(Flags);
- Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed()));
- Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed()));
+ Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed()));
+ Pkt.WriteFloat((float)(0.1 * Player->GetMaxSpeed()));
}
@@ -697,6 +826,8 @@ void cProtocol172::SendPlayerAbilities(void)
void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x0b); // Animation packet
Pkt.WriteVarInt(a_Entity.GetUniqueID());
Pkt.WriteChar(a_Animation);
@@ -708,6 +839,8 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x2A);
Pkt.WriteString(a_ParticleName);
Pkt.WriteFloat(a_SrcX);
@@ -726,6 +859,8 @@ void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_Sr
void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
Pkt.WriteString(a_Player.GetName());
Pkt.WriteBool(a_IsOnline);
@@ -738,18 +873,21 @@ void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
void cProtocol172::SendPlayerMaxSpeed(void)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x20); // Entity Properties
- Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID());
+ cPlayer * Player = m_Client->GetPlayer();
+ Pkt.WriteInt(Player->GetUniqueID());
Pkt.WriteInt(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
- Pkt.WriteDouble(0.1 * m_Client->GetPlayer()->GetNormalMaxSpeed());
- if (m_Client->GetPlayer()->IsSprinting())
+ Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed());
+ if (Player->IsSprinting())
{
Pkt.WriteShort(1); // Modifier count
Pkt.WriteInt64(0x662a6b8dda3e4c1c);
Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier
- Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed());
+ Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
Pkt.WriteByte(2);
}
else
@@ -764,17 +902,20 @@ void cProtocol172::SendPlayerMaxSpeed(void)
void cProtocol172::SendPlayerMoveLook(void)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
- Pkt.WriteDouble(m_Client->GetPlayer()->GetPosX());
+ cPlayer * Player = m_Client->GetPlayer();
+ Pkt.WriteDouble(Player->GetPosX());
// Protocol docs say this is PosY, but #323 says this is eye-pos
// Moreover, the "+ 0.001" is there because otherwise the player falls through the block they were standing on.
- Pkt.WriteDouble(m_Client->GetPlayer()->GetStance() + 0.001);
+ Pkt.WriteDouble(Player->GetStance() + 0.001);
- Pkt.WriteDouble(m_Client->GetPlayer()->GetPosZ());
- Pkt.WriteFloat((float)m_Client->GetPlayer()->GetYaw());
- Pkt.WriteFloat((float)m_Client->GetPlayer()->GetPitch());
- Pkt.WriteBool(m_Client->GetPlayer()->IsOnGround());
+ Pkt.WriteDouble(Player->GetPosZ());
+ Pkt.WriteFloat((float)Player->GetYaw());
+ Pkt.WriteFloat((float)Player->GetPitch());
+ Pkt.WriteBool(Player->IsOnGround());
}
@@ -793,10 +934,12 @@ void cProtocol172::SendPlayerPosition(void)
void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
{
+ ASSERT(m_State == 3); // In game mode?
+
// Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
Pkt.WriteVarInt(a_Player.GetUniqueID());
- Pkt.WriteString(Printf("%d", a_Player.GetUniqueID())); // TODO: Proper UUID
+ Pkt.WriteString(a_Player.GetClientHandle()->GetUUID());
Pkt.WriteString(a_Player.GetName());
Pkt.WriteFPInt(a_Player.GetPosX());
Pkt.WriteFPInt(a_Player.GetPosY());
@@ -816,6 +959,8 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x3f);
Pkt.WriteString(a_Channel);
Pkt.WriteShort((short)a_Message.size());
@@ -828,7 +973,9 @@ void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString &
void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
- cPacketizer Pkt(*this, 0x1E);
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x1e);
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_EffectID);
}
@@ -840,9 +987,10 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
void cProtocol172::SendRespawn(void)
{
cPacketizer Pkt(*this, 0x07); // Respawn packet
- Pkt.WriteInt(m_Client->GetPlayer()->GetWorld()->GetDimension());
+ cPlayer * Player = m_Client->GetPlayer();
+ Pkt.WriteInt(Player->GetWorld()->GetDimension());
Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
- Pkt.WriteByte((Byte)m_Client->GetPlayer()->GetEffectiveGameMode());
+ Pkt.WriteByte((Byte)Player->GetEffectiveGameMode());
Pkt.WriteString("default");
}
@@ -852,10 +1000,13 @@ void cProtocol172::SendRespawn(void)
void cProtocol172::SendExperience (void)
{
- cPacketizer Pkt(*this, 0x1F); //Experience Packet
- Pkt.WriteFloat(m_Client->GetPlayer()->GetXpPercentage());
- Pkt.WriteShort(m_Client->GetPlayer()->GetXpLevel());
- Pkt.WriteShort(m_Client->GetPlayer()->GetCurrentXp());
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x1f); // Experience Packet
+ cPlayer * Player = m_Client->GetPlayer();
+ Pkt.WriteFloat(Player->GetXpPercentage());
+ Pkt.WriteShort(Player->GetXpLevel());
+ Pkt.WriteShort(Player->GetCurrentXp());
}
@@ -864,6 +1015,8 @@ void cProtocol172::SendExperience (void)
void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x11);
Pkt.WriteVarInt(a_ExpOrb.GetUniqueID());
Pkt.WriteInt((int) a_ExpOrb.GetPosX());
@@ -878,7 +1031,9 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
{
- cPacketizer Pkt(*this, 0x3B);
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x3b);
Pkt.WriteString(a_Name);
Pkt.WriteString(a_DisplayName);
Pkt.WriteByte(a_Mode);
@@ -890,7 +1045,9 @@ void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString
void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
{
- cPacketizer Pkt(*this, 0x3C);
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x3c);
Pkt.WriteString(a_Player);
Pkt.WriteByte(a_Mode);
@@ -907,7 +1064,9 @@ void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString &
void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display)
{
- cPacketizer Pkt(*this, 0x3D);
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x3d);
Pkt.WriteByte((int) a_Display);
Pkt.WriteString(a_Objective);
}
@@ -918,6 +1077,8 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard
void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
Pkt.WriteString(a_SoundName);
Pkt.WriteInt(a_SrcX);
@@ -933,6 +1094,8 @@ void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int
void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x28); // Effect packet
Pkt.WriteInt(a_EffectID);
Pkt.WriteInt(a_SrcX);
@@ -948,6 +1111,8 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
Pkt.WriteVarInt(a_FallingBlock.GetUniqueID());
Pkt.WriteByte(70); // Falling block
@@ -968,6 +1133,8 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet
Pkt.WriteVarInt(a_Mob.GetUniqueID());
Pkt.WriteByte((Byte)a_Mob.GetMobType());
@@ -990,6 +1157,8 @@ void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
Pkt.WriteVarInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_ObjectType);
@@ -1013,6 +1182,8 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType,
void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
Pkt.WriteVarInt(a_Vehicle.GetUniqueID());
Pkt.WriteByte(a_VehicleType);
@@ -1034,10 +1205,34 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
+void cProtocol172::SendStatistics(const cStatManager & a_Manager)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x37);
+ Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
+
+ for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
+ {
+ StatValue Value = a_Manager.GetValue((eStatistic) i);
+
+ const AString & StatName = cStatInfo::GetName((eStatistic) i);
+
+ Pkt.WriteString(StatName);
+ Pkt.WriteVarInt(Value);
+ }
+}
+
+
+
+
+
void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet
- Pkt.WriteVarInt(a_Results.size());
+ Pkt.WriteVarInt((int)a_Results.size());
for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr)
{
@@ -1051,6 +1246,8 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x18);
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteFPInt(a_Entity.GetPosX());
@@ -1066,6 +1263,8 @@ void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet
Pkt.WriteVarInt(0); // EntityID = 0, always
Pkt.WriteByte(1); // Type = Thunderbolt
@@ -1080,6 +1279,8 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x03);
Pkt.WriteInt64(a_WorldAge);
Pkt.WriteInt64(a_TimeOfDay);
@@ -1091,6 +1292,8 @@ void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
Pkt.WriteInt(a_ChunkX);
Pkt.WriteInt(a_ChunkZ);
@@ -1105,6 +1308,8 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x35); // Update tile entity packet
Pkt.WriteInt(a_BlockEntity.GetPosX());
Pkt.WriteShort(a_BlockEntity.GetPosY());
@@ -1130,6 +1335,8 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x33);
Pkt.WriteInt(a_BlockX);
Pkt.WriteShort((short)a_BlockY);
@@ -1147,6 +1354,8 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x0a);
Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteInt(a_BlockX);
@@ -1160,6 +1369,8 @@ void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc
void cProtocol172::SendWeather(eWeather a_Weather)
{
+ ASSERT(m_State == 3); // In game mode?
+
{
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
@@ -1175,6 +1386,8 @@ void cProtocol172::SendWeather(eWeather a_Weather)
void cProtocol172::SendWholeInventory(const cWindow & a_Window)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x30); // Window Items packet
Pkt.WriteChar(a_Window.GetWindowID());
Pkt.WriteShort(a_Window.GetNumSlots());
@@ -1192,6 +1405,8 @@ void cProtocol172::SendWholeInventory(const cWindow & a_Window)
void cProtocol172::SendWindowClose(const cWindow & a_Window)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x2e);
Pkt.WriteChar(a_Window.GetWindowID());
}
@@ -1202,6 +1417,8 @@ void cProtocol172::SendWindowClose(const cWindow & a_Window)
void cProtocol172::SendWindowOpen(const cWindow & a_Window)
{
+ ASSERT(m_State == 3); // In game mode?
+
if (a_Window.GetWindowType() < 0)
{
// Do not send this packet for player inventory windows
@@ -1224,8 +1441,10 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window)
-void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
+void cProtocol172::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value)
{
+ ASSERT(m_State == 3); // In game mode?
+
cPacketizer Pkt(*this, 0x31); // Window Property packet
Pkt.WriteChar(a_Window.GetWindowID());
Pkt.WriteShort(a_Property);
@@ -1236,7 +1455,7 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property
-void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
+void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size)
{
// Write the incoming data into the comm log file:
if (g_ShouldLogCommIn)
@@ -1258,7 +1477,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
AString Hex;
CreateHexDump(Hex, a_Data, a_Size, 16);
m_CommLogFile.Printf("Incoming data: %d (0x%x) bytes: \n%s\n",
- a_Size, a_Size, Hex.c_str()
+ (unsigned)a_Size, (unsigned)a_Size, Hex.c_str()
);
m_CommLogFile.Flush();
}
@@ -1431,6 +1650,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true;
case 0x0f: // Confirm transaction - not used in MCS
case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
+ case 0x11: HandlePacketEnchantItem (a_ByteBuffer); return true;
case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true;
case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true;
@@ -1485,15 +1705,16 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
{
// Send the response:
AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{";
+ cServer * Server = cRoot::Get()->GetServer();
AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},",
- cRoot::Get()->GetServer()->GetMaxPlayers(),
- cRoot::Get()->GetServer()->GetNumPlayers()
+ Server->GetMaxPlayers(),
+ Server->GetNumPlayers()
);
AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},",
- cRoot::Get()->GetServer()->GetDescription().c_str()
+ Server->GetDescription().c_str()
);
AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"",
- cRoot::Get()->GetServer()->GetFaviconData().c_str()
+ Server->GetFaviconData().c_str()
);
Response.append("}");
@@ -1528,7 +1749,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
}
// Decrypt EncNonce using privkey
- cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
+ cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
if (res != 4)
@@ -1555,15 +1776,6 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
}
StartEncryption(DecryptedKey);
-
- // Send login success:
- {
- cPacketizer Pkt(*this, 0x02); // Login success packet
- Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
- Pkt.WriteString(m_Client->GetUsername());
- }
-
- m_State = 3; // State = Game
m_Client->HandleLogin(4, m_Client->GetUsername());
}
@@ -1582,13 +1794,14 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
return;
}
+ cServer * Server = cRoot::Get()->GetServer();
// If auth is required, then send the encryption request:
- if (cRoot::Get()->GetServer()->ShouldAuthenticate())
+ if (Server->ShouldAuthenticate())
{
cPacketizer Pkt(*this, 0x01);
- Pkt.WriteString(cRoot::Get()->GetServer()->GetServerID());
- const AString & PubKeyDer = cRoot::Get()->GetServer()->GetPublicKeyDER();
- Pkt.WriteShort(PubKeyDer.size());
+ Pkt.WriteString(Server->GetServerID());
+ const AString & PubKeyDer = Server->GetPublicKeyDER();
+ Pkt.WriteShort((short)PubKeyDer.size());
Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
Pkt.WriteShort(4);
Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
@@ -1596,14 +1809,6 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
return;
}
- // Send login success:
- {
- cPacketizer Pkt(*this, 0x02); // Login success packet
- Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
- Pkt.WriteString(Username);
- }
-
- m_State = 3; // State = Game
m_Client->HandleLogin(4, Username);
}
@@ -1696,13 +1901,15 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
case 1:
{
// Request stats
- // TODO
+ const cStatManager & Manager = m_Client->GetPlayer()->GetStatManager();
+ SendStatistics(Manager);
+
break;
}
case 2:
{
// Open Inventory achievement
- // TODO
+ m_Client->GetPlayer()->AwardAchievement(achOpenInv);
break;
}
}
@@ -1912,6 +2119,18 @@ void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
+void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer)
+{
+ HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment);
+
+ m_Client->HandleEnchantItem(WindowID, Enchantment);
+}
+
+
+
+
+
void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
@@ -1979,7 +2198,7 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet)
cCSLock Lock(m_CSPacket);
AString Pkt;
a_Packet.ReadAll(Pkt);
- WriteVarInt(Pkt.size());
+ WriteVarInt((UInt32)Pkt.size());
SendData(Pkt.data(), Pkt.size());
Flush();
}
@@ -1988,14 +2207,14 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet)
-void cProtocol172::SendData(const char * a_Data, int a_Size)
+void cProtocol172::SendData(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
- size_t NumBytes = ((size_t)a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : (size_t)a_Size;
+ size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
m_Client->SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
@@ -2119,6 +2338,13 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
}
break;
}
+ case TAG_Int:
+ {
+ if (TagName == "RepairCost")
+ {
+ a_Item.m_RepairCost = NBT.GetInt(tag);
+ }
+ }
default: LOGD("Unimplemented NBT data when parsing!"); break;
}
}
@@ -2135,14 +2361,15 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
- cSHA1Checksum Checksum;
- const AString & ServerID = cRoot::Get()->GetServer()->GetServerID();
+ cSha1Checksum Checksum;
+ cServer * Server = cRoot::Get()->GetServer();
+ const AString & ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
Checksum.Update(a_Key, 16);
- Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
+ Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
+ cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
}
@@ -2236,7 +2463,7 @@ cProtocol172::cPacketizer::~cPacketizer()
AString DataToSend;
// Send the packet length
- UInt32 PacketLen = m_Out.GetUsedSpace();
+ UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace();
m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen);
m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend);
m_Protocol.SendData(DataToSend.data(), DataToSend.size());
@@ -2291,6 +2518,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
// Send the enchantments and custom names:
cFastNBTWriter Writer;
+ if (a_Item.m_RepairCost != 0)
+ {
+ Writer.AddInt("RepairCost", a_Item.m_RepairCost);
+ }
if (!a_Item.m_Enchantments.IsEmpty())
{
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
@@ -2329,7 +2560,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
- WriteShort(Compressed.size());
+ WriteShort((short)Compressed.size());
WriteBuf(Compressed.data(), Compressed.size());
}
@@ -2399,7 +2630,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
- WriteShort(Compressed.size());
+ WriteShort((short)Compressed.size());
WriteBuf(Compressed.data(), Compressed.size());
}
@@ -2481,11 +2712,12 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
{
cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
- if (!RideableMinecart.GetContent().IsEmpty())
+ const cItem & MinecartContent = RideableMinecart.GetContent();
+ if (!MinecartContent.IsEmpty())
{
WriteByte(0x54);
- int Content = RideableMinecart.GetContent().m_ItemType;
- Content |= RideableMinecart.GetContent().m_ItemDamage << 8;
+ int Content = MinecartContent.m_ItemType;
+ Content |= MinecartContent.m_ItemDamage << 8;
WriteInt(Content);
WriteByte(0x55);
WriteInt(RideableMinecart.GetBlockHeight());
@@ -2535,6 +2767,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteByte(Frame.GetRotation());
break;
}
+ default: break;
}
}
@@ -2659,6 +2892,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).GetWitherInvulnerableTicks());
+ WriteByte(0x66); // Float at index 6
+ WriteFloat((float)(a_Mob.GetHealth()));
+ break;
+ }
case cMonster::mtSlime:
{
@@ -2745,3 +2987,64 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity)
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cProtocol176:
+
+cProtocol176::cProtocol176(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
+ super(a_Client, a_ServerAddress, a_ServerPort, a_State)
+{
+}
+
+
+
+
+
+void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
+{
+ // Called to spawn another player for the client
+ cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
+ Pkt.WriteVarInt(a_Player.GetUniqueID());
+ Pkt.WriteString(a_Player.GetClientHandle()->GetUUID());
+ Pkt.WriteString(a_Player.GetName());
+ Pkt.WriteVarInt(0); // We have no data to send here
+ Pkt.WriteFPInt(a_Player.GetPosX());
+ Pkt.WriteFPInt(a_Player.GetPosY());
+ Pkt.WriteFPInt(a_Player.GetPosZ());
+ Pkt.WriteByteAngle(a_Player.GetYaw());
+ Pkt.WriteByteAngle(a_Player.GetPitch());
+ short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
+ Pkt.WriteShort(ItemType);
+ Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6
+ Pkt.WriteFloat((float)a_Player.GetHealth());
+ Pkt.WriteByte(0x7f); // Metadata: end
+}
+
+
+
+
+
+void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
+{
+ // Send the response:
+ AString Response = "{\"version\":{\"name\":\"1.7.6\",\"protocol\":5},\"players\":{";
+ AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},",
+ cRoot::Get()->GetServer()->GetMaxPlayers(),
+ cRoot::Get()->GetServer()->GetNumPlayers()
+ );
+ AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},",
+ cRoot::Get()->GetServer()->GetDescription().c_str()
+ );
+ AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"",
+ cRoot::Get()->GetServer()->GetFaviconData().c_str()
+ );
+ Response.append("}");
+
+ cPacketizer Pkt(*this, 0x00); // Response packet
+ Pkt.WriteString(Response);
+}
+
+
+
+
+
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 41163009e..3c6a8c085 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -30,7 +30,8 @@ Declares the 1.7.x protocol classes:
#pragma warning(pop)
#endif
-#include "../Crypto.h"
+#include "PolarSSL++/AesCfb128Decryptor.h"
+#include "PolarSSL++/AesCfb128Encryptor.h"
@@ -87,6 +88,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
+ virtual void SendLoginSuccess (void) override;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
@@ -114,6 +116,7 @@ public:
virtual void SendSpawnMob (const cMonster & a_Mob) override;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
+ virtual void SendStatistics (const cStatManager & a_Manager) override;
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
@@ -126,7 +129,7 @@ public:
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
virtual void SendWindowOpen (const cWindow & a_Window) override;
- virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override;
+ virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override;
virtual AString GetAuthServerID(void) override { return m_AuthServerID; }
@@ -196,7 +199,7 @@ protected:
m_Out.WriteVarUTF8String(a_Value);
}
- void WriteBuf(const char * a_Data, int a_Size)
+ void WriteBuf(const char * a_Data, size_t a_Size)
{
m_Out.Write(a_Data, a_Size);
}
@@ -235,15 +238,15 @@ protected:
bool m_IsEncrypted;
- cAESCFBDecryptor m_Decryptor;
- cAESCFBEncryptor m_Encryptor;
+ cAesCfb128Decryptor m_Decryptor;
+ cAesCfb128Encryptor m_Encryptor;
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;
/** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */
- void AddReceivedData(const char * a_Data, int a_Size);
+ void AddReceivedData(const char * a_Data, size_t a_Size);
/** Reads and handles the packet. The packet length and type have already been read.
Returns true if the packet was understood, false if it was an unknown packet
@@ -252,7 +255,7 @@ protected:
// Packet handlers while in the Status state (m_State == 1):
void HandlePacketStatusPing (cByteBuffer & a_ByteBuffer);
- void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer);
+ virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer);
// Packet handlers while in the Login state (m_State == 2):
void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer);
@@ -279,6 +282,7 @@ protected:
void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer);
void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer);
void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer);
+ void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer);
void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer);
void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer);
@@ -287,7 +291,7 @@ protected:
void WritePacket(cByteBuffer & a_Packet);
/** Sends the data to the client, encrypting them if needed. */
- virtual void SendData(const char * a_Data, int a_Size) override;
+ virtual void SendData(const char * a_Data, size_t a_Size) override;
void SendCompass(const cWorld & a_World);
@@ -306,3 +310,22 @@ protected:
+
+/** The version 5 lengthed protocol, used by 1.7.6 through 1.7.9. */
+class cProtocol176 :
+ public cProtocol172
+{
+ typedef cProtocol172 super;
+
+public:
+ cProtocol176(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
+
+ // cProtocol172 overrides:
+ virtual void SendPlayerSpawn(const cPlayer & a_Player) override;
+ virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
+
+} ;
+
+
+
+
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 3b9003e60..b0cbb6def 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -59,6 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
case PROTO_VERSION_1_6_3: return "1.6.3";
case PROTO_VERSION_1_6_4: return "1.6.4";
case PROTO_VERSION_1_7_2: return "1.7.2";
+ case PROTO_VERSION_1_7_6: return "1.7.6";
}
ASSERT(!"Unknown protocol version");
return Printf("Unknown protocol (%d)", a_ProtocolVersion);
@@ -356,7 +357,7 @@ void cProtocolRecognizer::SendHealth(void)
-void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
+void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value)
{
ASSERT(m_Protocol != NULL);
m_Protocol->SendWindowProperty(a_Window, a_Property, a_Value);
@@ -396,6 +397,16 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W
+void cProtocolRecognizer::SendLoginSuccess(void)
+{
+ ASSERT(m_Protocol != NULL);
+ m_Protocol->SendLoginSuccess();
+}
+
+
+
+
+
void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
{
ASSERT(m_Protocol != NULL);
@@ -664,6 +675,16 @@ void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_Veh
+void cProtocolRecognizer::SendStatistics(const cStatManager & a_Manager)
+{
+ ASSERT(m_Protocol != NULL);
+ m_Protocol->SendStatistics(a_Manager);
+}
+
+
+
+
+
void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Results)
{
ASSERT(m_Protocol != NULL);
@@ -794,7 +815,7 @@ AString cProtocolRecognizer::GetAuthServerID(void)
-void cProtocolRecognizer::SendData(const char * a_Data, int a_Size)
+void cProtocolRecognizer::SendData(const char * a_Data, size_t a_Size)
{
// This is used only when handling the server ping
m_Client->SendData(a_Data, a_Size);
@@ -854,13 +875,13 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void)
// This must be a lengthed protocol, try if it has the entire initial handshake packet:
m_Buffer.ResetRead();
UInt32 PacketLen;
- UInt32 ReadSoFar = m_Buffer.GetReadableSpace();
+ UInt32 ReadSoFar = (UInt32)m_Buffer.GetReadableSpace();
if (!m_Buffer.ReadVarInt(PacketLen))
{
// Not enough bytes for the packet length, keep waiting
return false;
}
- ReadSoFar -= m_Buffer.GetReadableSpace();
+ ReadSoFar -= (UInt32)m_Buffer.GetReadableSpace();
if (!m_Buffer.CanReadBytes(PacketLen))
{
// Not enough bytes for the packet, keep waiting
@@ -931,7 +952,7 @@ bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void)
bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining)
{
UInt32 PacketType;
- UInt32 NumBytesRead = m_Buffer.GetReadableSpace();
+ UInt32 NumBytesRead = (UInt32)m_Buffer.GetReadableSpace();
if (!m_Buffer.ReadVarInt(PacketType))
{
return false;
@@ -950,7 +971,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
{
return false;
}
- NumBytesRead -= m_Buffer.GetReadableSpace();
+ NumBytesRead -= (UInt32)m_Buffer.GetReadableSpace();
switch (ProtocolVersion)
{
case PROTO_VERSION_1_7_2:
@@ -962,7 +983,19 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
m_Buffer.ReadBEShort(ServerPort);
m_Buffer.ReadVarInt(NextState);
m_Buffer.CommitRead();
- m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState);
+ m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
+ return true;
+ }
+ case PROTO_VERSION_1_7_6:
+ {
+ AString ServerAddress;
+ short ServerPort;
+ UInt32 NextState;
+ m_Buffer.ReadVarUTF8String(ServerAddress);
+ m_Buffer.ReadBEShort(ServerPort);
+ m_Buffer.ReadVarInt(NextState);
+ m_Buffer.CommitRead();
+ m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
return true;
}
}
@@ -980,6 +1013,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
void cProtocolRecognizer::SendLengthlessServerPing(void)
{
AString Reply;
+ cServer * Server = cRoot::Get()->GetServer();
switch (cRoot::Get()->GetPrimaryServerVersion())
{
case PROTO_VERSION_1_2_5:
@@ -987,11 +1021,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
{
// http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29
Printf(Reply, "%s%s%i%s%i",
- cRoot::Get()->GetServer()->GetDescription().c_str(),
+ Server->GetDescription().c_str(),
cChatColor::Delimiter.c_str(),
- cRoot::Get()->GetServer()->GetNumPlayers(),
+ Server->GetNumPlayers(),
cChatColor::Delimiter.c_str(),
- cRoot::Get()->GetServer()->GetMaxPlayers()
+ Server->GetMaxPlayers()
);
break;
}
@@ -1021,9 +1055,9 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
// http://wiki.vg/wiki/index.php?title=Server_List_Ping&oldid=3100
AString NumPlayers;
- Printf(NumPlayers, "%d", cRoot::Get()->GetServer()->GetNumPlayers());
+ Printf(NumPlayers, "%d", Server->GetNumPlayers());
AString MaxPlayers;
- Printf(MaxPlayers, "%d", cRoot::Get()->GetServer()->GetMaxPlayers());
+ Printf(MaxPlayers, "%d", Server->GetMaxPlayers());
AString ProtocolVersionNum;
Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion());
@@ -1037,7 +1071,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
Reply.push_back(0);
Reply.append(ProtocolVersionTxt);
Reply.push_back(0);
- Reply.append(cRoot::Get()->GetServer()->GetDescription());
+ Reply.append(Server->GetDescription());
Reply.push_back(0);
Reply.append(NumPlayers);
Reply.push_back(0);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index d7fb8fad2..3a291bf7a 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -18,8 +18,8 @@
// Adjust these if a new protocol is added or an old one is removed:
-#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4"
-#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4"
+#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9"
+#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4, 5"
@@ -50,6 +50,7 @@ public:
// These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols
PROTO_VERSION_1_7_2 = 4,
+ PROTO_VERSION_1_7_6 = 5,
} ;
cProtocolRecognizer(cClientHandle * a_Client);
@@ -90,6 +91,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
+ virtual void SendLoginSuccess (void) override;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
@@ -117,6 +119,7 @@ public:
virtual void SendSpawnMob (const cMonster & a_Mob) override;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
+ virtual void SendStatistics (const cStatManager & a_Manager) override;
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
@@ -129,11 +132,11 @@ public:
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
virtual void SendWindowOpen (const cWindow & a_Window) override;
- virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override;
+ virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override;
virtual AString GetAuthServerID(void) override;
- virtual void SendData(const char * a_Data, int a_Size) override;
+ virtual void SendData(const char * a_Data, size_t a_Size) override;
protected:
cProtocol * m_Protocol; //< The recognized protocol
diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp
index 72f2d9ba9..c511968be 100644
--- a/src/RCONServer.cpp
+++ b/src/RCONServer.cpp
@@ -59,7 +59,7 @@ public:
virtual void Finished(void) override
{
- m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, m_Buffer.size(), m_Buffer.c_str());
+ m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, (int)m_Buffer.size(), m_Buffer.c_str());
delete this;
}
@@ -169,7 +169,7 @@ cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_So
-void cRCONServer::cConnection::DataReceived(const char * a_Data, int a_Size)
+bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
{
// Append data to the buffer:
m_Buffer.append(a_Data, a_Size);
@@ -187,12 +187,12 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, int a_Size)
m_RCONServer.m_SocketThreads.RemoveClient(this);
m_Socket.CloseSocket();
delete this;
- return;
+ return false;
}
if (Length > (int)(m_Buffer.size() + 4))
{
// Incomplete packet yet, wait for more data to come
- return;
+ return false;
}
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
@@ -202,10 +202,11 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, int a_Size)
m_RCONServer.m_SocketThreads.RemoveClient(this);
m_Socket.CloseSocket();
delete this;
- return;
+ return false;
}
m_Buffer.erase(0, Length + 4);
} // while (m_Buffer.size() >= 14)
+ return false;
}
diff --git a/src/RCONServer.h b/src/RCONServer.h
index 88aac4b5f..47c746736 100644
--- a/src/RCONServer.h
+++ b/src/RCONServer.h
@@ -65,7 +65,7 @@ protected:
// cSocketThreads::cCallback overrides:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
virtual void GetOutgoingData(AString & a_Data) override;
virtual void SocketClosed(void) override;
diff --git a/src/Root.cpp b/src/Root.cpp
index 3555afb45..c82b05a66 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");
}
}
@@ -498,9 +499,9 @@ void cRoot::KickUser(int a_ClientID, const AString & a_Reason)
-void cRoot::AuthenticateUser(int a_ClientID)
+void cRoot::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID)
{
- m_Server->AuthenticateUser(a_ClientID);
+ m_Server->AuthenticateUser(a_ClientID, a_Name, a_UUID);
}
@@ -589,13 +590,13 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
{
class cCallback : public cPlayerListCallback
{
- unsigned m_BestRating;
- unsigned m_NameLength;
+ size_t m_BestRating;
+ size_t m_NameLength;
const AString m_PlayerName;
virtual bool Item (cPlayer * a_pPlayer)
{
- unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
+ size_t Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
if ((Rating > 0) && (Rating >= m_BestRating))
{
m_BestMatch = a_pPlayer;
@@ -625,7 +626,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
cPlayer * m_BestMatch;
unsigned m_NumMatches;
} Callback (a_PlayerName);
- ForEachPlayer( Callback );
+ ForEachPlayer(Callback);
if (Callback.m_NumMatches == 1)
{
@@ -762,8 +763,8 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output)
{
cWorld * World = itr->second;
int NumInGenerator = World->GetGeneratorQueueLength();
- int NumInSaveQueue = World->GetStorageSaveQueueLength();
- int NumInLoadQueue = World->GetStorageLoadQueueLength();
+ int NumInSaveQueue = (int)World->GetStorageSaveQueueLength();
+ int NumInLoadQueue = (int)World->GetStorageLoadQueueLength();
int NumValid = 0;
int NumDirty = 0;
int NumInLighting = 0;
@@ -783,8 +784,6 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output)
a_Output.Out(" block lighting: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
a_Output.Out(" heightmap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
a_Output.Out(" biomemap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
- int Rest = sizeof(cChunk) - sizeof(cChunkDef::BlockTypes) - 3 * sizeof(cChunkDef::BlockNibbles) - sizeof(cChunkDef::HeightMap) - sizeof(cChunkDef::BiomeMap);
- a_Output.Out(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024);
SumNumValid += NumValid;
SumNumDirty += NumDirty;
SumNumInLighting += NumInLighting;
diff --git a/src/Root.h b/src/Root.h
index 4bbd7586f..d2a4d1eed 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Authenticator.h"
+#include "Protocol/Authenticator.h"
#include "HTTPServer/HTTPServer.h"
#include "Defines.h"
@@ -89,7 +89,7 @@ public:
void KickUser(int a_ClientID, const AString & a_Reason);
/// Called by cAuthenticator to auth the specified user
- void AuthenticateUser(int a_ClientID);
+ void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID);
/// Executes commands queued in the command queue
void TickCommands(void);
diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp
index 4c89ce265..250f63aa9 100644
--- a/src/Scoreboard.cpp
+++ b/src/Scoreboard.cpp
@@ -261,7 +261,7 @@ void cTeam::SetDisplayName(const AString & a_Name)
-unsigned int cTeam::GetNumPlayers(void) const
+size_t cTeam::GetNumPlayers(void) const
{
return m_Players.size();
}
@@ -569,7 +569,7 @@ void cScoreboard::SendTo(cClientHandle & a_Client)
-unsigned int cScoreboard::GetNumObjectives(void) const
+size_t cScoreboard::GetNumObjectives(void) const
{
return m_Objectives.size();
}
@@ -578,7 +578,7 @@ unsigned int cScoreboard::GetNumObjectives(void) const
-unsigned int cScoreboard::GetNumTeams(void) const
+size_t cScoreboard::GetNumTeams(void) const
{
return m_Teams.size();
}
diff --git a/src/Scoreboard.h b/src/Scoreboard.h
index 2fae5e499..1e1973a10 100644
--- a/src/Scoreboard.h
+++ b/src/Scoreboard.h
@@ -153,7 +153,7 @@ public:
// tolua_begin
/** Returns the number of registered players */
- unsigned int GetNumPlayers(void) const;
+ size_t GetNumPlayers(void) const;
bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; }
bool CanSeeFriendlyInvisible(void) const { return m_CanSeeFriendlyInvisible; }
@@ -248,9 +248,9 @@ public:
cObjective * GetObjectiveIn(eDisplaySlot a_Slot);
- unsigned int GetNumObjectives(void) const;
+ size_t GetNumObjectives(void) const;
- unsigned int GetNumTeams(void) const;
+ size_t GetNumTeams(void) const;
void AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value = 1);
diff --git a/src/Server.cpp b/src/Server.cpp
index d1e53bfff..aa731cdd2 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -190,7 +190,7 @@ void cServer::PlayerDestroying(const cPlayer * a_Player)
bool cServer::InitServer(cIniFile & a_SettingsIni)
{
- m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!").c_str();
+ m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!");
m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100);
m_bIsHardcore = a_SettingsIni.GetValueSetB("Server", "HardcoreEnabled", false);
m_PlayerCount = 0;
@@ -275,7 +275,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
-int cServer::GetNumPlayers(void)
+int cServer::GetNumPlayers(void) const
{
cCSLock Lock(m_CSPlayerCount);
return m_PlayerCount;
@@ -476,7 +476,37 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
a_Output.Finished();
return;
}
-
+ if (split[0] == "load")
+ {
+ if (split.size() > 1)
+ {
+ cPluginManager::Get()->LoadPlugin(split[1]);
+
+ return;
+ }
+ else
+ {
+ a_Output.Out("No plugin given! Command: load <pluginname>");
+ a_Output.Finished();
+ return;
+ }
+ }
+
+ if (split[0] == "unload")
+ {
+ if (split.size() > 1)
+ {
+ cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1]));
+ return;
+ }
+ else
+ {
+ a_Output.Out("No plugin given! Command: unload <pluginname>");
+ a_Output.Finished();
+ return;
+ }
+ }
+
// There is currently no way a plugin can do these (and probably won't ever be):
if (split[0].compare("chunkstats") == 0)
{
@@ -567,6 +597,9 @@ void cServer::BindBuiltInConsoleCommands(void)
PlgMgr->BindConsoleCommand("restart", NULL, " - Restarts the server cleanly");
PlgMgr->BindConsoleCommand("stop", NULL, " - Stops the server cleanly");
PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics");
+ PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin");
+ PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin");
+
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
#endif
@@ -615,14 +648,14 @@ void cServer::KickUser(int a_ClientID, const AString & a_Reason)
-void cServer::AuthenticateUser(int a_ClientID)
+void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID)
{
cCSLock Lock(m_CSClients);
for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr)
{
if ((*itr)->GetUniqueID() == a_ClientID)
{
- (*itr)->Authenticate();
+ (*itr)->Authenticate(a_Name, a_UUID);
return;
}
} // for itr - m_Clients[]
diff --git a/src/Server.h b/src/Server.h
index b5280c59d..3d76c8ccf 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -23,7 +23,7 @@
#pragma warning(disable:4702)
#endif
-#include "Crypto.h"
+#include "PolarSSL++/RsaPrivateKey.h"
#ifdef _MSC_VER
#pragma warning(pop)
@@ -59,7 +59,7 @@ public: // tolua_export
// Player counts:
int GetMaxPlayers(void) const {return m_MaxPlayers; }
- int GetNumPlayers(void);
+ int GetNumPlayers(void) const;
void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
// Hardcore mode or not:
@@ -83,7 +83,7 @@ public: // tolua_export
void Shutdown(void);
void KickUser(int a_ClientID, const AString & a_Reason);
- void AuthenticateUser(int a_ClientID); // Called by cAuthenticator to auth the specified user
+ void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator to auth the specified user
const AString & GetServerID(void) const { return m_ServerID; } // tolua_export
@@ -109,7 +109,7 @@ public: // tolua_export
/** Returns base64 encoded favicon data (obtained from favicon.png) */
const AString & GetFaviconData(void) const { return m_FaviconData; }
- cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
+ cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }
@@ -168,7 +168,7 @@ private:
cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld
cClientHandleList m_ClientsToRemove; ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick()
- cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount
+ mutable cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount
int m_PlayerCount; ///< Number of players currently playing in the server
cCriticalSection m_CSPlayerCountDiff; ///< Locks the m_PlayerCountDiff
int m_PlayerCountDiff; ///< Adjustment to m_PlayerCount to be applied in the Tick thread
@@ -182,7 +182,7 @@ private:
bool m_bRestarting;
/** The private key used for the assymetric encryption start in the protocols */
- cRSAPrivateKey m_PrivateKey;
+ cRsaPrivateKey m_PrivateKey;
/** Public key for m_PrivateKey, ASN1-DER-encoded */
AString m_PublicKeyDER;
diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt
index 4f3f1ad0e..b2a29d45c 100644
--- a/src/Simulator/CMakeLists.txt
+++ b/src/Simulator/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Simulator ${SOURCE})
diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp
index bc5158d95..5ff736231 100644
--- a/src/Simulator/DelayedFluidSimulator.cpp
+++ b/src/Simulator/DelayedFluidSimulator.cpp
@@ -148,7 +148,7 @@ void cDelayedFluidSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_Chunk
{
SimulateBlock(a_Chunk, itr->x, itr->y, itr->z);
}
- m_TotalBlocks -= Blocks.size();
+ m_TotalBlocks -= (int)Blocks.size();
Blocks.clear();
}
}
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 470dfc791..311f8b4c4 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -95,8 +95,10 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
int NumMSecs = (int)a_Dt;
for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();)
{
- int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
- BLOCKTYPE BlockType = a_Chunk->GetBlock(idx);
+ int x = itr->x;
+ int y = itr->y;
+ int z = itr->z;
+ BLOCKTYPE BlockType = a_Chunk->GetBlock(x,y,z);
if (!IsAllowedBlock(BlockType))
{
@@ -125,7 +127,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width
);
*/
- NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx);
+ NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z);
if (BlockMeta == 0x0f)
{
// The fire burnt out completely
@@ -140,7 +142,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
if((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z))))
{
- a_Chunk->SetMeta(idx, BlockMeta + 1);
+ a_Chunk->SetMeta(x, y, z, BlockMeta + 1);
}
itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this
} // for itr - Data[]
@@ -350,7 +352,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel
{
continue;
}
- BlockType = Neighbour->GetBlock(X, a_RelY + gCrossCoords[i].y, Z);
+ BlockType = Neighbour->GetBlock(X, a_RelY + gNeighborCoords[i].y, Z);
if (!IsFuel(BlockType))
{
diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp
index 03e94e791..e95af3a1c 100644
--- a/src/Simulator/FloodyFluidSimulator.cpp
+++ b/src/Simulator/FloodyFluidSimulator.cpp
@@ -119,7 +119,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
if (SpreadFurther && (NewMeta < 8))
{
// Spread to the neighbors:
- Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
+ SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
}
// Mark as processed:
@@ -130,7 +130,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
-void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
+void cFloodyFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
{
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
diff --git a/src/Simulator/FloodyFluidSimulator.h b/src/Simulator/FloodyFluidSimulator.h
index 632de3bb2..8e1be5e6b 100644
--- a/src/Simulator/FloodyFluidSimulator.h
+++ b/src/Simulator/FloodyFluidSimulator.h
@@ -48,16 +48,13 @@ protected:
bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
/** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block.
- *
- * Returns whether the block was changed or not.
- */
+ Returns whether the block was changed or not. */
bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta);
- /** Spread water to neighbors.
- *
- * May be overridden to provide more sophisticated algorithms.
- */
- virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
+ /** Spread fluid to XZ neighbors.
+ The coords are of the block currently being processed; a_NewMeta is the new meta for the new fluid block.
+ Descendants may overridde to provide more sophisticated algorithms. */
+ virtual void SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
} ;
diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp
index 61c93ed73..4a84084d2 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:
@@ -154,7 +155,7 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a
Points.push_back(new Vector3i(a_X, a_Y, a_Z + 1));
Points.push_back(new Vector3i(a_X, a_Y, a_Z - 1));
- for (std::vector<Vector3i *>::iterator it = Points.begin(); it < Points.end(); it++)
+ for (std::vector<Vector3i *>::iterator it = Points.begin(); it < Points.end(); ++it)
{
Vector3i *Pos = (*it);
char BlockID = m_World.GetBlock(Pos->x, Pos->y, Pos->z);
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index 92659fab7..074063add 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -9,11 +9,13 @@
#include "../Entities/Pickup.h"
#include "../Blocks/BlockTorch.h"
#include "../Blocks/BlockDoor.h"
+#include "../Blocks/BlockButton.h"
+#include "../Blocks/BlockLever.h"
#include "../Piston.h"
-
+
cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulator(cWorld & a_World)
: super(a_World)
@@ -69,18 +71,19 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
// Checking only when a block is changed, as opposed to every tick, also improves performance
PoweredBlocksList * PoweredBlocks = a_Chunk->GetRedstoneSimulatorPoweredBlocksList();
- for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end(); ++itr)
+ for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end();)
{
if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{
+ ++itr;
continue;
}
if (!IsPotentialSource(Block))
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- PoweredBlocks->erase(itr);
- break;
+ itr = PoweredBlocks->erase(itr);
+ continue;
}
else if (
// Changeable sources
@@ -93,29 +96,10 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
)
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- PoweredBlocks->erase(itr);
- break;
- }
- else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
- {
- if (!a_Chunk->IsLightValid())
- {
- m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ());
- break;
- }
- else
- {
- NIBBLETYPE SkyLight;
- a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight);
-
- if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness();
- {
- LOGD("cIncrementalRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level");
- PoweredBlocks->erase(itr);
- break;
- }
- }
+ itr = PoweredBlocks->erase(itr);
+ continue;
}
+ ++itr;
}
LinkedBlocksList * LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList();
@@ -134,7 +118,9 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
// Things that can send power through a block but which depends on meta
((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
- (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
+ (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
+ (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) ||
+ (((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0))
)
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
@@ -157,14 +143,14 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
SimulatedPlayerToggleableList * SimulatedPlayerToggleableBlocks = a_Chunk->GetRedstoneSimulatorSimulatedPlayerToggleableList();
for (SimulatedPlayerToggleableList::iterator itr = SimulatedPlayerToggleableBlocks->begin(); itr != SimulatedPlayerToggleableBlocks->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)))
{
continue;
}
if (!IsAllowedBlock(Block))
{
- LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z);
SimulatedPlayerToggleableBlocks->erase(itr);
break;
}
@@ -173,7 +159,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
RepeatersDelayList * RepeatersDelayList = a_Chunk->GetRedstoneSimulatorRepeatersDelayList();
for (RepeatersDelayList::iterator itr = RepeatersDelayList->begin(); itr != RepeatersDelayList->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)))
{
continue;
}
@@ -239,9 +225,6 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
m_LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList();
m_Chunk = a_Chunk;
- int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
- int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
-
for (cRedstoneSimulatorChunkData::iterator dataitr = m_RedstoneSimulatorChunkData->begin(); dataitr != m_RedstoneSimulatorChunkData->end();)
{
if (dataitr->DataTwo)
@@ -250,67 +233,65 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
continue;
}
- int a_X = BaseX + dataitr->x;
- int a_Z = BaseZ + dataitr->z;
switch (dataitr->Data)
{
- case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_FENCE_GATE: HandleFenceGate(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
{
- HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data);
+ HandleRedstoneTorch(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
break;
}
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_WOODEN_BUTTON:
{
- HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data);
+ HandleRedstoneButton(dataitr->x, dataitr->y, dataitr->z);
break;
}
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
{
- HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data);
+ HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
break;
}
case E_BLOCK_PISTON:
case E_BLOCK_STICKY_PISTON:
{
- HandlePiston(a_X, dataitr->y, a_Z);
+ HandlePiston(dataitr->x, dataitr->y, dataitr->z);
break;
}
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
{
- HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data);
+ HandleRedstoneLamp(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
break;
}
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
{
- HandleDropSpenser(a_X, dataitr->y, a_Z);
+ HandleDropSpenser(dataitr->x, dataitr->y, dataitr->z);
break;
}
case E_BLOCK_WOODEN_DOOR:
case E_BLOCK_IRON_DOOR:
{
- HandleDoor(a_X, dataitr->y, a_Z);
+ HandleDoor(dataitr->x, dataitr->y, dataitr->z);
break;
}
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_POWERED_RAIL:
{
- HandleRail(a_X, dataitr->y, a_Z, dataitr->Data);
+ HandleRail(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
break;
}
case E_BLOCK_WOODEN_PRESSURE_PLATE:
@@ -318,7 +299,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
{
- HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data);
+ HandlePressurePlate(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
break;
}
default: LOGD("Unhandled block (!) or unimplemented redstone block: %s", ItemToString(dataitr->Data).c_str()); break;
@@ -360,7 +341,7 @@ void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_Blo
-void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
+void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
{
static const struct // Define which directions the torch can power
{
@@ -377,54 +358,58 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc
if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON)
{
// Check if the block the torch is on is powered
- int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
+ int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
+ AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
if (AreCoordsDirectlyPowered(X, Y, Z))
{
// There was a match, torch goes off
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
return;
}
// Torch still on, make all 4(X, Z) + 1(Y) sides powered
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{
- BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z);
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
+ {
+ continue;
+ }
if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
{
if (
((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc.
- (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
+ (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
)
{
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
+ SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
}
}
else
{
// Top side, power whatever is there, including blocks
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
+ SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
// Power all blocks surrounding block above torch
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_TORCH_ON);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP);
}
}
- if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath
+ if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath
{
- BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
+ BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ);
if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though!
{
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
}
}
}
else
{
// Check if the block the torch is on is powered
- int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
+ int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
+ AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
// See if off state torch can be turned on again
if (AreCoordsDirectlyPowered(X, Y, Z))
@@ -433,7 +418,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc
}
// Block torch on not powered, can be turned on again!
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
}
}
@@ -441,28 +426,47 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc
-void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE);
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered
}
-void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (IsLeverOn(Meta))
{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER);
+ NIBBLETYPE Dir = cBlockLeverHandler::BlockMetaDataToBlockFace(Meta);
+ switch (Dir) // Now, flip the direction into the type used by SetBlockLinkedPowered()
+ {
+ case BLOCK_FACE_YP:
+ case BLOCK_FACE_XP:
+ case BLOCK_FACE_ZP:
+ {
+ Dir--;
+ break;
+ }
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_ZM:
+ case BLOCK_FACE_YM:
+ {
+ Dir++;
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled lever metadata!");
+ return;
+ }
+ }
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir);
}
}
@@ -470,27 +474,29 @@ void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_Bloc
-void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
cChunkInterface ChunkInterface(m_World.GetChunkMap());
- NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData | 0x4);
- m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
}
}
else
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData & 0xFFFFFFFB);
- m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & 0xFFFFFFFB);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
}
}
}
@@ -499,18 +505,35 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY,
-void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
+void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (IsButtonOn(Meta))
{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockType);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+
+ NIBBLETYPE Dir = cBlockButtonHandler::BlockMetaDataToBlockFace(Meta);
+ switch (Dir) // Now, flip the direction into the type used by SetBlockLinkedPowered()
+ {
+ case BLOCK_FACE_XP:
+ case BLOCK_FACE_ZP:
+ {
+ Dir--;
+ break;
+ }
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_ZM:
+ {
+ Dir++;
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled button metadata!");
+ return;
+ }
+ }
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir);
}
}
@@ -518,7 +541,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_Blo
-void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
static const struct // Define which directions the wire can receive power from
{
@@ -552,128 +575,122 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block
};
// Check to see if directly beside a power source
- if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ))
+ unsigned char MyPower;
+ if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower))
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0);
+ m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ);
+ return;
}
- else
+
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+
+ if (MyPower < 1)
{
- NIBBLETYPE MetaToSet = 0;
- NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- int TimesMetaSmaller = 0, TimesFoundAWire = 0;
+ return;
+ }
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
+ MyPower--;
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
+ {
+ if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
{
- if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
+ BLOCKTYPE Type = 0;
+ if (a_RelBlockY + 1 >= cChunkDef::Height)
{
- if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)...
- {
- continue; // We don't receive power from that wire
- }
+ continue;
}
- else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type))
{
- if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)))
- {
- continue;
- }
+ continue;
}
-
- BLOCKTYPE SurroundType;
- NIBBLETYPE SurroundMeta;
- m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta);
-
- if (SurroundType == E_BLOCK_REDSTONE_WIRE)
+ if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)...
{
- TimesFoundAWire++;
-
- if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking
- {
- // Does surrounding wire have a higher power level than self?
- // >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list
- if (SurroundMeta >= MyMeta)
- {
- MetaToSet = SurroundMeta - 1; // To improve performance
- }
- }
-
- if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's
- {
- TimesMetaSmaller++;
- }
- }
+ continue; // We don't receive power from that wire
+ }
+ }
+ else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
+ {
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type))
+ {
+ continue;
+ }
+ if (cBlockInfo::IsSolid(Type))
+ {
+ continue;
+ }
}
- if ((TimesMetaSmaller == TimesFoundAWire) && (MyMeta != 0))
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
{
- // All surrounding metas were smaller - self must have been a wire that was
- // transferring power to other wires around.
- // However, self not directly powered anymore, so source must have been removed,
- // therefore, self must be set to meta zero
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
- return; // No need to process block power sets because self not powered
+ continue;
}
- else if (MyMeta != MetaToSet)
+ if (Type == E_BLOCK_REDSTONE_WIRE)
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet);
+ SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
}
}
- if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire
+ for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
{
- for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type))
{
- if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF)
- {
- SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- }
+ continue;
+ }
+ if (Type == E_BLOCK_REDSTONE_REPEATER_OFF)
+ {
+ SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
}
+ }
- // Wire still powered, power blocks beneath
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
+ // Wire still powered, power blocks beneath
+ SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower);
- switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ))
+ switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ case REDSTONE_NONE:
{
- case REDSTONE_NONE:
- {
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_X_POS:
- {
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_X_NEG:
- {
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_Z_POS:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_Z_NEG:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
- break;
- }
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower);
+ break;
+ }
+ case REDSTONE_X_POS:
+ {
+ SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower);
+ break;
+ }
+ case REDSTONE_X_NEG:
+ {
+ SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower);
+ break;
+ }
+ case REDSTONE_Z_POS:
+ {
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower);
+ break;
+ }
+ case REDSTONE_Z_NEG:
+ {
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower);
+ break;
}
}
}
@@ -682,25 +699,49 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block
-void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
+void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
{
- NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ /* Repeater Orientation Mini Guide:
+ ===================================
- bool IsOn = ((a_MyState == E_BLOCK_REDSTONE_REPEATER_ON) ? true : false); // Cache if repeater is on
- bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3); // Cache if repeater is pwoered
+ |
+ | Z Axis
+ V
- if (IsSelfPowered && !IsOn) // Queue a power change if I am receiving power but not on
- {
- QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, true);
- }
- else if (!IsSelfPowered && IsOn) // Queue a power change if I am not receiving power but on
+ X Axis ---->
+
+ Repeater directions, values from a cWorld::GetBlockMeta(a_RelBlockX , a_RelBlockY, a_RelBlockZ) lookup:
+
+ East (Right) (X+): 0x1
+ West (Left) (X-): 0x3
+ North (Up) (Z-): 0x2
+ South (Down) (Z+): 0x0
+ // TODO: Add E_META_XXX enum entries for all meta values and update project with them
+
+ Sun rises from East (X+)
+
+ */
+
+ // Create a variable holding my meta to avoid multiple lookups.
+ NIBBLETYPE a_Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON);
+
+ if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta)) // If we're locked, change nothing. Otherwise:
{
- QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, false);
+ bool IsSelfPowered = IsRepeaterPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta);
+ if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked.
+ {
+ QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, true);
+ }
+ else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked.
+ {
+ QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, false);
+ }
}
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
{
continue;
}
@@ -711,33 +752,33 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B
{
if (!IsOn)
{
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance
}
switch (a_Meta & 0x3) // We only want the direction (bottom) bits
{
case 0x0:
{
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM);
break;
}
case 0x1:
{
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP);
break;
}
case 0x2:
{
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP);
break;
}
case 0x3:
{
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM);
break;
}
}
@@ -750,7 +791,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B
{
if (IsOn)
{
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
}
m_RepeatersDelayList->erase(itr); // We can remove off repeaters which don't need further updating
return;
@@ -761,7 +802,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B
// Apparently, incrementing ticks only works reliably here, and not in SimChunk;
// With a world with lots of redstone, the repeaters simply do not delay
// I am confounded to say why. Perhaps optimisation failure.
- LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
+ LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
itr->a_ElapsedTicks++;
}
}
@@ -771,16 +812,19 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B
-void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
cPiston Piston(&m_World);
- if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness)
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
+ if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness)
{
- Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ);
+ Piston.ExtendPiston(BlockX, a_RelBlockY, BlockZ);
}
else
{
- Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ);
+ Piston.RetractPiston(BlockX, a_RelBlockY, BlockZ);
}
}
@@ -788,7 +832,7 @@ void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int
-void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
class cSetPowerToDropSpenser :
public cDropSpenserCallback
@@ -802,29 +846,31 @@ void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY
a_DropSpenser->SetRedstonePower(m_IsPowered);
return false;
}
- } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
+ } DrSpSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
- m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->DoWithDropSpenserAt(BlockX, a_RelBlockY, BlockZ, DrSpSP);
}
-void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
+void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
{
if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF)
{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
}
}
else
{
- if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
}
}
}
@@ -833,13 +879,16 @@ void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_Block
-void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
+ m_Chunk->BroadcastSoundEffect("game.tnt.primed", BlockX * 8, a_RelBlockY * 8, BlockZ * 8, 0.5f, 0.6f);
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0);
+ m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom
}
}
@@ -847,26 +896,29 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
-void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
{
cChunkInterface ChunkInterface(m_World.GetChunkMap());
- cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
- m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ cBlockDoorHandler::ChangeDoor(ChunkInterface, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
}
}
else
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
{
cChunkInterface ChunkInterface(m_World.GetChunkMap());
- cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
- m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ cBlockDoorHandler::ChangeDoor(ChunkInterface, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
}
}
}
@@ -875,7 +927,7 @@ void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a
-void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
class cSetPowerToCommandBlock :
public cCommandBlockCallback
@@ -889,37 +941,39 @@ void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_Block
a_CommandBlock->SetRedstonePower(m_IsPowered);
return false;
}
- } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
+ } CmdBlockSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
- m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->DoWithCommandBlockAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP);
}
-void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
+void cIncrementalRedstoneSimulator::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType)
{
switch (a_MyType)
{
case E_BLOCK_DETECTOR_RAIL:
{
- if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08)
+ if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08)
{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType);
}
break;
}
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_POWERED_RAIL:
{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08);
}
else
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07);
}
break;
}
@@ -931,22 +985,25 @@ void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a
-void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
{
- m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, true);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
}
}
else
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
{
- m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, false);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
}
}
}
@@ -955,13 +1012,13 @@ void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, i
-void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- bool m_bAreCoordsPowered = AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ);
+ bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
if (m_bAreCoordsPowered)
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
{
class cSetPowerToNoteBlock :
public cNoteBlockCallback
@@ -980,15 +1037,17 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY,
}
} NoteBlockSP(m_bAreCoordsPowered);
- m_World.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, NoteBlockSP);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->DoWithNoteBlockAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
}
}
else
{
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
{
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
}
}
}
@@ -997,10 +1056,10 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY,
-void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
int a_ChunkX, a_ChunkZ;
- cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ);
+ cChunkDef::BlockToChunk(a_RelBlockX, a_RelBlockZ, a_ChunkX, a_ChunkZ);
if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
{
@@ -1008,10 +1067,12 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_Blo
}
else
{
- NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness();
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ NIBBLETYPE SkyLight = m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ));
if (SkyLight > 8)
{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
}
}
}
@@ -1020,38 +1081,175 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_Blo
-void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
+void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType)
{
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
switch (a_MyType)
{
case E_BLOCK_STONE_PRESSURE_PLATE:
{
// MCS feature - stone pressure plates can only be triggered by players :D
- cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f, false);
+ cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.7f, false);
if (a_Player != NULL)
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
}
else
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
- m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0);
+ m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ);
}
break;
}
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ {
+ class cPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ m_NumberOfEntities(0),
+ m_X(a_BlockX),
+ m_Y(a_BlockY),
+ m_Z(a_BlockZ)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ Vector3f EntityPos = a_Entity->GetPosition();
+ Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
+ double Distance = (EntityPos - BlockPos).Length();
+
+ if (Distance <= 0.7)
+ {
+ m_NumberOfEntities++;
+ }
+ return false;
+ }
+
+ bool GetPowerLevel(unsigned char & a_PowerLevel) const
+ {
+ a_PowerLevel = std::min(m_NumberOfEntities, MAX_POWER_LEVEL);
+ return (a_PowerLevel > 0);
+ }
+
+ protected:
+ int m_NumberOfEntities;
+
+ int m_X;
+ int m_Y;
+ int m_Z;
+ };
+
+ cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
+ m_World.ForEachEntity(PressurePlateCallback);
+
+ unsigned char Power;
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (PressurePlateCallback.GetPowerLevel(Power))
+ {
+ if (Meta == E_META_PRESSURE_PLATE_RAISED)
+ {
+ m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
+ }
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
+ }
+ else
+ {
+ if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
+ {
+ m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
+ }
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
+ m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ);
+ }
+
+ break;
+ }
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ {
+ class cPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ m_NumberOfEntities(0),
+ m_X(a_BlockX),
+ m_Y(a_BlockY),
+ m_Z(a_BlockZ)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ Vector3f EntityPos = a_Entity->GetPosition();
+ Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
+ double Distance = (EntityPos - BlockPos).Length();
+
+ if (Distance <= 0.7)
+ {
+ m_NumberOfEntities++;
+ }
+ return false;
+ }
+
+ bool GetPowerLevel(unsigned char & a_PowerLevel) const
+ {
+ a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL);
+ return (a_PowerLevel > 0);
+ }
+
+ protected:
+ int m_NumberOfEntities;
+
+ int m_X;
+ int m_Y;
+ int m_Z;
+ };
+
+ cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
+ m_World.ForEachEntity(PressurePlateCallback);
+
+ unsigned char Power;
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (PressurePlateCallback.GetPowerLevel(Power))
+ {
+ if (Meta == E_META_PRESSURE_PLATE_RAISED)
+ {
+ m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
+ }
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
+ }
+ else
+ {
+ if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
+ {
+ m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
+ }
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
+ m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ);
+ }
+
+ break;
+ }
case E_BLOCK_WOODEN_PRESSURE_PLATE:
{
class cPressurePlateCallback :
public cEntityCallback
{
public:
- cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- m_Entity(NULL),
- m_World(a_World),
+ cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ m_FoundEntity(false),
m_X(a_BlockX),
m_Y(a_BlockY),
m_Z(a_BlockZ)
@@ -1066,7 +1264,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
if (Distance <= 0.7)
{
- m_Entity = a_Entity;
+ m_FoundEntity = true;
return true; // Break out, we only need to know for plates that at least one entity is on top
}
return false;
@@ -1074,45 +1272,47 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
bool FoundEntity(void) const
{
- return m_Entity != NULL;
+ return m_FoundEntity;
}
protected:
- cEntity * m_Entity;
- cWorld * m_World;
+ bool m_FoundEntity;
int m_X;
int m_Y;
int m_Z;
} ;
- cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World);
+ cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
m_World.ForEachEntity(PressurePlateCallback);
- NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
if (PressurePlateCallback.FoundEntity())
{
- if (Meta == 0x0)
+ if (Meta == E_META_PRESSURE_PLATE_RAISED)
{
- m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
+ m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
}
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
}
else
{
- if (Meta == 0x1)
+ if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
{
- m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
+ m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
}
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
- m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
+ m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ);
}
break;
}
default:
+ {
LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
break;
+ }
}
}
@@ -1120,11 +1320,15 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
-bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
+ PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); // Torches want to access neighbour's data when on a wall
+ for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
{
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
return true;
}
@@ -1136,11 +1340,14 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a
-bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list
{
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
return true;
}
@@ -1151,36 +1358,39 @@ bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_B
-
-bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
+// IsRepeaterPowered tests if a repeater should be powered by testing for power sources behind the repeater.
+// It takes the coordinates of the repeater the the meta value.
+bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
{
// Repeaters cannot be powered by any face except their back; verify that this is true for a source
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+ if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
- switch (a_Meta)
+ switch (a_Meta & 0x3)
{
case 0x0:
{
// Flip the coords to check the back of the repeater
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
+ if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; }
break;
}
case 0x1:
{
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
+ if (itr->a_SourcePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; }
break;
}
case 0x2:
{
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
+ if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; }
break;
}
case 0x3:
{
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
+ if (itr->a_SourcePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; }
break;
}
}
@@ -1188,28 +1398,28 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY
for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+ if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
- switch (a_Meta)
+ switch (a_Meta & 0x3)
{
case 0x0:
{
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
+ if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; }
break;
}
case 0x1:
{
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
+ if (itr->a_MiddlePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; }
break;
}
case 0x2:
{
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
+ if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; }
break;
}
case 0x3:
{
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
+ if (itr->a_MiddlePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; }
break;
}
}
@@ -1220,43 +1430,101 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY
-bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
+
+bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
+{
+ switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata
+ {
+ // If the repeater is looking up or down (If parallel to the Z axis)
+ case 0x0:
+ case 0x2:
+ {
+ // Check if eastern(right) neighbor is a powered on repeater who is facing us.
+ BLOCKTYPE Block = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater?
+ {
+ NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ) & 0x3;
+ if (OtherRepeaterDir == 0x3) { return true; } // If so, I am latched/locked.
+ }
+
+ // Check if western(left) neighbor is a powered on repeater who is facing us.
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
+ {
+ NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX -1, a_RelBlockY, a_RelBlockZ) & 0x3;
+ if (OtherRepeaterDir == 0x1) { return true; } // If so, I am latched/locked.
+ }
+
+ break;
+ }
+
+ // If the repeater is looking left or right (If parallel to the x axis)
+ case 0x1:
+ case 0x3:
+ {
+ // Check if southern(down) neighbor is a powered on repeater who is facing us.
+ BLOCKTYPE Block = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
+ {
+ NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1) & 0x3;
+ if (OtherRepeaterDir == 0x0) { return true; } // If so, am latched/locked.
+ }
+
+ // Check if northern(up) neighbor is a powered on repeater who is facing us.
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
+ {
+ NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1) & 0x3;
+ if (OtherRepeaterDir == 0x2) { return true; } // If so, I am latched/locked.
+ }
+
+ break;
+ }
+ }
+
+ return false; // None of the checks succeeded, I am not a locked repeater.
+}
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
{
// Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
- int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ;
+ int OldX = a_RelBlockX, OldY = a_RelBlockY, OldZ = a_RelBlockZ;
eBlockFace Face = cPiston::MetaDataToDirection(a_Meta);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+ if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
+ AddFaceDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face);
- if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (!itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
return true;
}
- a_BlockX = OldX;
- a_BlockY = OldY;
- a_BlockZ = OldZ;
+ a_RelBlockX = OldX;
+ a_RelBlockY = OldY;
+ a_RelBlockZ = OldZ;
}
for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+ if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
+ AddFaceDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face);
- if (!itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (!itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
return true;
}
- a_BlockX = OldX;
- a_BlockY = OldY;
- a_BlockZ = OldZ;
+ a_RelBlockX = OldX;
+ a_RelBlockY = OldY;
+ a_RelBlockZ = OldZ;
}
return false; // Source was in front of the piston's front face
}
@@ -1264,39 +1532,42 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY,
-bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel)
{
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+ a_PowerLevel = 0;
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
- return true;
+ continue;
}
+ a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel);
}
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr)
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
+ if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
- return true;
+ continue;
}
+ a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel);
}
- return false; // Source was in front of the piston's front face
+
+ return (a_PowerLevel != 0); // Source was in front of the piston's front face
}
-bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered)
+bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered)
{
for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr)
{
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
{
if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current?
{
@@ -1315,79 +1586,98 @@ bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_Block
-void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType)
+void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel)
{
+ BLOCKTYPE MiddleBlock = 0;
switch (a_Direction)
{
case BLOCK_FACE_XM:
{
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
- SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
break;
}
case BLOCK_FACE_XP:
{
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
- SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
break;
}
case BLOCK_FACE_YM:
{
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
break;
}
case BLOCK_FACE_YP:
{
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
break;
}
case BLOCK_FACE_ZM:
{
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock))
+ {
+ return;
+ }
- SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
break;
}
case BLOCK_FACE_ZP:
{
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock))
+ {
+ return;
+ }
- SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
break;
}
@@ -1403,7 +1693,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
-void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock)
+void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel)
{
static const struct
{
@@ -1411,16 +1701,16 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc
} gCrossCoords[] =
{
{ 1, 0, 0 },
- {-1, 0, 0 },
+ { -1, 0, 0 },
{ 0, 0, 1 },
- { 0, 0,-1 },
+ { 0, 0, -1 },
{ 0, 1, 0 },
- { 0,-1, 0 }
+ { 0, -1, 0 }
};
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions
{
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock);
+ SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_PowerLevel);
}
}
@@ -1428,32 +1718,55 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc
-void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock)
+void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel)
{
- BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
+ int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
+
+ BLOCKTYPE Block = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block))
+ {
+ return;
+ }
if (Block == E_BLOCK_AIR)
{
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
- PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList();
+ PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList();
+ for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
+ {
+ if (
+ itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ))
+ )
+ {
+ // Check for duplicates, update power level, don't add a new listing
+ itr->a_PowerLevel = a_PowerLevel;
+ return;
+ }
+ }
- for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
+ PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList();
+ for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list
{
if (
- itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
+ itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))
)
{
- // Check for duplicates
+ // Powered wires try to power their source - don't let them!
return;
}
}
sPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
+ RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ);
+ RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ);
+ RC.a_PowerLevel = a_PowerLevel;
Powered->push_back(RC);
}
@@ -1462,42 +1775,58 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY,
void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
- int a_BlockX, int a_BlockY, int a_BlockZ,
- int a_MiddleX, int a_MiddleY, int a_MiddleZ,
- int a_SourceX, int a_SourceY, int a_SourceZ,
- BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock
-)
+ int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ,
+ int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ,
+ int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ,
+ BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel
+ )
{
- BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ int MiddleX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelMiddleX;
+ int MiddleZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelMiddleZ;
+ int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
+ int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
+
+ BLOCKTYPE DestBlock = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock))
+ {
+ return;
+ }
if (DestBlock == E_BLOCK_AIR)
{
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
+ if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE))
+ {
+ return;
+ }
if (!IsViableMiddleBlock(a_MiddleBlock))
{
return;
}
- LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList();
-
- for (LinkedBlocksList::const_iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
+ LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorLinkedBlocksList();
+ for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
{
if (
- itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
- itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
- )
+ itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
+ itr->a_MiddlePos.Equals(Vector3i(MiddleX, a_RelMiddleY, MiddleZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ))
+ )
{
- // Check for duplicates
+ // Check for duplicates, update power level, don't add a new listing
+ itr->a_PowerLevel = a_PowerLevel;
return;
}
}
sLinkedPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
- RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
+ RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ);
+ RC.a_MiddlePos = Vector3i(MiddleX, a_RelMiddleY, MiddleZ);
+ RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ);
+ RC.a_PowerLevel = a_PowerLevel;
Linked->push_back(RC);
}
@@ -1505,11 +1834,11 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
-void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered)
+void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered)
{
for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr)
{
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
{
continue;
}
@@ -1529,7 +1858,7 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl
// We have arrive here; no block must be in list - add one
sSimulatedPlayerToggleableList RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
+ RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
RC.WasLastStatePowered = WasLastStatePowered;
m_SimulatedPlayerToggleableBlocks->push_back(RC);
}
@@ -1538,11 +1867,11 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl
-void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn)
+void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn)
{
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr)
{
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
{
if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry
{
@@ -1559,10 +1888,10 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a
// Self not in list, add self to list
sRepeatersDelayList RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
+ RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
// Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
- // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
+ // * 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility
RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
RC.a_ElapsedTicks = 0;
@@ -1575,52 +1904,64 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a
-cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ)
+cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
int Dir = REDSTONE_NONE;
- BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
- if (IsPotentialSource(NegX))
+ BLOCKTYPE NegX = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX))
{
- Dir |= (REDSTONE_X_POS);
+ if (IsPotentialSource(NegX))
+ {
+ Dir |= (REDSTONE_X_POS);
+ }
}
- BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
- if (IsPotentialSource(PosX))
+ BLOCKTYPE PosX = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX))
{
- Dir |= (REDSTONE_X_NEG);
+ if (IsPotentialSource(PosX))
+ {
+ Dir |= (REDSTONE_X_NEG);
+ }
}
- BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
- if (IsPotentialSource(NegZ))
+ BLOCKTYPE NegZ = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ))
{
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
- {
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ if (IsPotentialSource(NegZ))
{
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
+ if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ {
+ Dir ^= REDSTONE_X_POS;
+ Dir |= REDSTONE_X_NEG;
+ }
+ if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ {
+ Dir ^= REDSTONE_X_NEG;
+ Dir |= REDSTONE_X_POS;
+ }
+ Dir |= REDSTONE_Z_POS;
}
- Dir |= REDSTONE_Z_POS;
}
- BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
- if (IsPotentialSource(PosZ))
+ BLOCKTYPE PosZ = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ))
{
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ if (IsPotentialSource(PosZ))
{
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
- {
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
+ if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ {
+ Dir ^= REDSTONE_X_POS;
+ Dir |= REDSTONE_X_NEG;
+ }
+ if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ {
+ Dir ^= REDSTONE_X_NEG;
+ Dir |= REDSTONE_X_POS;
+ }
+ Dir |= REDSTONE_Z_NEG;
}
- Dir |= REDSTONE_Z_NEG;
}
return (eRedstoneDirection)Dir;
}
@@ -1638,12 +1979,3 @@ bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
-
-bool cIncrementalRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta)
-{
- return IsLeverOn(a_BlockMeta);
-}
-
-
-
-
diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h
index 8b7363366..233a3d408 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.h
+++ b/src/Simulator/IncrementalRedstoneSimulator.h
@@ -36,31 +36,35 @@ public:
private:
+ #define MAX_POWER_LEVEL 15
+
struct sPoweredBlocks // Define structure of the directly powered blocks list
{
Vector3i a_BlockPos; // Position of powered block
Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos
+ unsigned char a_PowerLevel;
};
struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
{
Vector3i a_BlockPos;
- Vector3i a_MiddlePos;
+ Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination
Vector3i a_SourcePos;
+ unsigned char a_PowerLevel;
};
- struct sSimulatedPlayerToggleableList
+ struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player)
{
- Vector3i a_BlockPos;
- bool WasLastStatePowered;
+ Vector3i a_RelBlockPos;
+ bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate
};
- struct sRepeatersDelayList
+ struct sRepeatersDelayList // Define structure of list containing repeaters' delay states
{
- Vector3i a_BlockPos;
- unsigned char a_DelayTicks;
- unsigned char a_ElapsedTicks;
- bool ShouldPowerOn;
+ Vector3i a_RelBlockPos;
+ unsigned char a_DelayTicks; // For how many ticks should the repeater delay
+ unsigned char a_ElapsedTicks; // How much of the previous has been elapsed?
+ bool ShouldPowerOn; // What happens when the delay time is fulfilled?
};
public:
@@ -87,85 +91,86 @@ private:
/* ====== SOURCES ====== */
/** Handles the redstone torch */
- void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
+ void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles the redstone block */
- void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles levers */
- void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles buttons */
- void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
+ void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles daylight sensors */
- void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles pressure plates */
- void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
+ void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
/* ==================== */
/* ====== CARRIERS ====== */
/** Handles redstone wire */
- void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles repeaters */
- void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
+ void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/* ====================== */
/* ====== DEVICES ====== */
/** Handles pistons */
- void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles dispensers and droppers */
- void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles TNT (exploding) */
- void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles redstone lamps */
- void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
+ void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles doords */
- void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles command blocks */
- void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles activator, detector, and powered rails */
- void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
+ void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
/** Handles trapdoors */
- void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles fence gates */
- void HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles noteblocks */
- void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/* ===================== */
/* ====== Helper functions ====== */
/** Marks a block as powered */
- void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock);
+ void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Marks a block as being powered through another block */
- void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock);
+ void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
- void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered);
+ void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered);
/** Marks the second block in a direction as linked powered */
- void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock);
+ void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Marks all blocks immediately surrounding a coordinate as powered */
- void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock);
+ void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Queues a repeater to be powered or unpowered */
- void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
+ void QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
/** Returns if a coordinate is powered or linked powered */
- bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); }
+ bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }
/** Returns if a coordinate is in the directly powered blocks list */
- bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
+ bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Returns if a coordinate is in the indirectly powered blocks list */
- bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
+ bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
- bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered);
+ bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered);
/** Returns if a repeater is powered */
- bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
+ bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
+ /** Returns if a repeater is locked */
+ bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
/** Returns if a piston is powered */
- bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
+ bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
/** Returns if a wire is powered
- The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire
- */
- bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ);
+ The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */
+ bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel);
/** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta);
/** Returns if button metadata marks it as emitting power */
- bool IsButtonOn(NIBBLETYPE a_BlockMeta);
+ bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); }
/* ============================== */
/* ====== Misc Functions ====== */
diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp
index f305ba61a..b8f34559f 100644
--- a/src/Simulator/SandSimulator.cpp
+++ b/src/Simulator/SandSimulator.cpp
@@ -64,7 +64,7 @@ void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0);
}
}
- m_TotalBlocks -= ChunkData.size();
+ m_TotalBlocks -= (int)ChunkData.size();
ChunkData.clear();
}
@@ -254,6 +254,10 @@ void cSandSimulator::FinishFalling(
{
// Rematerialize the material here:
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta);
+ if (a_FallingBlockType == E_BLOCK_ANVIL)
+ {
+ a_World->BroadcastSoundParticleEffect(1022, a_BlockX, a_BlockY, a_BlockZ, 0);
+ }
return;
}
diff --git a/src/Simulator/VanillaFluidSimulator.cpp b/src/Simulator/VanillaFluidSimulator.cpp
index 78aff9d68..18d9b07e1 100644
--- a/src/Simulator/VanillaFluidSimulator.cpp
+++ b/src/Simulator/VanillaFluidSimulator.cpp
@@ -35,14 +35,16 @@ cVanillaFluidSimulator::cVanillaFluidSimulator(
-void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
+void cVanillaFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
{
+ // Calculate the distance to the nearest "hole" in each direction:
int Cost[4];
Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS);
Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS);
Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS);
Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS);
+ // Find the minimum distance:
int MinCost = InfiniteCost;
for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
{
@@ -52,6 +54,7 @@ void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, in
}
}
+ // Spread in all directions where the distance matches the minimum:
if (Cost[0] == MinCost)
{
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
@@ -86,7 +89,10 @@ int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int
{
return Cost;
}
- if (!IsPassableForFluid(BlockType) && !IsBlockLiquid(BlockType))
+ if (
+ !IsPassableForFluid(BlockType) || // The block cannot be passed by the liquid ...
+ (IsAllowedBlock(BlockType) && (BlockMeta == 0)) // ... or if it is liquid, it is a source block
+ )
{
return Cost;
}
diff --git a/src/Simulator/VanillaFluidSimulator.h b/src/Simulator/VanillaFluidSimulator.h
index a9ea98b5a..89a56ca14 100644
--- a/src/Simulator/VanillaFluidSimulator.h
+++ b/src/Simulator/VanillaFluidSimulator.h
@@ -30,7 +30,7 @@ public:
protected:
// cFloodyFluidSimulator overrides:
- virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override;
+ virtual void SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override;
/** Recursively calculates the minimum number of blocks needed to descend a level. */
int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0);
diff --git a/src/StackWalker.cpp b/src/StackWalker.cpp
index b4f8ed8c7..b608d69e6 100644
--- a/src/StackWalker.cpp
+++ b/src/StackWalker.cpp
@@ -935,7 +935,8 @@ BOOL StackWalker::LoadModules()
break;
}
} // for (search for path separator...)
- if (strlen(szTemp) > 0)
+
+ if (szTemp[0] != '\0') // If szTemp is not empty (Note: This is more efficient than using strlen)
{
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
diff --git a/src/Statistics.cpp b/src/Statistics.cpp
new file mode 100644
index 000000000..5c0524f9e
--- /dev/null
+++ b/src/Statistics.cpp
@@ -0,0 +1,196 @@
+
+// Statistics.cpp
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Statistics.h"
+
+
+
+cStatInfo cStatInfo::ms_Info[statCount] = {
+ // The order must match the order of enum eStatistic
+
+ // http://minecraft.gamepedia.com/Achievements
+
+ /* Type | Name | Prerequisite */
+ cStatInfo(achOpenInv, "achievement.openInventory"),
+ cStatInfo(achMineWood, "achievement.mineWood", achOpenInv),
+ cStatInfo(achCraftWorkbench, "achievement.buildWorkBench", achMineWood),
+ cStatInfo(achCraftPickaxe, "achievement.buildPickaxe", achCraftWorkbench),
+ cStatInfo(achCraftFurnace, "achievement.buildFurnace", achCraftPickaxe),
+ cStatInfo(achAcquireIron, "achievement.acquireIron", achCraftFurnace),
+ cStatInfo(achCraftHoe, "achievement.buildHoe", achCraftWorkbench),
+ cStatInfo(achMakeBread, "achievement.makeBread", achCraftHoe),
+ cStatInfo(achBakeCake, "achievement.bakeCake", achCraftHoe),
+ cStatInfo(achCraftBetterPick, "achievement.buildBetterPickaxe", achCraftPickaxe),
+ cStatInfo(achCookFish, "achievement.cookFish", achAcquireIron),
+ cStatInfo(achOnARail, "achievement.onARail", achAcquireIron),
+ cStatInfo(achCraftSword, "achievement.buildSword", achCraftWorkbench),
+ cStatInfo(achKillMonster, "achievement.killEnemy", achCraftSword),
+ cStatInfo(achKillCow, "achievement.killCow", achCraftSword),
+ cStatInfo(achFlyPig, "achievement.flyPig", achKillCow),
+ cStatInfo(achSnipeSkeleton, "achievement.snipeSkeleton", achKillMonster),
+ cStatInfo(achDiamonds, "achievement.diamonds", achAcquireIron),
+ cStatInfo(achEnterPortal, "achievement.portal", achDiamonds),
+ cStatInfo(achReturnToSender, "achievement.ghast", achEnterPortal),
+ cStatInfo(achBlazeRod, "achievement.blazeRod", achEnterPortal),
+ cStatInfo(achBrewPotion, "achievement.potion", achBlazeRod),
+ cStatInfo(achEnterTheEnd, "achievement.theEnd", achBlazeRod),
+ cStatInfo(achDefeatDragon, "achievement.theEnd2", achEnterTheEnd),
+ cStatInfo(achCraftEnchantTable, "achievement.enchantments", achDiamonds),
+ cStatInfo(achOverkill, "achievement.overkill", achCraftEnchantTable),
+ cStatInfo(achBookshelf, "achievement.bookcase", achCraftEnchantTable),
+ cStatInfo(achExploreAllBiomes, "achievement.exploreAllBiomes", achEnterTheEnd),
+ cStatInfo(achSpawnWither, "achievement.spawnWither", achDefeatDragon),
+ cStatInfo(achKillWither, "achievement.killWither", achSpawnWither),
+ cStatInfo(achFullBeacon, "achievement.fullBeacon", achKillWither),
+ cStatInfo(achBreedCow, "achievement.breedCow", achKillCow),
+ cStatInfo(achThrowDiamonds, "achievement.diamondsToYou", achDiamonds),
+
+ // http://minecraft.gamepedia.com/Statistics
+
+ /* Type | Name */
+ cStatInfo(statGamesQuit, "stat.leaveGame"),
+ cStatInfo(statMinutesPlayed, "stat.playOneMinute"),
+ cStatInfo(statDistWalked, "stat.walkOneCm"),
+ cStatInfo(statDistSwum, "stat.swimOneCm"),
+ cStatInfo(statDistFallen, "stat.fallOneCm"),
+ cStatInfo(statDistClimbed, "stat.climbOneCm"),
+ cStatInfo(statDistFlown, "stat.flyOneCm"),
+ cStatInfo(statDistDove, "stat.diveOneCm"),
+ cStatInfo(statDistMinecart, "stat.minecartOneCm"),
+ cStatInfo(statDistBoat, "stat.boatOneCm"),
+ cStatInfo(statDistPig, "stat.pigOneCm"),
+ cStatInfo(statDistHorse, "stat.horseOneCm"),
+ cStatInfo(statJumps, "stat.jump"),
+ cStatInfo(statItemsDropped, "stat.drop"),
+ cStatInfo(statDamageDealt, "stat.damageDealt"),
+ cStatInfo(statDamageTaken, "stat.damageTaken"),
+ cStatInfo(statDeaths, "stat.deaths"),
+ cStatInfo(statMobKills, "stat.mobKills"),
+ cStatInfo(statAnimalsBred, "stat.animalsBred"),
+ cStatInfo(statPlayerKills, "stat.playerKills"),
+ cStatInfo(statFishCaught, "stat.fishCaught"),
+ cStatInfo(statJunkFished, "stat.junkFished"),
+ cStatInfo(statTreasureFished, "stat.treasureFished")
+};
+
+
+
+
+
+
+cStatInfo::cStatInfo()
+ : m_Type(statInvalid)
+ , m_Depends(statInvalid)
+{}
+
+
+
+
+
+cStatInfo::cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends)
+ : m_Type(a_Type)
+ , m_Name(a_Name)
+ , m_Depends(a_Depends)
+{}
+
+
+
+
+
+const AString & cStatInfo::GetName(const eStatistic a_Type)
+{
+ ASSERT((a_Type > statInvalid) && (a_Type < statCount));
+
+ return ms_Info[a_Type].m_Name;
+}
+
+
+
+
+
+eStatistic cStatInfo::GetType(const AString & a_Name)
+{
+ for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i)
+ {
+ if (NoCaseCompare(ms_Info[i].m_Name, a_Name) == 0)
+ {
+ return ms_Info[i].m_Type;
+ }
+ }
+
+ return statInvalid;
+}
+
+
+
+
+
+eStatistic cStatInfo::GetPrerequisite(const eStatistic a_Type)
+{
+ ASSERT((a_Type > statInvalid) && (a_Type < statCount));
+
+ return ms_Info[a_Type].m_Depends;
+}
+
+
+
+
+
+cStatManager::cStatManager()
+{
+ Reset();
+}
+
+
+
+
+
+StatValue cStatManager::GetValue(const eStatistic a_Stat) const
+{
+ ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
+
+ return m_MainStats[a_Stat];
+}
+
+
+
+
+
+void cStatManager::SetValue(const eStatistic a_Stat, const StatValue a_Value)
+{
+ ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
+
+ m_MainStats[a_Stat] = a_Value;
+}
+
+
+
+
+
+StatValue cStatManager::AddValue(const eStatistic a_Stat, const StatValue a_Delta)
+{
+ ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
+
+ m_MainStats[a_Stat] += a_Delta;
+
+ return m_MainStats[a_Stat];
+}
+
+
+
+
+
+void cStatManager::Reset(void)
+{
+ for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
+ {
+ m_MainStats[i] = 0;
+ }
+}
+
+
+
+
+
diff --git a/src/Statistics.h b/src/Statistics.h
new file mode 100644
index 000000000..f37f32e1e
--- /dev/null
+++ b/src/Statistics.h
@@ -0,0 +1,164 @@
+
+// Statistics.h
+
+
+
+
+#pragma once
+
+
+
+
+// tolua_begin
+enum eStatistic
+{
+ // The order must match the order of cStatInfo::ms_Info
+
+ statInvalid = -1,
+
+ /* Achievements */
+ achOpenInv, /* Taking Inventory */
+ achMineWood, /* Getting Wood */
+ achCraftWorkbench, /* Benchmarking */
+ achCraftPickaxe, /* Time to Mine! */
+ achCraftFurnace, /* Hot Topic */
+ achAcquireIron, /* Acquire Hardware */
+ achCraftHoe, /* Time to Farm! */
+ achMakeBread, /* Bake Bread */
+ achBakeCake, /* The Lie */
+ achCraftBetterPick, /* Getting an Upgrade */
+ achCookFish, /* Delicious Fish */
+ achOnARail, /* On A Rail */
+ achCraftSword, /* Time to Strike! */
+ achKillMonster, /* Monster Hunter */
+ achKillCow, /* Cow Tipper */
+ achFlyPig, /* When Pigs Fly */
+ achSnipeSkeleton, /* Sniper Duel */
+ achDiamonds, /* DIAMONDS! */
+ achEnterPortal, /* We Need to Go Deeper */
+ achReturnToSender, /* Return to Sender */
+ achBlazeRod, /* Into Fire */
+ achBrewPotion, /* Local Brewery */
+ achEnterTheEnd, /* The End? */
+ achDefeatDragon, /* The End. */
+ achCraftEnchantTable, /* Enchanter */
+ achOverkill, /* Overkill */
+ achBookshelf, /* Librarian */
+ achExploreAllBiomes, /* Adventuring Time */
+ achSpawnWither, /* The Beginning? */
+ achKillWither, /* The Beginning. */
+ achFullBeacon, /* Beaconator */
+ achBreedCow, /* Repopulation */
+ achThrowDiamonds, /* Diamonds to you! */
+
+ /* Statistics */
+ statGamesQuit,
+ statMinutesPlayed,
+ statDistWalked,
+ statDistSwum,
+ statDistFallen,
+ statDistClimbed,
+ statDistFlown,
+ statDistDove,
+ statDistMinecart,
+ statDistBoat,
+ statDistPig,
+ statDistHorse,
+ statJumps,
+ statItemsDropped,
+ statDamageDealt,
+ statDamageTaken,
+ statDeaths,
+ statMobKills,
+ statAnimalsBred,
+ statPlayerKills,
+ statFishCaught,
+ statJunkFished,
+ statTreasureFished,
+
+ statCount
+};
+// tolua_end
+
+
+
+
+
+
+/** Class used to store and query statistic-related information. */
+class cStatInfo
+{
+public:
+
+ cStatInfo();
+
+ cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends = statInvalid);
+
+ /** Type -> Name */
+ static const AString & GetName(const eStatistic a_Type);
+
+ /** Name -> Type */
+ static eStatistic GetType(const AString & a_Name);
+
+ /** Returns stat prerequisite. (Used for achievements) */
+ static eStatistic GetPrerequisite(const eStatistic a_Type);
+
+private:
+
+ eStatistic m_Type;
+
+ AString m_Name;
+
+ eStatistic m_Depends;
+
+ static cStatInfo ms_Info[statCount];
+};
+
+
+
+
+/* Signed (?) integral value. */
+typedef int StatValue; // tolua_export
+
+
+
+
+/** Class that manages the statistics and achievements of a single player. */
+// tolua_begin
+class cStatManager
+{
+public:
+ // tolua_end
+
+ cStatManager();
+
+ // tolua_begin
+
+ /** Return the value of the specified stat. */
+ StatValue GetValue(const eStatistic a_Stat) const;
+
+ /** Set the value of the specified stat. */
+ void SetValue(const eStatistic a_Stat, const StatValue a_Value);
+
+ /** Reset everything. */
+ void Reset();
+
+ /** Increment the specified stat.
+ *
+ * Returns the new value.
+ */
+ StatValue AddValue(const eStatistic a_Stat, const StatValue a_Delta = 1);
+
+ // tolua_end
+
+private:
+
+ StatValue m_MainStats[statCount];
+
+ // TODO 10-05-2014 xdot: Use, mine, craft statistics
+
+
+}; // tolua_export
+
+
+
diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp
index 5b9a3bb0a..71d64e71e 100644
--- a/src/StringCompression.cpp
+++ b/src/StringCompression.cpp
@@ -11,15 +11,15 @@
/// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2()
-int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor)
+int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor)
{
- uLongf CompressedSize = compressBound(a_Length);
+ uLongf CompressedSize = compressBound((uLong)a_Length);
// HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
// It saves us one allocation and one memcpy of the entire compressed data
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
a_Compressed.resize(CompressedSize);
- int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor);
+ int errorcode = compress2((Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef *)a_Data, (uLong)a_Length, a_Factor);
if (errorcode != Z_OK)
{
return errorcode;
@@ -33,14 +33,14 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, in
/// Uncompresses a_Data into a_Decompressed; returns Z_XXX error constants same as zlib's uncompress()
-int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize)
+int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize)
{
// HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
// It saves us one allocation and one memcpy of the entire compressed data
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
a_Uncompressed.resize(a_UncompressedSize);
uLongf UncompressedSize = (uLongf)a_UncompressedSize; // On some architectures the uLongf is different in size to int, that may be the cause of the -5 error
- int errorcode = uncompress((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, a_Length);
+ int errorcode = uncompress((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, (uLong)a_Length);
if (errorcode != Z_OK)
{
return errorcode;
@@ -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()
@@ -63,7 +63,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
z_stream strm;
memset(&strm, 0, sizeof(strm));
strm.next_in = (Bytef *)a_Data;
- strm.avail_in = a_Length;
+ strm.avail_in = (uInt)a_Length;
strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
@@ -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
@@ -126,7 +127,7 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U
z_stream strm;
memset(&strm, 0, sizeof(strm));
strm.next_in = (Bytef *)a_Data;
- strm.avail_in = a_Length;
+ strm.avail_in = (uInt)a_Length;
strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
@@ -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..038240797 100644
--- a/src/StringCompression.h
+++ b/src/StringCompression.h
@@ -10,16 +10,16 @@
/// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2()
-extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor);
+extern int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor);
/// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress()
-extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);
+extern int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t 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.cpp b/src/StringUtils.cpp
index ad622d707..7488a3073 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -247,18 +247,22 @@ int NoCaseCompare(const AString & s1, const AString & s2)
-unsigned int RateCompareString(const AString & s1, const AString & s2 )
+size_t RateCompareString(const AString & s1, const AString & s2)
{
- unsigned int MatchedLetters = 0;
- unsigned int s1Length = s1.length();
+ size_t MatchedLetters = 0;
+ size_t s1Length = s1.length();
- if( s1Length > s2.length() ) return 0; // Definitely not a match
+ if (s1Length > s2.length())
+ {
+ // Definitely not a match
+ return 0;
+ }
- for (unsigned int i = 0; i < s1Length; i++)
+ for (size_t i = 0; i < s1Length; i++)
{
- char c1 = (char)toupper( s1[i] );
- char c2 = (char)toupper( s2[i] );
- if( c1 == c2 )
+ char c1 = (char)toupper(s1[i]);
+ char c2 = (char)toupper(s2[i]);
+ if (c1 == c2)
{
++MatchedLetters;
}
@@ -288,11 +292,11 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString &
// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
-AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8)
+AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8)
{
a_UTF8.clear();
a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size
- for (int i = 0; i < a_NumShorts; i++)
+ for (size_t i = 0; i < a_NumShorts; i++)
{
int c = GetBEShort(&a_RawData[i * 2]);
if (c < 0x80)
@@ -531,32 +535,32 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a
format binary data this way:
00001234: 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 1234567890abcdef
*/
-AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_LineLength)
+AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, size_t a_BytesPerLine)
{
- ASSERT(a_LineLength <= 120); // Due to using a fixed size line buffer; increase line[]'s size to lift this max
+ ASSERT(a_BytesPerLine <= 120); // Due to using a fixed size line buffer; increase line[]'s size to lift this max
char line[512];
char * p;
char * q;
- a_Out.reserve(a_Size / a_LineLength * (18 + 6 * a_LineLength));
- for (int i = 0; i < a_Size; i += a_LineLength)
+ a_Out.reserve(a_Size / a_BytesPerLine * (18 + 6 * a_BytesPerLine));
+ for (size_t i = 0; i < a_Size; i += a_BytesPerLine)
{
- int k = a_Size - i;
- if (k > a_LineLength)
+ size_t k = a_Size - i;
+ if (k > a_BytesPerLine)
{
- k = a_LineLength;
+ k = a_BytesPerLine;
}
#ifdef _MSC_VER
// MSVC provides a "secure" version of sprintf()
- int Count = sprintf_s(line, sizeof(line), "%08x:", i);
+ int Count = sprintf_s(line, sizeof(line), "%08x:", (unsigned)i);
#else
- int Count = sprintf(line, "%08x:", i);
+ int Count = sprintf(line, "%08x:", (unsigned)i);
#endif
// Remove the terminating NULL / leftover garbage in line, after the sprintf-ed value
memset(line + Count, 32, sizeof(line) - Count);
p = line + 10;
- q = p + 2 + a_LineLength * 3 + 1;
- for (int j = 0; j < k; j++)
+ q = p + 2 + a_BytesPerLine * 3 + 1;
+ for (size_t j = 0; j < k; j++)
{
unsigned char c = ((unsigned char *)a_Data)[i + j];
p[0] = HEX(c >> 4);
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 4feff7553..87b574a34 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -11,6 +11,9 @@
+#include <string>
+
+
typedef std::string AString;
@@ -52,19 +55,19 @@ extern AString & StrToLower(AString & s);
extern int NoCaseCompare(const AString & s1, const AString & s2); // tolua_export
/// Case-insensitive string comparison that returns a rating of equal-ness between [0 - s1.length()]
-extern unsigned int RateCompareString(const AString & s1, const AString & s2 );
+extern size_t RateCompareString(const AString & s1, const AString & s2);
/// Replaces *each* occurence of iNeedle in iHayStack with iReplaceWith
extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export
/// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
-extern AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8);
+extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8);
/// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16
extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16);
/// Creates a nicely formatted HEX dump of the given memory block. Max a_BytesPerLine is 120
-extern AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_BytesPerLine);
+extern AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, size_t a_BytesPerLine);
/// Returns a copy of a_Message with all quotes and backslashes escaped by a backslash
extern AString EscapeString(const AString & a_Message); // tolua_export
@@ -79,10 +82,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/Tracer.cpp b/src/Tracer.cpp
index 6da6b2ad7..be42430a5 100644
--- a/src/Tracer.cpp
+++ b/src/Tracer.cpp
@@ -219,6 +219,10 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int
return false;
}
+ if ((pos.y < 0) || (pos.y >= cChunkDef::Height))
+ {
+ return false;
+ }
BLOCKTYPE BlockID = m_World->GetBlock(pos.x, pos.y, pos.z);
// Block is counted as a collision if we are not doing a line of sight and it is solid,
// or if the block is not air and not water. That way mobs can still see underwater.
@@ -226,7 +230,7 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int
{
BlockHitPosition = pos;
int Normal = GetHitNormal(a_Start, End, pos );
- if(Normal > 0)
+ if (Normal > 0)
{
HitNormal = m_NormalTable[Normal-1];
}
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt
index cef2a9f35..5b5b8cc18 100644
--- a/src/UI/CMakeLists.txt
+++ b/src/UI/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(UI ${SOURCE})
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 88977e005..507b45833 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -13,6 +13,8 @@
#include "Window.h"
#include "../CraftingRecipes.h"
#include "../Root.h"
+#include "../FastRandom.h"
+#include "../BlockArea.h"
@@ -145,6 +147,7 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
FreeSlots = 0;
}
int Filling = (FreeSlots > DraggingItem.m_ItemCount) ? DraggingItem.m_ItemCount : FreeSlots;
+
Slot.m_ItemCount += (char)Filling;
DraggingItem.m_ItemCount -= (char)Filling;
if (DraggingItem.m_ItemCount <= 0)
@@ -167,7 +170,6 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
{
m_ParentWindow.BroadcastWholeWindow();
}
-
}
@@ -242,7 +244,7 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player)
-void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
+void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
{
for (int i = 0; i < m_NumSlots; i++)
{
@@ -262,7 +264,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_
{
NumFit = a_ItemStack.m_ItemCount;
}
- if (a_Apply)
+ if (a_ShouldApply)
{
cItem NewSlot(a_ItemStack);
NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
@@ -483,6 +485,7 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
// Get the current recipe:
cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
+ const cItem & Result = Recipe.GetResult();
cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1;
cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize);
@@ -490,18 +493,22 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
// If possible, craft:
if (DraggingItem.IsEmpty())
{
- DraggingItem = Recipe.GetResult();
+ DraggingItem = Result;
Recipe.ConsumeIngredients(Grid);
Grid.CopyToItems(PlayerSlots);
+
+ HandleCraftItem(Result, a_Player);
}
- else if (DraggingItem.IsEqual(Recipe.GetResult()))
+ else if (DraggingItem.IsEqual(Result))
{
- cItemHandler * Handler = ItemHandler(Recipe.GetResult().m_ItemType);
- if (DraggingItem.m_ItemCount + Recipe.GetResult().m_ItemCount <= Handler->GetMaxStackSize())
+ cItemHandler * Handler = ItemHandler(Result.m_ItemType);
+ if (DraggingItem.m_ItemCount + Result.m_ItemCount <= Handler->GetMaxStackSize())
{
- DraggingItem.m_ItemCount += Recipe.GetResult().m_ItemCount;
+ DraggingItem.m_ItemCount += Result.m_ItemCount;
Recipe.ConsumeIngredients(Grid);
Grid.CopyToItems(PlayerSlots);
+
+ HandleCraftItem(Result, a_Player);
}
}
@@ -591,6 +598,731 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
+void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Player)
+{
+ switch (a_Result.m_ItemType)
+ {
+ case E_BLOCK_WORKBENCH: a_Player.AwardAchievement(achCraftWorkbench); break;
+ case E_BLOCK_FURNACE: a_Player.AwardAchievement(achCraftFurnace); break;
+ case E_BLOCK_CAKE: a_Player.AwardAchievement(achBakeCake); break;
+ case E_BLOCK_ENCHANTMENT_TABLE: a_Player.AwardAchievement(achCraftEnchantTable); break;
+ case E_BLOCK_BOOKCASE: a_Player.AwardAchievement(achBookshelf); break;
+ case E_ITEM_WOODEN_PICKAXE: a_Player.AwardAchievement(achCraftPickaxe); break;
+ case E_ITEM_WOODEN_SWORD: a_Player.AwardAchievement(achCraftSword); break;
+ case E_ITEM_STONE_PICKAXE: a_Player.AwardAchievement(achCraftBetterPick); break;
+ case E_ITEM_WOODEN_HOE: a_Player.AwardAchievement(achCraftHoe); break;
+ case E_ITEM_BREAD: a_Player.AwardAchievement(achMakeBread); break;
+ default: break;
+ }
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSlotAreaAnvil:
+
+cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) :
+ cSlotAreaTemporary(3, a_ParentWindow),
+ m_MaximumCost(0)
+{
+}
+
+
+
+
+
+void cSlotAreaAnvil::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
+{
+ ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
+ if (a_SlotNum != 2)
+ {
+ super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
+ UpdateResult(a_Player);
+ return;
+ }
+
+ bool bAsync = false;
+ if (GetSlot(a_SlotNum, a_Player) == NULL)
+ {
+ LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum);
+ return;
+ }
+
+ if (a_ClickAction == caDblClick)
+ {
+ return;
+ }
+
+ if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick))
+ {
+ ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
+ return;
+ }
+
+ cItem Slot(*GetSlot(a_SlotNum, a_Player));
+ if (!Slot.IsSameType(a_ClickedItem))
+ {
+ LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
+ LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
+ LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
+ bAsync = true;
+ }
+ cItem & DraggingItem = a_Player.GetDraggingItem();
+
+ if (Slot.IsEmpty())
+ {
+ return;
+ }
+ if (!DraggingItem.IsEmpty())
+ {
+ if (!(DraggingItem.IsEqual(Slot) && ((DraggingItem.m_ItemCount + Slot.m_ItemCount) <= cItemHandler::GetItemHandler(Slot)->GetMaxStackSize())))
+ {
+ return;
+ }
+ }
+
+ if (!CanTakeResultItem(a_Player))
+ {
+ return;
+ }
+
+ cItem NewItem = cItem(Slot);
+ NewItem.m_ItemCount += DraggingItem.m_ItemCount;
+
+ Slot.Empty();
+ DraggingItem.Empty();
+ SetSlot(a_SlotNum, a_Player, Slot);
+
+ DraggingItem = NewItem;
+ OnTakeResult(a_Player);
+
+ if (bAsync)
+ {
+ m_ParentWindow.BroadcastWholeWindow();
+ }
+}
+
+
+
+
+
+void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem)
+{
+ if (a_SlotNum != 2)
+ {
+ super::ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
+ UpdateResult(a_Player);
+ return;
+ }
+
+ // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover:
+ cItem Slot(*GetSlot(a_SlotNum, a_Player));
+
+ if (Slot.IsEmpty() || !CanTakeResultItem(a_Player))
+ {
+ return;
+ }
+
+ m_ParentWindow.DistributeStack(Slot, a_Player, this, true);
+ if (Slot.IsEmpty())
+ {
+ Slot.Empty();
+ OnTakeResult(a_Player);
+ }
+ SetSlot(a_SlotNum, a_Player, Slot);
+
+ // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them:
+ m_ParentWindow.BroadcastWholeWindow();
+}
+
+
+
+
+
+void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ const cItem * Slot = GetSlot(i, a_Player);
+ if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
+ {
+ // Different items
+ continue;
+ }
+ int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
+ if (NumFit <= 0)
+ {
+ // Full stack already
+ continue;
+ }
+ if (NumFit > a_ItemStack.m_ItemCount)
+ {
+ NumFit = a_ItemStack.m_ItemCount;
+ }
+ if (a_ShouldApply)
+ {
+ cItem NewSlot(a_ItemStack);
+ NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
+ SetSlot(i, a_Player, NewSlot);
+ }
+ a_ItemStack.m_ItemCount -= NumFit;
+ if (a_ItemStack.IsEmpty())
+ {
+ UpdateResult(a_Player);
+ return;
+ }
+ } // for i - Slots
+ UpdateResult(a_Player);
+}
+
+
+
+
+
+void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player)
+{
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.DeltaExperience(-cPlayer::XpForLevel(m_MaximumCost));
+ }
+ SetSlot(0, a_Player, cItem());
+
+ if (m_StackSizeToBeUsedInRepair > 0)
+ {
+ const cItem * Item = GetSlot(1, a_Player);
+ if (!Item->IsEmpty() && (Item->m_ItemCount > m_StackSizeToBeUsedInRepair))
+ {
+ cItem NewSecondItem(*Item);
+ NewSecondItem.m_ItemCount -= m_StackSizeToBeUsedInRepair;
+ SetSlot(1, a_Player, NewSecondItem);
+ }
+ else
+ {
+ SetSlot(1, a_Player, cItem());
+ }
+ }
+ else
+ {
+ SetSlot(1, a_Player, cItem());
+ }
+ m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player);
+
+ m_MaximumCost = 0;
+ ((cAnvilWindow*)&m_ParentWindow)->SetRepairedItemName("", NULL);
+
+ int PosX, PosY, PosZ;
+ ((cAnvilWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ);
+
+ BLOCKTYPE Block;
+ NIBBLETYPE BlockMeta;
+ a_Player.GetWorld()->GetBlockTypeMeta(PosX, PosY, PosZ, Block, BlockMeta);
+
+ cFastRandom Random;
+ if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && (Random.NextFloat(1.0F) < 0.12F))
+ {
+ NIBBLETYPE Orientation = BlockMeta & 0x3;
+ NIBBLETYPE AnvilDamage = BlockMeta >> 2;
+ ++AnvilDamage;
+
+ if (AnvilDamage > 2)
+ {
+ // Anvil will break
+ a_Player.GetWorld()->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, (NIBBLETYPE)0);
+ a_Player.GetWorld()->BroadcastSoundParticleEffect(1020, PosX, PosY, PosZ, 0);
+ a_Player.CloseWindow(false);
+ }
+ else
+ {
+ a_Player.GetWorld()->SetBlockMeta(PosX, PosY, PosZ, Orientation | (AnvilDamage << 2));
+ a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0);
+ }
+ }
+ else
+ {
+ a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0);
+ }
+}
+
+
+
+
+
+bool cSlotAreaAnvil::CanTakeResultItem(cPlayer & a_Player)
+{
+ return (
+ (
+ a_Player.IsGameModeCreative() || // Is the player in gamemode?
+ (a_Player.GetXpLevel() >= m_MaximumCost) // or the player have enough exp?
+ ) &&
+ (!GetSlot(2, a_Player)->IsEmpty()) && // Is a item in the result slot?
+ (m_MaximumCost > 0) // When no maximum cost is set, the item isn't set from the UpdateResult() method and can't be a valid enchanting result.
+ );
+}
+
+
+
+
+
+void cSlotAreaAnvil::OnPlayerRemoved(cPlayer & a_Player)
+{
+ TossItems(a_Player, 0, 2);
+ super::OnPlayerRemoved(a_Player);
+}
+
+
+
+
+
+void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player)
+{
+ cItem Input(*GetSlot(0, a_Player));
+ cItem SecondInput(*GetSlot(1, a_Player));
+ cItem Output(*GetSlot(2, a_Player));
+
+ if (Input.IsEmpty() && !Output.IsEmpty())
+ {
+ Output.Empty();
+ SetSlot(2, a_Player, Output);
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ return;
+ }
+
+ m_MaximumCost = 0;
+ m_StackSizeToBeUsedInRepair = 0;
+ int RepairCost = Input.m_RepairCost;
+ int NeedExp = 0;
+ bool IsEnchantBook = false;
+ if (!SecondInput.IsEmpty())
+ {
+ IsEnchantBook = (SecondInput.m_ItemType == E_ITEM_ENCHANTED_BOOK);
+
+ RepairCost += SecondInput.m_RepairCost;
+ if (Input.IsDamageable() && cItemHandler::GetItemHandler(Input)->CanRepairWithRawMaterial(SecondInput.m_ItemType))
+ {
+ // Tool and armor repair with special item (iron / gold / diamond / ...)
+ int DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4);
+ if (DamageDiff <= 0)
+ {
+ // No enchantment
+ Output.Empty();
+ SetSlot(2, a_Player, Output);
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ return;
+ }
+
+ int x = 0;
+ while ((DamageDiff > 0) && (x < SecondInput.m_ItemCount))
+ {
+ Input.m_ItemDamage -= DamageDiff;
+ NeedExp += std::max(1, DamageDiff / 100) + (int)Input.m_Enchantments.Count();
+ DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4);
+
+ ++x;
+ }
+ m_StackSizeToBeUsedInRepair = x;
+ }
+ else
+ {
+ // Tool and armor repair with two tools / armors
+ if (!IsEnchantBook && (!Input.IsSameType(SecondInput) || !Input.IsDamageable()))
+ {
+ // No enchantment
+ Output.Empty();
+ SetSlot(2, a_Player, Output);
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ return;
+ }
+
+ if ((Input.GetMaxDamage() > 0) && !IsEnchantBook)
+ {
+ int FirstDamageDiff = Input.GetMaxDamage() - Input.m_ItemDamage;
+ int SecondDamageDiff = SecondInput.GetMaxDamage() - SecondInput.m_ItemDamage;
+ int Damage = SecondDamageDiff + Input.GetMaxDamage() * 12 / 100;
+
+ int NewItemDamage = Input.GetMaxDamage() - (FirstDamageDiff + Damage);
+ if (NewItemDamage > 0)
+ {
+ NewItemDamage = 0;
+ }
+
+ if (NewItemDamage < Input.m_ItemDamage)
+ {
+ Input.m_ItemDamage = NewItemDamage;
+ NeedExp += std::max(1, Damage / 100);
+ }
+ }
+
+ // TODO: Add enchantments.
+ }
+ }
+
+ int NameChangeExp = 0;
+ const AString & RepairedItemName = ((cAnvilWindow*)&m_ParentWindow)->GetRepairedItemName();
+ if (RepairedItemName.empty())
+ {
+ // Remove custom name
+ if (!Input.m_CustomName.empty())
+ {
+ NameChangeExp = (Input.IsDamageable()) ? 7 : (Input.m_ItemCount * 5);
+ NeedExp += NameChangeExp;
+ Input.m_CustomName = "";
+ }
+ }
+ else if (RepairedItemName != Input.m_CustomName)
+ {
+ // Change custom name
+ NameChangeExp = (Input.IsDamageable()) ? 7 : (Input.m_ItemCount * 5);
+ NeedExp += NameChangeExp;
+
+ if (!Input.m_CustomName.empty())
+ {
+ RepairCost += NameChangeExp / 2;
+ }
+
+ Input.m_CustomName = RepairedItemName;
+ }
+
+ // TODO: Add enchantment exp cost.
+
+ m_MaximumCost = RepairCost + NeedExp;
+
+ if (NeedExp < 0)
+ {
+ Input.Empty();
+ }
+
+ if ((NameChangeExp == NeedExp) && (NameChangeExp > 0) && (m_MaximumCost >= 40))
+ {
+ m_MaximumCost = 39;
+ }
+ if (m_MaximumCost >= 40 && !a_Player.IsGameModeCreative())
+ {
+ Input.Empty();
+ }
+
+ if (!Input.IsEmpty())
+ {
+ RepairCost = std::max(Input.m_RepairCost, SecondInput.m_RepairCost);
+ if (!Input.m_CustomName.empty())
+ {
+ RepairCost -= 9;
+ }
+ RepairCost = std::max(RepairCost, 0);
+ RepairCost += 2;
+ Input.m_RepairCost = RepairCost;
+ }
+
+ SetSlot(2, a_Player, Input);
+ m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player);
+}
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSlotAreaEnchanting:
+
+cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) :
+ cSlotAreaTemporary(1, a_ParentWindow)
+{
+ a_ParentWindow.m_SlotArea = this;
+}
+
+
+
+
+
+void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
+{
+ ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
+
+ bool bAsync = false;
+ if (GetSlot(a_SlotNum, a_Player) == NULL)
+ {
+ LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum);
+ return;
+ }
+
+ switch (a_ClickAction)
+ {
+ case caShiftLeftClick:
+ case caShiftRightClick:
+ {
+ ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
+ return;
+ }
+
+ case caDblClick:
+ {
+ DblClicked(a_Player, a_SlotNum);
+ return;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ cItem Slot(*GetSlot(a_SlotNum, a_Player));
+ if (!Slot.IsSameType(a_ClickedItem))
+ {
+ LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
+ LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
+ LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
+ bAsync = true;
+ }
+ cItem & DraggingItem = a_Player.GetDraggingItem();
+ switch (a_ClickAction)
+ {
+ case caRightClick:
+ {
+ // Right-clicked
+ if (DraggingItem.IsEmpty())
+ {
+ DraggingItem = Slot.CopyOne();
+ Slot.Empty();
+ break;
+ }
+
+ if (Slot.IsEmpty())
+ {
+ Slot = DraggingItem.CopyOne();
+ DraggingItem.m_ItemCount -= 1;
+ if (DraggingItem.m_ItemCount <= 0)
+ {
+ DraggingItem.Empty();
+ }
+ }
+ else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1))
+ {
+ // Swap contents
+ cItem tmp(DraggingItem);
+ DraggingItem = Slot;
+ Slot = tmp;
+ }
+ break;
+ }
+
+ case caLeftClick:
+ {
+ // Left-clicked
+ if (DraggingItem.IsEmpty())
+ {
+ DraggingItem = Slot.CopyOne();
+ Slot.Empty();
+ break;
+ }
+
+ if (DraggingItem.IsEqual(Slot))
+ {
+ // Do nothing
+ break;
+ }
+
+ if (!Slot.IsEmpty())
+ {
+ if (DraggingItem.m_ItemCount == 1)
+ {
+ // Swap contents
+ cItem tmp(DraggingItem);
+ DraggingItem = Slot;
+ Slot = tmp;
+ }
+ }
+ else
+ {
+ Slot = DraggingItem.CopyOne();
+ DraggingItem.m_ItemCount -= 1;
+ if (DraggingItem.m_ItemCount <= 0)
+ {
+ DraggingItem.Empty();
+ }
+ }
+ break;
+ }
+ default:
+ {
+ LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction));
+ m_ParentWindow.BroadcastWholeWindow();
+ return;
+ }
+ } // switch (a_ClickAction
+
+ SetSlot(a_SlotNum, a_Player, Slot);
+ if (bAsync)
+ {
+ m_ParentWindow.BroadcastWholeWindow();
+ }
+ UpdateResult(a_Player);
+}
+
+
+
+
+
+void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum)
+{
+ cItem & Dragging = a_Player.GetDraggingItem();
+ if ((!Dragging.IsEmpty()) || (a_SlotNum != 0))
+ {
+ return;
+ }
+
+ cItem Item = *GetSlot(0, a_Player);
+ if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false))
+ {
+ m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true);
+ }
+}
+
+
+
+
+
+void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
+{
+ const cItem * Slot = GetSlot(0, a_Player);
+ if (!Slot->IsEmpty())
+ {
+ return;
+ }
+
+ if (a_Apply)
+ {
+ SetSlot(0, a_Player, a_ItemStack.CopyOne());
+ }
+ a_ItemStack.m_ItemCount -= 1;
+ if (a_ItemStack.m_ItemCount <= 0)
+ {
+ a_ItemStack.Empty();
+ }
+
+ UpdateResult(a_Player);
+}
+
+
+
+
+
+void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player)
+{
+ // Toss the item in the enchanting slot
+ TossItems(a_Player, 0, 1);
+
+ super::OnPlayerRemoved(a_Player);
+}
+
+
+
+
+
+void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player)
+{
+ cItem Item = *GetSlot(0, a_Player);
+
+ if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty())
+ {
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ m_ParentWindow.SetProperty(1, 0, a_Player);
+ m_ParentWindow.SetProperty(2, 0, a_Player);
+ }
+ else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK)
+ {
+ int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15);
+
+ cFastRandom Random;
+ int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves));
+ int topSlot = std::max(base / 3, 1);
+ int middleSlot = (base * 2) / 3 + 1;
+ int bottomSlot = std::max(base, Bookshelves * 2);
+
+ m_ParentWindow.SetProperty(0, topSlot, a_Player);
+ m_ParentWindow.SetProperty(1, middleSlot, a_Player);
+ m_ParentWindow.SetProperty(2, bottomSlot, a_Player);
+ }
+ else
+ {
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ m_ParentWindow.SetProperty(1, 0, a_Player);
+ m_ParentWindow.SetProperty(2, 0, a_Player);
+ }
+}
+
+
+
+
+
+int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World)
+{
+ int PosX, PosY, PosZ;
+ ((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ);
+
+ int Bookshelves = 0;
+ cBlockArea Area;
+ Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2);
+
+ static const struct
+ {
+ int m_BookX, m_BookY, m_BookZ; // Coords to check for bookcases
+ int m_AirX, m_AirY, m_AirZ; // Coords to check for air; if not air, the bookcase won't be counted
+ } CheckCoords[] =
+ {
+ { 0, 0, 0, 1, 0, 1 }, // Bookcase at {0, 0, 0}, air at {1, 0, 1}
+ { 0, 0, 1, 1, 0, 1 }, // Bookcase at {0, 0, 1}, air at {1, 0, 1}
+ { 0, 0, 2, 1, 0, 2 }, // Bookcase at {0, 0, 2}, air at {1, 0, 2}
+ { 0, 0, 3, 1, 0, 3 }, // Bookcase at {0, 0, 3}, air at {1, 0, 3}
+ { 0, 0, 4, 1, 0, 3 }, // Bookcase at {0, 0, 4}, air at {1, 0, 3}
+ { 1, 0, 4, 1, 0, 3 }, // Bookcase at {1, 0, 4}, air at {1, 0, 3}
+ { 2, 0, 4, 2, 0, 3 }, // Bookcase at {2, 0, 4}, air at {2, 0, 3}
+ { 3, 0, 4, 3, 0, 3 }, // Bookcase at {3, 0, 4}, air at {3, 0, 3}
+ { 4, 0, 4, 3, 0, 3 }, // Bookcase at {4, 0, 4}, air at {3, 0, 3}
+ { 4, 0, 3, 3, 0, 3 }, // Bookcase at {4, 0, 3}, air at {3, 0, 3}
+ { 4, 0, 2, 3, 0, 2 }, // Bookcase at {4, 0, 2}, air at {3, 0, 2}
+ { 4, 0, 1, 3, 0, 1 }, // Bookcase at {4, 0, 1}, air at {3, 0, 1}
+ { 4, 0, 0, 3, 0, 1 }, // Bookcase at {4, 0, 0}, air at {3, 0, 1}
+ { 3, 0, 0, 3, 0, 1 }, // Bookcase at {3, 0, 0}, air at {3, 0, 1}
+ { 2, 0, 0, 2, 0, 1 }, // Bookcase at {2, 0, 0}, air at {2, 0, 1}
+ { 1, 0, 0, 1, 0, 1 }, // Bookcase at {1, 0, 0}, air at {1, 0, 1}
+
+ { 0, 1, 0, 1, 1, 1 }, // Bookcase at {0, 1, 0}, air at {1, 1, 1}
+ { 0, 1, 1, 1, 1, 1 }, // Bookcase at {0, 1, 1}, air at {1, 1, 1}
+ { 0, 1, 2, 1, 1, 2 }, // Bookcase at {0, 1, 2}, air at {1, 1, 2}
+ { 0, 1, 3, 1, 1, 3 }, // Bookcase at {0, 1, 3}, air at {1, 1, 3}
+ { 0, 1, 4, 1, 1, 3 }, // Bookcase at {0, 1, 4}, air at {1, 1, 3}
+ { 1, 1, 4, 1, 1, 3 }, // Bookcase at {1, 1, 4}, air at {1, 1, 3}
+ { 2, 1, 4, 2, 1, 3 }, // Bookcase at {2, 1, 4}, air at {2, 1, 3}
+ { 3, 1, 4, 3, 1, 3 }, // Bookcase at {3, 1, 4}, air at {3, 1, 3}
+ { 4, 1, 4, 3, 1, 3 }, // Bookcase at {4, 1, 4}, air at {3, 1, 3}
+ { 4, 1, 3, 3, 1, 3 }, // Bookcase at {4, 1, 3}, air at {3, 1, 3}
+ { 4, 1, 2, 3, 1, 2 }, // Bookcase at {4, 1, 2}, air at {3, 1, 2}
+ { 4, 1, 1, 3, 1, 1 }, // Bookcase at {4, 1, 1}, air at {3, 1, 1}
+ { 4, 1, 0, 3, 1, 1 }, // Bookcase at {4, 1, 0}, air at {3, 1, 1}
+ { 3, 1, 0, 3, 1, 1 }, // Bookcase at {3, 1, 0}, air at {3, 1, 1}
+ { 2, 1, 0, 2, 1, 1 }, // Bookcase at {2, 1, 0}, air at {2, 1, 1}
+ { 1, 1, 0, 1, 1, 1 }, // Bookcase at {1, 1, 0}, air at {1, 1, 1}
+ };
+
+ for (size_t i = 0; i < ARRAYCOUNT(CheckCoords); i++)
+ {
+ if (
+ (Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot
+ (Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place
+ )
+ {
+ Bookshelves++;
+ }
+ } // for i - CheckCoords
+
+ return Bookshelves;
+}
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnderChest:
@@ -686,7 +1418,7 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
// Something has changed in the window, broadcast the entire window to all clients
ASSERT(a_ItemGrid == &(m_Furnace->GetContents()));
-
+
m_ParentWindow.BroadcastWholeWindow();
}
@@ -694,6 +1426,21 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
+void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player)
+{
+ /** TODO 2014-05-12 xdot: Figure out when to call this method. */
+ switch (a_Result.m_ItemType)
+ {
+ case E_ITEM_IRON: a_Player.AwardAchievement(achAcquireIron); break;
+ case E_ITEM_COOKED_FISH: a_Player.AwardAchievement(achCookFish); break;
+ default: break;
+ }
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaInventoryBase:
@@ -787,6 +1534,80 @@ void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bo
+void cSlotAreaArmor::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
+{
+ ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
+
+ bool bAsync = false;
+ if (GetSlot(a_SlotNum, a_Player) == NULL)
+ {
+ LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum);
+ return;
+ }
+
+ if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick))
+ {
+ ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
+ return;
+ }
+
+ // Armors haven't a dbl click
+ if (a_ClickAction == caDblClick)
+ {
+ return;
+ }
+
+ cItem Slot(*GetSlot(a_SlotNum, a_Player));
+ if (!Slot.IsSameType(a_ClickedItem))
+ {
+ LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
+ LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
+ LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
+ bAsync = true;
+ }
+ cItem & DraggingItem = a_Player.GetDraggingItem();
+ if ((a_ClickAction != caRightClick) && (a_ClickAction != caLeftClick))
+ {
+ LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction));
+ m_ParentWindow.BroadcastWholeWindow();
+ return;
+ }
+
+ if (DraggingItem.IsEmpty() || CanPlaceInSlot(a_SlotNum, DraggingItem))
+ {
+ // Swap contents
+ cItem tmp(DraggingItem);
+ DraggingItem = Slot;
+ Slot = tmp;
+ }
+
+ SetSlot(a_SlotNum, a_Player, Slot);
+ if (bAsync)
+ {
+ m_ParentWindow.BroadcastWholeWindow();
+ }
+}
+
+
+
+
+
+bool cSlotAreaArmor::CanPlaceInSlot(int a_SlotNum, const cItem & a_Item)
+{
+ switch (a_SlotNum)
+ {
+ case 0: return ItemCategory::IsHelmet (a_Item.m_ItemType);
+ case 1: return ItemCategory::IsChestPlate(a_Item.m_ItemType);
+ case 2: return ItemCategory::IsLeggings (a_Item.m_ItemType);
+ case 3: return ItemCategory::IsBoots (a_Item.m_ItemType);
+ }
+ return false;
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaItemGrid:
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index 25b367cff..e297bcff7 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -9,6 +9,7 @@
#pragma once
#include "../Inventory.h"
+#include "Window.h"
@@ -19,6 +20,8 @@ class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cCraftingRecipe;
+class cEnchantingWindow;
+class cWorld;
@@ -66,7 +69,7 @@ public:
/// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting.
/// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill.
virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks);
-
+
protected:
int m_NumSlots;
cWindow & m_ParentWindow;
@@ -143,8 +146,13 @@ public:
{
}
- // Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.)
+ /** Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) */
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+
+ /** Called when a player clicks in the window. Parameters taken from the click packet. */
+ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
+
+ bool CanPlaceInSlot(int a_SlotNum, const cItem & a_Item);
} ;
@@ -246,12 +254,80 @@ protected:
/// Retrieves the recipe for the specified player from the map, or creates one if not found
cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player);
+
+ /// Called after an item has been crafted to handle statistics e.t.c.
+ void HandleCraftItem(const cItem & a_Result, cPlayer & a_Player);
+} ;
+
+
+
+
+
+class cSlotAreaAnvil :
+ public cSlotAreaTemporary
+{
+ typedef cSlotAreaTemporary super;
+
+public:
+ cSlotAreaAnvil(cAnvilWindow & a_ParentWindow);
+
+ // cSlotArea overrides:
+ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
+ virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+
+ // cSlotAreaTemporary overrides:
+ virtual void OnPlayerRemoved(cPlayer & a_Player) override;
+
+ /** Can the player take the item from the slot? */
+ bool CanTakeResultItem(cPlayer & a_Player);
+
+ /** This function will call, when the player take the item from the slot. */
+ void OnTakeResult(cPlayer & a_Player);
+
+ /** Handles a click in the item slot. */
+ void UpdateResult(cPlayer & a_Player);
+
+protected:
+ /** The maximum cost of repairing/renaming in the anvil. */
+ int m_MaximumCost;
+
+ /** The stack size of the second item where was used for repair */
+ char m_StackSizeToBeUsedInRepair;
} ;
+class cSlotAreaEnchanting :
+ public cSlotAreaTemporary
+{
+ typedef cSlotAreaTemporary super;
+
+public:
+ cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow);
+
+ // cSlotArea overrides:
+ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
+ virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+
+ // cSlotAreaTemporary overrides:
+ virtual void OnPlayerRemoved(cPlayer & a_Player) override;
+
+ /* Get the count of bookshelves who stand in the near of the enchanting table */
+ int GetBookshelvesCount(cWorld * a_World);
+
+protected:
+ /** Handles a click in the item slot. */
+ void UpdateResult(cPlayer & a_Player);
+};
+
+
+
+
+
class cSlotAreaChest :
public cSlotArea
{
@@ -324,6 +400,9 @@ protected:
// cItemGrid::cListener overrides:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
+
+ /// Called after an item has been smelted to handle statistics e.t.c.
+ void HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player);
} ;
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index aae7b99a3..46885390b 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -591,7 +591,7 @@ void cWindow::OnLeftPaintEnd(cPlayer & a_Player)
const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots();
cItem ToDistribute(a_Player.GetDraggingItem());
- int ToEachSlot = (int)ToDistribute.m_ItemCount / SlotNums.size();
+ int ToEachSlot = (int)ToDistribute.m_ItemCount / (int)SlotNums.size();
int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, ToEachSlot, SlotNums);
@@ -805,6 +805,111 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cAnvilWindow:
+
+cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtAnvil, "Repair"),
+ m_RepairedItemName(""),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_AnvilSlotArea = new cSlotAreaAnvil(*this);
+ m_SlotAreas.push_back(m_AnvilSlotArea);
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player)
+{
+ m_RepairedItemName = a_Name;
+
+ if (a_Player != NULL)
+ {
+ m_AnvilSlotArea->UpdateResult(*a_Player);
+ }
+}
+
+
+
+
+
+void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
+{
+ a_PosX = m_BlockX;
+ a_PosY = m_BlockY;
+ a_PosZ = m_BlockZ;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cEnchantingWindow:
+
+cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtEnchantment, "Enchant"),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_SlotAreas.push_back(new cSlotAreaEnchanting(*this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cEnchantingWindow::SetProperty(int a_Property, int a_Value)
+{
+ m_PropertyValue[a_Property] = a_Value;
+
+ super::SetProperty(a_Property, a_Value);
+}
+
+
+
+
+
+void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player)
+{
+ m_PropertyValue[a_Property] = a_Value;
+
+ super::SetProperty(a_Property, a_Value, a_Player);
+}
+
+
+
+
+
+int cEnchantingWindow::GetPropertyValue(int a_Property)
+{
+ return m_PropertyValue[a_Property];
+}
+
+
+
+
+
+void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
+{
+ a_PosX = m_BlockX;
+ a_PosY = m_BlockY;
+ a_PosZ = m_BlockZ;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChestWindow:
cChestWindow::cChestWindow(cChestEntity * a_Chest) :
diff --git a/src/UI/Window.h b/src/UI/Window.h
index 030182888..542dccb88 100644
--- a/src/UI/Window.h
+++ b/src/UI/Window.h
@@ -24,6 +24,7 @@ class cEnderChestEntity;
class cFurnaceEntity;
class cHopperEntity;
class cSlotArea;
+class cSlotAreaAnvil;
class cWorld;
typedef std::list<cPlayer *> cPlayerList;
@@ -136,11 +137,11 @@ public:
void SetWindowTitle(const AString & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; }
/// Sends the UpdateWindowProperty (0x69) packet to all clients of the window
- void SetProperty(int a_Property, int a_Value);
+ virtual void SetProperty(int a_Property, int a_Value);
/// Sends the UpdateWindowPropert(0x69) packet to the specified player
- void SetProperty(int a_Property, int a_Value, cPlayer & a_Player);
-
+ virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player);
+
// tolua_end
void OwnerDestroyed(void);
@@ -165,7 +166,7 @@ public:
/// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea
void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum);
-
+
protected:
cSlotAreas m_SlotAreas;
@@ -231,6 +232,58 @@ public:
+class cAnvilWindow :
+ public cWindow
+{
+ typedef cWindow super;
+public:
+ cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /** Gets the repaired item name. */
+ AString GetRepairedItemName(void) const { return m_RepairedItemName; }
+
+ /** Set the repaired item name. */
+ void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player);
+
+ /** Gets the Position from the Anvil */
+ void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
+
+protected:
+ cSlotAreaAnvil * m_AnvilSlotArea;
+ AString m_RepairedItemName;
+ int m_BlockX, m_BlockY, m_BlockZ;
+} ;
+
+
+
+
+
+class cEnchantingWindow :
+ public cWindow
+{
+ typedef cWindow super;
+public:
+ cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+ virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player) override;
+ virtual void SetProperty(int a_Property, int a_Value) override;
+
+ /** Return the Value of a Property */
+ int GetPropertyValue(int a_Property);
+
+ /** Get the Position from the Enchantment Table */
+ void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
+
+ cSlotArea * m_SlotArea;
+
+protected:
+ int m_PropertyValue[3];
+ int m_BlockX, m_BlockY, m_BlockZ;
+};
+
+
+
+
+
class cFurnaceWindow :
public cWindow
{
diff --git a/src/Vector3.h b/src/Vector3.h
index a00e14508..5faac1457 100644
--- a/src/Vector3.h
+++ b/src/Vector3.h
@@ -5,6 +5,8 @@
#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
#include <math.h>
+#include <list>
+#include <vector>
@@ -40,7 +42,6 @@ public:
Vector3(const Vector3<_T> * a_Rhs) : x(a_Rhs->x), y(a_Rhs->y), z(a_Rhs->z) {}
// tolua_begin
-
inline void Set(T a_x, T a_y, T a_z)
{
x = a_x;
@@ -105,13 +106,18 @@ public:
inline bool Equals(const Vector3<T> & a_Rhs) const
{
- return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z;
+ // Perform a bitwise comparison of the contents - we want to know whether this object is exactly equal
+ // To perform EPS-based comparison, use the EqualsEps() function
+ return (
+ (memcmp(&x, &a_Rhs.x, sizeof(x)) == 0) &&
+ (memcmp(&y, &a_Rhs.y, sizeof(y)) == 0) &&
+ (memcmp(&z, &a_Rhs.z, sizeof(z)) == 0)
+ );
}
-
- inline bool operator < (const Vector3<T> & a_Rhs)
+
+ inline bool EqualsEps(const Vector3<T> & a_Rhs, T a_Eps) const
{
- // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ?
- return (x < a_Rhs.x) || (x == a_Rhs.x && y < a_Rhs.y) || (x == a_Rhs.x && y == a_Rhs.y && z < a_Rhs.z);
+ return (Abs(x - a_Rhs.x) < a_Eps) && (Abs(y - a_Rhs.y) < a_Eps) && (Abs(z - a_Rhs.z) < a_Eps);
}
inline void Move(T a_X, T a_Y, T a_Z)
@@ -130,6 +136,16 @@ public:
// tolua_end
+ inline bool operator != (const Vector3<T> & a_Rhs) const
+ {
+ return !Equals(a_Rhs);
+ }
+
+ inline bool operator == (const Vector3<T> & a_Rhs) const
+ {
+ return Equals(a_Rhs);
+ }
+
inline void operator += (const Vector3<T> & a_Rhs)
{
x += a_Rhs.x;
@@ -158,8 +174,16 @@ public:
z *= a_v;
}
- // tolua_begin
+ inline Vector3<T> & operator = (const Vector3<T> & a_Rhs)
+ {
+ x = a_Rhs.x;
+ y = a_Rhs.y;
+ z = a_Rhs.z;
+ return *this;
+ }
+ // tolua_begin
+
inline Vector3<T> operator + (const Vector3<T>& a_Rhs) const
{
return Vector3<T>(
@@ -212,7 +236,7 @@ public:
*/
inline double LineCoeffToXYPlane(const Vector3<T> & a_OtherEnd, T a_Z) const
{
- if (abs(z - a_OtherEnd.z) < EPS)
+ if (Abs(z - a_OtherEnd.z) < EPS)
{
return NO_INTERSECTION;
}
@@ -227,7 +251,7 @@ public:
*/
inline double LineCoeffToXZPlane(const Vector3<T> & a_OtherEnd, T a_Y) const
{
- if (abs(y - a_OtherEnd.y) < EPS)
+ if (Abs(y - a_OtherEnd.y) < EPS)
{
return NO_INTERSECTION;
}
@@ -242,7 +266,7 @@ public:
*/
inline double LineCoeffToYZPlane(const Vector3<T> & a_OtherEnd, T a_X) const
{
- if (abs(x - a_OtherEnd.x) < EPS)
+ if (Abs(x - a_OtherEnd.x) < EPS)
{
return NO_INTERSECTION;
}
@@ -255,7 +279,15 @@ public:
/** Return value of LineCoeffToPlane() if the line is parallel to the plane. */
static const double NO_INTERSECTION;
+
+protected:
+ /** Returns the absolute value of the given argument.
+ Templatized because the standard library differentiates between abs() and fabs(). */
+ static T Abs(T a_Value)
+ {
+ return (a_Value < 0) ? -a_Value : a_Value;
+ }
};
// tolua_end
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index 402cd3035..08e164d78 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -89,6 +89,7 @@ bool cWebAdmin::Init(void)
m_IniFile.AddHeaderComment(" Password format: Password=*password*; for example:");
m_IniFile.AddHeaderComment(" [User:admin]");
m_IniFile.AddHeaderComment(" Password=admin");
+ m_IniFile.WriteFile("webadmin.ini");
}
if (!m_IniFile.GetValueSetB("WebAdmin", "Enabled", true))
@@ -229,10 +230,11 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque
} // for itr - Data->m_Form[]
// Parse the URL into individual params:
- size_t idxQM = a_Request.GetURL().find('?');
+ const AString & URL = a_Request.GetURL();
+ size_t idxQM = URL.find('?');
if (idxQM != AString::npos)
{
- cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, a_Request.GetURL().c_str() + idxQM + 1, a_Request.GetURL().length() - idxQM - 1, *Data);
+ cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, URL.c_str() + idxQM + 1, URL.length() - idxQM - 1, *Data);
URLParams.Finish();
for (cHTTPFormParser::const_iterator itr = URLParams.begin(), end = URLParams.end(); itr != end; ++itr)
{
@@ -284,11 +286,6 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque
Content = GetDefaultPage();
}
- if (ShouldWrapInTemplate && (URL.size() > 1))
- {
- Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>";
- }
-
int MemUsageKiB = cRoot::GetPhysicalRAMUsage();
if (MemUsageKiB > 0)
{
@@ -388,7 +385,6 @@ AString cWebAdmin::GetDefaultPage(void)
{
continue;
}
- AString VersionNum;
AppendPrintf(Content, "<li>%s V.%i</li>", itr->second->GetName().c_str(), itr->second->GetVersion());
}
Content += "</ul>";
@@ -490,7 +486,7 @@ void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_
-void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size)
+void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size)
{
UNUSED(a_Connection);
cRequestData * Data = (cRequestData *)(a_Request.GetUserData());
@@ -537,7 +533,7 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest &
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWebAdmin::cWebadminRequestData
-void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, int a_Size)
+void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, size_t a_Size)
{
m_Form.Parse(a_Data, a_Size);
}
diff --git a/src/WebAdmin.h b/src/WebAdmin.h
index a2a07a543..d5e45828f 100644
--- a/src/WebAdmin.h
+++ b/src/WebAdmin.h
@@ -151,7 +151,7 @@ protected:
virtual ~cRequestData() {} // Force a virtual destructor in all descendants
/** Called when a new chunk of body data is received */
- virtual void OnBody(const char * a_Data, int a_Size) = 0;
+ virtual void OnBody(const char * a_Data, size_t a_Size) = 0;
} ;
/** The body handler for requests in the "/webadmin" and "/~webadmin" paths */
@@ -169,14 +169,14 @@ protected:
}
// cRequestData overrides:
- virtual void OnBody(const char * a_Data, int a_Size) override;
+ virtual void OnBody(const char * a_Data, size_t a_Size) override;
// cHTTPFormParser::cCallbacks overrides. Files are ignored:
- virtual void OnFileStart(cHTTPFormParser &, const AString & a_FileName) override
+ virtual void OnFileStart(cHTTPFormParser &, const AString & a_FileName) override
{
UNUSED(a_FileName);
}
- virtual void OnFileData(cHTTPFormParser &, const char * a_Data, int a_Size) override
+ virtual void OnFileData(cHTTPFormParser &, const char * a_Data, size_t a_Size) override
{
UNUSED(a_Data);
UNUSED(a_Size);
@@ -216,7 +216,7 @@ protected:
// cHTTPServer::cCallbacks overrides:
virtual void OnRequestBegun (cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
- virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override;
+ virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override;
virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
} ; // tolua_export
diff --git a/src/World.cpp b/src/World.cpp
index e39a605bb..807065bfa 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -316,12 +316,9 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather)
{
return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes
}
- default:
- {
- LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
- return -1;
- }
- } // switch (Weather)
+ }
+ LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
+ return -1;
}
@@ -397,10 +394,14 @@ void cWorld::InitializeSpawn(void)
// For the debugging builds, don't make the server build too much world upon start:
#if defined(_DEBUG) || defined(ANDROID_NDK)
- int ViewDist = 9;
+ const int DefaultViewDist = 9;
#else
- int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
+ const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
#endif // _DEBUG
+ cIniFile IniFile;
+ IniFile.ReadFile(m_IniFileName);
+ int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
+ IniFile.WriteFile(m_IniFileName);
LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str());
for (int x = 0; x < ViewDist; x++)
@@ -521,21 +522,6 @@ void cWorld::Start(void)
}
AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld");
m_Dimension = StringToDimension(Dimension);
- switch (m_Dimension)
- {
- case dimNether:
- case dimOverworld:
- case dimEnd:
- {
- break;
- }
- default:
- {
- LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", Dimension.c_str());
- m_Dimension = dimOverworld;
- break;
- }
- } // switch (m_Dimension)
// Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
int KeyNum = IniFile.FindKey("SpawnPosition");
@@ -574,7 +560,7 @@ void cWorld::Start(void)
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
- int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone);
+ int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slAll);
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
@@ -592,12 +578,6 @@ void cWorld::Start(void)
case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break;
case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break;
case dimEnd: DefaultMonsters = "enderman"; break;
- default:
- {
- ASSERT(!"Unhandled world dimension");
- DefaultMonsters = "wither";
- break;
- }
}
m_bAnimals = IniFile.GetValueSetB("Monsters", "AnimalsOn", true);
AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters);
@@ -687,6 +667,30 @@ void cWorld::GenerateRandomSpawn(void)
+eWeather cWorld::ChooseNewWeather()
+{
+ // Pick a new weather. Only reasonable transitions allowed:
+ switch (m_Weather)
+ {
+ case eWeather_Sunny:
+ case eWeather_ThunderStorm: return eWeather_Rain;
+
+ case eWeather_Rain:
+ {
+ // 1/8 chance of turning into a thunderstorm
+ return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
+ }
+ }
+
+ LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather);
+ ASSERT(!"Unknown weather");
+ return eWeather_Sunny;
+}
+
+
+
+
+
void cWorld::Stop(void)
{
// Delete the clients that have been in this world:
@@ -786,30 +790,8 @@ void cWorld::TickWeather(float a_Dt)
else
{
// Change weather:
-
- // Pick a new weather. Only reasonable transitions allowed:
- eWeather NewWeather = m_Weather;
- switch (m_Weather)
- {
- case eWeather_Sunny: NewWeather = eWeather_Rain; break;
- case eWeather_ThunderStorm: NewWeather = eWeather_Rain; break;
- case eWeather_Rain:
- {
- // 1/8 chance of turning into a thunderstorm
- NewWeather = ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
- break;
- }
-
- default:
- {
- LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather);
- ASSERT(!"Unknown weather");
- NewWeather = eWeather_Sunny;
- }
- }
-
- SetWeather(NewWeather);
- } // else (m_WeatherInterval > 0)
+ SetWeather(ChooseNewWeather());
+ }
if (m_Weather == eWeather_ThunderStorm)
{
@@ -860,7 +842,7 @@ void cWorld::TickMobs(float a_Dt)
{
m_ChunkMap->SpawnMobs(Spawner);
// do the spawn
- for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++)
+ for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2)
{
SpawnMobFinalize(*itr2);
}
@@ -870,14 +852,14 @@ void cWorld::TickMobs(float a_Dt)
// move close mobs
cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(-1, 64 * 16);// MG TODO : deal with this magic number (the 16 is the size of a block)
- for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++)
+ for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; ++itr)
{
itr->second.m_Monster.Tick(a_Dt, itr->second.m_Chunk);
}
// remove too far mobs
cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(128 * 16, -1);// MG TODO : deal with this magic number (the 16 is the size of a block)
- for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++)
+ for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; ++itr)
{
itr->second.m_Monster.Destroy(true);
}
@@ -1632,7 +1614,6 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated)
{
- MTRand r1;
a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
@@ -1642,9 +1623,9 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
continue;
}
- float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5));
- float SpeedY = (float)(a_FlyAwaySpeed * r1.randInt(50));
- float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5));
+ float SpeedX = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
+ float SpeedY = (float)(a_FlyAwaySpeed * GetTickRandomNumber(50));
+ float SpeedZ = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
cPickup * Pickup = new cPickup(
a_BlockX, a_BlockY, a_BlockZ,
@@ -1692,6 +1673,11 @@ int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NI
int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
{
+ if (a_Reward < 1)
+ {
+ return -1;
+ }
+
cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward);
ExpOrb->Initialize(this);
return ExpOrb->GetUniqueID();
@@ -2420,13 +2406,13 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_
bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback)
{
cPlayer * BestMatch = NULL;
- unsigned int BestRating = 0;
- unsigned int NameLength = a_PlayerNameHint.length();
+ size_t BestRating = 0;
+ size_t NameLength = a_PlayerNameHint.length();
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
- unsigned int Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName());
+ size_t Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName());
if (Rating >= BestRating)
{
BestMatch = *itr;
@@ -2440,7 +2426,6 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa
if (BestMatch != NULL)
{
- LOG("Compared %s and %s with rating %i", a_PlayerNameHint.c_str(), BestMatch->GetName().c_str(), BestRating);
return a_Callback.Item (BestMatch);
}
return false;
@@ -2890,7 +2875,7 @@ void cWorld::TickQueuedBlocks(void)
m_BlockTickQueueCopy.clear();
m_BlockTickQueue.swap(m_BlockTickQueueCopy);
- for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); itr++)
+ for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); ++itr)
{
BlockTickQueueItem * Block = (*itr);
Block->TicksToWait -= 1;
@@ -2981,7 +2966,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
-int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed)
+int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed)
{
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL)
@@ -2993,7 +2978,6 @@ int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProje
delete Projectile;
return -1;
}
- BroadcastSpawnEntity(*Projectile);
return Projectile->GetUniqueID();
}
diff --git a/src/World.h b/src/World.h
index bb2eb0b21..86cbb3e7e 100644
--- a/src/World.h
+++ b/src/World.h
@@ -126,15 +126,15 @@ public:
int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
- virtual Int64 GetWorldAge (void) const { return m_WorldAge; } // override, cannot specify due to tolua
- virtual Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } // override, cannot specify due to tolua
+ virtual Int64 GetWorldAge (void) const override { return m_WorldAge; }
+ virtual Int64 GetTimeOfDay(void) const override { return m_TimeOfDay; }
void SetTicksUntilWeatherChange(int a_WeatherInterval)
{
m_WeatherInterval = a_WeatherInterval;
}
- virtual void SetTimeOfDay(Int64 a_TimeOfDay) // override, cannot specify due to tolua
+ virtual void SetTimeOfDay(Int64 a_TimeOfDay) override
{
m_TimeOfDay = a_TimeOfDay;
m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
@@ -351,7 +351,7 @@ public:
/** Is the trapdoor open? Returns false if there is no trapdoor at the specified coords. */
bool IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
- /** Set the state of a trapdoor. Returns true if the trapdoor was update, false if there was no trapdoor at those coords. */
+ /** Set the state of a trapdoor. Returns true if the trapdoor was updated, false if there was no trapdoor at those coords. */
bool SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open); // tolua_export
/** Regenerate the given chunk: */
@@ -430,10 +430,10 @@ public:
// tolua_begin
/** Spawns item pickups for each item in the list. May compress pickups if too many entities: */
- virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false); // override; cannot specify it here due to tolua
+ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) override;
/** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */
- virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false); // override; cannot specify it here due to tolua
+ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false) override;
/** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */
int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta);
@@ -457,7 +457,7 @@ public:
// tolua_begin
bool DigBlock (int a_X, int a_Y, int a_Z);
- virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); // override, cannot specify due to tolua
+ virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) override;
double GetSpawnX(void) const { return m_SpawnX; }
double GetSpawnY(void) const { return m_SpawnY; }
@@ -508,7 +508,7 @@ public:
| 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
+ virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) override; // tolua_export
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp
@@ -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);
@@ -707,11 +707,13 @@ public:
bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
- virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export // override, cannot specify due to tolua
+ virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) override; // tolua_export
int SpawnMobFinalize(cMonster* a_Monster);
- /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */
- int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export
+ /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
+ Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata
+ */
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed = NULL); // tolua_export
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
@@ -938,7 +940,10 @@ private:
/** <summary>Generates a random spawnpoint on solid land by walking chunks and finding their biomes</summary> */
void GenerateRandomSpawn(void);
-
+
+ /** Chooses a reasonable transition from the current weather to a new weather **/
+ eWeather ChooseNewWeather(void);
+
/** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt
index 2c83c4662..2844f7fe5 100644
--- a/src/WorldStorage/CMakeLists.txt
+++ b/src/WorldStorage/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(WorldStorage ${SOURCE})
diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp
index be25fd1a4..a047d67c7 100644
--- a/src/WorldStorage/FastNBT.cpp
+++ b/src/WorldStorage/FastNBT.cpp
@@ -29,7 +29,7 @@
// cParsedNBT:
#define NEEDBYTES(N) \
- if (m_Length - m_Pos < N) \
+ if (m_Length - m_Pos < (size_t)N) \
{ \
return false; \
}
@@ -38,7 +38,7 @@
-cParsedNBT::cParsedNBT(const char * a_Data, int a_Length) :
+cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) :
m_Data(a_Data),
m_Length(a_Length),
m_Pos(0)
@@ -79,14 +79,14 @@ bool cParsedNBT::Parse(void)
-bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen)
+bool cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringLen)
{
NEEDBYTES(2);
a_StringStart = m_Pos + 2;
- a_StringLen = GetBEShort(m_Data + m_Pos);
- if (a_StringLen < 0)
+ a_StringLen = (size_t)GetBEShort(m_Data + m_Pos);
+ if (a_StringLen > 0xffff)
{
- // Invalid string length
+ // Suspicious string length
return false;
}
m_Pos += 2 + a_StringLen;
@@ -99,8 +99,10 @@ bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen)
bool cParsedNBT::ReadCompound(void)
{
+ ASSERT(m_Tags.size() > 0);
+
// Reads the latest tag as a compound
- int ParentIdx = m_Tags.size() - 1;
+ int ParentIdx = (int)m_Tags.size() - 1;
int PrevSibling = -1;
for (;;)
{
@@ -114,13 +116,13 @@ bool cParsedNBT::ReadCompound(void)
m_Tags.push_back(cFastNBTTag(TagType, ParentIdx, PrevSibling));
if (PrevSibling >= 0)
{
- m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1;
+ m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1;
}
else
{
- m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1;
+ m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1;
}
- PrevSibling = m_Tags.size() - 1;
+ PrevSibling = (int)m_Tags.size() - 1;
RETURN_FALSE_IF_FALSE(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength));
RETURN_FALSE_IF_FALSE(ReadTag());
} // while (true)
@@ -146,20 +148,20 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType)
}
// Read items:
- int ParentIdx = m_Tags.size() - 1;
+ int ParentIdx = (int)m_Tags.size() - 1;
int PrevSibling = -1;
for (int i = 0; i < Count; i++)
{
m_Tags.push_back(cFastNBTTag(a_ChildrenType, ParentIdx, PrevSibling));
if (PrevSibling >= 0)
{
- m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1;
+ m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1;
}
else
{
- m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1;
+ m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1;
}
- PrevSibling = m_Tags.size() - 1;
+ PrevSibling = (int)m_Tags.size() - 1;
RETURN_FALSE_IF_FALSE(ReadTag());
} // for (i)
m_Tags[ParentIdx].m_LastChild = PrevSibling;
@@ -279,7 +281,7 @@ int cParsedNBT::FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLen
for (int Child = m_Tags[a_Tag].m_FirstChild; Child != -1; Child = m_Tags[Child].m_NextSibling)
{
if (
- (m_Tags[Child].m_NameLength == (int)a_NameLength) &&
+ (m_Tags[Child].m_NameLength == a_NameLength) &&
(memcmp(m_Data + m_Tags[Child].m_NameStart, a_Name, a_NameLength) == 0)
)
{
@@ -336,7 +338,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) :
m_Stack[0].m_Type = TAG_Compound;
m_Result.reserve(100 * 1024);
m_Result.push_back(TAG_Compound);
- WriteString(a_RootTagName.data(), a_RootTagName.size());
+ WriteString(a_RootTagName.data(), (UInt16)a_RootTagName.size());
}
@@ -345,7 +347,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) :
void cFastNBTWriter::BeginCompound(const AString & a_Name)
{
- if (m_CurrentStack >= MAX_STACK)
+ if (m_CurrentStack >= MAX_STACK - 1)
{
ASSERT(!"Stack overflow");
return;
@@ -376,7 +378,7 @@ void cFastNBTWriter::EndCompound(void)
void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType)
{
- if (m_CurrentStack >= MAX_STACK)
+ if (m_CurrentStack >= MAX_STACK - 1)
{
ASSERT(!"Stack overflow");
return;
@@ -389,7 +391,7 @@ void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType)
++m_CurrentStack;
m_Stack[m_CurrentStack].m_Type = TAG_List;
- m_Stack[m_CurrentStack].m_Pos = m_Result.size() - 4;
+ m_Stack[m_CurrentStack].m_Pos = (int)m_Result.size() - 4;
m_Stack[m_CurrentStack].m_Count = 0;
m_Stack[m_CurrentStack].m_ItemType = a_ChildrenType;
}
@@ -493,7 +495,7 @@ void cFastNBTWriter::AddString(const AString & a_Name, const AString & a_Value)
void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements)
{
TagCommon(a_Name, TAG_ByteArray);
- Int32 len = htonl(a_NumElements);
+ u_long len = htonl((u_long)a_NumElements);
m_Result.append((const char *)&len, 4);
m_Result.append(a_Value, a_NumElements);
}
@@ -505,7 +507,7 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value,
void cFastNBTWriter::AddIntArray(const AString & a_Name, const int * a_Value, size_t a_NumElements)
{
TagCommon(a_Name, TAG_IntArray);
- Int32 len = htonl(a_NumElements);
+ u_long len = htonl((u_long)a_NumElements);
size_t cap = m_Result.capacity();
size_t size = m_Result.length();
if ((cap - size) < (4 + a_NumElements * 4))
@@ -534,7 +536,7 @@ void cFastNBTWriter::Finish(void)
-void cFastNBTWriter::WriteString(const char * a_Data, short a_Length)
+void cFastNBTWriter::WriteString(const char * a_Data, UInt16 a_Length)
{
Int16 Len = htons(a_Length);
m_Result.append((const char *)&Len, 2);
diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h
index 1b8b09c21..fe28005ac 100644
--- a/src/WorldStorage/FastNBT.h
+++ b/src/WorldStorage/FastNBT.h
@@ -61,10 +61,10 @@ public:
// The following members are indices into the data stream. m_DataLength == 0 if no data available
// They must not be pointers, because the datastream may be copied into another AString object in the meantime.
- int m_NameStart;
- int m_NameLength;
- int m_DataStart;
- int m_DataLength;
+ size_t m_NameStart;
+ size_t m_NameLength;
+ size_t m_DataStart;
+ size_t m_DataLength;
// The following members are indices into the array returned; -1 if not valid
// They must not be pointers, because pointers would not survive std::vector reallocation
@@ -114,7 +114,7 @@ Each primitive tag also stores the length of the contained data, in bytes.
class cParsedNBT
{
public:
- cParsedNBT(const char * a_Data, int a_Length);
+ cParsedNBT(const char * a_Data, size_t a_Length);
bool IsValid(void) const {return m_IsValid; }
@@ -122,33 +122,33 @@ public:
int GetRoot(void) const {return 0; }
/** Returns the first child of the specified tag, or -1 if none / not applicable. */
- int GetFirstChild (int a_Tag) const { return m_Tags[a_Tag].m_FirstChild; }
+ int GetFirstChild (int a_Tag) const { return m_Tags[(size_t)a_Tag].m_FirstChild; }
/** Returns the last child of the specified tag, or -1 if none / not applicable. */
- int GetLastChild (int a_Tag) const { return m_Tags[a_Tag].m_LastChild; }
+ int GetLastChild (int a_Tag) const { return m_Tags[(size_t)a_Tag].m_LastChild; }
/** Returns the next sibling of the specified tag, or -1 if none. */
- int GetNextSibling(int a_Tag) const { return m_Tags[a_Tag].m_NextSibling; }
+ int GetNextSibling(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_NextSibling; }
/** Returns the previous sibling of the specified tag, or -1 if none. */
- int GetPrevSibling(int a_Tag) const { return m_Tags[a_Tag].m_PrevSibling; }
+ int GetPrevSibling(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_PrevSibling; }
/** Returns the length of the tag's data, in bytes.
Not valid for Compound or List tags! */
- int GetDataLength (int a_Tag) const
+ size_t GetDataLength (int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type != TAG_List);
- ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound);
- return m_Tags[a_Tag].m_DataLength;
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound);
+ return m_Tags[(size_t)a_Tag].m_DataLength;
}
/** Returns the data stored in this tag.
Not valid for Compound or List tags! */
const char * GetData(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type != TAG_List);
- ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound);
- return m_Data + m_Tags[a_Tag].m_DataStart;
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound);
+ return m_Data + m_Tags[(size_t)a_Tag].m_DataStart;
}
/** Returns the direct child tag of the specified name, or -1 if no such tag. */
@@ -163,47 +163,47 @@ public:
/** Returns the child tag of the specified path (Name1\Name2\Name3...), or -1 if no such tag. */
int FindTagByPath(int a_Tag, const AString & a_Path) const;
- eTagType GetType(int a_Tag) const { return m_Tags[a_Tag].m_Type; }
+ eTagType GetType(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_Type; }
/** Returns the children type for a List tag; undefined on other tags. If list empty, returns TAG_End. */
eTagType GetChildrenType(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_List);
- return (m_Tags[a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[m_Tags[a_Tag].m_FirstChild].m_Type;
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_List);
+ return (m_Tags[(size_t)a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[(size_t)m_Tags[(size_t)a_Tag].m_FirstChild].m_Type;
}
/** Returns the value stored in a Byte tag. Not valid for any other tag type. */
inline unsigned char GetByte(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Byte);
- return (unsigned char)(m_Data[m_Tags[a_Tag].m_DataStart]);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Byte);
+ return (unsigned char)(m_Data[(size_t)m_Tags[(size_t)a_Tag].m_DataStart]);
}
/** Returns the value stored in a Short tag. Not valid for any other tag type. */
inline Int16 GetShort(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Short);
- return GetBEShort(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Short);
+ return GetBEShort(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in an Int tag. Not valid for any other tag type. */
inline Int32 GetInt(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Int);
- return GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Int);
+ return GetBEInt(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in a Long tag. Not valid for any other tag type. */
inline Int64 GetLong(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Long);
- return NetworkToHostLong8(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Long);
+ return NetworkToHostLong8(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in a Float tag. Not valid for any other tag type. */
inline float GetFloat(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Float);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Float);
// Cause a compile-time error if sizeof(float) != 4
// If your platform produces a compiler error here, you'll need to add code that manually decodes 32-bit floats
@@ -212,7 +212,7 @@ public:
UNUSED(Check1);
UNUSED(Check2);
- Int32 i = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
+ Int32 i = GetBEInt(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
float f;
memcpy(&f, &i, sizeof(f));
return f;
@@ -228,16 +228,16 @@ public:
UNUSED(Check1);
UNUSED(Check2);
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Double);
- return NetworkToHostDouble8(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Double);
+ return NetworkToHostDouble8(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in a String tag. Not valid for any other tag type. */
inline AString GetString(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_String);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_String);
AString res;
- res.assign(m_Data + m_Tags[a_Tag].m_DataStart, m_Tags[a_Tag].m_DataLength);
+ res.assign(m_Data + m_Tags[(size_t)a_Tag].m_DataStart, (size_t)m_Tags[(size_t)a_Tag].m_DataLength);
return res;
}
@@ -245,21 +245,21 @@ public:
inline AString GetName(int a_Tag) const
{
AString res;
- res.assign(m_Data + m_Tags[a_Tag].m_NameStart, m_Tags[a_Tag].m_NameLength);
+ res.assign(m_Data + m_Tags[(size_t)a_Tag].m_NameStart, (size_t)m_Tags[(size_t)a_Tag].m_NameLength);
return res;
}
protected:
const char * m_Data;
- int m_Length;
+ size_t m_Length;
std::vector<cFastNBTTag> m_Tags;
bool m_IsValid; // True if parsing succeeded
// Used while parsing:
- int m_Pos;
+ size_t m_Pos;
bool Parse(void);
- bool ReadString(int & a_StringStart, int & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors
+ bool ReadString(size_t & a_StringStart, size_t & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors
bool ReadCompound(void); // Reads the latest tag as a compound
bool ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType
bool ReadTag(void); // Reads the latest tag, depending on its m_Type setting
@@ -319,7 +319,7 @@ protected:
bool IsStackTopCompound(void) const { return (m_Stack[m_CurrentStack].m_Type == TAG_Compound); }
- void WriteString(const char * a_Data, short a_Length);
+ void WriteString(const char * a_Data, UInt16 a_Length);
inline void TagCommon(const AString & a_Name, eTagType a_Type)
{
@@ -330,7 +330,7 @@ protected:
{
// Compound: add the type and name:
m_Result.push_back((char)a_Type);
- WriteString(a_Name.c_str(), (short)a_Name.length());
+ WriteString(a_Name.c_str(), (UInt16)a_Name.length());
}
else
{
diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp
index 744fc731f..181cfde0d 100644
--- a/src/WorldStorage/FireworksSerializer.cpp
+++ b/src/WorldStorage/FireworksSerializer.cpp
@@ -96,7 +96,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
if (ExplosionName == "Colors")
{
// Divide by four as data length returned in bytes
- int DataLength = a_NBT.GetDataLength(explosiontag);
+ size_t DataLength = a_NBT.GetDataLength(explosiontag);
// round to the next highest multiple of four
DataLength -= DataLength % 4;
if (DataLength == 0)
@@ -105,14 +105,14 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
}
const char * ColourData = (a_NBT.GetData(explosiontag));
- for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ for (size_t i = 0; i < DataLength; i += 4)
{
a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
}
}
else if (ExplosionName == "FadeColors")
{
- int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
+ size_t DataLength = a_NBT.GetDataLength(explosiontag) / 4;
// round to the next highest multiple of four
DataLength -= DataLength % 4;
if (DataLength == 0)
@@ -121,7 +121,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
}
const char * FadeColourData = (a_NBT.GetData(explosiontag));
- for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ for (size_t i = 0; i < DataLength; i += 4)
{
a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
}
@@ -231,7 +231,7 @@ void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkIte
-int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
+int cFireworkItem::GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta)
{
/*
Colours are supposed to be calculated via: R << 16 + G << 8 + B
diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h
index 5b87bafdb..59f1b09b0 100644
--- a/src/WorldStorage/FireworksSerializer.h
+++ b/src/WorldStorage/FireworksSerializer.h
@@ -81,7 +81,7 @@ public:
static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
/** Returns a colour code for fireworks used by the network code */
- static int GetVanillaColourCodeFromDye(short a_DyeMeta);
+ static int GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta);
bool m_HasFlicker;
bool m_HasTrail;
@@ -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 df72d1cc9..012fc52f3 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -152,6 +152,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
if (CurrLine >= 0)
{
unsigned int Width = a_NBT.GetShort(CurrLine);
+ if (Width != 128)
+ {
+ return false;
+ }
m_Map->m_Width = Width;
}
@@ -159,6 +163,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
if (CurrLine >= 0)
{
unsigned int Height = a_NBT.GetShort(CurrLine);
+ if (Height >= 256)
+ {
+ return false;
+ }
m_Map->m_Height = Height;
}
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 415693ae2..a3b0d57be 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -28,7 +28,7 @@
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
@@ -39,7 +39,7 @@
#include "../Mobs/Creeper.h"
#include "../Mobs/Enderman.h"
#include "../Mobs/Horse.h"
-#include "../Mobs/Magmacube.h"
+#include "../Mobs/MagmaCube.h"
#include "../Mobs/Sheep.h"
#include "../Mobs/Slime.h"
#include "../Mobs/Skeleton.h"
@@ -88,23 +88,48 @@ void cNBTChunkSerializer::Finish(void)
void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName)
{
m_Writer.BeginCompound(a_CompoundName);
- m_Writer.AddShort("id", (short)(a_Item.m_ItemType));
- m_Writer.AddShort("Damage", a_Item.m_ItemDamage);
- m_Writer.AddByte ("Count", a_Item.m_ItemCount);
+ m_Writer.AddShort("id", (short)(a_Item.m_ItemType));
+ m_Writer.AddShort("Damage", a_Item.m_ItemDamage);
+ m_Writer.AddByte ("Count", a_Item.m_ItemCount);
if (a_Slot >= 0)
{
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
}
- // Write the enchantments:
- if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)))
+ // Write the tag compound (for enchantment, firework, custom name and repair cost):
+ if (
+ (!a_Item.m_Enchantments.IsEmpty()) ||
+ ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) ||
+ (a_Item.m_RepairCost > 0) ||
+ (a_Item.m_CustomName != "") ||
+ (a_Item.m_Lore != "")
+ )
{
m_Writer.BeginCompound("tag");
+ if (a_Item.m_RepairCost > 0)
+ {
+ m_Writer.AddInt("RepairCost", a_Item.m_RepairCost);
+ }
+
+ if ((a_Item.m_CustomName != "") || (a_Item.m_Lore != ""))
+ {
+ m_Writer.BeginCompound("display");
+ if (a_Item.m_CustomName != "")
+ {
+ m_Writer.AddString("Name", a_Item.m_CustomName);
+ }
+ if (a_Item.m_Lore != "")
+ {
+ m_Writer.AddString("Lore", a_Item.m_Lore);
+ }
+ m_Writer.EndCompound();
+ }
+
if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
{
cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
}
-
+
if (!a_Item.m_Enchantments.IsEmpty())
{
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
@@ -366,38 +391,41 @@ void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart)
{
- const char * EntityClass = NULL;
- switch (a_Minecart->GetPayload())
- {
- case cMinecart::mpNone: EntityClass = "MinecartRideable"; break;
- case cMinecart::mpChest: EntityClass = "MinecartChest"; break;
- case cMinecart::mpFurnace: EntityClass = "MinecartFurnace"; break;
- case cMinecart::mpTNT: EntityClass = "MinecartTNT"; break;
- case cMinecart::mpHopper: EntityClass = "MinecartHopper"; break;
- default:
- {
- ASSERT(!"Unhandled minecart payload type");
- return;
- }
- } // switch (payload)
-
m_Writer.BeginCompound("");
- AddBasicEntity(a_Minecart, EntityClass);
+
switch (a_Minecart->GetPayload())
{
case cMinecart::mpChest:
{
+ AddBasicEntity(a_Minecart, "MinecartChest");
// Add chest contents into the Items tag:
AddMinecartChestContents((cMinecartWithChest *)a_Minecart);
break;
}
-
case cMinecart::mpFurnace:
{
+ AddBasicEntity(a_Minecart, "MinecartFurnace");
// TODO: Add "Push" and "Fuel" tags
break;
}
+ case cMinecart::mpHopper:
+ {
+ AddBasicEntity(a_Minecart, "MinecartHopper");
+ // TODO: Add hopper contents?
+ break;
+ }
+ case cMinecart::mpTNT:
+ {
+ AddBasicEntity(a_Minecart, "MinecartTNT");
+ break;
+ }
+ case cMinecart::mpNone:
+ {
+ AddBasicEntity(a_Minecart, "MinecartRideable");
+ break;
+ }
} // switch (Payload)
+
m_Writer.EndCompound();
}
@@ -490,7 +518,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
}
case cMonster::mtMagmaCube:
{
- m_Writer.AddByte("Size", ((const cMagmaCube *)a_Monster)->GetSize());
+ m_Writer.AddInt("Size", ((const cMagmaCube *)a_Monster)->GetSize());
break;
}
case cMonster::mtSheep:
@@ -516,7 +544,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
}
case cMonster::mtWither:
{
- m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks());
+ m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks());
break;
}
case cMonster::mtWolf:
@@ -621,10 +649,17 @@ void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
switch (a_Hanging->GetDirection())
{
- case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
- case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
- case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
- case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
+ case BLOCK_FACE_YM: m_Writer.AddByte("Dir", (unsigned char)2); break;
+ case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break;
+ case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break;
+ case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break;
+
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_XP:
+ case BLOCK_FACE_NONE:
+ {
+ break;
+ }
}
}
@@ -692,10 +727,9 @@ void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Mineca
-bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
{
m_IsLightValid = a_IsLightValid;
- return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
}
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 51d104970..112afc27e 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -9,7 +9,7 @@
#pragma once
-#include "../ChunkDef.h"
+#include "ChunkDataCallback.h"
@@ -121,7 +121,7 @@ protected:
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// cChunkDataSeparateCollector overrides:
- virtual bool LightIsValid(bool a_IsLightValid) override;
+ virtual void LightIsValid(bool a_IsLightValid) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index d8531d965..1cf99efd9 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:
@@ -159,7 +192,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
int SizeX = a_NBT.GetShort(TSizeX);
int SizeY = a_NBT.GetShort(TSizeY);
int SizeZ = a_NBT.GetShort(TSizeZ);
- if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1))
+ if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > 256) || (SizeZ < 1) || (SizeZ > 65535))
{
LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ);
return false;
@@ -197,11 +230,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
// Copy the block types and metas:
- int NumBytes = a_BlockArea.GetBlockCount();
+ size_t NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
{
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
- NumBytes, a_NBT.GetDataLength(TBlockTypes)
+ (int)NumBytes, (int)a_NBT.GetDataLength(TBlockTypes)
);
NumBytes = a_NBT.GetDataLength(TBlockTypes);
}
@@ -209,11 +242,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
if (AreMetasPresent)
{
- int NumBytes = a_BlockArea.GetBlockCount();
+ size_t NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
{
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
- NumBytes, a_NBT.GetDataLength(TBlockMetas)
+ (int)NumBytes, (int)a_NBT.GetDataLength(TBlockMetas)
);
NumBytes = a_NBT.GetDataLength(TBlockMetas);
}
diff --git a/src/WorldStorage/StatSerializer.cpp b/src/WorldStorage/StatSerializer.cpp
new file mode 100644
index 000000000..74113941c
--- /dev/null
+++ b/src/WorldStorage/StatSerializer.cpp
@@ -0,0 +1,146 @@
+
+// StatSerializer.cpp
+
+
+#include "Globals.h"
+#include "StatSerializer.h"
+
+#include "../Statistics.h"
+
+
+
+
+
+cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager)
+ : m_Manager(a_Manager)
+{
+ // Even though stats are shared between worlds, they are (usually) saved
+ // inside the folder of the default world.
+
+ AString StatsPath;
+ Printf(StatsPath, "%s/stats", a_WorldName.c_str());
+
+ m_Path = StatsPath + "/" + a_PlayerName + ".json";
+
+ // Ensure that the directory exists.
+ cFile::CreateFolder(FILE_IO_PREFIX + StatsPath);
+}
+
+
+
+
+
+bool cStatSerializer::Load(void)
+{
+ AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
+ if (Data.empty())
+ {
+ return false;
+ }
+
+ Json::Value Root;
+ Json::Reader Reader;
+
+ if (Reader.parse(Data, Root, false))
+ {
+ return LoadStatFromJSON(Root);
+ }
+
+ return false;
+}
+
+
+
+
+
+bool cStatSerializer::Save(void)
+{
+ Json::Value Root;
+ SaveStatToJSON(Root);
+
+ cFile File;
+ if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
+ {
+ return false;
+ }
+
+ Json::StyledWriter Writer;
+ AString JsonData = Writer.write(Root);
+
+ File.Write(JsonData.data(), JsonData.size());
+ File.Close();
+
+ return true;
+}
+
+
+
+
+
+void cStatSerializer::SaveStatToJSON(Json::Value & a_Out)
+{
+ for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
+ {
+ StatValue Value = m_Manager->GetValue((eStatistic) i);
+
+ if (Value != 0)
+ {
+ const AString & StatName = cStatInfo::GetName((eStatistic) i);
+
+ a_Out[StatName] = Value;
+ }
+
+ // TODO 2014-05-11 xdot: Save "progress"
+ }
+}
+
+
+
+
+
+bool cStatSerializer::LoadStatFromJSON(const Json::Value & a_In)
+{
+ m_Manager->Reset();
+
+ for (Json::ValueIterator it = a_In.begin() ; it != a_In.end() ; ++it)
+ {
+ AString StatName = it.key().asString();
+
+ eStatistic StatType = cStatInfo::GetType(StatName);
+
+ if (StatType == statInvalid)
+ {
+ LOGWARNING("Invalid statistic type \"%s\"", StatName.c_str());
+ continue;
+ }
+
+ Json::Value & Node = *it;
+
+ if (Node.isInt())
+ {
+ m_Manager->SetValue(StatType, Node.asInt());
+ }
+ else if (Node.isObject())
+ {
+ StatValue Value = Node.get("value", 0).asInt();
+
+ // TODO 2014-05-11 xdot: Load "progress"
+
+ m_Manager->SetValue(StatType, Value);
+ }
+ else
+ {
+ LOGWARNING("Invalid statistic value for type \"%s\"", StatName.c_str());
+ }
+ }
+
+ return true;
+}
+
+
+
+
+
+
+
+
diff --git a/src/WorldStorage/StatSerializer.h b/src/WorldStorage/StatSerializer.h
new file mode 100644
index 000000000..72f8d74f1
--- /dev/null
+++ b/src/WorldStorage/StatSerializer.h
@@ -0,0 +1,55 @@
+
+// StatSerializer.h
+
+// Declares the cStatSerializer class that is used for saving stats into JSON
+
+
+
+
+
+#pragma once
+
+#include "json/json.h"
+
+
+
+
+
+// fwd:
+class cStatManager;
+
+
+
+
+class cStatSerializer
+{
+public:
+
+ cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager);
+
+ /* Try to load the player statistics. Returns whether the operation was successful or not. */
+ bool Load(void);
+
+ /* Try to save the player statistics. Returns whether the operation was successful or not. */
+ bool Save(void);
+
+
+protected:
+
+ void SaveStatToJSON(Json::Value & a_Out);
+
+ bool LoadStatFromJSON(const Json::Value & a_In);
+
+
+private:
+
+ cStatManager* m_Manager;
+
+ AString m_Path;
+
+
+} ;
+
+
+
+
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 48934d074..d310c9124 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -27,7 +27,6 @@
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
-
#include "../Mobs/Monster.h"
#include "../Mobs/IncludeAllMonsters.h"
@@ -36,7 +35,12 @@
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
+#include "../Entities/ThrownEggEntity.h"
+#include "../Entities/ThrownEnderPearlEntity.h"
+#include "../Entities/ThrownSnowballEntity.h"
+#include "../Entities/FireChargeEntity.h"
+#include "../Entities/GhastFireballEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
@@ -92,7 +96,7 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
gzFile gz = gzopen((FILE_IO_PREFIX + fnam).c_str(), "wb");
if (gz != NULL)
{
- gzwrite(gz, Writer.GetResult().data(), Writer.GetResult().size());
+ gzwrite(gz, Writer.GetResult().data(), (unsigned)Writer.GetResult().size());
}
gzclose(gz);
}
@@ -248,7 +252,7 @@ bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString &
strm.next_out = (Bytef *)Uncompressed;
strm.avail_out = sizeof(Uncompressed);
strm.next_in = (Bytef *)a_Data.data();
- strm.avail_in = a_Data.size();
+ strm.avail_in = (uInt)a_Data.size();
int res = inflate(&strm, Z_FINISH);
inflateEnd(&strm);
if (res != Z_STREAM_END)
@@ -401,7 +405,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
-void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length)
+void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length)
{
int Child = a_NBT.FindChildByName(a_Tag, a_ChildName);
if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length))
@@ -436,8 +440,8 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
// Save blockdata:
a_Writer.BeginList("Sections", TAG_Compound);
- int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
- int SliceSizeNibble = SliceSizeBlock / 2;
+ size_t SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
+ size_t SliceSizeNibble = SliceSizeBlock / 2;
const char * BlockTypes = (const char *)(Serializer.m_BlockTypes);
const char * BlockMetas = (const char *)(Serializer.m_BlockMetas);
#ifdef DEBUG_SKYLIGHT
@@ -641,18 +645,16 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
}
int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
- if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
+ if ((Damage > 0) && (a_NBT.GetType(Damage) == TAG_Short))
{
- return false;
+ a_Item.m_ItemDamage = a_NBT.GetShort(Damage);
}
- a_Item.m_ItemDamage = a_NBT.GetShort(Damage);
int Count = a_NBT.FindChildByName(a_TagIdx, "Count");
- if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte))
+ if ((Count > 0) && (a_NBT.GetType(Count) == TAG_Byte))
{
- return false;
+ a_Item.m_ItemCount = a_NBT.GetByte(Count);
}
- a_Item.m_ItemCount = a_NBT.GetByte(Count);
// Find the "tag" tag, used for enchantments and other extra data
int TagTag = a_NBT.FindChildByName(a_TagIdx, "tag");
@@ -662,6 +664,29 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
return true;
}
+ // Load repair cost:
+ int RepairCost = a_NBT.FindChildByName(TagTag, "RepairCost");
+ if ((RepairCost > 0) && (a_NBT.GetType(RepairCost) == TAG_Int))
+ {
+ a_Item.m_RepairCost = a_NBT.GetInt(RepairCost);
+ }
+
+ // Load display name:
+ int DisplayTag = a_NBT.FindChildByName(TagTag, "display");
+ if (DisplayTag > 0)
+ {
+ int DisplayName = a_NBT.FindChildByName(DisplayTag, "Name");
+ if ((DisplayName > 0) && (a_NBT.GetType(DisplayName) == TAG_String))
+ {
+ a_Item.m_CustomName = a_NBT.GetString(DisplayName);
+ }
+ int Lore = a_NBT.FindChildByName(DisplayTag, "Lore");
+ if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String))
+ {
+ a_Item.m_Lore = a_NBT.GetString(Lore);
+ }
+ }
+
// Load enchantments:
const char * EnchName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
int EnchTag = a_NBT.FindChildByName(TagTag, EnchName);
@@ -670,6 +695,7 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
}
+ // Load firework data:
int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion"));
if (EnchTag > 0)
{
@@ -1052,7 +1078,7 @@ void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, cons
-void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength)
+void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength)
{
if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0)
{
@@ -1757,7 +1783,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cCavespider> Monster(new cCavespider());
+ std::auto_ptr<cCaveSpider> Monster(new cCaveSpider());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -1970,7 +1996,10 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT
{
int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
- if (SizeIdx < 0) { return; }
+ if (SizeIdx < 0)
+ {
+ return;
+ }
int Size = a_NBT.GetInt(SizeIdx);
@@ -2128,7 +2157,10 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
- if (SizeIdx < 0) { return; }
+ if (SizeIdx < 0)
+ {
+ return;
+ }
int Size = a_NBT.GetInt(SizeIdx);
@@ -2272,7 +2304,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
if (CurrLine > 0)
{
- Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine));
+ Monster->SetWitherInvulnerableTicks(a_NBT.GetInt(CurrLine));
}
a_Entities.push_back(Monster.release());
@@ -2598,14 +2630,14 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
unsigned ChunkOffset = ChunkLocation >> 8;
- m_File.Seek(ChunkOffset * 4096);
+ m_File.Seek((int)ChunkOffset * 4096);
int ChunkSize = 0;
if (m_File.Read(&ChunkSize, 4) != 4)
{
return false;
}
- ChunkSize = ntohl(ChunkSize);
+ ChunkSize = ntohl((u_long)ChunkSize);
char CompressionType = 0;
if (m_File.Read(&CompressionType, 1) != 1)
{
@@ -2650,7 +2682,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
// Store the chunk data:
m_File.Seek(ChunkSector * 4096);
- unsigned ChunkSize = htonl(a_Data.size() + 1);
+ u_long ChunkSize = htonl((u_long)a_Data.size() + 1);
if (m_File.Write(&ChunkSize, 4) != 4)
{
LOGWARNING("Cannot save chunk [%d, %d], writing(1) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
@@ -2668,8 +2700,13 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
return false;
}
+ // Add padding to 4K boundary:
+ size_t BytesWritten = a_Data.size() + MCA_CHUNK_HEADER_LENGTH;
+ static const char Padding[4095] = {0};
+ m_File.Write(Padding, 4096 - (BytesWritten % 4096));
+
// Store the header:
- ChunkSize = (a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
+ ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
ASSERT(ChunkSize < 256);
m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize);
if (m_File.Seek(0) < 0)
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 1773ee882..7542a828a 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -145,7 +145,7 @@ protected:
void LoadMobHeadFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
- void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
+ void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t 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);
@@ -221,7 +221,7 @@ protected:
cMCAFile * LoadMCAFile(const cChunkCoords & a_Chunk);
/// Copies a_Length bytes of data from the specified NBT Tag's Child into the a_Destination buffer
- void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length);
+ void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length);
// cWSSchema overrides:
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index bb9d4b9e6..7a113849a 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -107,15 +107,13 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
-bool cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
{
- if (!a_IsLightValid)
+ if (a_IsLightValid)
{
- return false;
+ m_Root["IsLightValid"] = true;
+ m_HasJsonData = true;
}
- m_Root["IsLightValid"] = true;
- m_HasJsonData = true;
- return true;
}
@@ -468,7 +466,15 @@ cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_
for (int i = 0; i < NumChunks; i++)
{
sChunkHeader * Header = new sChunkHeader;
- READ(*Header);
+
+ // Here we do not use the READ macro, as it does not free the resources
+ // allocated with new in case of error.
+ if (f.Read(Header, sizeof(*Header)) != sizeof(*Header))
+ {
+ LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", "Header", m_FileName.c_str(), __LINE__, f.Tell());
+ delete Header;
+ return;
+ }
m_ChunkHeaders.push_back(Header);
} // for i - chunk headers
@@ -593,7 +599,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
// Decompress the data:
AString UncompressedData;
{
- int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize);
+ int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize);
if (errorcode != Z_OK)
{
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
@@ -673,7 +679,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
// Re-compress data
AString CompressedData;
{
- int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor);
+ int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor);
if (errorcode != Z_OK)
{
LOGERROR("Error %d compressing data for chunk [%d, %d]",
@@ -685,9 +691,9 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
}
// Save into file's cache
- Header->m_UncompressedSize = Converted.size();
- Header->m_CompressedSize = CompressedData.size();
- NewDataContents.append( CompressedData );
+ Header->m_UncompressedSize = (int)Converted.size();
+ Header->m_CompressedSize = (int)CompressedData.size();
+ NewDataContents.append(CompressedData);
}
// Done converting
@@ -723,7 +729,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
Offset += Header->m_CompressedSize;
// Crude data integrity check:
- const int ExpectedSize = (16*256*16)*2 + (16*256*16)/2; // For version 2
+ const int ExpectedSize = (16 * 256 * 16) * 2 + (16 * 256 * 16) / 2; // For version 2
if (UncompressedSize < ExpectedSize)
{
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing",
@@ -737,7 +743,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
// Decompress the data:
AString UncompressedData;
{
- int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize);
+ int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize);
if (errorcode != Z_OK)
{
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
@@ -797,7 +803,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
++index2;
}
InChunkOffset += index2 / 2;
- index2 = 0;
AString Converted(ConvertedData, ExpectedSize);
@@ -822,9 +827,9 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
}
// Save into file's cache
- Header->m_UncompressedSize = Converted.size();
- Header->m_CompressedSize = CompressedData.size();
- NewDataContents.append( CompressedData );
+ Header->m_UncompressedSize = (int)Converted.size();
+ Header->m_CompressedSize = (int)CompressedData.size();
+ NewDataContents.append(CompressedData);
}
// Done converting
@@ -839,7 +844,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
-bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World)
+bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World)
{
// Crude data integrity check:
if (a_UncompressedSize < cChunkDef::BlockDataSize)
@@ -854,7 +859,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
// Decompress the data:
AString UncompressedData;
- int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, a_UncompressedSize);
+ int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, (size_t)a_UncompressedSize);
if (errorcode != Z_OK)
{
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
@@ -866,7 +871,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
if (a_UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
a_UncompressedSize, UncompressedData.size(),
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
);
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 4df146ec3..b148005f6 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -14,6 +14,7 @@
#include "WorldStorage.h"
#include "../Vector3.h"
#include "json/json.h"
+#include "ChunkDataCallback.h"
@@ -21,7 +22,7 @@
/// Helper class for serializing a chunk into Json
class cJsonChunkSerializer :
- public cChunkDataCollector
+ public cChunkDataArrayCollector
{
public:
@@ -42,7 +43,7 @@ protected:
// cChunkDataCollector overrides:
virtual void Entity (cEntity * a_Entity) override;
virtual void BlockEntity (cBlockEntity * a_Entity) override;
- virtual bool LightIsValid (bool a_IsLightValid) override;
+ virtual void LightIsValid (bool a_IsLightValid) override;
} ;
@@ -135,7 +136,7 @@ protected:
bool EraseChunkData(const cChunkCoords & a_Chunk);
/// Loads the chunk from the data (no locking needed)
- bool LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World);
+ bool LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World);
void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World);
diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp
index 711c8612f..6867ad5bc 100644
--- a/src/WorldStorage/WorldStorage.cpp
+++ b/src/WorldStorage/WorldStorage.cpp
@@ -150,7 +150,7 @@ size_t cWorldStorage::GetSaveQueueLength(void)
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate)
{
- m_LoadQueue.EnqueueItemIfNotPresent(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
+ m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
m_Event.Set();
}
@@ -243,7 +243,6 @@ void cWorldStorage::Execute(void)
bool Success;
do
{
- Success = false;
if (m_ShouldTerminate)
{
return;
diff --git a/src/main.cpp b/src/main.cpp
index 68eea7f4d..6925d9ff1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -61,7 +61,7 @@ void NonCtrlHandler(int a_Signal)
std::signal(SIGSEGV, SIG_DFL);
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGSEGV: Segmentation fault");
- exit(EXIT_FAILURE);
+ abort();
}
case SIGABRT:
#ifdef SIGABRT_COMPAT
@@ -71,7 +71,7 @@ void NonCtrlHandler(int a_Signal)
std::signal(a_Signal, SIG_DFL);
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
- exit(EXIT_FAILURE);
+ abort();
}
case SIGINT:
case SIGTERM:
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 000000000..1fbd88f04
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required (VERSION 2.6)
+
+enable_testing()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+add_subdirectory(ChunkData)
diff --git a/tests/ChunkData/ArraytoCoord.cpp b/tests/ChunkData/ArraytoCoord.cpp
new file mode 100644
index 000000000..0daf38f7b
--- /dev/null
+++ b/tests/ChunkData/ArraytoCoord.cpp
@@ -0,0 +1,89 @@
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+
+
+int main(int argc, char** argv)
+{
+ {
+ // Test first segment
+ cChunkData buffer;
+
+ BLOCKTYPE SrcBlockBuffer[16 * 16 * 256];
+ memset(SrcBlockBuffer, 0x00, sizeof(SrcBlockBuffer));
+ SrcBlockBuffer[7 + (4 * 16) + (5 * 16 * 16)] = 0xcd;
+ buffer.SetBlockTypes(SrcBlockBuffer);
+ testassert(buffer.GetBlock(7, 5, 4) == 0xcd);
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ SrcNibbleBuffer[(6 + (1 * 16) + (2 * 16 * 16)) / 2] = 0xe;
+ buffer.SetMetas(SrcNibbleBuffer);
+ testassert(buffer.GetMeta(6, 2, 1) == 0xe);
+
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ SrcNibbleBuffer[(6 + (1 * 16) + (2 * 16 * 16)) / 2] = 0xe;
+ buffer.SetBlockLight(SrcNibbleBuffer);
+ testassert(buffer.GetBlockLight(6, 2, 1) == 0xe);
+
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ SrcNibbleBuffer[(6 + (1 * 16) + (2 * 16 * 16)) / 2] = 0xe;
+ buffer.SetSkyLight(SrcNibbleBuffer);
+ testassert(buffer.GetSkyLight(6, 2, 1) == 0xe);
+ }
+
+ {
+ // test following segment
+ cChunkData buffer;
+
+ BLOCKTYPE SrcBlockBuffer[16 * 16 * 256];
+ memset(SrcBlockBuffer, 0x00, sizeof(SrcBlockBuffer));
+ SrcBlockBuffer[7 + (4 * 16) + (24 * 16 * 16)] = 0xcd;
+ buffer.SetBlockTypes(SrcBlockBuffer);
+ testassert(buffer.GetBlock(7, 24, 4) == 0xcd);
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ SrcNibbleBuffer[(6 + (1 * 16) + (24 * 16 * 16)) / 2] = 0xe;
+ buffer.SetMetas(SrcNibbleBuffer);
+ testassert(buffer.GetMeta(6, 24, 1) == 0xe);
+
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ SrcNibbleBuffer[(6 + 1 * 16 + 24 * 16 * 16) / 2] = 0xe;
+ buffer.SetBlockLight(SrcNibbleBuffer);
+ testassert(buffer.GetBlockLight(6, 24, 1) == 0xe);
+
+ memset(SrcNibbleBuffer, 0xff, sizeof(SrcNibbleBuffer));
+ SrcNibbleBuffer[(6 + (1 * 16) + (24 * 16 * 16)) / 2] = 0xe;
+ buffer.SetSkyLight(SrcNibbleBuffer);
+ testassert(buffer.GetSkyLight(6, 24, 1) == 0xe);
+ }
+
+ {
+ // test zeros
+ cChunkData buffer;
+
+ BLOCKTYPE SrcBlockBuffer[16 * 16 * 256];
+ memset(SrcBlockBuffer, 0x00, sizeof(SrcBlockBuffer));
+ buffer.SetBlockTypes(SrcBlockBuffer);
+ testassert(buffer.GetBlock(7, 24, 4) == 0x00);
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ buffer.SetMetas(SrcNibbleBuffer);
+ testassert(buffer.GetMeta(6, 24, 1) == 0x0);
+
+ memset(SrcNibbleBuffer, 0x00, sizeof(SrcNibbleBuffer));
+ buffer.SetBlockLight(SrcNibbleBuffer);
+ testassert(buffer.GetBlockLight(6, 24, 1) == 0x0);
+
+ memset(SrcNibbleBuffer, 0xff, sizeof(SrcNibbleBuffer));
+ buffer.SetSkyLight(SrcNibbleBuffer);
+ testassert(buffer.GetSkyLight(6, 24, 1) == 0xf);
+ }
+
+ // All tests passed:
+ return 0;
+}
+
diff --git a/tests/ChunkData/CMakeLists.txt b/tests/ChunkData/CMakeLists.txt
new file mode 100644
index 000000000..381e11cc2
--- /dev/null
+++ b/tests/ChunkData/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required (VERSION 2.6)
+
+enable_testing()
+
+include_directories(${CMAKE_SOURCE_DIR}/src/)
+
+add_definitions(-DTEST_GLOBALS=1)
+add_library(ChunkBuffer ${CMAKE_SOURCE_DIR}/src/ChunkData.cpp ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp)
+
+
+add_executable(creatable-exe creatable.cpp)
+target_link_libraries(creatable-exe ChunkBuffer)
+add_test(NAME creatable-test COMMAND creatable-exe)
+
+add_executable(coordinates-exe Coordinates.cpp)
+target_link_libraries(coordinates-exe ChunkBuffer)
+add_test(NAME coordinates-test COMMAND coordinates-exe)
+
+add_executable(copies-exe Copies.cpp)
+target_link_libraries(copies-exe ChunkBuffer)
+add_test(NAME copies-test COMMAND copies-exe)
+
+add_executable(arraystocoords-exe ArraytoCoord.cpp)
+target_link_libraries(arraystocoords-exe ChunkBuffer)
+add_test(NAME arraystocoords-test COMMAND arraystocoords-exe)
+
+add_executable(copyblocks-exe CopyBlocks.cpp)
+target_link_libraries(copyblocks-exe ChunkBuffer)
+add_test(NAME copyblocks-test COMMAND copyblocks-exe)
diff --git a/tests/ChunkData/Coordinates.cpp b/tests/ChunkData/Coordinates.cpp
new file mode 100644
index 000000000..48d731c7e
--- /dev/null
+++ b/tests/ChunkData/Coordinates.cpp
@@ -0,0 +1,143 @@
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+
+
+int main(int argc, char** argv)
+{
+ {
+ cChunkData buffer;
+
+ // Empty chunks
+ buffer.SetBlock(0, 0, 0, 0xAB);
+ testassert(buffer.GetBlock(0, 0, 0) == 0xAB);
+ buffer.SetMeta(0, 16, 0, 0xC);
+ testassert(buffer.GetMeta(0, 16, 0) == 0xC);
+
+ // loaded but not written segments
+ testassert(buffer.GetBlock(1, 0, 0) == 0x0);
+ testassert(buffer.GetMeta(1, 16, 0) == 0x0);
+
+ // Notloaded segments
+ testassert(buffer.GetBlock(0, 32, 0) == 0x0);
+ testassert(buffer.GetMeta(0, 48, 0) == 0x0);
+
+ // Out of Range
+ CheckAsserts(
+ buffer.SetBlock(-1, 0, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetBlock(0, -1, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetBlock(0, 0, -1, 0);
+ );
+ CheckAsserts(
+ buffer.SetBlock(256, 0, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetBlock(0, 256, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetBlock(0, 0, 256, 0);
+ );
+
+ // Out of Range
+ CheckAsserts(
+ buffer.GetBlock(-1, 0, 0);
+ );
+ CheckAsserts(
+ buffer.GetBlock(0, -1, 0);
+ );
+ CheckAsserts(
+ buffer.GetBlock(0, 0, -1);
+ );
+ CheckAsserts(
+ buffer.GetBlock(256, 0, 0);
+ );
+ CheckAsserts(
+ buffer.GetBlock(0, 256, 0);
+ );
+ CheckAsserts(
+ buffer.GetBlock(0, 0, 256);
+ );
+
+ // Out of Range
+ CheckAsserts(
+ buffer.SetMeta(-1, 0, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetMeta(0, -1, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetMeta(0, 0, -1, 0);
+ );
+ CheckAsserts(
+ buffer.SetMeta(256, 0, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetMeta(0, 256, 0, 0);
+ );
+ CheckAsserts(
+ buffer.SetMeta(0, 0, 256, 0);
+ );
+
+ // Out of Range
+ CheckAsserts(
+ buffer.GetMeta(-1, 0, 0);
+ );
+ CheckAsserts(
+ buffer.GetMeta(0, -1, 0);
+ );
+ CheckAsserts(
+ buffer.GetMeta(0, 0, -1);
+ );
+ CheckAsserts(
+ buffer.GetMeta(256, 0, 0);
+ );
+ CheckAsserts(
+ buffer.GetMeta(0, 256, 0);
+ );
+ CheckAsserts(
+ buffer.GetMeta(0, 0, 256);
+ );
+ }
+
+ {
+ cChunkData buffer;
+
+ // Zero's
+ buffer.SetBlock(0, 0, 0, 0x0);
+ buffer.SetBlock(0, 0, 1, 0xab);
+ testassert(buffer.GetBlock(0, 0, 0) == 0x0);
+ testassert(buffer.GetBlock(0, 0, 1) == 0xab);
+
+ buffer.SetMeta(0, 16, 0, 0x0);
+ buffer.SetMeta(0, 16, 1, 0xc);
+ testassert(buffer.GetMeta(0, 16, 0) == 0x0);
+ testassert(buffer.GetMeta(0, 16, 1) == 0xc);
+ }
+
+
+ {
+ // Operator =
+ cChunkData buffer;
+ buffer.SetBlock(0, 0, 0, 0x42);
+ cChunkData copy;
+ #if __cplusplus < 201103L
+ copy = buffer;
+ #else
+ copy = std::move(buffer);
+ #endif
+ testassert(copy.GetBlock(0, 0, 0) == 0x42);
+ #if __cplusplus < 201103L
+ copy = copy;
+ #else
+ copy = std::move(copy);
+ #endif
+ testassert(copy.GetBlock(0, 0, 0) == 0x42);
+ }
+
+ return 0;
+}
diff --git a/tests/ChunkData/Copies.cpp b/tests/ChunkData/Copies.cpp
new file mode 100644
index 000000000..312441eee
--- /dev/null
+++ b/tests/ChunkData/Copies.cpp
@@ -0,0 +1,134 @@
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+
+
+int main(int argc, char** argv)
+{
+ {
+ cChunkData buffer;
+
+ buffer.SetBlock(3, 1, 4, 0xDE);
+ buffer.SetMeta(3, 1, 4, 0xA);
+
+ cChunkData copy = buffer.Copy();
+ testassert(copy.GetBlock(3, 1, 4) == 0xDE);
+ testassert(copy.GetMeta(3, 1, 4) == 0xA);
+
+ BLOCKTYPE SrcBlockBuffer[16 * 16 * 256];
+ for (int i = 0; i < 16 * 16 * 256; i += 4)
+ {
+ SrcBlockBuffer[i + 0] = 0xde;
+ SrcBlockBuffer[i + 1] = 0xad;
+ SrcBlockBuffer[i + 2] = 0xbe;
+ SrcBlockBuffer[i + 3] = 0xef;
+ }
+
+ buffer.SetBlockTypes(SrcBlockBuffer);
+ BLOCKTYPE DstBlockBuffer[16 * 16 * 256];
+ buffer.CopyBlockTypes(DstBlockBuffer);
+ testassert(memcmp(SrcBlockBuffer, DstBlockBuffer, (16 * 16 * 256) - 1) == 0);
+
+ memset(SrcBlockBuffer, 0x00, 16 * 16 * 256);
+ buffer.SetBlockTypes(SrcBlockBuffer);
+ buffer.CopyBlockTypes(DstBlockBuffer);
+ testassert(memcmp(SrcBlockBuffer, DstBlockBuffer, (16 * 16 * 256) - 1) == 0);
+ }
+
+ {
+ cChunkData buffer;
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ for (int i = 0; i < 16 * 16 * 256 / 2; i += 4)
+ {
+ SrcNibbleBuffer[i + 0] = 0xde;
+ SrcNibbleBuffer[i + 1] = 0xad;
+ SrcNibbleBuffer[i + 2] = 0xbe;
+ SrcNibbleBuffer[i + 3] = 0xef;
+ }
+
+ buffer.SetMetas(SrcNibbleBuffer);
+ NIBBLETYPE DstNibbleBuffer[16 * 16 * 256/ 2];
+ buffer.CopyMetas(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+
+ memset(SrcNibbleBuffer, 0x00, 16 * 16 * 256 /2);
+ buffer.SetMetas(SrcNibbleBuffer);
+ buffer.CopyMetas(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+ }
+
+ {
+ cChunkData buffer;
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ for (int i = 0; i < 16 * 16 * 256 / 2; i += 4)
+ {
+ SrcNibbleBuffer[i + 0] = 0xde;
+ SrcNibbleBuffer[i + 1] = 0xad;
+ SrcNibbleBuffer[i + 2] = 0xbe;
+ SrcNibbleBuffer[i + 3] = 0xef;
+ }
+
+ buffer.SetBlockLight(SrcNibbleBuffer);
+ NIBBLETYPE DstNibbleBuffer[16 * 16 * 256 / 2];
+ buffer.CopyBlockLight(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 /2) - 1) == 0);
+
+ memset(SrcNibbleBuffer, 0x00, 16 * 16 * 256 /2);
+ buffer.SetBlockLight(SrcNibbleBuffer);
+ buffer.CopyBlockLight(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 /2) - 1) == 0);
+ }
+
+ {
+ cChunkData buffer;
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ for (int i = 0; i < 16 * 16 * 256 / 2; i += 4)
+ {
+ SrcNibbleBuffer[i + 0] = 0xde;
+ SrcNibbleBuffer[i + 1] = 0xad;
+ SrcNibbleBuffer[i + 2] = 0xbe;
+ SrcNibbleBuffer[i + 3] = 0xef;
+ }
+
+ buffer.SetSkyLight(SrcNibbleBuffer);
+ NIBBLETYPE DstNibbleBuffer[16 * 16 * 256/ 2];
+ buffer.CopySkyLight(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+
+ memset(SrcNibbleBuffer, 0xFF, 16 * 16 * 256 / 2);
+ buffer.SetSkyLight(SrcNibbleBuffer);
+ buffer.CopySkyLight(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+ }
+
+ {
+ cChunkData buffer;
+
+ BLOCKTYPE SrcBlockBuffer[16 * 16 * 256];
+ memset(SrcBlockBuffer, 0x00, 16 * 16 * 256);
+ BLOCKTYPE DstBlockBuffer[16 * 16 * 256];
+ buffer.CopyBlockTypes(DstBlockBuffer);
+ testassert(memcmp(SrcBlockBuffer, DstBlockBuffer, (16 * 16 * 256) - 1) == 0);
+
+ NIBBLETYPE SrcNibbleBuffer[16 * 16 * 256 / 2];
+ memset(SrcNibbleBuffer, 0x00, 16 * 16 * 256 / 2);
+ NIBBLETYPE DstNibbleBuffer[16 * 16 * 256 / 2];
+ buffer.CopyMetas(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+
+ memset(SrcNibbleBuffer, 0x00, 16 * 16 * 256 / 2);
+ buffer.CopyBlockLight(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+
+ memset(SrcNibbleBuffer, 0xFF, 16 * 16 * 256 / 2);
+ buffer.CopySkyLight(DstNibbleBuffer);
+ testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 / 2) - 1) == 0);
+ }
+
+ // All tests successful:
+ return 0;
+}
diff --git a/tests/ChunkData/CopyBlocks.cpp b/tests/ChunkData/CopyBlocks.cpp
new file mode 100644
index 000000000..be8cab234
--- /dev/null
+++ b/tests/ChunkData/CopyBlocks.cpp
@@ -0,0 +1,76 @@
+
+// CopyBlocks.cpp
+
+// Implements the test for cChunkData::CopyBlockTypes() range copying
+
+
+
+
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+
+
+
+
+int main(int argc, char ** argv)
+{
+ // Set up a cChunkData with known contents - all blocks 0x01, all metas 0x02:
+ cChunkData Data;
+ cChunkDef::BlockTypes BlockTypes;
+ cChunkDef::BlockNibbles BlockMetas;
+ memset(BlockTypes, 0x01, sizeof(BlockTypes));
+ memset(BlockMetas, 0x02, sizeof(BlockMetas));
+ Data.SetBlockTypes(BlockTypes);
+ Data.SetMetas(BlockMetas);
+
+ // Try to read varying amounts of blocktypes from the cChunkData.
+ // Verify that the exact amount of memory is copied, by copying to a larger buffer and checking its boundaries
+ BLOCKTYPE TestBuffer[5 * cChunkDef::NumBlocks];
+ size_t WritePosIdx = 2 * cChunkDef::NumBlocks;
+ BLOCKTYPE * WritePosition = &TestBuffer[WritePosIdx];
+ memset(TestBuffer, 0x03, sizeof(TestBuffer));
+ size_t LastReportedStep = 1;
+ for (size_t idx = 0; idx < 5000; idx += 7)
+ {
+ if (idx / 500 != LastReportedStep)
+ {
+ printf("Testing index %u...\n", (unsigned)idx);
+ LastReportedStep = idx / 500;
+ }
+
+ for (size_t len = 3; len < 1000; len += 13)
+ {
+ Data.CopyBlockTypes(WritePosition, idx, len);
+
+ // Verify the data copied:
+ for (size_t i = 0; i < len; i++)
+ {
+ assert_test(WritePosition[i] == 0x01);
+ }
+ // Verify the space before the copied data hasn't been changed:
+ for (size_t i = 0; i < WritePosIdx; i++)
+ {
+ assert_test(TestBuffer[i] == 0x03);
+ }
+ // Verify the space after the copied data hasn't been changed:
+ for (size_t i = WritePosIdx + idx + len; i < ARRAYCOUNT(TestBuffer); i++)
+ {
+ assert_test(TestBuffer[i] == 0x03);
+ }
+
+ // Re-initialize the buffer for the next test:
+ for (size_t i = 0; i < len; i++)
+ {
+ WritePosition[i] = 0x03;
+ }
+ } // for len
+ } // for idx
+ return 0;
+}
+
+
+
+
+
diff --git a/tests/ChunkData/creatable.cpp b/tests/ChunkData/creatable.cpp
new file mode 100644
index 000000000..1321bf49b
--- /dev/null
+++ b/tests/ChunkData/creatable.cpp
@@ -0,0 +1,9 @@
+
+#include "Globals.h"
+#include "ChunkData.h"
+
+int main(int argc, char** argv)
+{
+ cChunkData buffer;
+ return 0;
+}
diff --git a/uploadCoverage.sh b/uploadCoverage.sh
new file mode 100755
index 000000000..fc17ddc2c
--- /dev/null
+++ b/uploadCoverage.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]
+ then
+ find tests -type f -name '*.gcda' -exec sh -c 'cp {} $(dirname {})/../$(basename {})' \;
+ coveralls --exclude lib --exclude Android >/dev/null
+fi
+
+