From 5ae3e94decf3ae97ceafa746fb09477f4445b577 Mon Sep 17 00:00:00 2001 From: Ben Kerllenevich Date: Sat, 28 Aug 2021 08:20:27 -0400 Subject: [PATCH] Updated Upstream (Paper) Upstream has released updates that appear to apply and compile correctly --- build.gradle.kts | 12 +- gradle.properties | 2 +- ....patch => 0001-Airplane-API-Changes.patch} | 0 patches/api/0001-Tuinity-API-Changes.patch | 140 - ....patch => 0002-Build-System-Changes.patch} | 0 ...s.patch => 0003-Purpur-config-files.patch} | 6 +- ...patch => 0004-Purpur-client-support.patch} | 2 +- ...s.patch => 0005-Default-permissions.patch} | 0 ...007-Ridables.patch => 0006-Ridables.patch} | 0 ...ch => 0007-Allow-inventory-resizing.patch} | 0 ...t-API.patch => 0008-Advancement-API.patch} | 0 ...0-Llama-API.patch => 0009-Llama-API.patch} | 0 ...{0011-AFK-API.patch => 0010-AFK-API.patch} | 2 +- ...atch => 0011-Bring-back-server-name.patch} | 4 +- ...t.patch => 0012-ExecuteCommandEvent.patch} | 0 ... 0013-LivingEntity-safeFallDistance.patch} | 0 ...old.patch => 0014-Lagging-threshold.patch} | 4 +- ...h => 0015-ItemFactory-getMonsterEgg.patch} | 0 ...16-PlayerSetSpawnerTypeWithEggEvent.patch} | 0 ...ch => 0017-EMC-MonsterEggSpawnEvent.patch} | 0 ....patch => 0018-Villager-resetOffers.patch} | 0 ...ch => 0019-Player-invulnerabilities.patch} | 2 +- ...1-Anvil-API.patch => 0020-Anvil-API.patch} | 0 ... 0021-ItemStack-convenience-methods.patch} | 0 ...d-to-crystals-and-crystals-shoot-ph.patch} | 0 ...atch => 0023-ChatColor-conveniences.patch} | 0 ...024-LivingEntity-broadcastItemBreak.patch} | 0 ...atch => 0025-Item-entity-immunities.patch} | 0 ...t-Improve-output-of-plugins-command.patch} | 0 ...able-zombie-aggressiveness-towards-.patch} | 0 ...-to-recipe-s-ExactChoice-ingredient.patch} | 0 ...check-to-EntityDamagedByEntityEvent.patch} | 0 ...d-API.patch => 0030-Left-handed-API.patch} | 0 ...31-Alphabetize-in-game-plugins-list.patch} | 0 ...lf-API.patch => 0032-Rabid-Wolf-API.patch} | 0 ...c-warnings-missing-param-and-return.patch} | 10 +- ...tch => 0034-PlayerBookTooLargeEvent.patch} | 0 ...herite-armor-grants-fire-resistance.patch} | 0 ...036-Add-EntityTeleportHinderedEvent.patch} | 0 ... => 0037-Add-StructureGenerateEvent.patch} | 0 ...Add-unsafe-Entity-serialization-API.patch} | 0 ...n-change-for-adventure-deprecations.patch} | 22 +- ...tment-target-for-bows-and-crossbows.patch} | 0 ...> 0041-Iron-golem-poppy-calms-anger.patch} | 0 ...42-API-for-any-mob-to-burn-daylight.patch} | 0 ...atch => 0043-Flying-Fall-Damage-API.patch} | 2 +- ...d-back-player-spawned-endermite-API.patch} | 0 ... 0045-Fix-default-permission-system.patch} | 0 ...oner-API.patch => 0046-Summoner-API.patch} | 0 ...-version-command-output-for-console.patch} | 0 ...mpt-parameters-to-resource-pack-api.patch} | 2 +- ... => 0049-Extended-OfflinePlayer-API.patch} | 0 ...he-ability-to-add-combustible-items.patch} | 4 +- ...tch => 0001-Airplane-Server-Changes.patch} | 222 +- .../server/0001-Tuinity-Server-Changes.patch | 39699 ---------------- ...Airplane-defaults-closer-to-vanilla.patch} | 2 +- patches/server/0003-Rebrand.patch | 158 + ...s.patch => 0004-Purpur-config-files.patch} | 64 +- patches/server/0004-Rebrand.patch | 956 - ...patch => 0005-Purpur-client-support.patch} | 6 +- ...0006-Component-related-conveniences.patch} | 10 +- ...008-Ridables.patch => 0007-Ridables.patch} | 46 +- ...Configurable-entity-base-attributes.patch} | 6 +- ...s-stuff.patch => 0009-Timings-stuff.patch} | 13 +- ...0010-Barrels-and-enderchests-6-rows.patch} | 2 +- ...t-API.patch => 0011-Advancement-API.patch} | 0 ...3-Llama-API.patch => 0012-Llama-API.patch} | 0 ...{0014-AFK-API.patch => 0013-AFK-API.patch} | 14 +- ...atch => 0014-Bring-back-server-name.patch} | 4 +- ...> 0015-Configurable-server-mod-name.patch} | 10 +- ... 0016-LivingEntity-safeFallDistance.patch} | 6 +- ...old.patch => 0017-Lagging-threshold.patch} | 14 +- ...h => 0018-ItemFactory-getMonsterEgg.patch} | 0 ...19-PlayerSetSpawnerTypeWithEggEvent.patch} | 0 ...ch => 0020-EMC-MonsterEggSpawnEvent.patch} | 0 ...ch => 0021-Player-invulnerabilities.patch} | 12 +- ...3-Anvil-API.patch => 0022-Anvil-API.patch} | 6 +- ...3-Configurable-villager-brain-ticks.patch} | 0 ...0024-Alternative-Keepalive-Handling.patch} | 4 +- ...s.patch => 0025-Silk-touch-spawners.patch} | 0 ...72-Fix-Add-turtle-egg-block-options.patch} | 0 ...-vanilla-command-permission-handler.patch} | 10 +- ...settings-suppressing-pointless-logs.patch} | 2 +- ...> 0029-Disable-outdated-build-check.patch} | 4 +- ...gs.patch => 0030-Giants-AI-settings.patch} | 0 ...> 0031-Zombie-horse-naturally-spawn.patch} | 2 +- ...032-Charged-creeper-naturally-spawn.patch} | 0 ...it-naturally-spawn-toast-and-killer.patch} | 0 ...er-showing-in-ping-before-server-fu.patch} | 0 ...35-Dont-send-useless-entity-packets.patch} | 4 +- ...atch => 0036-Tulips-change-fox-type.patch} | 0 ...patch => 0037-Breedable-Polar-Bears.patch} | 0 ...atch => 0038-Chickens-can-retaliate.patch} | 0 ...ption-to-set-armorstand-step-height.patch} | 2 +- ....patch => 0040-Cat-spawning-options.patch} | 0 ...n-black-cats-spawning-in-swamp-huts.patch} | 0 ...ms.patch => 0042-Cows-eat-mushrooms.patch} | 0 ...ow-rotation-when-shearing-mooshroom.patch} | 0 ...patch => 0044-Pigs-give-saddle-back.patch} | 0 ...5-Snowman-drop-and-put-back-pumpkin.patch} | 0 ...6-Ender-dragon-always-drop-full-exp.patch} | 0 ... 0047-Signs-editable-on-right-click.patch} | 0 ...tch => 0048-Signs-allow-color-codes.patch} | 4 +- ...oisten-from-water-directly-under-it.patch} | 4 +- ...Minecart-settings-and-WASD-controls.patch} | 6 +- ...ble-loot-drops-on-death-by-cramming.patch} | 2 +- ...tion-to-toggle-milk-curing-bad-omen.patch} | 0 ...ould-check-if-entity-can-use-portal.patch} | 0 ...054-Fix-the-dead-lagging-the-server.patch} | 6 +- ...Skip-events-if-there-s-no-listeners.patch} | 14 +- ... 0056-Add-permission-for-F3-N-debug.patch} | 10 +- ...ch => 0057-Configurable-TPS-Catchup.patch} | 6 +- ...ow-loyalty-on-tridents-to-work-in-t.patch} | 0 ...erman-and-creeper-griefing-controls.patch} | 0 ...060-Villagers-follow-emerald-blocks.patch} | 2 +- ...ch => 0061-Allow-leashing-villagers.patch} | 4 +- ...rable-search-radius-for-villagers-t.patch} | 2 +- ...tch => 0063-Implement-infinite-lava.patch} | 2 +- ...4-Make-lava-flow-speed-configurable.patch} | 0 ...dd-player-death-exp-control-options.patch} | 2 +- ...rable-void-damage-height-and-damage.patch} | 6 +- ...=> 0067-Add-canSaveToDisk-to-Entity.patch} | 6 +- ...spenser-curse-of-binding-protection.patch} | 2 +- ...-for-boats-to-eject-players-on-land.patch} | 2 +- ...-mends-most-damages-equipment-first.patch} | 0 ...071-Add-5-second-tps-average-in-tps.patch} | 12 +- ...h => 0072-Implement-elytra-settings.patch} | 4 +- ...atch => 0073-Item-entity-immunities.patch} | 10 +- ...mand.patch => 0074-Add-ping-command.patch} | 4 +- ...mand.patch => 0075-Add-demo-command.patch} | 4 +- ...d.patch => 0076-Add-credits-command.patch} | 4 +- ...=> 0077-Configurable-jockey-options.patch} | 0 ...d-to-crystals-and-crystals-shoot-ph.patch} | 0 ...> 0079-Add-phantom-spawning-options.patch} | 0 ...080-Implement-bed-explosion-options.patch} | 2 +- ...nt-respawn-anchor-explosion-options.patch} | 0 ...Add-allow-water-in-end-world-option.patch} | 12 +- ... => 0083-Allow-color-codes-in-books.patch} | 2 +- ...espan.patch => 0084-Entity-lifespan.patch} | 4 +- ...eport-to-spawn-if-outside-world-bor.patch} | 6 +- ...ty.patch => 0086-Squid-EAR-immunity.patch} | 4 +- ...-Configurable-feature-seed-settings.patch} | 2 +- ...atch => 0088-Phantoms-burn-in-light.patch} | 0 ...0089-Configurable-villager-breeding.patch} | 2 +- ... 0090-Redstone-deactivates-spawners.patch} | 0 ...ch => 0091-Totems-work-in-inventory.patch} | 2 +- ...-Add-vindicator-johnny-spawn-chance.patch} | 0 ...on-to-disable-certain-block-updates.patch} | 2 +- ...0094-Dispensers-place-anvils-option.patch} | 0 ...rs.patch => 0095-Allow-anvil-colors.patch} | 2 +- ... 0096-Add-no-random-tick-block-list.patch} | 4 +- ...-disable-dolphin-treasure-searching.patch} | 0 ...patch => 0098-Short-enderman-height.patch} | 2 +- ...top-squids-floating-on-top-of-water.patch} | 6 +- ...-height-for-nether-surface-builders.patch} | 0 ...ng-obsidian-valid-for-portal-frames.patch} | 2 +- ...ities-can-use-portals-configuration.patch} | 6 +- ...103-LivingEntity-broadcastItemBreak.patch} | 4 +- ...tomizable-wither-health-and-healing.patch} | 0 ...gling-special-MobSpawners-per-world.patch} | 4 +- ...patch => 0106-Raid-cooldown-setting.patch} | 0 ...-config-options-per-projectile-type.patch} | 0 ...able-zombie-aggressiveness-towards-.patch} | 0 ...ent-TileEntity-Lore-and-DisplayName.patch} | 4 +- ...-to-recipe-s-ExactChoice-ingredient.patch} | 0 ...y.patch => 0111-Flying-squids-Oh-my.patch} | 0 ...patch => 0112-Infinity-bow-settings.patch} | 2 +- ...ge.patch => 0113-Stonecutter-damage.patch} | 4 +- ...=> 0114-Configurable-daylight-cycle.patch} | 8 +- ...e-and-mending-enchantments-together.patch} | 2 +- ...6-Furnace-uses-lava-from-underneath.patch} | 0 ...ws-should-not-reset-despawn-counter.patch} | 0 ...e-add-farmland-mechanics-from-Alpha.patch} | 2 +- ...ustable-breeding-cooldown-to-config.patch} | 8 +- ...-entity-breeding-times-configurable.patch} | 0 ...es-from-item-forms-of-entities-to-e.patch} | 6 +- ...when-using-a-Name-Tag-on-an-Armor-S.patch} | 2 +- ...ting-and-weeping-vines-growth-rates.patch} | 0 ...twisting-vines-configurable-max-gro.patch} | 0 ...lowing-Endermen-to-despawn-even-whi.patch} | 0 ...check-to-EntityDamagedByEntityEvent.patch} | 2 +- ...27-Add-configurable-snowball-damage.patch} | 0 ...reak-door-minimum-difficulty-option.patch} | 0 ...d-API.patch => 0129-Left-handed-API.patch} | 4 +- ...0-Changeable-Mob-Left-Handed-Chance.patch} | 4 +- ...=> 0131-Add-boat-fall-damage-config.patch} | 2 +- ...0132-Snow-Golem-rate-of-fire-config.patch} | 0 ...-Configurable-disable-give-dropping.patch} | 2 +- ... => 0134-Lobotomize-stuck-villagers.patch} | 2 +- ...illager-Clerics-to-farm-Nether-Wart.patch} | 2 +- ...ied-Piglin-death-always-counting-as.patch} | 0 ...timise-player-list-ticksSpread-out-.patch} | 6 +- ...le-chance-for-wolves-to-spawn-rabid.patch} | 0 ...figurable-default-wolf-collar-color.patch} | 0 ...tch => 0140-Phantom-flames-on-swoop.patch} | 0 ...-to-open-even-with-a-solid-block-on.patch} | 0 ...SBar.patch => 0142-Implement-TPSBar.patch} | 18 +- ...h => 0143-Striders-give-saddle-back.patch} | 0 ...tch => 0144-PlayerBookTooLargeEvent.patch} | 2 +- ...herite-armor-grants-fire-resistance.patch} | 4 +- ...146-Fix-rotating-UP-DOWN-CW-and-CCW.patch} | 0 ...ack.patch => 0147-Add-MC-4-fix-back.patch} | 8 +- ...efing-bypass-to-everything-affected.patch} | 6 +- ...llow-Note-Block-sounds-when-blocked.patch} | 0 ...150-Add-EntityTeleportHinderedEvent.patch} | 4 +- ... => 0151-Add-StructureGenerateEvent.patch} | 4 +- ... => 0152-Farmland-trampling-changes.patch} | 2 +- ...3-Movement-options-for-armor-stands.patch} | 6 +- ....patch => 0154-Fix-stuck-in-portals.patch} | 6 +- ...ggle-for-water-sensitive-mob-damage.patch} | 2 +- ...6-Config-to-always-tame-in-Creative.patch} | 0 ... 0157-End-crystal-explosion-options.patch} | 0 ...Add-unsafe-Entity-serialization-API.patch} | 4 +- ...ther-Ender-Dragon-can-ride-vehicles.patch} | 0 ...atch => 0160-Dont-run-with-scissors.patch} | 6 +- ...nch-Man.patch => 0161-One-Punch-Man.patch} | 2 +- ...162-Add-config-for-snow-on-blue-ice.patch} | 0 ...r-Pearl-cooldown-damage-and-Endermi.patch} | 2 +- ...to-ignore-nearby-mobs-when-sleeping.patch} | 2 +- ...d-back-player-spawned-endermite-API.patch} | 0 ...n-aggressiveness-towards-Endermites.patch} | 0 ...Dragon-Head-wearers-and-stare-aggro.patch} | 0 ...ig.patch => 0168-Tick-fluids-config.patch} | 0 ...69-Config-to-disable-Llama-caravans.patch} | 0 ...g-to-make-Creepers-explode-on-death.patch} | 0 ...rable-ravager-griefable-blocks-list.patch} | 0 ...172-Sneak-to-bulk-process-composter.patch} | 2 +- ...h => 0173-Config-for-skipping-night.patch} | 2 +- ...174-Add-config-for-villager-trading.patch} | 2 +- ...=> 0175-Allow-infinity-on-crossbows.patch} | 2 +- ...ngs.patch => 0176-Drowning-Settings.patch} | 8 +- ...reak-individual-slabs-when-sneaking.patch} | 2 +- ...to-disable-hostile-mob-spawn-on-ice.patch} | 0 ...g-to-show-Armor-Stand-arms-on-spawn.patch} | 2 +- ...tion-to-make-doors-require-redstone.patch} | 0 ...Config-to-allow-for-unsafe-enchants.patch} | 8 +- ...0182-Configurable-sponge-absorption.patch} | 0 ...ch => 0183-Projectile-offset-config.patch} | 0 ...or-powered-rail-activation-distance.patch} | 0 ...> 0185-Piglin-portal-spawn-modifier.patch} | 0 ...Config-to-change-max-number-of-bees.patch} | 2 +- ...le-damage-settings-for-magma-blocks.patch} | 4 +- ...-Config-for-wither-explosion-radius.patch} | 0 ... => 0189-Gamemode-extra-permissions.patch} | 6 +- ...ng-the-blocks-that-turn-into-dirt-p.patch} | 0 ...0191-Configurable-piston-push-limit.patch} | 0 ...192-Configurable-broadcast-settings.patch} | 4 +- ...-6278.patch => 0193-Fix-SPIGOT-6278.patch} | 0 ... => 0194-Configurable-mob-blindness.patch} | 2 +- ...hidden-players-from-entity-selector.patch} | 2 +- ...-to-impact-Creeper-explosion-radius.patch} | 0 ...> 0197-Iron-golem-poppy-calms-anger.patch} | 0 ...ots.patch => 0198-Breedable-parrots.patch} | 0 ...gurable-powered-rail-boost-modifier.patch} | 2 +- ...ge-multiplier-critical-damage-value.patch} | 2 +- ...n-to-disable-dragon-egg-teleporting.patch} | 0 ...fig-for-unverified-username-message.patch} | 4 +- ...-anvil-cumulative-cost-configurable.patch} | 6 +- ...4-ShulkerBox-allow-oversized-stacks.patch} | 2 +- ...e-can-work-when-raining-or-at-night.patch} | 0 ...06-API-for-any-mob-to-burn-daylight.patch} | 16 +- ...dvancement-triggers-on-entity-death.patch} | 6 +- ...h => 0208-Config-MobEffect-by-world.patch} | 2 +- ...eacon-Activation-Range-Configurable.patch} | 0 ...0210-Add-toggle-for-sand-duping-fix.patch} | 0 ...gle-for-end-portal-safe-teleporting.patch} | 4 +- ...atch => 0212-Flying-Fall-Damage-API.patch} | 4 +- ...ke-lightning-rod-range-configurable.patch} | 4 +- ...ng-food-fills-hunger-bar-completely.patch} | 2 +- ...ayer-join-full-server-by-permission.patch} | 4 +- ...tch => 0216-Populator-seed-controls.patch} | 0 ...ermission-bypass-for-portal-waiting.patch} | 2 +- ...8-Shulker-spawn-from-bullet-options.patch} | 0 ...ating-glow-berries-adds-glow-effect.patch} | 2 +- ...-Option-to-make-drowned-break-doors.patch} | 0 ...nfigurable-hunger-starvation-damage.patch} | 0 ...-System.out-calls-to-plugin-loggers.patch} | 6 +- ...h => 0223-Armor-click-equip-options.patch} | 2 +- ...nd.patch => 0224-Add-uptime-command.patch} | 10 +- ...atch => 0225-Structure-seed-options.patch} | 6 +- ...tch => 0226-Tool-actionable-options.patch} | 0 ...-bed-respawn-location-not-resetting.patch} | 6 +- ...8-Store-placer-on-Block-when-placed.patch} | 4 +- ...oner-API.patch => 0229-Summoner-API.patch} | 0 ...mizable-sleeping-actionbar-messages.patch} | 4 +- ...-shulker-box-items-from-dropping-co.patch} | 2 +- ...232-Silk-touchable-budding-amethyst.patch} | 0 ...tch => 0233-Big-dripleaf-tilt-delay.patch} | 0 ...0234-Player-ridable-in-water-option.patch} | 2 +- ...-Enderman-teleport-on-projectile-hi.patch} | 0 ...ue-Crash-with-Plugin-or-Datapack-Ge.patch} | 0 ...d.patch => 0237-Add-compass-command.patch} | 10 +- ...nt-horses-from-standing-with-riders.patch} | 0 ...h => 0239-Toggle-for-kinetic-damage.patch} | 4 +- ...-Option-for-disable-observer-clocks.patch} | 2 +- ...zeable-Zombie-Villager-curing-times.patch} | 0 ...-Option-for-sponges-to-work-on-lava.patch} | 0 ...243-Toggle-for-Wither-s-spawn-sound.patch} | 0 ...-breaks-from-solid-neighbors-config.patch} | 0 ...move-curse-of-binding-with-weakness.patch} | 0 ...0246-Conduit-behavior-configuration.patch} | 0 ...patch => 0247-Cauldron-fill-chances.patch} | 0 ...o-allow-mobs-to-pathfind-over-rails.patch} | 0 ...mpt-parameters-to-resource-pack-api.patch} | 2 +- ... 0250-Shulker-change-color-with-dye.patch} | 0 ... => 0251-Extended-OfflinePlayer-API.patch} | 2 +- ...he-ability-to-add-combustible-items.patch} | 12 +- patches/server/0253-Fix-sinking-boats.patch | 22 - ...in-and-thunder-should-stop-on-sleep.patch} | 2 +- ...-blocks-to-grow-into-trees-naturall.patch} | 0 ...-right-click-to-use-exp-for-mending.patch} | 4 +- 311 files changed, 669 insertions(+), 41361 deletions(-) rename patches/api/{0002-Airplane-API-Changes.patch => 0001-Airplane-API-Changes.patch} (100%) delete mode 100644 patches/api/0001-Tuinity-API-Changes.patch rename patches/api/{0003-Build-System-Changes.patch => 0002-Build-System-Changes.patch} (100%) rename patches/api/{0004-Purpur-config-files.patch => 0003-Purpur-config-files.patch} (80%) rename patches/api/{0005-Purpur-client-support.patch => 0004-Purpur-client-support.patch} (89%) rename patches/api/{0006-Default-permissions.patch => 0005-Default-permissions.patch} (100%) rename patches/api/{0007-Ridables.patch => 0006-Ridables.patch} (100%) rename patches/api/{0008-Allow-inventory-resizing.patch => 0007-Allow-inventory-resizing.patch} (100%) rename patches/api/{0009-Advancement-API.patch => 0008-Advancement-API.patch} (100%) rename patches/api/{0010-Llama-API.patch => 0009-Llama-API.patch} (100%) rename patches/api/{0011-AFK-API.patch => 0010-AFK-API.patch} (96%) rename patches/api/{0012-Bring-back-server-name.patch => 0011-Bring-back-server-name.patch} (89%) rename patches/api/{0013-ExecuteCommandEvent.patch => 0012-ExecuteCommandEvent.patch} (100%) rename patches/api/{0014-LivingEntity-safeFallDistance.patch => 0013-LivingEntity-safeFallDistance.patch} (100%) rename patches/api/{0015-Lagging-threshold.patch => 0014-Lagging-threshold.patch} (89%) rename patches/api/{0016-ItemFactory-getMonsterEgg.patch => 0015-ItemFactory-getMonsterEgg.patch} (100%) rename patches/api/{0017-PlayerSetSpawnerTypeWithEggEvent.patch => 0016-PlayerSetSpawnerTypeWithEggEvent.patch} (100%) rename patches/api/{0018-EMC-MonsterEggSpawnEvent.patch => 0017-EMC-MonsterEggSpawnEvent.patch} (100%) rename patches/api/{0019-Villager-resetOffers.patch => 0018-Villager-resetOffers.patch} (100%) rename patches/api/{0020-Player-invulnerabilities.patch => 0019-Player-invulnerabilities.patch} (92%) rename patches/api/{0021-Anvil-API.patch => 0020-Anvil-API.patch} (100%) rename patches/api/{0022-ItemStack-convenience-methods.patch => 0021-ItemStack-convenience-methods.patch} (100%) rename patches/api/{0023-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch => 0022-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch} (100%) rename patches/api/{0024-ChatColor-conveniences.patch => 0023-ChatColor-conveniences.patch} (100%) rename patches/api/{0025-LivingEntity-broadcastItemBreak.patch => 0024-LivingEntity-broadcastItemBreak.patch} (100%) rename patches/api/{0026-Item-entity-immunities.patch => 0025-Item-entity-immunities.patch} (100%) rename patches/api/{0027-Spigot-Improve-output-of-plugins-command.patch => 0026-Spigot-Improve-output-of-plugins-command.patch} (100%) rename patches/api/{0028-Add-option-to-disable-zombie-aggressiveness-towards-.patch => 0027-Add-option-to-disable-zombie-aggressiveness-towards-.patch} (100%) rename patches/api/{0029-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch => 0028-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch} (100%) rename patches/api/{0030-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch => 0029-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch} (100%) rename patches/api/{0031-Left-handed-API.patch => 0030-Left-handed-API.patch} (100%) rename patches/api/{0032-Alphabetize-in-game-plugins-list.patch => 0031-Alphabetize-in-game-plugins-list.patch} (100%) rename patches/api/{0033-Rabid-Wolf-API.patch => 0032-Rabid-Wolf-API.patch} (100%) rename patches/api/{0034-Fix-javadoc-warnings-missing-param-and-return.patch => 0033-Fix-javadoc-warnings-missing-param-and-return.patch} (99%) rename patches/api/{0035-PlayerBookTooLargeEvent.patch => 0034-PlayerBookTooLargeEvent.patch} (100%) rename patches/api/{0036-Full-netherite-armor-grants-fire-resistance.patch => 0035-Full-netherite-armor-grants-fire-resistance.patch} (100%) rename patches/api/{0037-Add-EntityTeleportHinderedEvent.patch => 0036-Add-EntityTeleportHinderedEvent.patch} (100%) rename patches/api/{0038-Add-StructureGenerateEvent.patch => 0037-Add-StructureGenerateEvent.patch} (100%) rename patches/api/{0039-Add-unsafe-Entity-serialization-API.patch => 0038-Add-unsafe-Entity-serialization-API.patch} (100%) rename patches/api/{0040-Conflict-on-change-for-adventure-deprecations.patch => 0039-Conflict-on-change-for-adventure-deprecations.patch} (98%) rename patches/api/{0041-Add-enchantment-target-for-bows-and-crossbows.patch => 0040-Add-enchantment-target-for-bows-and-crossbows.patch} (100%) rename patches/api/{0042-Iron-golem-poppy-calms-anger.patch => 0041-Iron-golem-poppy-calms-anger.patch} (100%) rename patches/api/{0043-API-for-any-mob-to-burn-daylight.patch => 0042-API-for-any-mob-to-burn-daylight.patch} (100%) rename patches/api/{0044-Flying-Fall-Damage-API.patch => 0043-Flying-Fall-Damage-API.patch} (92%) rename patches/api/{0045-Add-back-player-spawned-endermite-API.patch => 0044-Add-back-player-spawned-endermite-API.patch} (100%) rename patches/api/{0046-Fix-default-permission-system.patch => 0045-Fix-default-permission-system.patch} (100%) rename patches/api/{0047-Summoner-API.patch => 0046-Summoner-API.patch} (100%) rename patches/api/{0048-Clean-up-version-command-output-for-console.patch => 0047-Clean-up-version-command-output-for-console.patch} (100%) rename patches/api/{0049-Add-force-and-prompt-parameters-to-resource-pack-api.patch => 0048-Add-force-and-prompt-parameters-to-resource-pack-api.patch} (98%) rename patches/api/{0050-Extended-OfflinePlayer-API.patch => 0049-Extended-OfflinePlayer-API.patch} (100%) rename patches/api/{0051-Added-the-ability-to-add-combustible-items.patch => 0050-Added-the-ability-to-add-combustible-items.patch} (92%) rename patches/server/{0002-Airplane-Server-Changes.patch => 0001-Airplane-Server-Changes.patch} (94%) delete mode 100644 patches/server/0001-Tuinity-Server-Changes.patch rename patches/server/{0003-Change-Airplane-defaults-closer-to-vanilla.patch => 0002-Change-Airplane-defaults-closer-to-vanilla.patch} (96%) create mode 100644 patches/server/0003-Rebrand.patch rename patches/server/{0005-Purpur-config-files.patch => 0004-Purpur-config-files.patch} (90%) delete mode 100644 patches/server/0004-Rebrand.patch rename patches/server/{0006-Purpur-client-support.patch => 0005-Purpur-client-support.patch} (91%) rename patches/server/{0007-Component-related-conveniences.patch => 0006-Component-related-conveniences.patch} (92%) rename patches/server/{0008-Ridables.patch => 0007-Ridables.patch} (99%) rename patches/server/{0009-Configurable-entity-base-attributes.patch => 0008-Configurable-entity-base-attributes.patch} (99%) rename patches/server/{0010-Timings-stuff.patch => 0009-Timings-stuff.patch} (86%) rename patches/server/{0011-Barrels-and-enderchests-6-rows.patch => 0010-Barrels-and-enderchests-6-rows.patch} (99%) rename patches/server/{0012-Advancement-API.patch => 0011-Advancement-API.patch} (100%) rename patches/server/{0013-Llama-API.patch => 0012-Llama-API.patch} (100%) rename patches/server/{0014-AFK-API.patch => 0013-AFK-API.patch} (96%) rename patches/server/{0015-Bring-back-server-name.patch => 0014-Bring-back-server-name.patch} (91%) rename patches/server/{0016-Configurable-server-mod-name.patch => 0015-Configurable-server-mod-name.patch} (75%) rename patches/server/{0017-LivingEntity-safeFallDistance.patch => 0016-LivingEntity-safeFallDistance.patch} (94%) rename patches/server/{0018-Lagging-threshold.patch => 0017-Lagging-threshold.patch} (82%) rename patches/server/{0019-ItemFactory-getMonsterEgg.patch => 0018-ItemFactory-getMonsterEgg.patch} (100%) rename patches/server/{0020-PlayerSetSpawnerTypeWithEggEvent.patch => 0019-PlayerSetSpawnerTypeWithEggEvent.patch} (100%) rename patches/server/{0021-EMC-MonsterEggSpawnEvent.patch => 0020-EMC-MonsterEggSpawnEvent.patch} (100%) rename patches/server/{0022-Player-invulnerabilities.patch => 0021-Player-invulnerabilities.patch} (94%) rename patches/server/{0023-Anvil-API.patch => 0022-Anvil-API.patch} (96%) rename patches/server/{0024-Configurable-villager-brain-ticks.patch => 0023-Configurable-villager-brain-ticks.patch} (100%) rename patches/server/{0025-Alternative-Keepalive-Handling.patch => 0024-Alternative-Keepalive-Handling.patch} (95%) rename patches/server/{0026-Silk-touch-spawners.patch => 0025-Silk-touch-spawners.patch} (100%) rename patches/server/{0027-MC-168772-Fix-Add-turtle-egg-block-options.patch => 0026-MC-168772-Fix-Add-turtle-egg-block-options.patch} (100%) rename patches/server/{0028-Fix-vanilla-command-permission-handler.patch => 0027-Fix-vanilla-command-permission-handler.patch} (81%) rename patches/server/{0029-Logger-settings-suppressing-pointless-logs.patch => 0028-Logger-settings-suppressing-pointless-logs.patch} (96%) rename patches/server/{0030-Disable-outdated-build-check.patch => 0029-Disable-outdated-build-check.patch} (88%) rename patches/server/{0031-Giants-AI-settings.patch => 0030-Giants-AI-settings.patch} (100%) rename patches/server/{0032-Zombie-horse-naturally-spawn.patch => 0031-Zombie-horse-naturally-spawn.patch} (97%) rename patches/server/{0033-Charged-creeper-naturally-spawn.patch => 0032-Charged-creeper-naturally-spawn.patch} (100%) rename patches/server/{0034-Rabbit-naturally-spawn-toast-and-killer.patch => 0033-Rabbit-naturally-spawn-toast-and-killer.patch} (100%) rename patches/server/{0035-Fix-outdated-server-showing-in-ping-before-server-fu.patch => 0034-Fix-outdated-server-showing-in-ping-before-server-fu.patch} (100%) rename patches/server/{0036-Dont-send-useless-entity-packets.patch => 0035-Dont-send-useless-entity-packets.patch} (94%) rename patches/server/{0037-Tulips-change-fox-type.patch => 0036-Tulips-change-fox-type.patch} (100%) rename patches/server/{0038-Breedable-Polar-Bears.patch => 0037-Breedable-Polar-Bears.patch} (100%) rename patches/server/{0039-Chickens-can-retaliate.patch => 0038-Chickens-can-retaliate.patch} (100%) rename patches/server/{0040-Add-option-to-set-armorstand-step-height.patch => 0039-Add-option-to-set-armorstand-step-height.patch} (94%) rename patches/server/{0041-Cat-spawning-options.patch => 0040-Cat-spawning-options.patch} (100%) rename patches/server/{0042-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch => 0041-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch} (100%) rename patches/server/{0043-Cows-eat-mushrooms.patch => 0042-Cows-eat-mushrooms.patch} (100%) rename patches/server/{0044-Fix-cow-rotation-when-shearing-mooshroom.patch => 0043-Fix-cow-rotation-when-shearing-mooshroom.patch} (100%) rename patches/server/{0045-Pigs-give-saddle-back.patch => 0044-Pigs-give-saddle-back.patch} (100%) rename patches/server/{0046-Snowman-drop-and-put-back-pumpkin.patch => 0045-Snowman-drop-and-put-back-pumpkin.patch} (100%) rename patches/server/{0047-Ender-dragon-always-drop-full-exp.patch => 0046-Ender-dragon-always-drop-full-exp.patch} (100%) rename patches/server/{0048-Signs-editable-on-right-click.patch => 0047-Signs-editable-on-right-click.patch} (100%) rename patches/server/{0049-Signs-allow-color-codes.patch => 0048-Signs-allow-color-codes.patch} (96%) rename patches/server/{0050-Allow-soil-to-moisten-from-water-directly-under-it.patch => 0049-Allow-soil-to-moisten-from-water-directly-under-it.patch} (90%) rename patches/server/{0051-Minecart-settings-and-WASD-controls.patch => 0050-Minecart-settings-and-WASD-controls.patch} (97%) rename patches/server/{0052-Disable-loot-drops-on-death-by-cramming.patch => 0051-Disable-loot-drops-on-death-by-cramming.patch} (95%) rename patches/server/{0053-Option-to-toggle-milk-curing-bad-omen.patch => 0052-Option-to-toggle-milk-curing-bad-omen.patch} (100%) rename patches/server/{0054-End-gateway-should-check-if-entity-can-use-portal.patch => 0053-End-gateway-should-check-if-entity-can-use-portal.patch} (100%) rename patches/server/{0055-Fix-the-dead-lagging-the-server.patch => 0054-Fix-the-dead-lagging-the-server.patch} (84%) rename patches/server/{0056-Skip-events-if-there-s-no-listeners.patch => 0055-Skip-events-if-there-s-no-listeners.patch} (59%) rename patches/server/{0057-Add-permission-for-F3-N-debug.patch => 0056-Add-permission-for-F3-N-debug.patch} (56%) rename patches/server/{0058-Configurable-TPS-Catchup.patch => 0057-Configurable-TPS-Catchup.patch} (89%) rename patches/server/{0059-Add-option-to-allow-loyalty-on-tridents-to-work-in-t.patch => 0058-Add-option-to-allow-loyalty-on-tridents-to-work-in-t.patch} (100%) rename patches/server/{0060-Add-enderman-and-creeper-griefing-controls.patch => 0059-Add-enderman-and-creeper-griefing-controls.patch} (100%) rename patches/server/{0061-Villagers-follow-emerald-blocks.patch => 0060-Villagers-follow-emerald-blocks.patch} (98%) rename patches/server/{0062-Allow-leashing-villagers.patch => 0061-Allow-leashing-villagers.patch} (96%) rename patches/server/{0063-Implement-configurable-search-radius-for-villagers-t.patch => 0062-Implement-configurable-search-radius-for-villagers-t.patch} (96%) rename patches/server/{0064-Implement-infinite-lava.patch => 0063-Implement-infinite-lava.patch} (97%) rename patches/server/{0065-Make-lava-flow-speed-configurable.patch => 0064-Make-lava-flow-speed-configurable.patch} (100%) rename patches/server/{0066-Add-player-death-exp-control-options.patch => 0065-Add-player-death-exp-control-options.patch} (97%) rename patches/server/{0067-Configurable-void-damage-height-and-damage.patch => 0066-Configurable-void-damage-height-and-damage.patch} (92%) rename patches/server/{0068-Add-canSaveToDisk-to-Entity.patch => 0067-Add-canSaveToDisk-to-Entity.patch} (93%) rename patches/server/{0069-Dispenser-curse-of-binding-protection.patch => 0068-Dispenser-curse-of-binding-protection.patch} (97%) rename patches/server/{0070-Add-option-for-boats-to-eject-players-on-land.patch => 0069-Add-option-for-boats-to-eject-players-on-land.patch} (95%) rename patches/server/{0071-Mending-mends-most-damages-equipment-first.patch => 0070-Mending-mends-most-damages-equipment-first.patch} (100%) rename patches/server/{0072-Add-5-second-tps-average-in-tps.patch => 0071-Add-5-second-tps-average-in-tps.patch} (93%) rename patches/server/{0073-Implement-elytra-settings.patch => 0072-Implement-elytra-settings.patch} (97%) rename patches/server/{0074-Item-entity-immunities.patch => 0073-Item-entity-immunities.patch} (95%) rename patches/server/{0075-Add-ping-command.patch => 0074-Add-ping-command.patch} (95%) rename patches/server/{0076-Add-demo-command.patch => 0075-Add-demo-command.patch} (95%) rename patches/server/{0077-Add-credits-command.patch => 0076-Add-credits-command.patch} (95%) rename patches/server/{0078-Configurable-jockey-options.patch => 0077-Configurable-jockey-options.patch} (100%) rename patches/server/{0079-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch => 0078-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch} (100%) rename patches/server/{0080-Add-phantom-spawning-options.patch => 0079-Add-phantom-spawning-options.patch} (100%) rename patches/server/{0081-Implement-bed-explosion-options.patch => 0080-Implement-bed-explosion-options.patch} (97%) rename patches/server/{0082-Implement-respawn-anchor-explosion-options.patch => 0081-Implement-respawn-anchor-explosion-options.patch} (100%) rename patches/server/{0083-Add-allow-water-in-end-world-option.patch => 0082-Add-allow-water-in-end-world-option.patch} (91%) rename patches/server/{0084-Allow-color-codes-in-books.patch => 0083-Allow-color-codes-in-books.patch} (97%) rename patches/server/{0085-Entity-lifespan.patch => 0084-Entity-lifespan.patch} (95%) rename patches/server/{0086-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch => 0085-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch} (94%) rename patches/server/{0087-Squid-EAR-immunity.patch => 0086-Squid-EAR-immunity.patch} (93%) rename patches/server/{0088-Configurable-feature-seed-settings.patch => 0087-Configurable-feature-seed-settings.patch} (99%) rename patches/server/{0089-Phantoms-burn-in-light.patch => 0088-Phantoms-burn-in-light.patch} (100%) rename patches/server/{0090-Configurable-villager-breeding.patch => 0089-Configurable-villager-breeding.patch} (95%) rename patches/server/{0091-Redstone-deactivates-spawners.patch => 0090-Redstone-deactivates-spawners.patch} (100%) rename patches/server/{0092-Totems-work-in-inventory.patch => 0091-Totems-work-in-inventory.patch} (96%) rename patches/server/{0093-Add-vindicator-johnny-spawn-chance.patch => 0092-Add-vindicator-johnny-spawn-chance.patch} (100%) rename patches/server/{0094-Add-option-to-disable-certain-block-updates.patch => 0093-Add-option-to-disable-certain-block-updates.patch} (99%) rename patches/server/{0095-Dispensers-place-anvils-option.patch => 0094-Dispensers-place-anvils-option.patch} (100%) rename patches/server/{0096-Allow-anvil-colors.patch => 0095-Allow-anvil-colors.patch} (96%) rename patches/server/{0097-Add-no-random-tick-block-list.patch => 0096-Add-no-random-tick-block-list.patch} (95%) rename patches/server/{0098-Add-option-to-disable-dolphin-treasure-searching.patch => 0097-Add-option-to-disable-dolphin-treasure-searching.patch} (100%) rename patches/server/{0099-Short-enderman-height.patch => 0098-Short-enderman-height.patch} (97%) rename patches/server/{0100-Stop-squids-floating-on-top-of-water.patch => 0099-Stop-squids-floating-on-top-of-water.patch} (93%) rename patches/server/{0101-Use-configured-height-for-nether-surface-builders.patch => 0100-Use-configured-height-for-nether-surface-builders.patch} (100%) rename patches/server/{0102-Crying-obsidian-valid-for-portal-frames.patch => 0101-Crying-obsidian-valid-for-portal-frames.patch} (96%) rename patches/server/{0103-Entities-can-use-portals-configuration.patch => 0102-Entities-can-use-portals-configuration.patch} (92%) rename patches/server/{0104-LivingEntity-broadcastItemBreak.patch => 0103-LivingEntity-broadcastItemBreak.patch} (85%) rename patches/server/{0105-Customizable-wither-health-and-healing.patch => 0104-Customizable-wither-health-and-healing.patch} (100%) rename patches/server/{0106-Allow-toggling-special-MobSpawners-per-world.patch => 0105-Allow-toggling-special-MobSpawners-per-world.patch} (97%) rename patches/server/{0107-Raid-cooldown-setting.patch => 0106-Raid-cooldown-setting.patch} (100%) rename patches/server/{0108-Despawn-rate-config-options-per-projectile-type.patch => 0107-Despawn-rate-config-options-per-projectile-type.patch} (100%) rename patches/server/{0109-Add-option-to-disable-zombie-aggressiveness-towards-.patch => 0108-Add-option-to-disable-zombie-aggressiveness-towards-.patch} (100%) rename patches/server/{0110-Persistent-TileEntity-Lore-and-DisplayName.patch => 0109-Persistent-TileEntity-Lore-and-DisplayName.patch} (98%) rename patches/server/{0111-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch => 0110-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch} (100%) rename patches/server/{0112-Flying-squids-Oh-my.patch => 0111-Flying-squids-Oh-my.patch} (100%) rename patches/server/{0113-Infinity-bow-settings.patch => 0112-Infinity-bow-settings.patch} (97%) rename patches/server/{0114-Stonecutter-damage.patch => 0113-Stonecutter-damage.patch} (96%) rename patches/server/{0115-Configurable-daylight-cycle.patch => 0114-Configurable-daylight-cycle.patch} (94%) rename patches/server/{0116-Allow-infinite-and-mending-enchantments-together.patch => 0115-Allow-infinite-and-mending-enchantments-together.patch} (95%) rename patches/server/{0117-Furnace-uses-lava-from-underneath.patch => 0116-Furnace-uses-lava-from-underneath.patch} (100%) rename patches/server/{0118-Arrows-should-not-reset-despawn-counter.patch => 0117-Arrows-should-not-reset-despawn-counter.patch} (100%) rename patches/server/{0119-Ability-to-re-add-farmland-mechanics-from-Alpha.patch => 0118-Ability-to-re-add-farmland-mechanics-from-Alpha.patch} (95%) rename patches/server/{0120-Add-adjustable-breeding-cooldown-to-config.patch => 0119-Add-adjustable-breeding-cooldown-to-config.patch} (94%) rename patches/server/{0121-Make-entity-breeding-times-configurable.patch => 0120-Make-entity-breeding-times-configurable.patch} (100%) rename patches/server/{0122-Apply-display-names-from-item-forms-of-entities-to-e.patch => 0121-Apply-display-names-from-item-forms-of-entities-to-e.patch} (97%) rename patches/server/{0123-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch => 0122-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch} (95%) rename patches/server/{0124-Add-twisting-and-weeping-vines-growth-rates.patch => 0123-Add-twisting-and-weeping-vines-growth-rates.patch} (100%) rename patches/server/{0125-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch => 0124-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch} (100%) rename patches/server/{0126-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch => 0125-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch} (100%) rename patches/server/{0127-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch => 0126-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch} (97%) rename patches/server/{0128-Add-configurable-snowball-damage.patch => 0127-Add-configurable-snowball-damage.patch} (100%) rename patches/server/{0129-Zombie-break-door-minimum-difficulty-option.patch => 0128-Zombie-break-door-minimum-difficulty-option.patch} (100%) rename patches/server/{0130-Left-handed-API.patch => 0129-Left-handed-API.patch} (83%) rename patches/server/{0131-Changeable-Mob-Left-Handed-Chance.patch => 0130-Changeable-Mob-Left-Handed-Chance.patch} (90%) rename patches/server/{0132-Add-boat-fall-damage-config.patch => 0131-Add-boat-fall-damage-config.patch} (97%) rename patches/server/{0133-Snow-Golem-rate-of-fire-config.patch => 0132-Snow-Golem-rate-of-fire-config.patch} (100%) rename patches/server/{0134-EMC-Configurable-disable-give-dropping.patch => 0133-EMC-Configurable-disable-give-dropping.patch} (95%) rename patches/server/{0135-Lobotomize-stuck-villagers.patch => 0134-Lobotomize-stuck-villagers.patch} (97%) rename patches/server/{0136-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch => 0135-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch} (99%) rename patches/server/{0137-Toggle-for-Zombified-Piglin-death-always-counting-as.patch => 0136-Toggle-for-Zombified-Piglin-death-always-counting-as.patch} (100%) rename patches/server/{0138-Spread-out-and-optimise-player-list-ticksSpread-out-.patch => 0137-Spread-out-and-optimise-player-list-ticksSpread-out-.patch} (91%) rename patches/server/{0139-Configurable-chance-for-wolves-to-spawn-rabid.patch => 0138-Configurable-chance-for-wolves-to-spawn-rabid.patch} (100%) rename patches/server/{0140-Configurable-default-wolf-collar-color.patch => 0139-Configurable-default-wolf-collar-color.patch} (100%) rename patches/server/{0141-Phantom-flames-on-swoop.patch => 0140-Phantom-flames-on-swoop.patch} (100%) rename patches/server/{0142-Option-for-chests-to-open-even-with-a-solid-block-on.patch => 0141-Option-for-chests-to-open-even-with-a-solid-block-on.patch} (100%) rename patches/server/{0143-Implement-TPSBar.patch => 0142-Implement-TPSBar.patch} (95%) rename patches/server/{0144-Striders-give-saddle-back.patch => 0143-Striders-give-saddle-back.patch} (100%) rename patches/server/{0145-PlayerBookTooLargeEvent.patch => 0144-PlayerBookTooLargeEvent.patch} (96%) rename patches/server/{0146-Full-netherite-armor-grants-fire-resistance.patch => 0145-Full-netherite-armor-grants-fire-resistance.patch} (94%) rename patches/server/{0147-Fix-rotating-UP-DOWN-CW-and-CCW.patch => 0146-Fix-rotating-UP-DOWN-CW-and-CCW.patch} (100%) rename patches/server/{0148-Add-MC-4-fix-back.patch => 0147-Add-MC-4-fix-back.patch} (78%) rename patches/server/{0149-Add-mobGriefing-bypass-to-everything-affected.patch => 0148-Add-mobGriefing-bypass-to-everything-affected.patch} (99%) rename patches/server/{0150-Config-to-allow-Note-Block-sounds-when-blocked.patch => 0149-Config-to-allow-Note-Block-sounds-when-blocked.patch} (100%) rename patches/server/{0151-Add-EntityTeleportHinderedEvent.patch => 0150-Add-EntityTeleportHinderedEvent.patch} (98%) rename patches/server/{0152-Add-StructureGenerateEvent.patch => 0151-Add-StructureGenerateEvent.patch} (92%) rename patches/server/{0153-Farmland-trampling-changes.patch => 0152-Farmland-trampling-changes.patch} (97%) rename patches/server/{0154-Movement-options-for-armor-stands.patch => 0153-Movement-options-for-armor-stands.patch} (94%) rename patches/server/{0155-Fix-stuck-in-portals.patch => 0154-Fix-stuck-in-portals.patch} (92%) rename patches/server/{0156-Toggle-for-water-sensitive-mob-damage.patch => 0155-Toggle-for-water-sensitive-mob-damage.patch} (98%) rename patches/server/{0157-Config-to-always-tame-in-Creative.patch => 0156-Config-to-always-tame-in-Creative.patch} (100%) rename patches/server/{0158-End-crystal-explosion-options.patch => 0157-End-crystal-explosion-options.patch} (100%) rename patches/server/{0159-Add-unsafe-Entity-serialization-API.patch => 0158-Add-unsafe-Entity-serialization-API.patch} (97%) rename patches/server/{0160-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch => 0159-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch} (100%) rename patches/server/{0161-Dont-run-with-scissors.patch => 0160-Dont-run-with-scissors.patch} (93%) rename patches/server/{0162-One-Punch-Man.patch => 0161-One-Punch-Man.patch} (96%) rename patches/server/{0163-Add-config-for-snow-on-blue-ice.patch => 0162-Add-config-for-snow-on-blue-ice.patch} (100%) rename patches/server/{0164-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch => 0163-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch} (98%) rename patches/server/{0165-Config-to-ignore-nearby-mobs-when-sleeping.patch => 0164-Config-to-ignore-nearby-mobs-when-sleeping.patch} (96%) rename patches/server/{0166-Add-back-player-spawned-endermite-API.patch => 0165-Add-back-player-spawned-endermite-API.patch} (100%) rename patches/server/{0167-Config-Enderman-aggressiveness-towards-Endermites.patch => 0166-Config-Enderman-aggressiveness-towards-Endermites.patch} (100%) rename patches/server/{0168-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch => 0167-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch} (100%) rename patches/server/{0169-Tick-fluids-config.patch => 0168-Tick-fluids-config.patch} (100%) rename patches/server/{0170-Config-to-disable-Llama-caravans.patch => 0169-Config-to-disable-Llama-caravans.patch} (100%) rename patches/server/{0171-Config-to-make-Creepers-explode-on-death.patch => 0170-Config-to-make-Creepers-explode-on-death.patch} (100%) rename patches/server/{0172-Configurable-ravager-griefable-blocks-list.patch => 0171-Configurable-ravager-griefable-blocks-list.patch} (100%) rename patches/server/{0173-Sneak-to-bulk-process-composter.patch => 0172-Sneak-to-bulk-process-composter.patch} (98%) rename patches/server/{0174-Config-for-skipping-night.patch => 0173-Config-for-skipping-night.patch} (96%) rename patches/server/{0175-Add-config-for-villager-trading.patch => 0174-Add-config-for-villager-trading.patch} (97%) rename patches/server/{0176-Allow-infinity-on-crossbows.patch => 0175-Allow-infinity-on-crossbows.patch} (98%) rename patches/server/{0177-Drowning-Settings.patch => 0176-Drowning-Settings.patch} (89%) rename patches/server/{0178-Break-individual-slabs-when-sneaking.patch => 0177-Break-individual-slabs-when-sneaking.patch} (97%) rename patches/server/{0179-Config-to-disable-hostile-mob-spawn-on-ice.patch => 0178-Config-to-disable-hostile-mob-spawn-on-ice.patch} (100%) rename patches/server/{0180-Config-to-show-Armor-Stand-arms-on-spawn.patch => 0179-Config-to-show-Armor-Stand-arms-on-spawn.patch} (96%) rename patches/server/{0181-Option-to-make-doors-require-redstone.patch => 0180-Option-to-make-doors-require-redstone.patch} (100%) rename patches/server/{0182-Config-to-allow-for-unsafe-enchants.patch => 0181-Config-to-allow-for-unsafe-enchants.patch} (93%) rename patches/server/{0183-Configurable-sponge-absorption.patch => 0182-Configurable-sponge-absorption.patch} (100%) rename patches/server/{0184-Projectile-offset-config.patch => 0183-Projectile-offset-config.patch} (100%) rename patches/server/{0185-Config-for-powered-rail-activation-distance.patch => 0184-Config-for-powered-rail-activation-distance.patch} (100%) rename patches/server/{0186-Piglin-portal-spawn-modifier.patch => 0185-Piglin-portal-spawn-modifier.patch} (100%) rename patches/server/{0187-Config-to-change-max-number-of-bees.patch => 0186-Config-to-change-max-number-of-bees.patch} (96%) rename patches/server/{0188-Configurable-damage-settings-for-magma-blocks.patch => 0187-Configurable-damage-settings-for-magma-blocks.patch} (95%) rename patches/server/{0189-Config-for-wither-explosion-radius.patch => 0188-Config-for-wither-explosion-radius.patch} (100%) rename patches/server/{0190-Gamemode-extra-permissions.patch => 0189-Gamemode-extra-permissions.patch} (96%) rename patches/server/{0191-Config-for-changing-the-blocks-that-turn-into-dirt-p.patch => 0190-Config-for-changing-the-blocks-that-turn-into-dirt-p.patch} (100%) rename patches/server/{0192-Configurable-piston-push-limit.patch => 0191-Configurable-piston-push-limit.patch} (100%) rename patches/server/{0193-Configurable-broadcast-settings.patch => 0192-Configurable-broadcast-settings.patch} (94%) rename patches/server/{0194-Fix-SPIGOT-6278.patch => 0193-Fix-SPIGOT-6278.patch} (100%) rename patches/server/{0195-Configurable-mob-blindness.patch => 0194-Configurable-mob-blindness.patch} (96%) rename patches/server/{0196-Hide-hidden-players-from-entity-selector.patch => 0195-Hide-hidden-players-from-entity-selector.patch} (98%) rename patches/server/{0197-Config-for-health-to-impact-Creeper-explosion-radius.patch => 0196-Config-for-health-to-impact-Creeper-explosion-radius.patch} (100%) rename patches/server/{0198-Iron-golem-poppy-calms-anger.patch => 0197-Iron-golem-poppy-calms-anger.patch} (100%) rename patches/server/{0199-Breedable-parrots.patch => 0198-Breedable-parrots.patch} (100%) rename patches/server/{0200-Configurable-powered-rail-boost-modifier.patch => 0199-Configurable-powered-rail-boost-modifier.patch} (96%) rename patches/server/{0201-Add-config-change-multiplier-critical-damage-value.patch => 0200-Add-config-change-multiplier-critical-damage-value.patch} (95%) rename patches/server/{0202-Option-to-disable-dragon-egg-teleporting.patch => 0201-Option-to-disable-dragon-egg-teleporting.patch} (100%) rename patches/server/{0203-Config-for-unverified-username-message.patch => 0202-Config-for-unverified-username-message.patch} (94%) rename patches/server/{0204-Make-anvil-cumulative-cost-configurable.patch => 0203-Make-anvil-cumulative-cost-configurable.patch} (88%) rename patches/server/{0205-ShulkerBox-allow-oversized-stacks.patch => 0204-ShulkerBox-allow-oversized-stacks.patch} (97%) rename patches/server/{0206-Bee-can-work-when-raining-or-at-night.patch => 0205-Bee-can-work-when-raining-or-at-night.patch} (100%) rename patches/server/{0207-API-for-any-mob-to-burn-daylight.patch => 0206-API-for-any-mob-to-burn-daylight.patch} (96%) rename patches/server/{0208-Fix-advancement-triggers-on-entity-death.patch => 0207-Fix-advancement-triggers-on-entity-death.patch} (96%) rename patches/server/{0209-Config-MobEffect-by-world.patch => 0208-Config-MobEffect-by-world.patch} (98%) rename patches/server/{0210-Beacon-Activation-Range-Configurable.patch => 0209-Beacon-Activation-Range-Configurable.patch} (100%) rename patches/server/{0211-Add-toggle-for-sand-duping-fix.patch => 0210-Add-toggle-for-sand-duping-fix.patch} (100%) rename patches/server/{0212-Add-toggle-for-end-portal-safe-teleporting.patch => 0211-Add-toggle-for-end-portal-safe-teleporting.patch} (95%) rename patches/server/{0213-Flying-Fall-Damage-API.patch => 0212-Flying-Fall-Damage-API.patch} (91%) rename patches/server/{0214-Make-lightning-rod-range-configurable.patch => 0213-Make-lightning-rod-range-configurable.patch} (92%) rename patches/server/{0215-Burp-after-eating-food-fills-hunger-bar-completely.patch => 0214-Burp-after-eating-food-fills-hunger-bar-completely.patch} (97%) rename patches/server/{0216-Allow-player-join-full-server-by-permission.patch => 0215-Allow-player-join-full-server-by-permission.patch} (89%) rename patches/server/{0217-Populator-seed-controls.patch => 0216-Populator-seed-controls.patch} (100%) rename patches/server/{0218-Add-permission-bypass-for-portal-waiting.patch => 0217-Add-permission-bypass-for-portal-waiting.patch} (94%) rename patches/server/{0219-Shulker-spawn-from-bullet-options.patch => 0218-Shulker-spawn-from-bullet-options.patch} (100%) rename patches/server/{0220-Eating-glow-berries-adds-glow-effect.patch => 0219-Eating-glow-berries-adds-glow-effect.patch} (97%) rename patches/server/{0221-Option-to-make-drowned-break-doors.patch => 0220-Option-to-make-drowned-break-doors.patch} (100%) rename patches/server/{0222-Configurable-hunger-starvation-damage.patch => 0221-Configurable-hunger-starvation-damage.patch} (100%) rename patches/server/{0223-Redirect-System.out-calls-to-plugin-loggers.patch => 0222-Redirect-System.out-calls-to-plugin-loggers.patch} (95%) rename patches/server/{0224-Armor-click-equip-options.patch => 0223-Armor-click-equip-options.patch} (98%) rename patches/server/{0225-Add-uptime-command.patch => 0224-Add-uptime-command.patch} (95%) rename patches/server/{0226-Structure-seed-options.patch => 0225-Structure-seed-options.patch} (92%) rename patches/server/{0227-Tool-actionable-options.patch => 0226-Tool-actionable-options.patch} (100%) rename patches/server/{0228-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch => 0227-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch} (89%) rename patches/server/{0229-Store-placer-on-Block-when-placed.patch => 0228-Store-placer-on-Block-when-placed.patch} (94%) rename patches/server/{0230-Summoner-API.patch => 0229-Summoner-API.patch} (100%) rename patches/server/{0231-Customizable-sleeping-actionbar-messages.patch => 0230-Customizable-sleeping-actionbar-messages.patch} (95%) rename patches/server/{0232-option-to-disable-shulker-box-items-from-dropping-co.patch => 0231-option-to-disable-shulker-box-items-from-dropping-co.patch} (96%) rename patches/server/{0233-Silk-touchable-budding-amethyst.patch => 0232-Silk-touchable-budding-amethyst.patch} (100%) rename patches/server/{0234-Big-dripleaf-tilt-delay.patch => 0233-Big-dripleaf-tilt-delay.patch} (100%) rename patches/server/{0235-Player-ridable-in-water-option.patch => 0234-Player-ridable-in-water-option.patch} (96%) rename patches/server/{0236-Config-to-disable-Enderman-teleport-on-projectile-hi.patch => 0235-Config-to-disable-Enderman-teleport-on-projectile-hi.patch} (100%) rename patches/server/{0237-Fix-Important-Issue-Crash-with-Plugin-or-Datapack-Ge.patch => 0236-Fix-Important-Issue-Crash-with-Plugin-or-Datapack-Ge.patch} (100%) rename patches/server/{0238-Add-compass-command.patch => 0237-Add-compass-command.patch} (96%) rename patches/server/{0239-Config-to-prevent-horses-from-standing-with-riders.patch => 0238-Config-to-prevent-horses-from-standing-with-riders.patch} (100%) rename patches/server/{0240-Toggle-for-kinetic-damage.patch => 0239-Toggle-for-kinetic-damage.patch} (92%) rename patches/server/{0241-Add-Option-for-disable-observer-clocks.patch => 0240-Add-Option-for-disable-observer-clocks.patch} (95%) rename patches/server/{0242-Customizeable-Zombie-Villager-curing-times.patch => 0241-Customizeable-Zombie-Villager-curing-times.patch} (100%) rename patches/server/{0243-Option-for-sponges-to-work-on-lava.patch => 0242-Option-for-sponges-to-work-on-lava.patch} (100%) rename patches/server/{0244-Toggle-for-Wither-s-spawn-sound.patch => 0243-Toggle-for-Wither-s-spawn-sound.patch} (100%) rename patches/server/{0245-Cactus-breaks-from-solid-neighbors-config.patch => 0244-Cactus-breaks-from-solid-neighbors-config.patch} (100%) rename patches/server/{0246-Config-to-remove-curse-of-binding-with-weakness.patch => 0245-Config-to-remove-curse-of-binding-with-weakness.patch} (100%) rename patches/server/{0247-Conduit-behavior-configuration.patch => 0246-Conduit-behavior-configuration.patch} (100%) rename patches/server/{0248-Cauldron-fill-chances.patch => 0247-Cauldron-fill-chances.patch} (100%) rename patches/server/{0249-Config-to-allow-mobs-to-pathfind-over-rails.patch => 0248-Config-to-allow-mobs-to-pathfind-over-rails.patch} (100%) rename patches/server/{0250-Add-force-and-prompt-parameters-to-resource-pack-api.patch => 0249-Add-force-and-prompt-parameters-to-resource-pack-api.patch} (95%) rename patches/server/{0251-Shulker-change-color-with-dye.patch => 0250-Shulker-change-color-with-dye.patch} (100%) rename patches/server/{0252-Extended-OfflinePlayer-API.patch => 0251-Extended-OfflinePlayer-API.patch} (99%) rename patches/server/{0254-Added-the-ability-to-add-combustible-items.patch => 0252-Added-the-ability-to-add-combustible-items.patch} (90%) delete mode 100644 patches/server/0253-Fix-sinking-boats.patch rename patches/server/{0255-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch => 0253-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch} (97%) rename patches/server/{0256-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch => 0254-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch} (100%) rename patches/server/{0257-Shift-right-click-to-use-exp-for-mending.patch => 0255-Shift-right-click-to-use-exp-for-mending.patch} (96%) diff --git a/build.gradle.kts b/build.gradle.kts index 83da0a285..5362d9141 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { java id("com.github.johnrengelman.shadow") version "7.0.0" apply false - id("io.papermc.paperweight.patcher") version "1.1.9" + id("io.papermc.paperweight.patcher") version "1.1.11" } repositories { @@ -11,15 +11,10 @@ repositories { onlyForConfigurations("paperclip") } } - maven("https://maven.quiltmc.org/repository/release/") { - content { - onlyForConfigurations("remapper") - } - } } dependencies { - remapper("org.quiltmc:tiny-remapper:0.4.1") + remapper("org.quiltmc:tiny-remapper:0.4.3:fat") paperclip("io.papermc:paperclip:2.0.1") } @@ -67,6 +62,9 @@ paperweight { apiPatchDir.set(layout.projectDirectory.dir("patches/api")) apiOutputDir.set(layout.projectDirectory.dir("Purpur-API")) + remapRepo.set("https://maven.quiltmc.org/repository/release/") + decompileRepo.set("https://files.minecraftforge.net/maven/") + serverPatchDir.set(layout.projectDirectory.dir("patches/server")) serverOutputDir.set(layout.projectDirectory.dir("Purpur-Server")) } diff --git a/gradle.properties b/gradle.properties index 0e03be3a6..e7340c21f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ version = 1.17.1-R0.1-SNAPSHOT mcVersion = 1.17.1 packageVersion = 1_17_R1 -paperCommit = 565cd3306ccd13f4d787344623aad5ba0b9e2f04 +paperCommit = e8f787219d8c3d98256cc7af2a40584463651a87 org.gradle.caching = true org.gradle.parallel = true diff --git a/patches/api/0002-Airplane-API-Changes.patch b/patches/api/0001-Airplane-API-Changes.patch similarity index 100% rename from patches/api/0002-Airplane-API-Changes.patch rename to patches/api/0001-Airplane-API-Changes.patch diff --git a/patches/api/0001-Tuinity-API-Changes.patch b/patches/api/0001-Tuinity-API-Changes.patch deleted file mode 100644 index 1a2e43c41..000000000 --- a/patches/api/0001-Tuinity-API-Changes.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 21 Mar 2020 20:12:48 -0700 -Subject: [PATCH] Tuinity API Changes - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 83870d54a5ff1017ad7455e9c931fdee54354434..d6607c1cc3b976367f0087810de698281d4733ab 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1679,6 +1679,14 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - } - // Paper end - -+ // Tuinity start - add config to timings report -+ @NotNull -+ public org.bukkit.configuration.file.YamlConfiguration getTuinityConfig() -+ { -+ throw new UnsupportedOperationException("Not supported yet."); -+ } -+ // Tuinity end - add config to timings report -+ - /** - * Sends the component to the player - * -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 953d3470811d5877bd8a9653343f4c38770b266f..6d5c60a7def6926421df09214e9a9053a321bc00 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -3706,6 +3706,26 @@ public interface World extends PluginMessageRecipient, Metadatable, net.kyori.ad - * @param viewDistance view distance in [2, 32] - */ - void setNoTickViewDistance(int viewDistance); -+ -+ // Tuinity start - add view distances -+ /** -+ * Gets the sending view distance for this world. -+ *

-+ * Sending view distance is the view distance where chunks will load in for players in this world. -+ *

-+ * @return The sending view distance for this world. -+ */ -+ public int getSendViewDistance(); -+ -+ /** -+ * Sets the sending view distance for this world. -+ *

-+ * Sending view distance is the view distance where chunks will load in for players in this world. -+ *

-+ * @param viewDistance view distance in [2, 32] or -1 -+ */ -+ public void setSendViewDistance(int viewDistance); -+ // Tuinity end - add view distances - // Paper end - view distance api - - // Spigot start -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 3ec1be36b90dbedb8631135555da4b69110e4791..c87cb640dc829a266e85e97a2e3bb2f0f52a2eaa 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1887,23 +1887,63 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * Gets the view distance for this player - * - * @return the player's view distance -- * @deprecated This is unimplemented and will throw an exception at runtime. The {@link org.bukkit.World World}-based methods still work. -+ * // Tuinity - implemented - * @see org.bukkit.World#getViewDistance() - * @see org.bukkit.World#getNoTickViewDistance() - */ -- @Deprecated -+ //@Deprecated // Tuinity - implemented - public int getViewDistance(); - - /** - * Sets the view distance for this player - * - * @param viewDistance the player's view distance -- * @deprecated This is unimplemented and will throw an exception at runtime. The {@link org.bukkit.World World}-based methods still work. -+ * // Tuinity - implemented - * @see org.bukkit.World#setViewDistance(int) - * @see org.bukkit.World#setNoTickViewDistance(int) - */ -- @Deprecated -+ //@Deprecated // Tuinity - implemented - public void setViewDistance(int viewDistance); -+ -+ // Tuinity start - add view distances api -+ /** -+ * Gets the no-ticking view distance for this player. -+ *

-+ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not -+ * be set to tick. -+ *

-+ * @return The no-tick view distance for this player. -+ */ -+ public int getNoTickViewDistance(); -+ -+ /** -+ * Sets the no-ticking view distance for this player. -+ *

-+ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not -+ * be set to tick. -+ *

-+ * @param viewDistance view distance in [2, 32] or -1 -+ */ -+ public void setNoTickViewDistance(int viewDistance); -+ -+ /** -+ * Gets the sending view distance for this player. -+ *

-+ * Sending view distance is the view distance where chunks will load in for players. -+ *

-+ * @return The sending view distance for this player. -+ */ -+ public int getSendViewDistance(); -+ -+ /** -+ * Sets the sending view distance for this player. -+ *

-+ * Sending view distance is the view distance where chunks will load in for players. -+ *

-+ * @param viewDistance view distance in [2, 32] or -1 -+ */ -+ public void setSendViewDistance(int viewDistance); -+ // Tuinity end - add view distances api - // Paper end - - /** diff --git a/patches/api/0003-Build-System-Changes.patch b/patches/api/0002-Build-System-Changes.patch similarity index 100% rename from patches/api/0003-Build-System-Changes.patch rename to patches/api/0002-Build-System-Changes.patch diff --git a/patches/api/0004-Purpur-config-files.patch b/patches/api/0003-Purpur-config-files.patch similarity index 80% rename from patches/api/0004-Purpur-config-files.patch rename to patches/api/0003-Purpur-config-files.patch index 5ecb38276..94ede091a 100644 --- a/patches/api/0004-Purpur-config-files.patch +++ b/patches/api/0003-Purpur-config-files.patch @@ -5,12 +5,12 @@ Subject: [PATCH] Purpur config files diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index d6607c1cc3b976367f0087810de698281d4733ab..6aa18a3ff909b1b24082b5fe4f71d82d67a2354a 100644 +index 83870d54a5ff1017ad7455e9c931fdee54354434..7347636e2845f7723706ab280c2a788302c67854 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1687,6 +1687,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -1679,6 +1679,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi } - // Tuinity end - add config to timings report + // Paper end + // Purpur start + @NotNull diff --git a/patches/api/0005-Purpur-client-support.patch b/patches/api/0004-Purpur-client-support.patch similarity index 89% rename from patches/api/0005-Purpur-client-support.patch rename to patches/api/0004-Purpur-client-support.patch index 27ce8e6d1..2476bb46e 100644 --- a/patches/api/0005-Purpur-client-support.patch +++ b/patches/api/0004-Purpur-client-support.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Purpur client support diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index c87cb640dc829a266e85e97a2e3bb2f0f52a2eaa..fa4147d4dc36e7f442587428c66e2378511ea6b0 100644 +index 5084ef3cb0884fb5c170859bc7be57a9fcba0a3c..ef68c7ee481eb7f50f2561a211b4add801e5e8dd 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -2299,4 +2299,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/patches/api/0006-Default-permissions.patch b/patches/api/0005-Default-permissions.patch similarity index 100% rename from patches/api/0006-Default-permissions.patch rename to patches/api/0005-Default-permissions.patch diff --git a/patches/api/0007-Ridables.patch b/patches/api/0006-Ridables.patch similarity index 100% rename from patches/api/0007-Ridables.patch rename to patches/api/0006-Ridables.patch diff --git a/patches/api/0008-Allow-inventory-resizing.patch b/patches/api/0007-Allow-inventory-resizing.patch similarity index 100% rename from patches/api/0008-Allow-inventory-resizing.patch rename to patches/api/0007-Allow-inventory-resizing.patch diff --git a/patches/api/0009-Advancement-API.patch b/patches/api/0008-Advancement-API.patch similarity index 100% rename from patches/api/0009-Advancement-API.patch rename to patches/api/0008-Advancement-API.patch diff --git a/patches/api/0010-Llama-API.patch b/patches/api/0009-Llama-API.patch similarity index 100% rename from patches/api/0010-Llama-API.patch rename to patches/api/0009-Llama-API.patch diff --git a/patches/api/0011-AFK-API.patch b/patches/api/0010-AFK-API.patch similarity index 96% rename from patches/api/0011-AFK-API.patch rename to patches/api/0010-AFK-API.patch index b51da3275..357aa2361 100644 --- a/patches/api/0011-AFK-API.patch +++ b/patches/api/0010-AFK-API.patch @@ -81,7 +81,7 @@ index 0000000000000000000000000000000000000000..0c8b3e5e4ba412624357ea5662a78862 + } +} diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index fa4147d4dc36e7f442587428c66e2378511ea6b0..841e7d45b8cefee0cc9fbca1977ea007f446d824 100644 +index ef68c7ee481eb7f50f2561a211b4add801e5e8dd..a894626a7900798812b2afc3712d04fa583ae31e 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -2307,5 +2307,24 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/patches/api/0012-Bring-back-server-name.patch b/patches/api/0011-Bring-back-server-name.patch similarity index 89% rename from patches/api/0012-Bring-back-server-name.patch rename to patches/api/0011-Bring-back-server-name.patch index 157a630ad..381907977 100644 --- a/patches/api/0012-Bring-back-server-name.patch +++ b/patches/api/0011-Bring-back-server-name.patch @@ -25,10 +25,10 @@ index d36e4bc3c3713407704b865574cba28662f17315..fc956758335734ac89e86e9c5fbbb6cc + // Purpur end } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 6aa18a3ff909b1b24082b5fe4f71d82d67a2354a..b1c470734a48e3895e805b49c74809d46a005664 100644 +index 7347636e2845f7723706ab280c2a788302c67854..6f809515d87d70cc824f7414fa48de07fec4f726 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1809,4 +1809,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -1801,4 +1801,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi @NotNull io.papermc.paper.datapack.DatapackManager getDatapackManager(); // Paper end diff --git a/patches/api/0013-ExecuteCommandEvent.patch b/patches/api/0012-ExecuteCommandEvent.patch similarity index 100% rename from patches/api/0013-ExecuteCommandEvent.patch rename to patches/api/0012-ExecuteCommandEvent.patch diff --git a/patches/api/0014-LivingEntity-safeFallDistance.patch b/patches/api/0013-LivingEntity-safeFallDistance.patch similarity index 100% rename from patches/api/0014-LivingEntity-safeFallDistance.patch rename to patches/api/0013-LivingEntity-safeFallDistance.patch diff --git a/patches/api/0015-Lagging-threshold.patch b/patches/api/0014-Lagging-threshold.patch similarity index 89% rename from patches/api/0015-Lagging-threshold.patch rename to patches/api/0014-Lagging-threshold.patch index 2e5a6e78f..c687e6371 100644 --- a/patches/api/0015-Lagging-threshold.patch +++ b/patches/api/0014-Lagging-threshold.patch @@ -24,10 +24,10 @@ index fc956758335734ac89e86e9c5fbbb6cc965d0e59..39490406f914a5082d9d4b3937d9df63 // Purpur end } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index b1c470734a48e3895e805b49c74809d46a005664..0b68d0bd03822ed90effc4e57d288973f3164f16 100644 +index 6f809515d87d70cc824f7414fa48de07fec4f726..573e0e4dc692952035221a5222ca106e12461310 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1817,5 +1817,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -1809,5 +1809,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull String getServerName(); diff --git a/patches/api/0016-ItemFactory-getMonsterEgg.patch b/patches/api/0015-ItemFactory-getMonsterEgg.patch similarity index 100% rename from patches/api/0016-ItemFactory-getMonsterEgg.patch rename to patches/api/0015-ItemFactory-getMonsterEgg.patch diff --git a/patches/api/0017-PlayerSetSpawnerTypeWithEggEvent.patch b/patches/api/0016-PlayerSetSpawnerTypeWithEggEvent.patch similarity index 100% rename from patches/api/0017-PlayerSetSpawnerTypeWithEggEvent.patch rename to patches/api/0016-PlayerSetSpawnerTypeWithEggEvent.patch diff --git a/patches/api/0018-EMC-MonsterEggSpawnEvent.patch b/patches/api/0017-EMC-MonsterEggSpawnEvent.patch similarity index 100% rename from patches/api/0018-EMC-MonsterEggSpawnEvent.patch rename to patches/api/0017-EMC-MonsterEggSpawnEvent.patch diff --git a/patches/api/0019-Villager-resetOffers.patch b/patches/api/0018-Villager-resetOffers.patch similarity index 100% rename from patches/api/0019-Villager-resetOffers.patch rename to patches/api/0018-Villager-resetOffers.patch diff --git a/patches/api/0020-Player-invulnerabilities.patch b/patches/api/0019-Player-invulnerabilities.patch similarity index 92% rename from patches/api/0020-Player-invulnerabilities.patch rename to patches/api/0019-Player-invulnerabilities.patch index e86bed51e..6c7da7f9f 100644 --- a/patches/api/0020-Player-invulnerabilities.patch +++ b/patches/api/0019-Player-invulnerabilities.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Player invulnerabilities diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 841e7d45b8cefee0cc9fbca1977ea007f446d824..b59a297a9eb21f0e7d70d9662fd7c0e0080ff3e1 100644 +index a894626a7900798812b2afc3712d04fa583ae31e..8e59e4e4bf3a9ca80332ddd7b6de5a93855c2d0c 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -2326,5 +2326,26 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/patches/api/0021-Anvil-API.patch b/patches/api/0020-Anvil-API.patch similarity index 100% rename from patches/api/0021-Anvil-API.patch rename to patches/api/0020-Anvil-API.patch diff --git a/patches/api/0022-ItemStack-convenience-methods.patch b/patches/api/0021-ItemStack-convenience-methods.patch similarity index 100% rename from patches/api/0022-ItemStack-convenience-methods.patch rename to patches/api/0021-ItemStack-convenience-methods.patch diff --git a/patches/api/0023-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/patches/api/0022-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch similarity index 100% rename from patches/api/0023-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch rename to patches/api/0022-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch diff --git a/patches/api/0024-ChatColor-conveniences.patch b/patches/api/0023-ChatColor-conveniences.patch similarity index 100% rename from patches/api/0024-ChatColor-conveniences.patch rename to patches/api/0023-ChatColor-conveniences.patch diff --git a/patches/api/0025-LivingEntity-broadcastItemBreak.patch b/patches/api/0024-LivingEntity-broadcastItemBreak.patch similarity index 100% rename from patches/api/0025-LivingEntity-broadcastItemBreak.patch rename to patches/api/0024-LivingEntity-broadcastItemBreak.patch diff --git a/patches/api/0026-Item-entity-immunities.patch b/patches/api/0025-Item-entity-immunities.patch similarity index 100% rename from patches/api/0026-Item-entity-immunities.patch rename to patches/api/0025-Item-entity-immunities.patch diff --git a/patches/api/0027-Spigot-Improve-output-of-plugins-command.patch b/patches/api/0026-Spigot-Improve-output-of-plugins-command.patch similarity index 100% rename from patches/api/0027-Spigot-Improve-output-of-plugins-command.patch rename to patches/api/0026-Spigot-Improve-output-of-plugins-command.patch diff --git a/patches/api/0028-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/api/0027-Add-option-to-disable-zombie-aggressiveness-towards-.patch similarity index 100% rename from patches/api/0028-Add-option-to-disable-zombie-aggressiveness-towards-.patch rename to patches/api/0027-Add-option-to-disable-zombie-aggressiveness-towards-.patch diff --git a/patches/api/0029-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch b/patches/api/0028-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch similarity index 100% rename from patches/api/0029-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch rename to patches/api/0028-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch diff --git a/patches/api/0030-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch b/patches/api/0029-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch similarity index 100% rename from patches/api/0030-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch rename to patches/api/0029-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch diff --git a/patches/api/0031-Left-handed-API.patch b/patches/api/0030-Left-handed-API.patch similarity index 100% rename from patches/api/0031-Left-handed-API.patch rename to patches/api/0030-Left-handed-API.patch diff --git a/patches/api/0032-Alphabetize-in-game-plugins-list.patch b/patches/api/0031-Alphabetize-in-game-plugins-list.patch similarity index 100% rename from patches/api/0032-Alphabetize-in-game-plugins-list.patch rename to patches/api/0031-Alphabetize-in-game-plugins-list.patch diff --git a/patches/api/0033-Rabid-Wolf-API.patch b/patches/api/0032-Rabid-Wolf-API.patch similarity index 100% rename from patches/api/0033-Rabid-Wolf-API.patch rename to patches/api/0032-Rabid-Wolf-API.patch diff --git a/patches/api/0034-Fix-javadoc-warnings-missing-param-and-return.patch b/patches/api/0033-Fix-javadoc-warnings-missing-param-and-return.patch similarity index 99% rename from patches/api/0034-Fix-javadoc-warnings-missing-param-and-return.patch rename to patches/api/0033-Fix-javadoc-warnings-missing-param-and-return.patch index 615a24aa5..47802f336 100644 --- a/patches/api/0034-Fix-javadoc-warnings-missing-param-and-return.patch +++ b/patches/api/0033-Fix-javadoc-warnings-missing-param-and-return.patch @@ -489,7 +489,7 @@ index 3afd5f5c0208a4ee93b5dbfc2aab2b9d2e8a7544..7838731e0e16bdccfb79e74ceb64148f /** diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 0b68d0bd03822ed90effc4e57d288973f3164f16..86141c856478c6b39f7ef52f590a68e564da1ba9 100644 +index 573e0e4dc692952035221a5222ca106e12461310..6962b1d13fc6fdda973ba12cb2bba5553ce5ae50 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -1652,6 +1652,9 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi @@ -566,10 +566,10 @@ index afb7b136b461202026290624836446cff9f9e45d..087579fdff09237409c9f80446e7a15a /** diff --git a/src/main/java/org/bukkit/WorldCreator.java b/src/main/java/org/bukkit/WorldCreator.java -index c0454d977119b28115b7698a2c4287f0f56efa55..445c1c13a85f7abb5fd319f9aeb05572bb1f63f6 100644 +index 14986911b4d0099ea2c91ab2196a771b7dee4c50..d1eed20ea3b27f0800a08b42b62aac401bfe7347 100644 --- a/src/main/java/org/bukkit/WorldCreator.java +++ b/src/main/java/org/bukkit/WorldCreator.java -@@ -71,6 +71,8 @@ public class WorldCreator { +@@ -73,6 +73,8 @@ public class WorldCreator { * * @param levelName LevelName of the world that will be created * @param worldKey NamespacedKey of the world that will be created @@ -578,7 +578,7 @@ index c0454d977119b28115b7698a2c4287f0f56efa55..445c1c13a85f7abb5fd319f9aeb05572 */ @NotNull public static WorldCreator ofNameAndKey(@NotNull String levelName, @NotNull NamespacedKey worldKey) { -@@ -82,6 +84,8 @@ public class WorldCreator { +@@ -84,6 +86,8 @@ public class WorldCreator { * LevelName will be the Key part of the NamespacedKey. * * @param worldKey NamespacedKey of the world that will be created @@ -949,7 +949,7 @@ index a6a7429ed2e1eefb2b12b7480ed74fcc3963a864..e8027e1d505dda6effbb1698550016e8 NORMAL(false), diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index b59a297a9eb21f0e7d70d9662fd7c0e0080ff3e1..89345f789bb6f5e87463f423c69f1fb8a350bfaa 100644 +index 8e59e4e4bf3a9ca80332ddd7b6de5a93855c2d0c..8fad3187f8b1fc099420eef905505cdbab4a9fb7 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -2121,6 +2121,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/patches/api/0035-PlayerBookTooLargeEvent.patch b/patches/api/0034-PlayerBookTooLargeEvent.patch similarity index 100% rename from patches/api/0035-PlayerBookTooLargeEvent.patch rename to patches/api/0034-PlayerBookTooLargeEvent.patch diff --git a/patches/api/0036-Full-netherite-armor-grants-fire-resistance.patch b/patches/api/0035-Full-netherite-armor-grants-fire-resistance.patch similarity index 100% rename from patches/api/0036-Full-netherite-armor-grants-fire-resistance.patch rename to patches/api/0035-Full-netherite-armor-grants-fire-resistance.patch diff --git a/patches/api/0037-Add-EntityTeleportHinderedEvent.patch b/patches/api/0036-Add-EntityTeleportHinderedEvent.patch similarity index 100% rename from patches/api/0037-Add-EntityTeleportHinderedEvent.patch rename to patches/api/0036-Add-EntityTeleportHinderedEvent.patch diff --git a/patches/api/0038-Add-StructureGenerateEvent.patch b/patches/api/0037-Add-StructureGenerateEvent.patch similarity index 100% rename from patches/api/0038-Add-StructureGenerateEvent.patch rename to patches/api/0037-Add-StructureGenerateEvent.patch diff --git a/patches/api/0039-Add-unsafe-Entity-serialization-API.patch b/patches/api/0038-Add-unsafe-Entity-serialization-API.patch similarity index 100% rename from patches/api/0039-Add-unsafe-Entity-serialization-API.patch rename to patches/api/0038-Add-unsafe-Entity-serialization-API.patch diff --git a/patches/api/0040-Conflict-on-change-for-adventure-deprecations.patch b/patches/api/0039-Conflict-on-change-for-adventure-deprecations.patch similarity index 98% rename from patches/api/0040-Conflict-on-change-for-adventure-deprecations.patch rename to patches/api/0039-Conflict-on-change-for-adventure-deprecations.patch index 9f21f6ca5..2247a84e7 100644 --- a/patches/api/0040-Conflict-on-change-for-adventure-deprecations.patch +++ b/patches/api/0039-Conflict-on-change-for-adventure-deprecations.patch @@ -72,7 +72,7 @@ index 39490406f914a5082d9d4b3937d9df63c222efa6..e4ec2a0c15a6ada5bef9671e427cd564 return server.getShutdownMessage(); } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 86141c856478c6b39f7ef52f590a68e564da1ba9..80c70522eecb08c0dbfadcdeb21c9cfac42d7902 100644 +index 6962b1d13fc6fdda973ba12cb2bba5553ce5ae50..6888deaba01cd2edb8a84ad0a1cdfc6feb132ab2 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -270,7 +270,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi @@ -170,7 +170,7 @@ index c8d37184d8e882a4084a1bfef85faa330588600b..46bae5c13ce2b973b114682f6a338981 /** diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 89345f789bb6f5e87463f423c69f1fb8a350bfaa..cce3d28121c89411e0acc4a8d45a624395a0ac85 100644 +index 8fad3187f8b1fc099420eef905505cdbab4a9fb7..2306f62a4631fc9969549caa728a95b737796bcb 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -75,7 +75,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM @@ -790,10 +790,10 @@ index 93089ce61d2e1888df13b7c9629a79cd6f5f767a..ea0480064068f34ea34d4b68ef12d0f8 /** diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java -index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0cac57945a7 100644 +index d5b39fb4fc16a342b5661e08df1506858168d20d..723eb266fe1f965d2f08c6f3e8c652d0a0e52d58 100644 --- a/src/main/java/org/bukkit/scoreboard/Team.java +++ b/src/main/java/org/bukkit/scoreboard/Team.java -@@ -110,7 +110,7 @@ public interface Team { +@@ -108,7 +108,7 @@ public interface Team { * @deprecated in favour of {@link #displayName()} */ @NotNull @@ -802,7 +802,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca String getDisplayName() throws IllegalStateException; /** -@@ -122,7 +122,7 @@ public interface Team { +@@ -120,7 +120,7 @@ public interface Team { * @throws IllegalStateException if this team has been unregistered * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} */ @@ -811,7 +811,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca void setDisplayName(@NotNull String displayName) throws IllegalStateException, IllegalArgumentException; /** -@@ -133,7 +133,7 @@ public interface Team { +@@ -131,7 +131,7 @@ public interface Team { * @deprecated in favour of {@link #prefix()} */ @NotNull @@ -820,7 +820,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca String getPrefix() throws IllegalStateException; /** -@@ -146,7 +146,7 @@ public interface Team { +@@ -144,7 +144,7 @@ public interface Team { * @throws IllegalStateException if this team has been unregistered * @deprecated in favour of {@link #prefix(net.kyori.adventure.text.Component)} */ @@ -829,7 +829,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca void setPrefix(@NotNull String prefix) throws IllegalStateException, IllegalArgumentException; /** -@@ -157,7 +157,7 @@ public interface Team { +@@ -155,7 +155,7 @@ public interface Team { * @deprecated in favour of {@link #suffix()} */ @NotNull @@ -838,7 +838,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca String getSuffix() throws IllegalStateException; /** -@@ -170,7 +170,7 @@ public interface Team { +@@ -168,7 +168,7 @@ public interface Team { * @throws IllegalStateException if this team has been unregistered * @deprecated in favour of {@link #suffix(net.kyori.adventure.text.Component)} */ @@ -847,7 +847,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca void setSuffix(@NotNull String suffix) throws IllegalStateException, IllegalArgumentException; /** -@@ -184,7 +184,7 @@ public interface Team { +@@ -182,7 +182,7 @@ public interface Team { * @deprecated in favour of {@link #color()} */ @NotNull @@ -856,7 +856,7 @@ index 30fce0df75494eb9b7409f08ea3d6ff894f7c79f..12789cd0ee7d6e29fa122f040e8ce0ca ChatColor getColor() throws IllegalStateException; /** -@@ -197,7 +197,7 @@ public interface Team { +@@ -195,7 +195,7 @@ public interface Team { * no color * @deprecated in favour of {@link #color(net.kyori.adventure.text.format.NamedTextColor)} */ diff --git a/patches/api/0041-Add-enchantment-target-for-bows-and-crossbows.patch b/patches/api/0040-Add-enchantment-target-for-bows-and-crossbows.patch similarity index 100% rename from patches/api/0041-Add-enchantment-target-for-bows-and-crossbows.patch rename to patches/api/0040-Add-enchantment-target-for-bows-and-crossbows.patch diff --git a/patches/api/0042-Iron-golem-poppy-calms-anger.patch b/patches/api/0041-Iron-golem-poppy-calms-anger.patch similarity index 100% rename from patches/api/0042-Iron-golem-poppy-calms-anger.patch rename to patches/api/0041-Iron-golem-poppy-calms-anger.patch diff --git a/patches/api/0043-API-for-any-mob-to-burn-daylight.patch b/patches/api/0042-API-for-any-mob-to-burn-daylight.patch similarity index 100% rename from patches/api/0043-API-for-any-mob-to-burn-daylight.patch rename to patches/api/0042-API-for-any-mob-to-burn-daylight.patch diff --git a/patches/api/0044-Flying-Fall-Damage-API.patch b/patches/api/0043-Flying-Fall-Damage-API.patch similarity index 92% rename from patches/api/0044-Flying-Fall-Damage-API.patch rename to patches/api/0043-Flying-Fall-Damage-API.patch index 3d82e72a8..cf19cbc20 100644 --- a/patches/api/0044-Flying-Fall-Damage-API.patch +++ b/patches/api/0043-Flying-Fall-Damage-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Flying Fall Damage API diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index cce3d28121c89411e0acc4a8d45a624395a0ac85..8748199736a288f602e4cf5fb5ac4a08278f38b9 100644 +index 2306f62a4631fc9969549caa728a95b737796bcb..fcc4c6851ef932ab2e84d8758e7618856b98fdcf 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -2352,5 +2352,19 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/patches/api/0045-Add-back-player-spawned-endermite-API.patch b/patches/api/0044-Add-back-player-spawned-endermite-API.patch similarity index 100% rename from patches/api/0045-Add-back-player-spawned-endermite-API.patch rename to patches/api/0044-Add-back-player-spawned-endermite-API.patch diff --git a/patches/api/0046-Fix-default-permission-system.patch b/patches/api/0045-Fix-default-permission-system.patch similarity index 100% rename from patches/api/0046-Fix-default-permission-system.patch rename to patches/api/0045-Fix-default-permission-system.patch diff --git a/patches/api/0047-Summoner-API.patch b/patches/api/0046-Summoner-API.patch similarity index 100% rename from patches/api/0047-Summoner-API.patch rename to patches/api/0046-Summoner-API.patch diff --git a/patches/api/0048-Clean-up-version-command-output-for-console.patch b/patches/api/0047-Clean-up-version-command-output-for-console.patch similarity index 100% rename from patches/api/0048-Clean-up-version-command-output-for-console.patch rename to patches/api/0047-Clean-up-version-command-output-for-console.patch diff --git a/patches/api/0049-Add-force-and-prompt-parameters-to-resource-pack-api.patch b/patches/api/0048-Add-force-and-prompt-parameters-to-resource-pack-api.patch similarity index 98% rename from patches/api/0049-Add-force-and-prompt-parameters-to-resource-pack-api.patch rename to patches/api/0048-Add-force-and-prompt-parameters-to-resource-pack-api.patch index d6170f7a4..8a7d8f85a 100644 --- a/patches/api/0049-Add-force-and-prompt-parameters-to-resource-pack-api.patch +++ b/patches/api/0048-Add-force-and-prompt-parameters-to-resource-pack-api.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add force and prompt parameters to resource pack api diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 8748199736a288f602e4cf5fb5ac4a08278f38b9..82112d408a8ce139d041bad6c9af9a5eb28777d0 100644 +index fcc4c6851ef932ab2e84d8758e7618856b98fdcf..91a2817c8a0874d3092de19837969e3867e88cbc 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -1490,6 +1490,88 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM diff --git a/patches/api/0050-Extended-OfflinePlayer-API.patch b/patches/api/0049-Extended-OfflinePlayer-API.patch similarity index 100% rename from patches/api/0050-Extended-OfflinePlayer-API.patch rename to patches/api/0049-Extended-OfflinePlayer-API.patch diff --git a/patches/api/0051-Added-the-ability-to-add-combustible-items.patch b/patches/api/0050-Added-the-ability-to-add-combustible-items.patch similarity index 92% rename from patches/api/0051-Added-the-ability-to-add-combustible-items.patch rename to patches/api/0050-Added-the-ability-to-add-combustible-items.patch index a79bc6974..93f7369e1 100644 --- a/patches/api/0051-Added-the-ability-to-add-combustible-items.patch +++ b/patches/api/0050-Added-the-ability-to-add-combustible-items.patch @@ -34,10 +34,10 @@ index e4ec2a0c15a6ada5bef9671e427cd56413f18d80..390a0d09b78e46cfebe78bfa3d1dd73a // Purpur end } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 80c70522eecb08c0dbfadcdeb21c9cfac42d7902..faf8cff5c1b586d9404bdecb522d45a09fc7fe92 100644 +index 6888deaba01cd2edb8a84ad0a1cdfc6feb132ab2..88767865cc2dce0e341eef0f53323af6f95fb841 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1827,5 +1827,20 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -1819,5 +1819,20 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi * @return True if lagging */ boolean isLagging(); diff --git a/patches/server/0002-Airplane-Server-Changes.patch b/patches/server/0001-Airplane-Server-Changes.patch similarity index 94% rename from patches/server/0002-Airplane-Server-Changes.patch rename to patches/server/0001-Airplane-Server-Changes.patch index 058b46730..3a92773c8 100644 --- a/patches/server/0002-Airplane-Server-Changes.patch +++ b/patches/server/0001-Airplane-Server-Changes.patch @@ -19,21 +19,23 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/build.gradle.kts b/build.gradle.kts -index 324285684ea1a79c3844142046dca9a34f78e1a9..467ac5ba77cc35dc84c38161881db37e8f9adc14 100644 +index b3687f632bbf06c933a6ef04dc2236ccf3c030b8..8a56862f59b7b7d64580b46c561643a1d99348c7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -35,7 +35,7 @@ repositories { +@@ -29,8 +29,8 @@ repositories { } dependencies { -- implementation(project(":Tuinity-API")) // Tuinity +- implementation(project(":Paper-API")) +- implementation(project(":Paper-MojangAPI")) + implementation(project(":Airplane-API")) // Airplane // Tuinity - implementation("io.papermc.paper:paper-mojangapi:1.17.1-R0.1-SNAPSHOT") // Tuinity ++ implementation("io.papermc.paper:paper-mojangapi:1.17.1-R0.1-SNAPSHOT") // Airplane // Paper start implementation("org.jline:jline-terminal-jansi:3.12.1") -@@ -71,6 +71,10 @@ dependencies { + implementation("net.minecrell:terminalconsoleappender:1.2.0") +@@ -65,6 +65,10 @@ dependencies { implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation - implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Tuinity + implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Paper + implementation("com.github.technove:AIR:fe3dbb4420") // Airplane - config + implementation ("me.carleslc.Simple-YAML:Simple-Yaml:1.7.2") // Airplane - more config @@ -42,39 +44,39 @@ index 324285684ea1a79c3844142046dca9a34f78e1a9..467ac5ba77cc35dc84c38161881db37e testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test testImplementation("junit:junit:4.13.1") testImplementation("org.hamcrest:hamcrest-library:1.3") -@@ -88,7 +92,7 @@ tasks.jar { +@@ -82,7 +86,7 @@ tasks.jar { attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Tuinity-$implementationVersion", // Tuinity -+ "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane // Tuinity +- "Implementation-Version" to "git-Paper-$implementationVersion", ++ "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane "Implementation-Vendor" to date, // Paper "Specification-Title" to "Bukkit", "Specification-Version" to project.version, diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index b5728243f01aa6ea75cb42af453fd9348a5f438b..4cd8116fd623fbc9e175986526d3ae51a72b76e0 100644 +index 7d44abcb4fff9717a1af55879deb7eb9c2d9e7e9..5fc65b0224b5c56039d60baf30f2de35f8bfb1c6 100644 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -229,7 +229,8 @@ public class TimingsExport extends Thread { +@@ -228,7 +228,8 @@ public class TimingsExport extends Thread { + parent.put("config", createObject( pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), - pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Tuinity - add config to timings report -- pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)) // Tuinity - add config to timings report -+ pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)), // Tuinity - add config to timings report +- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) ++ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), + pair("airplane", mapAsJSON(gg.airplane.AirplaneConfig.getConfigCopy(), null)) )); new TimingsExport(listeners, parent, history).start(); diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 3918b24c98faa5232c7ffd733ba8000562132785..f5d01bce4d5547b4aeca96b7962b2090f47ea541 100644 +index 218f5bafeed8551b55b91c7fccaf6935c8b631ca..9d70f944af2c81ab5ab23b06857d740db74709d9 100644 --- a/src/main/java/com/destroystokyo/paper/Metrics.java +++ b/src/main/java/com/destroystokyo/paper/Metrics.java @@ -593,7 +593,7 @@ public class Metrics { boolean logFailedRequests = config.getBoolean("logFailedRequests", false); // Only start Metrics, if it's enabled in the config if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Tuinity", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page -+ Metrics metrics = new Metrics("Airplane", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page // Airplane +- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); ++ Metrics metrics = new Metrics("Airplane", serverUUID, logFailedRequests, Bukkit.getLogger()); // Airplane metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { String minecraftVersion = Bukkit.getVersion(); @@ -82,13 +84,13 @@ index 3918b24c98faa5232c7ffd733ba8000562132785..f5d01bce4d5547b4aeca96b7962b2090 metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline")); -- metrics.addCustomChart(new Metrics.SimplePie("tuinity_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page -+ metrics.addCustomChart(new Metrics.SimplePie("airplane_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page // Airplane +- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); ++ metrics.addCustomChart(new Metrics.SimplePie("airplane_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Airplane metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { Map> map = new HashMap<>(); diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 2e0191e5cfe8e29fb0a6c4fc6a2a570d4b8ae449..cba14fd282d1294eba4581336c5e438484df76f9 100644 +index 5fd8f682d0a76bf804137018e1d3d4b44a31d9f7..25f1656a47037b0245cdd32e475b41e64dbad1de 100644 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java @@ -202,16 +202,26 @@ public class PaperConfig { @@ -120,52 +122,20 @@ index 2e0191e5cfe8e29fb0a6c4fc6a2a570d4b8ae449..cba14fd282d1294eba4581336c5e4384 int timingHistoryLength = getInt("timings.history-length", 3600); timingsServerName = getString("timings.server-name", "Unknown Server"); diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -index d50b61876f15d95b836b3dd81d9c3492c91a8448..5460f57f0473868b3fb09c526a1767f717a2740e 100644 +index 580bae0d414d371a07a6bfeefc41fdd989dc0083..030731923811f7748e8f9086f88e913031f1ec21 100644 --- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java @@ -29,8 +29,8 @@ public class PaperVersionFetcher implements VersionFetcher { @Nonnull @Override public Component getVersionMessage(@Nonnull String serverVersion) { -- String[] parts = serverVersion.substring("git-Tuinity-".length()).split("[-\\s]"); // Tuinity -- final Component updateMessage = getUpdateStatusMessage("Spottedleaf/Tuinity", GITHUB_BRANCH_NAME, parts[0]); // Tuinity -+ String[] parts = serverVersion.substring("git-Airplane-".length()).split("[-\\s]"); // Tuinity -+ final Component updateMessage = getUpdateStatusMessage("TECHNOVE/Airplane", GITHUB_BRANCH_NAME, parts[0]); // Tuinity +- String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]"); +- final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]); ++ String[] parts = serverVersion.substring("git-Airplane-".length()).split("[-\\s]"); // Airplane ++ final Component updateMessage = getUpdateStatusMessage("TECHNOVE/Airplane", GITHUB_BRANCH_NAME, parts[0]); // Airplane final Component history = getHistory(); return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage; -diff --git a/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java b/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java -index a2f52a68420a2d23d8f54f61f7aeede41567dc0f..4da3e83b61b89978aed968d4aaec3308f3f00995 100644 ---- a/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java -+++ b/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java -@@ -398,6 +398,8 @@ public final class CollisionUtil { - final List into, final boolean loadChunks, final boolean collidesWithUnloaded, - final boolean checkBorder, final boolean checkOnly, final BiPredicate predicate) { - boolean ret = false; -+ BlockPos.MutableBlockPos mutablePos; // Airplane -+ - - if (checkBorder) { - if (CollisionUtil.isAlmostCollidingOnBorder(getter.getWorldBorder(), aabb)) { -@@ -408,7 +410,8 @@ public final class CollisionUtil { - ret = true; - } - } -- } -+ mutablePos = entity.cachedBlockPos; // Airplane -+ } else mutablePos = new BlockPos.MutableBlockPos(); // Airplane - - int minBlockX = Mth.floor(aabb.minX - COLLISION_EPSILON) - 1; - int maxBlockX = Mth.floor(aabb.maxX + COLLISION_EPSILON) + 1; -@@ -424,7 +427,7 @@ public final class CollisionUtil { - final int minBlock = minSection << 4; - final int maxBlock = (maxSection << 4) | 15; - -- BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); -+ //BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); // Airplane - moved up - CollisionContext collisionShape = null; - - // special cases: diff --git a/src/main/java/gg/airplane/AirplaneCommand.java b/src/main/java/gg/airplane/AirplaneCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..89c89e633f14b5820147e734b1b7ad8cadfdce80 @@ -1612,7 +1582,7 @@ index 0000000000000000000000000000000000000000..a7f297ebb569f7c1f205e967ca485be7 + } +} diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java -index 82e8338c69e846ab9ff0a9b9427d968e0a67927e..ea372e5018fad6edbd82a38c2c89baa3f51712bf 100644 +index 69faebb95924946f648cf9f86ff777d3274e3f28..1b246a401e626ba3034c36deedd8488a49479c96 100644 --- a/src/main/java/net/minecraft/Util.java +++ b/src/main/java/net/minecraft/Util.java @@ -332,6 +332,10 @@ public class Util { @@ -1636,19 +1606,19 @@ index 82e8338c69e846ab9ff0a9b9427d968e0a67927e..ea372e5018fad6edbd82a38c2c89baa3 public static CompletableFuture> sequenceFailFast(List> futures) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f25bb4214cffd0050241ea229b6acb0c16b2b0a5..0a78b208cbafc850e24501f65197e1cd2e8efcf5 100644 +index edd2333e0fb24a50bc388249224e9311aa90a10f..1490753c9f47769177212051924306493efdc5d5 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1716,7 +1716,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! -+ return "Airplane"; // Airplane - Airplane > // Tuinity - Tuinity > //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! +- return "Paper"; //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! ++ return "Airplane"; // Airplane - Airplane > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! } public SystemReport fillSystemReport(SystemReport details) { -@@ -2292,6 +2292,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; - if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(com.tuinity.tuinity.config.TuinityConfig.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Tuinity - send full pos for hard colliding entities to prevent collision problems due to desync + if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(com.destroystokyo.paper.PaperConfig.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync + if (flag2 || flag3 || this.entity instanceof AbstractArrow) { // Airplane if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { if (flag2) { @@ -1745,7 +1715,7 @@ index d73aa6032bf56448f518cff9f019b3f7a1c5eddb..7eb6614c126d03435689a92c0064baff this.wasOnGround = this.entity.isOnGround(); this.teleportDelay = 0; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index f9ed48f5bbde84fd1804e482f2777b516cc3a1ef..29ce41330bd291a050441fc5aecd7eef65ff471c 100644 +index f40ac8dbd1193410c5fe164a0952f2394e111248..2db8a773c035a74ceb6cd31311b1b0e053775434 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -775,7 +775,20 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -1774,8 +1744,8 @@ index f9ed48f5bbde84fd1804e482f2777b516cc3a1ef..29ce41330bd291a050441fc5aecd7eef } // Paper start - optimise random block ticking private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); -- private final com.tuinity.tuinity.util.math.ThreadUnsafeRandom randomTickRandom = new com.tuinity.tuinity.util.math.ThreadUnsafeRandom(); -+ private final com.tuinity.tuinity.util.math.ThreadUnsafeRandom randomTickRandom = new com.tuinity.tuinity.util.math.ThreadUnsafeRandom(); public java.util.Random getThreadUnsafeRandom() { return this.randomTickRandom; } // Airplane - getter +- private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); ++ private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); public java.util.Random getThreadUnsafeRandom() { return this.randomTickRandom; } // Airplane - getter // Paper end + private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Airplane @@ -1914,10 +1884,10 @@ index 7437f01ca8f416e2c9150250e324af4725a4efb6..bdcd0e38a3ba904811112f41d8bfbfc0 int LARGE_MAX_STACK_SIZE = 64; diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index b4c15376da0ba9c33efe7e7da648690e7a931981..da01861990da0307cfba14cb2492baf7761a3930 100644 +index 2a3d2dbd764c3f86430bda78d3ae9431ae9015c8..16ee8991b8993c243b23131da7d4790d9c71bccd 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -336,6 +336,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -338,6 +338,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n protected int numCollisions = 0; // Paper public void inactiveTick() { } // Spigot end @@ -1928,7 +1898,7 @@ index b4c15376da0ba9c33efe7e7da648690e7a931981..da01861990da0307cfba14cb2492baf7 public float getBukkitYaw() { return this.yRot; -@@ -355,17 +359,36 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -357,17 +361,36 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n this.isLegacyTrackingEntity = isLegacyTrackingEntity; } @@ -1950,7 +1920,7 @@ index b4c15376da0ba9c33efe7e7da648690e7a931981..da01861990da0307cfba14cb2492baf7 + } + public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getPlayersInTrackRange() { - // Tuinity start - determine highest range of passengers + // Paper start - determine highest range of passengers if (this.passengers.isEmpty()) { return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()] .getObjectsInRange(MCUtil.getCoordinateKey(this)); @@ -1966,7 +1936,7 @@ index b4c15376da0ba9c33efe7e7da648690e7a931981..da01861990da0307cfba14cb2492baf7 for (Entity passenger : passengers) { org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType; int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal()); -@@ -374,6 +397,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -376,6 +399,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n range = passengerRange; } } @@ -1975,16 +1945,16 @@ index b4c15376da0ba9c33efe7e7da648690e7a931981..da01861990da0307cfba14cb2492baf7 + // Airplane end return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this)); - // Tuinity end - determine highest range of passengers -@@ -2432,9 +2458,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + // Paper end - determine highest range of passengers +@@ -2435,9 +2461,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - // Tuinity start - return com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this.level, this, axisalignedbb, null, + // Paper start + return io.papermc.paper.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this.level, this, axisalignedbb, null, - false, false, false, true, (iblockdata, blockposition) -> { - return iblockdata.isSuffocating(this.level, blockposition); - }); + false, false, false, true, this.level.isAlmostSuffocating); // Airplane - don't allocate lambda here - // Tuinity end + // Paper end } } diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java @@ -2001,7 +1971,7 @@ index ac99265aacd4a28490705e3079ed04023fb1c54a..96b881fcb4c3871b2fc00080afc19900 this.factory = entitytypes_b; this.category = enumcreaturetype; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index b2e48e16bc944e6c5898f3d415e935c421243e16..f025d03149089a8acdfa55f54b5b754cba4bd4d1 100644 +index 6175360eb2b19c8197cc5b82a09030211afd838b..f0ce1e4364e1a549163c8a3a714fb20df42ae3c3 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -142,7 +142,6 @@ import org.bukkit.event.entity.EntityTeleportEvent; @@ -2046,7 +2016,7 @@ index b2e48e16bc944e6c5898f3d415e935c421243e16..f025d03149089a8acdfa55f54b5b754c } diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index c73f3aa6dd75fe03c7e18180487d7bd6374b6339..c7a400e72ca2aae31ae8882b8df946b14b18e006 100644 +index 8a864238e154e2131834d013652746b7e7a78c97..b8e512e1c4b00b468b2d22add5653b98f4a2c81a 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -207,10 +207,10 @@ public abstract class Mob extends LivingEntity { @@ -2146,7 +2116,7 @@ index 9cbfda029782385d1a7987f5be46d450bd8a758e..d3e97858dacc850012e5585ac44a1aea public boolean hasAttribute(Attribute attribute) { diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index efe66264ad5717bf3aac0fbda07275fb5571acc1..68188f3322a9af8eac423afc5f87bc4f88f4a5bb 100644 +index afbb2acd27416c801af3d718850b82a170734cd3..0b206a3f964f5143e0720890d78d682b8b558c15 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java @@ -68,6 +68,7 @@ public class AcquirePoi extends Behavior { @@ -2291,7 +2261,7 @@ index 15787afad42f9299638a1c9e57d26678805f18ee..0d220ea2d2651c46ba60c68bdd8dad31 this.level.getProfiler().pop(); this.level.getProfiler().push("goatActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index 158719d46c96bb733a00e08c8285f41a48406abf..2dac4bc346eb1dde1f8d92c3e5b9648b2c433617 100644 +index 063f3e4c67e6716c9a03dbe4b72eafd32e4f0d53..dae6f7a05426ea31d13c82458b33e20abc2571b6 100644 --- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java @@ -243,10 +243,16 @@ public class ItemEntity extends Entity { @@ -2561,7 +2531,7 @@ index 6b960f0a31175bcfd8d477ee5b3c4d783303cdd5..3a81d3a58b937c9800cd0be738439cff int i = 0; diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java -index ec781ab232d12cedb5f0236860377c4917c576d7..ced4b354e83ad68f8f1aacdefe2f0ce0035bd4a7 100644 +index 6200a8ab4f7b2c40e7139cfb90a62f42c5828de2..f6a8e10347b9a374e2da9d28734b72443555459d 100644 --- a/src/main/java/net/minecraft/world/level/BlockGetter.java +++ b/src/main/java/net/minecraft/world/level/BlockGetter.java @@ -73,6 +73,16 @@ public interface BlockGetter extends LevelHeightAccessor { @@ -2642,10 +2612,10 @@ index e7ca5d6fb8922e7e8065864f736b06056be080a0..833ad6fbedfc275b3fde640b0e873f23 final String id; private final GameRules.Category category; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 61a4dea715689b0ce9247040db5dd2080ee2e167..496000e65ffd5df5ea23783341dac5e2b9b63d0c 100644 +index b93056b91e7ebd49e6ddb53ccb6c05c056088df9..6f4e6105aa1d6546daa2424f57972fd29db25fa3 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -177,6 +177,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -175,6 +175,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here @@ -2654,7 +2624,7 @@ index 61a4dea715689b0ce9247040db5dd2080ee2e167..496000e65ffd5df5ea23783341dac5e2 // Paper start - fix and optimise world upgrading // copied from below public static ResourceKey getDimensionKey(DimensionType manager) { -@@ -453,6 +455,91 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -450,6 +452,91 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return null; } @@ -2746,10 +2716,10 @@ index 61a4dea715689b0ce9247040db5dd2080ee2e167..496000e65ffd5df5ea23783341dac5e2 public boolean isInWorldBounds(BlockPos pos) { return pos.isValidLocation(this); // Paper - use better/optimized check } -@@ -988,13 +1075,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -985,13 +1072,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { try { tickConsumer.accept(entity); - MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick + MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick - } catch (Throwable throwable) { + } catch (Throwable throwable) { // Airplane - diff on change ServerLevel.tick if (throwable instanceof ThreadDeath) throw throwable; // Paper @@ -2762,7 +2732,7 @@ index 61a4dea715689b0ce9247040db5dd2080ee2e167..496000e65ffd5df5ea23783341dac5e2 // Paper end } } -@@ -1448,6 +1535,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1445,6 +1532,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } public ProfilerFiller getProfiler() { @@ -2771,7 +2741,7 @@ index 61a4dea715689b0ce9247040db5dd2080ee2e167..496000e65ffd5df5ea23783341dac5e2 } diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index c6821bfb28b582733cd977864c28ca5cf0c69872..ea77694307e5972b6c9ecf5f23515885974ed493 100644 +index 403f50ef908f65c62d4aaa7e5328faa0a7654480..e5fa91b5e19edab169b361865e7a6b2742c9ca4b 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -407,12 +407,12 @@ public final class NaturalSpawner { @@ -2909,7 +2879,7 @@ index 52de9852f87d346714a950b60a0004d386ac10f0..305a8f5ea917c7e242011fa98a3e1615 @Override diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index a3f0e2ab3eeebeb7c43fda3ddb1f16f8696255d3..99e75feae404d8812f55d562acb11af94330e2c1 100644 +index d41851f9119c334cae3fc2c433d6450a3eed9096..ddf82e65d3ef1f53b72017bf5159b9f7b5484632 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java @@ -44,7 +44,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -3002,8 +2972,8 @@ index a3f0e2ab3eeebeb7c43fda3ddb1f16f8696255d3..99e75feae404d8812f55d562acb11af9 + boolean flag1 = to.isCompletelyEmpty(enumdirection); // Airplane if (itemstack1.isEmpty()) { - int originalCount = stack.getCount(); // Paper -@@ -735,7 +758,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem +@@ -731,7 +754,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @Override protected void setItems(NonNullList list) { @@ -3032,12 +3002,12 @@ index ed3518fe7c841d9e1a9c97626acaa3d765a6d76f..ac564148956beb984650341c5c099457 @Override diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 4f6a356e3a27915f1d95132a0a5fddb163735cf6..b2e71a78424dbe1ce87b982b073d8534de890181 100644 +index 86686c24b0b7de4b4bfadbc77419a8872a8e86ee..e265980f07d95a7912bf8873819033e51ef04c98 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -172,11 +172,25 @@ public class LevelChunk implements ChunkAccess { } - // Tuinity end - rewrite light engine + // Paper end - rewrite light engine + // Airplane start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively + private int lightningTick; @@ -3058,7 +3028,7 @@ index 4f6a356e3a27915f1d95132a0a5fddb163735cf6..b2e71a78424dbe1ce87b982b073d8534 public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes, UpgradeData upgradeData, TickList blockTickScheduler, TickList fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer loadToWorldConsumer) { + this.levelHeight = world.getHeight(); this.minBuildHeight = world.getMinBuildHeight(); // Airplane - // Tuinity start + // Paper start this.blockNibbles = StarLightEngine.getFilledEmptyLight(world); this.skyNibbles = StarLightEngine.getFilledEmptyLight(world); @@ -220,6 +234,7 @@ public class LevelChunk implements ChunkAccess { @@ -3092,7 +3062,7 @@ index 4f6a356e3a27915f1d95132a0a5fddb163735cf6..b2e71a78424dbe1ce87b982b073d8534 @Override diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -index ebeb3e3b0619b034a9681da999e9ac33cc241718..5b5ada474cff54b424946fc628d30f25a6774684 100644 +index c9e942669458668a184aaec3bc0a5509dd6ab5f0..178e56ffc87ea2beb4d84d1f278f4acf90102379 100644 --- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java @@ -263,13 +263,17 @@ public class PalettedContainer implements PaletteResize { @@ -3115,10 +3085,10 @@ index ebeb3e3b0619b034a9681da999e9ac33cc241718..5b5ada474cff54b424946fc628d30f25 for(int j = 0; j < 4096; ++j) { T object2 = this.get(j); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 9815a91040e7cbcbcd171e68b0a935ea26ff8a2a..384897c21ea16b5760d9218c292dd29c9dceeab7 100644 +index 4ec0cd61c860a90bbe44244bb3f6b628c4533c98..6b870d5d45a668e52eec639e149b43722489dab0 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -485,6 +485,7 @@ public class ChunkSerializer { +@@ -502,6 +502,7 @@ public class ChunkSerializer { return new AsyncSaveData(blockLight, skyLight, blockTickListSerialized, fluidTickListSerialized, blockEntitiesSerialized, world.getGameTime()); } @@ -3126,7 +3096,7 @@ index 9815a91040e7cbcbcd171e68b0a935ea26ff8a2a..384897c21ea16b5760d9218c292dd29c public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { return saveChunk(world, chunk, null); } -@@ -518,6 +519,7 @@ public class ChunkSerializer { +@@ -535,6 +536,7 @@ public class ChunkSerializer { ThreadedLevelLightEngine lightenginethreaded = world.getChunkSource().getLightEngine(); boolean flag = chunk.isLightCorrect(); @@ -3134,7 +3104,7 @@ index 9815a91040e7cbcbcd171e68b0a935ea26ff8a2a..384897c21ea16b5760d9218c292dd29c for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { int finalI = i; // CraftBukkit - decompile errors LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> { -@@ -532,7 +534,7 @@ public class ChunkSerializer { +@@ -549,7 +551,7 @@ public class ChunkSerializer { nbttagcompound2.putByte("Y", (byte) (i & 255)); if (chunksection != LevelChunk.EMPTY_SECTION) { @@ -3142,7 +3112,7 @@ index 9815a91040e7cbcbcd171e68b0a935ea26ff8a2a..384897c21ea16b5760d9218c292dd29c + chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates", is); // Airplane - reuse array } - // Tuinity start - replace light engine + // Paper start - replace light engine diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java index da1ad0b2679e392ed81b50c15f012c63cb5c939e..81e83022421e2c311c32f6e6007cfc0c82efb822 100644 --- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java @@ -3170,7 +3140,7 @@ index 3b13f6ea36a3bfecabe09221eb5c48dddab119db..c02b9104c0cc1a7319cca29d5e32a5c2 @Override public T get(int id) { diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -index 6e3e873efa1f50f53cb6503bde8a981f9cefd006..32d15354ceb46fb06b1c36049d3a8bfba718acaf 100644 +index 7fda7da544b2d0bbd3803d88ee34c92350a8b8ef..adf91f3006a2d224c957f08520f93f761c3ba832 100644 --- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java +++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java @@ -45,6 +45,8 @@ public abstract class FlowingFluid extends Fluid { @@ -3381,19 +3351,19 @@ index fcb7bd9f3b6b6ada0f2e5692bce32ab76b8798a7..61c2096f2c034dbc3ad33b193b058c7d } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 57dab1be4bfa91c7c9d7e53e7fe388a94dc60e0b..fe5eac5f01461c9ca81301142218aa131475dfe7 100644 +index 4687827c096ecf8872ab39b00fbf9261ba5c3689..fe1b046f707ee145327475b7f923928f4dfcad05 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -240,7 +240,7 @@ import javax.annotation.Nullable; // Paper +@@ -246,7 +246,7 @@ import javax.annotation.Nullable; // Paper import javax.annotation.Nonnull; // Paper public final class CraftServer implements Server { -- private final String serverName = "Tuinity"; // Tuinity // Paper -+ private final String serverName = "Airplane"; // Airplane // Tuinity // Paper +- private final String serverName = "Paper"; // Paper ++ private final String serverName = "Airplane"; // Paper // Airplane private final String serverVersion; private final String bukkitVersion = Versioning.getBukkitVersion(); private final Logger logger = Logger.getLogger("Minecraft"); -@@ -997,6 +997,11 @@ public final class CraftServer implements Server { +@@ -1001,6 +1001,11 @@ public final class CraftServer implements Server { plugin.getDescription().getName(), "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies." )); @@ -3418,10 +3388,10 @@ index 0b3b46348ac9195bff1492ffc11fcbff7d3f5c6f..4010052c53f3a2831b4d5aa1c041d858 } } diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java b/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java -index 49dc0c441b9dd7e7745cf15ced67f383ebee1f99..b343d8ee7435312929558efdaf127334d8e2fff6 100644 +index 909b2c98e7a9117d2f737245e4661792ffafb744..9da898c6f44832b4421b8c2745e3121bd13a71ab 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java -@@ -19,7 +19,8 @@ public class MinecraftInternalPlugin extends PluginBase { +@@ -22,7 +22,8 @@ public class MinecraftInternalPlugin extends PluginBase { private boolean enabled = true; private final String pluginName; @@ -3431,7 +3401,7 @@ index 49dc0c441b9dd7e7745cf15ced67f383ebee1f99..b343d8ee7435312929558efdaf127334 public MinecraftInternalPlugin() { this.pluginName = "Minecraft"; -@@ -72,7 +73,12 @@ public class MinecraftInternalPlugin extends PluginBase { +@@ -75,7 +76,12 @@ public class MinecraftInternalPlugin extends PluginBase { @Override public PluginLogger getLogger() { @@ -3445,7 +3415,7 @@ index 49dc0c441b9dd7e7745cf15ced67f383ebee1f99..b343d8ee7435312929558efdaf127334 } @Override -@@ -82,7 +88,7 @@ public class MinecraftInternalPlugin extends PluginBase { +@@ -85,7 +91,7 @@ public class MinecraftInternalPlugin extends PluginBase { @Override public Server getServer() { @@ -3467,20 +3437,20 @@ index d752720f2f234b9dbd2117333fee1bfad663ec02..9868b3a9a35cea9689c76ea9b62f2732 // Paper start - try to shutdown on main server.safeShutdown(false, false); diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 001b1e5197eaa51bfff9031aa6c69876c9a47960..1788d79ea489e446d3d9f541693d4ba3dfc26015 100644 +index 774556a62eb240da42e84db4502e2ed43495be17..7217088fda330c97c6edd007159aa6b2dee41bfb 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java @@ -11,7 +11,7 @@ public final class Versioning { public static String getBukkitVersion() { String result = "Unknown-Version"; -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/com.tuinity/tuinity-api/pom.properties"); // Tuinity -+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/gg.airplane/airplane-api/pom.properties"); // Tuinity // Airplane +- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); ++ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/gg.airplane/airplane-api/pom.properties"); // Airplane Properties properties = new Properties(); if (stream != null) { diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 966639cc6ba6684bfb52e91ac047808cf4d003e4..0d56df555b8d2de12447cc2e869c9eba20c5ea6d 100644 +index b5da2f39ff6e2e7cb519c5d22be6ae4d77dc60ab..79c9f8e81f6592e6d922f6fdfe088a4dd54d44f8 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -37,6 +37,10 @@ import co.aikar.timings.MinecraftTimings; @@ -3514,7 +3484,7 @@ index 966639cc6ba6684bfb52e91ac047808cf4d003e4..0d56df555b8d2de12447cc2e869c9eba + // Airplane end + } - // Tuinity end + // Paper end } @@ -226,12 +245,12 @@ public class ActivationRange if ( MinecraftServer.currentTick > entity.activatedTick ) @@ -3531,7 +3501,7 @@ index 966639cc6ba6684bfb52e91ac047808cf4d003e4..0d56df555b8d2de12447cc2e869c9eba entity.activatedTick = MinecraftServer.currentTick; } } -@@ -276,7 +295,7 @@ public class ActivationRange +@@ -279,7 +298,7 @@ public class ActivationRange if ( entity instanceof LivingEntity ) { LivingEntity living = (LivingEntity) entity; diff --git a/patches/server/0001-Tuinity-Server-Changes.patch b/patches/server/0001-Tuinity-Server-Changes.patch deleted file mode 100644 index 3bc0f0be2..000000000 --- a/patches/server/0001-Tuinity-Server-Changes.patch +++ /dev/null @@ -1,39699 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 12 Jun 2021 16:40:34 +0200 -Subject: [PATCH] Tuinity Server Changes - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -diff --git a/build.gradle.kts b/build.gradle.kts -index 3927eb2cd13499bca7561ae7d9be45ae86522125..324285684ea1a79c3844142046dca9a34f78e1a9 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -1,10 +1,16 @@ - import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer - import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer - import io.papermc.paperweight.tasks.BaseTask -+import io.papermc.paperweight.tasks.GenerateReobfMappings -+import io.papermc.paperweight.tasks.PatchMappings -+import io.papermc.paperweight.util.constants.* - import io.papermc.paperweight.util.Git -+import io.papermc.paperweight.util.cache - import io.papermc.paperweight.util.defaultOutput - import io.papermc.paperweight.util.openZip - import io.papermc.paperweight.util.path -+import io.papermc.paperweight.util.registering -+import io.papermc.paperweight.util.set - import shadow.org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE - import java.nio.file.Files - import java.util.Locale -@@ -25,11 +31,12 @@ repositories { - } - } - // Paper end -+ maven("https://repo.velocitypowered.com/snapshots/") // Tuinity - } - - dependencies { -- implementation(project(":Paper-API")) -- implementation(project(":Paper-MojangAPI")) -+ implementation(project(":Tuinity-API")) // Tuinity -+ implementation("io.papermc.paper:paper-mojangapi:1.17.1-R0.1-SNAPSHOT") // Tuinity - // Paper start - implementation("org.jline:jline-terminal-jansi:3.12.1") - implementation("net.minecrell:terminalconsoleappender:1.2.0") -@@ -62,6 +69,7 @@ dependencies { - implementation("io.netty:netty-all:4.1.65.Final") // Paper - - implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation -+ implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Tuinity - - testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test - testImplementation("junit:junit:4.13.1") -@@ -74,13 +82,13 @@ tasks.jar { - manifest { - val git = Git(rootProject.layout.projectDirectory.path) - val gitHash = git("rev-parse", "--short=7", "HEAD").getText().trim() -- val implementationVersion = System.getenv("BUILD_NUMBER") ?: "\"$gitHash\"" -+ val implementationVersion = /* System.getenv("BUILD_NUMBER") ?: */ "\"$gitHash\"" // Tuinity - Do not use CI build number for implementation version (always use git hash) - val date = git("show", "-s", "--format=%ci", gitHash).getText().trim() // Paper - val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper - attributes( - "Main-Class" to "org.bukkit.craftbukkit.Main", - "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Paper-$implementationVersion", -+ "Implementation-Version" to "git-Tuinity-$implementationVersion", // Tuinity - "Implementation-Vendor" to date, // Paper - "Specification-Title" to "Bukkit", - "Specification-Version" to project.version, -@@ -105,6 +113,22 @@ publishing { - } - } - -+val generateReobfMappings = rootProject.tasks.named("generateReobfMappings") -+ -+val patchReobfMappings by tasks.registering { -+ inputMappings.set(generateReobfMappings.flatMap { it.reobfMappings }) -+ patch.set(rootProject.layout.cache.resolve("paperweight/upstreams/paper/build-data/reobf-mappings-patch.tiny")) -+ -+ fromNamespace.set(DEOBF_NAMESPACE) -+ toNamespace.set(SPIGOT_NAMESPACE) -+ -+ outputMappings.set(layout.cache.resolve("paperweight/mappings/reobf-patched.tiny")) -+} -+ -+tasks.reobfJar { -+ mappingsFile.set(patchReobfMappings.flatMap { it.outputMappings }) -+} -+ - val generatePom = tasks.named("generatePomFileForMavenPublication") - - tasks.shadowJar { -@@ -176,7 +200,7 @@ tasks.test { - fun TaskContainer.registerRunTask( - name: String, block: JavaExec.() -> Unit - ): TaskProvider = register(name) { -- group = "paper" -+ group = "paperweight" - standardInput = System.`in` - workingDir = rootProject.layout.projectDirectory.dir( - providers.gradleProperty("runWorkDir").forUseAtConfigurationTime().orElse("run") -diff --git a/src/main/java/ca/spottedleaf/dataconverter/converters/DataConverter.java b/src/main/java/ca/spottedleaf/dataconverter/converters/DataConverter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1863c606be715683d53863a0c9293525d199c9cf ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/converters/DataConverter.java -@@ -0,0 +1,54 @@ -+package ca.spottedleaf.dataconverter.converters; -+ -+import java.util.Comparator; -+ -+public abstract class DataConverter { -+ -+ public static final Comparator> LOWEST_VERSION_COMPARATOR = (x, y) -> { -+ return Long.compare(x.getEncodedVersion(), y.getEncodedVersion()); -+ }; -+ -+ protected final int toVersion; -+ protected final int versionStep; -+ -+ public DataConverter(final int toVersion) { -+ this.toVersion = toVersion; -+ this.versionStep = 0; -+ } -+ -+ public DataConverter(final int toVersion, final int versionStep) { -+ this.toVersion = toVersion; -+ this.versionStep = versionStep; -+ } -+ -+ public final int getToVersion() { -+ return this.toVersion; -+ } -+ -+ public final int getVersionStep() { -+ return this.versionStep; -+ } -+ -+ public final long getEncodedVersion() { -+ return encodeVersions(this.toVersion, this.versionStep); -+ } -+ -+ public abstract R convert(final T data, final long sourceVersion, final long toVersion); -+ -+ // step must be in the lower bits, so that encodeVersions(version, step) < encodeVersions(version, step + 1) -+ public static long encodeVersions(final int version, final int step) { -+ return ((long)version << 32) | (step & 0xFFFFFFFFL); -+ } -+ -+ public static int getVersion(final long encoded) { -+ return (int)(encoded >>> 32); -+ } -+ -+ public static int getStep(final long encoded) { -+ return (int)encoded; -+ } -+ -+ public static String encodedToString(final long encoded) { -+ return getVersion(encoded) + "." + getStep(encoded); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataHook.java b/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataHook.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ef054cf466358a5cccf4d6044914d63394605d1a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataHook.java -@@ -0,0 +1,11 @@ -+package ca.spottedleaf.dataconverter.converters.datatypes; -+ -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public interface DataHook { -+ -+ public MapType preHook(final MapType data, final long fromVersion, final long toVersion); -+ -+ public MapType postHook(final MapType data, final long fromVersion, final long toVersion); -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataType.java b/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b56a7f9ace3b947fed49101b6e9936721fb99ea5 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataType.java -@@ -0,0 +1,7 @@ -+package ca.spottedleaf.dataconverter.converters.datatypes; -+ -+public abstract class DataType { -+ -+ public abstract R convert(final T data, final long fromVersion, final long toVersion); -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataWalker.java b/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataWalker.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cf9fae4451ead4860343b915fb70e3a7cdf0de31 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/converters/datatypes/DataWalker.java -@@ -0,0 +1,9 @@ -+package ca.spottedleaf.dataconverter.converters.datatypes; -+ -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public interface DataWalker { -+ -+ public MapType walk(final MapType data, final long fromVersion, final long toVersion); -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCDataConverter.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCDataConverter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..64f442922a9ca26a723653acb7a5398fca6076fd ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCDataConverter.java -@@ -0,0 +1,69 @@ -+package ca.spottedleaf.dataconverter.minecraft; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataType; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCDataType; -+import ca.spottedleaf.dataconverter.types.json.JsonMapType; -+import ca.spottedleaf.dataconverter.types.nbt.NBTMapType; -+import com.google.gson.JsonObject; -+import it.unimi.dsi.fastutil.longs.LongArrayList; -+import net.minecraft.nbt.CompoundTag; -+ -+public final class MCDataConverter { -+ -+ private static final LongArrayList BREAKPOINTS = MCVersionRegistry.getBreakpoints(); -+ -+ public static CompoundTag convertTag(final MCDataType type, final CompoundTag data, final int fromVersion, final int toVersion) { -+ final NBTMapType wrapped = new NBTMapType(data); -+ -+ final NBTMapType replaced = (NBTMapType)convert(type, wrapped, fromVersion, toVersion); -+ -+ return replaced == null ? wrapped.getTag() : replaced.getTag(); -+ } -+ -+ public static JsonObject convertJson(final MCDataType type, final JsonObject data, final boolean compressed, final int fromVersion, final int toVersion) { -+ final JsonMapType wrapped = new JsonMapType(data, compressed); -+ -+ final JsonMapType replaced = (JsonMapType)convert(type, wrapped, fromVersion, toVersion); -+ -+ return replaced == null ? wrapped.getJson() : replaced.getJson(); -+ } -+ -+ public static R convert(final DataType type, final T data, int fromVersion, final int toVersion) { -+ Object ret = data; -+ -+ long currentVersion = DataConverter.encodeVersions(fromVersion < 99 ? 99 : fromVersion, Integer.MAX_VALUE); -+ final long nextVersion = DataConverter.encodeVersions(toVersion, Integer.MAX_VALUE); -+ -+ for (int i = 0, len = BREAKPOINTS.size(); i < len; ++i) { -+ final long breakpoint = BREAKPOINTS.getLong(i); -+ -+ if (currentVersion >= breakpoint) { -+ continue; -+ } -+ -+ final Object converted = type.convert((T)ret, currentVersion, Math.min(nextVersion, breakpoint - 1)); -+ if (converted != null) { -+ ret = converted; -+ } -+ -+ currentVersion = Math.min(nextVersion, breakpoint - 1); -+ -+ if (currentVersion == nextVersion) { -+ break; -+ } -+ } -+ -+ if (currentVersion != nextVersion) { -+ final Object converted = type.convert((T)ret, currentVersion, nextVersion); -+ if (converted != null) { -+ ret = converted; -+ } -+ } -+ -+ return (R)ret; -+ } -+ -+ private MCDataConverter() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1026027daf0073063ccb1befce12e166fcfb4225 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java -@@ -0,0 +1,304 @@ -+package ca.spottedleaf.dataconverter.minecraft; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; -+import it.unimi.dsi.fastutil.ints.IntArrayList; -+import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet; -+import it.unimi.dsi.fastutil.ints.IntRBTreeSet; -+import it.unimi.dsi.fastutil.longs.LongArrayList; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import java.lang.reflect.Field; -+import java.util.Arrays; -+import java.util.Comparator; -+import java.util.Locale; -+ -+public final class MCVersionRegistry { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final Int2ObjectLinkedOpenHashMap VERSION_NAMES = new Int2ObjectLinkedOpenHashMap<>(); -+ protected static final IntArrayList VERSION_LIST; -+ protected static final LongArrayList DATA_VERSION_LIST; -+ -+ protected static final IntArrayList DATACONVERTER_VERSIONS_LIST; -+ protected static final IntLinkedOpenHashSet DATACONVERTER_VERSIONS = new IntLinkedOpenHashSet(); -+ protected static final Int2ObjectLinkedOpenHashMap SUBVERSIONS = new Int2ObjectLinkedOpenHashMap<>(); -+ protected static final LongArrayList BREAKPOINTS = new LongArrayList(); -+ static { -+ // Note: Some of these are nameless. -+ // Unless a data version is specified here, it will NOT have converters ran for it. Please add them on update! -+ final int[] converterVersions = new int[] { -+ 99, -+ 100, -+ 101, -+ 102, -+ 105, -+ 106, -+ 107, -+ 108, -+ 109, -+ 110, -+ 111, -+ 113, -+ 135, -+ 143, -+ 147, -+ 165, -+ 501, -+ 502, -+ 505, -+ 700, -+ 701, -+ 702, -+ 703, -+ 704, -+ 705, -+ 804, -+ 806, -+ 808, -+ 808, -+ 813, -+ 816, -+ 820, -+ 1022, -+ 1125, -+ 1344, -+ 1446, -+ 1450, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1456, -+ 1458, -+ 1460, -+ 1466, -+ 1470, -+ 1474, -+ 1475, -+ 1480, -+ 1481, -+ 1483, -+ 1484, -+ 1486, -+ 1487, -+ 1488, -+ 1490, -+ 1492, -+ 1494, -+ 1496, -+ 1500, -+ 1501, -+ 1502, -+ 1506, -+ 1510, -+ 1514, -+ 1515, -+ 1624, -+ 1800, -+ 1801, -+ 1802, -+ 1803, -+ 1904, -+ 1905, -+ 1906, -+ 1909, -+ 1911, -+ 1917, -+ 1918, -+ 1920, -+ 1925, -+ 1928, -+ 1929, -+ 1931, -+ 1936, -+ 1946, -+ 1948, -+ 1953, -+ 1955, -+ 1961, -+ 1963, -+ 2100, -+ 2202, -+ 2209, -+ 2211, -+ 2218, -+ 2501, -+ 2502, -+ 2503, -+ 2505, -+ 2508, -+ 2509, -+ 2511, -+ 2514, -+ 2516, -+ 2518, -+ 2519, -+ 2522, -+ 2523, -+ 2527, -+ 2528, -+ 2529, -+ 2531, -+ 2533, -+ 2535, -+ 2550, -+ 2551, -+ 2552, -+ 2553, -+ 2558, -+ 2568, -+ 2671, -+ 2679, -+ 2680, -+ 2684, -+ 2686, -+ 2688, -+ 2690, -+ 2691, -+ 2696, -+ 2700, -+ 2701, -+ 2702, -+ 2704, -+ 2707, -+ 2710, -+ 2717 -+ // All up to 1.17.1 -+ }; -+ Arrays.sort(converterVersions); -+ -+ DATACONVERTER_VERSIONS.addAll(DATACONVERTER_VERSIONS_LIST = new IntArrayList(converterVersions)); -+ -+ // add sub versions -+ registerSubVersion(MCVersions.V17W47A, 1); -+ registerSubVersion(MCVersions.V17W47A, 2); -+ registerSubVersion(MCVersions.V17W47A, 3); -+ registerSubVersion(MCVersions.V17W47A, 4); -+ registerSubVersion(MCVersions.V17W47A, 5); -+ registerSubVersion(MCVersions.V17W47A, 6); -+ registerSubVersion(MCVersions.V17W47A, 7); -+ -+ // register breakpoints here -+ -+ // Too much changed in this version. -+ registerBreakpoint(MCVersions.V17W47A); -+ registerBreakpoint(MCVersions.V17W47A, Integer.MAX_VALUE); -+ -+ -+ } -+ -+ static { -+ final Field[] fields = MCVersions.class.getDeclaredFields(); -+ for (final Field field : fields) { -+ final String name = field.getName(); -+ final int value; -+ try { -+ value = field.getInt(null); -+ } catch (final Exception ex) { -+ throw new RuntimeException(ex); -+ } -+ -+ if (VERSION_NAMES.containsKey(value) && value != MCVersions.V15W33B) { // Mojang registered 15w33a and 15w33b under the same id. -+ LOGGER.warn("Error registering version \"" + name + "\", version number '" + value + "' is already associated with \"" + VERSION_NAMES.get(value) + "\""); -+ } -+ -+ VERSION_NAMES.put(value, name.substring(1).replace("_PRE", "-PRE").replace("_RC", "-RC").replace('_', '.').toLowerCase(Locale.ROOT)); -+ } -+ -+ for (final int version : DATACONVERTER_VERSIONS) { -+ if (VERSION_NAMES.containsKey(version)) { -+ continue; -+ } -+ -+ // find closest greatest version above this one -+ int closest = Integer.MAX_VALUE; -+ String closestName = null; -+ for (final int v : VERSION_NAMES.keySet()) { -+ if (v > version && v < closest) { -+ closest = v; -+ closestName = VERSION_NAMES.get(v); -+ } -+ } -+ -+ if (closestName == null) { -+ VERSION_NAMES.put(version, "unregistered_v" + version); -+ } else { -+ VERSION_NAMES.put(version, closestName + "-dev" + (closest - version)); -+ } -+ } -+ -+ // Explicit override for V99, as 99 is very special. -+ VERSION_NAMES.put(99, "pre_converter"); -+ -+ VERSION_LIST = new IntArrayList(new IntRBTreeSet(VERSION_NAMES.keySet())); -+ -+ DATA_VERSION_LIST = new LongArrayList(); -+ for (final int version : VERSION_LIST) { -+ DATA_VERSION_LIST.add(DataConverter.encodeVersions(version, 0)); -+ -+ final IntArrayList subVersions = SUBVERSIONS.get(version); -+ if (subVersions == null) { -+ continue; -+ } -+ -+ for (final int step : subVersions) { -+ DATA_VERSION_LIST.add(DataConverter.encodeVersions(version, step)); -+ } -+ } -+ -+ DATA_VERSION_LIST.sort(Comparator.naturalOrder()); -+ } -+ -+ private static void registerSubVersion(final int version, final int step) { -+ if (DATA_VERSION_LIST != null) { -+ throw new IllegalStateException("Added too late!"); -+ } -+ SUBVERSIONS.computeIfAbsent(version, (final int keyInMap) -> { -+ return new IntArrayList(); -+ }).add(step); -+ } -+ -+ private static void registerBreakpoint(final int version) { -+ registerBreakpoint(version, 0); -+ } -+ -+ private static void registerBreakpoint(final int version, final int step) { -+ BREAKPOINTS.add(DataConverter.encodeVersions(version, step)); -+ } -+ -+ // returns only versions that have dataconverters -+ public static boolean hasDataConverters(final int version) { -+ return DATACONVERTER_VERSIONS.contains(version); -+ } -+ -+ public String getVersionName(final int version) { -+ return VERSION_NAMES.get(version); -+ } -+ -+ public boolean isRegisteredVersion(final int version) { -+ return VERSION_NAMES.containsKey(version); -+ } -+ -+ public static IntArrayList getVersionList() { -+ return VERSION_LIST; -+ } -+ -+ public static LongArrayList getDataVersionList() { -+ return DATA_VERSION_LIST; -+ } -+ -+ public static int getMaxVersion() { -+ return VERSION_LIST.getInt(VERSION_LIST.size() - 1); -+ } -+ -+ public static LongArrayList getBreakpoints() { -+ return BREAKPOINTS; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersions.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersions.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6b954f25089aa8bb66359280d4aca596e3f8530f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersions.java -@@ -0,0 +1,366 @@ -+package ca.spottedleaf.dataconverter.minecraft; -+ -+@SuppressWarnings("unused") -+public final class MCVersions { -+ -+ /* https://minecraft.fandom.com/wiki/Data_version */ -+ -+ public static final int V15W32A = 100; -+ public static final int V15W32B = 103; -+ public static final int V15W32C = 104; -+ public static final int V15W33A = 111; -+ public static final int V15W33B = 111; -+ public static final int V15W33C = 112; -+ public static final int V15W34A = 114; -+ public static final int V15W34B = 115; -+ public static final int V15W34C = 116; -+ public static final int V15W34D = 117; -+ public static final int V15W35A = 118; -+ public static final int V15W35B = 119; -+ public static final int V15W35C = 120; -+ public static final int V15W35D = 121; -+ public static final int V15W35E = 122; -+ public static final int V15W36A = 123; -+ public static final int V15W36B = 124; -+ public static final int V15W36C = 125; -+ public static final int V15W36D = 126; -+ public static final int V15W37A = 127; -+ public static final int V15W38A = 128; -+ public static final int V15W38B = 129; -+ public static final int V15W39A = 130; -+ public static final int V15W39B = 131; -+ public static final int V15W39C = 132; -+ public static final int V15W40A = 133; -+ public static final int V15W40B = 134; -+ public static final int V15W41A = 136; -+ public static final int V15W41B = 137; -+ public static final int V15W42A = 138; -+ public static final int V15W43A = 139; -+ public static final int V15W43B = 140; -+ public static final int V15W43C = 141; -+ public static final int V15W44A = 142; -+ public static final int V15W44B = 143; -+ public static final int V15W45A = 145; -+ public static final int V15W46A = 146; -+ public static final int V15W47A = 148; -+ public static final int V15W47B = 149; -+ public static final int V15W47C = 150; -+ public static final int V15W49A = 151; -+ public static final int V15W49B = 152; -+ public static final int V15W50A = 153; -+ public static final int V15W51A = 154; -+ public static final int V15W51B = 155; -+ public static final int V16W02A = 156; -+ public static final int V16W03A = 157; -+ public static final int V16W04A = 158; -+ public static final int V16W05A = 159; -+ public static final int V16W05B = 160; -+ public static final int V16W06A = 161; -+ public static final int V16W07A = 162; -+ public static final int V16W07B = 163; -+ public static final int V1_9_PRE1 = 164; -+ public static final int V1_9_PRE2 = 165; -+ public static final int V1_9_PRE3 = 167; -+ public static final int V1_9_PRE4 = 168; -+ public static final int V1_9 = 169; -+ public static final int V1_9_1_PRE1 = 170; -+ public static final int V1_9_1_PRE2 = 171; -+ public static final int V1_9_1_PRE3 = 172; -+ public static final int V1_9_1 = 175; -+ public static final int V1_9_2 = 176; -+ public static final int V16W14A = 177; -+ public static final int V16W15A = 178; -+ public static final int V16W15B = 179; -+ public static final int V1_9_3_PRE1 = 180; -+ public static final int V1_9_3_PRE2 = 181; -+ public static final int V1_9_3_PRE3 = 182; -+ public static final int V1_9_3 = 183; -+ public static final int V1_9_4 = 184; -+ public static final int V16W20A = 501; -+ public static final int V16W21A = 503; -+ public static final int V16W21B = 504; -+ public static final int V1_10_PRE1 = 506; -+ public static final int V1_10_PRE2 = 507; -+ public static final int V1_10 = 510; -+ public static final int V1_10_1 = 511; -+ public static final int V1_10_2 = 512; -+ public static final int V16W32A = 800; -+ public static final int V16W32B = 801; -+ public static final int V16W33A = 802; -+ public static final int V16W35A = 803; -+ public static final int V16W36A = 805; -+ public static final int V16W38A = 807; -+ public static final int V16W39A = 809; -+ public static final int V16W39B = 811; -+ public static final int V16W39C = 812; -+ public static final int V16W40A = 813; -+ public static final int V16W41A = 814; -+ public static final int V16W42A = 815; -+ public static final int V16W43A = 816; -+ public static final int V16W44A = 817; -+ public static final int V1_11_PRE1 = 818; -+ public static final int V1_11 = 819; -+ public static final int V16W50A = 920; -+ public static final int V1_11_1 = 921; -+ public static final int V1_11_2 = 922; -+ public static final int V17W06A = 1022; -+ public static final int V17W13A = 1122; -+ public static final int V17W13B = 1123; -+ public static final int V17W14A = 1124; -+ public static final int V17W15A = 1125; -+ public static final int V17W16A = 1126; -+ public static final int V17W16B = 1127; -+ public static final int V17W17A = 1128; -+ public static final int V17W17B = 1129; -+ public static final int V17W18A = 1130; -+ public static final int V17W18B = 1131; -+ public static final int V1_12_PRE1 = 1132; -+ public static final int V1_12_PRE2 = 1133; -+ public static final int V1_12_PRE3 = 1134; -+ public static final int V1_12_PRE4 = 1135; -+ public static final int V1_12_PRE5 = 1136; -+ public static final int V1_12_PRE6 = 1137; -+ public static final int V1_12_PRE7 = 1138; -+ public static final int V1_12 = 1139; -+ public static final int V17W31A = 1239; -+ public static final int V1_12_1_PRE1 = 1240; -+ public static final int V1_12_1 = 1241; -+ public static final int V1_12_2_PRE1 = 1341; -+ public static final int V1_12_2_PRE2 = 1342; -+ public static final int V1_12_2 = 1343; -+ public static final int V17W43A = 1444; -+ public static final int V17W43B = 1445; -+ public static final int V17W45A = 1447; -+ public static final int V17W45B = 1448; -+ public static final int V17W46A = 1449; -+ public static final int V17W47A = 1451; -+ public static final int V17W47B = 1452; -+ public static final int V17W48A = 1453; -+ public static final int V17W49A = 1454; -+ public static final int V17W49B = 1455; -+ public static final int V17W50A = 1457; -+ public static final int V18W01A = 1459; -+ public static final int V18W02A = 1461; -+ public static final int V18W03A = 1462; -+ public static final int V18W03B = 1463; -+ public static final int V18W05A = 1464; -+ public static final int V18W06A = 1466; -+ public static final int V18W07A = 1467; -+ public static final int V18W07B = 1468; -+ public static final int V18W07C = 1469; -+ public static final int V18W08A = 1470; -+ public static final int V18W08B = 1471; -+ public static final int V18W09A = 1472; -+ public static final int V18W10A = 1473; -+ public static final int V18W10B = 1474; -+ public static final int V18W10C = 1476; -+ public static final int V18W10D = 1477; -+ public static final int V18W11A = 1478; -+ public static final int V18W14A = 1479; -+ public static final int V18W14B = 1481; -+ public static final int V18W15A = 1482; -+ public static final int V18W16A = 1483; -+ public static final int V18W19A = 1484; -+ public static final int V18W19B = 1485; -+ public static final int V18W20A = 1489; -+ public static final int V18W20B = 1491; -+ public static final int V18W20C = 1493; -+ public static final int V18W21A = 1495; -+ public static final int V18W21B = 1496; -+ public static final int V18W22A = 1497; -+ public static final int V18W22B = 1498; -+ public static final int V18W22C = 1499; -+ public static final int V1_13_PRE1 = 1501; -+ public static final int V1_13_PRE2 = 1502; -+ public static final int V1_13_PRE3 = 1503; -+ public static final int V1_13_PRE4 = 1504; -+ public static final int V1_13_PRE5 = 1511; -+ public static final int V1_13_PRE6 = 1512; -+ public static final int V1_13_PRE7 = 1513; -+ public static final int V1_13_PRE8 = 1516; -+ public static final int V1_13_PRE9 = 1517; -+ public static final int V1_13_PRE10 = 1518; -+ public static final int V1_13 = 1519; -+ public static final int V18W30A = 1620; -+ public static final int V18W30B = 1621; -+ public static final int V18W31A = 1622; -+ public static final int V18W32A = 1623; -+ public static final int V18W33A = 1625; -+ public static final int V1_13_1_PRE1 = 1626; -+ public static final int V1_13_1_PRE2 = 1627; -+ public static final int V1_13_1 = 1628; -+ public static final int V1_13_2_PRE1 = 1629; -+ public static final int V1_13_2_PRE2 = 1630; -+ public static final int V1_13_2 = 1631; -+ public static final int V18W43A = 1901; -+ public static final int V18W43B = 1902; -+ public static final int V18W43C = 1903; -+ public static final int V18W44A = 1907; -+ public static final int V18W45A = 1908; -+ public static final int V18W46A = 1910; -+ public static final int V18W47A = 1912; -+ public static final int V18W47B = 1913; -+ public static final int V18W48A = 1914; -+ public static final int V18W48B = 1915; -+ public static final int V18W49A = 1916; -+ public static final int V18W50A = 1919; -+ public static final int V19W02A = 1921; -+ public static final int V19W03A = 1922; -+ public static final int V19W03B = 1923; -+ public static final int V19W03C = 1924; -+ public static final int V19W04A = 1926; -+ public static final int V19W04B = 1927; -+ public static final int V19W05A = 1930; -+ public static final int V19W06A = 1931; -+ public static final int V19W07A = 1932; -+ public static final int V19W08A = 1933; -+ public static final int V19W08B = 1934; -+ public static final int V19W09A = 1935; -+ public static final int V19W11A = 1937; -+ public static final int V19W11B = 1938; -+ public static final int V19W12A = 1940; -+ public static final int V19W12B = 1941; -+ public static final int V19W13A = 1942; -+ public static final int V19W13B = 1943; -+ public static final int V19W14A = 1944; -+ public static final int V19W14B = 1945; -+ public static final int V1_14_PRE1 = 1947; -+ public static final int V1_14_PRE2 = 1948; -+ public static final int V1_14_PRE3 = 1949; -+ public static final int V1_14_PRE4 = 1950; -+ public static final int V1_14_PRE5 = 1951; -+ public static final int V1_14 = 1952; -+ public static final int V1_14_1_PRE1 = 1955; -+ public static final int V1_14_1_PRE2 = 1956; -+ public static final int V1_14_1 = 1957; -+ public static final int V1_14_2_PRE1 = 1958; -+ public static final int V1_14_2_PRE2 = 1959; -+ public static final int V1_14_2_PRE3 = 1960; -+ public static final int V1_14_2_PRE4 = 1962; -+ public static final int V1_14_2 = 1963; -+ public static final int V1_14_3_PRE1 = 1964; -+ public static final int V1_14_3_PRE2 = 1965; -+ public static final int V1_14_3_PRE3 = 1966; -+ public static final int V1_14_3_PRE4 = 1967; -+ public static final int V1_14_3 = 1968; -+ public static final int V1_14_4_PRE1 = 1969; -+ public static final int V1_14_4_PRE2 = 1970; -+ public static final int V1_14_4_PRE3 = 1971; -+ public static final int V1_14_4_PRE4 = 1972; -+ public static final int V1_14_4_PRE5 = 1973; -+ public static final int V1_14_4_PRE6 = 1974; -+ public static final int V1_14_4_PRE7 = 1975; -+ public static final int V1_14_4 = 1976; -+ public static final int V19W34A = 2200; -+ public static final int V19W35A = 2201; -+ public static final int V19W36A = 2203; -+ public static final int V19W37A = 2204; -+ public static final int V19W38A = 2205; -+ public static final int V19W38B = 2206; -+ public static final int V19W39A = 2207; -+ public static final int V19W40A = 2208; -+ public static final int V19W41A = 2210; -+ public static final int V19W42A = 2212; -+ public static final int V19W44A = 2213; -+ public static final int V19W45A = 2214; -+ public static final int V19W45B = 2215; -+ public static final int V19W46A = 2216; -+ public static final int V19W46B = 2217; -+ public static final int V1_15_PRE1 = 2218; -+ public static final int V1_15_PRE2 = 2219; -+ public static final int V1_15_PRE3 = 2220; -+ public static final int V1_15_PRE4 = 2221; -+ public static final int V1_15_PRE5 = 2222; -+ public static final int V1_15_PRE6 = 2223; -+ public static final int V1_15_PRE7 = 2224; -+ public static final int V1_15 = 2225; -+ public static final int V1_15_1_PRE1 = 2226; -+ public static final int V1_15_1 = 2227; -+ public static final int V1_15_2_PRE1 = 2228; -+ public static final int V1_15_2_PRE2 = 2229; -+ public static final int V1_15_2 = 2230; -+ public static final int V20W06A = 2504; -+ public static final int V20W07A = 2506; -+ public static final int V20W08A = 2507; -+ public static final int V20W09A = 2510; -+ public static final int V20W10A = 2512; -+ public static final int V20W11A = 2513; -+ public static final int V20W12A = 2515; -+ public static final int V20W13A = 2520; -+ public static final int V20W13B = 2521; -+ public static final int V20W14A = 2524; -+ public static final int V20W15A = 2525; -+ public static final int V20W16A = 2526; -+ public static final int V20W17A = 2529; -+ public static final int V20W18A = 2532; -+ public static final int V20W19A = 2534; -+ public static final int V20W20A = 2536; -+ public static final int V20W20B = 2537; -+ public static final int V20W21A = 2554; -+ public static final int V20W22A = 2555; -+ public static final int V1_16_PRE1 = 2556; -+ public static final int V1_16_PRE2 = 2557; -+ public static final int V1_16_PRE3 = 2559; -+ public static final int V1_16_PRE4 = 2560; -+ public static final int V1_16_PRE5 = 2561; -+ public static final int V1_16_PRE6 = 2562; -+ public static final int V1_16_PRE7 = 2563; -+ public static final int V1_16_PRE8 = 2564; -+ public static final int V1_16_RC1 = 2565; -+ public static final int V1_16 = 2566; -+ public static final int V1_16_1 = 2567; -+ public static final int V20W27A = 2569; -+ public static final int V20W28A = 2570; -+ public static final int V20W29A = 2571; -+ public static final int V20W30A = 2572; -+ public static final int V1_16_2_PRE1 = 2573; -+ public static final int V1_16_2_PRE2 = 2574; -+ public static final int V1_16_2_PRE3 = 2575; -+ public static final int V1_16_2_RC1 = 2576; -+ public static final int V1_16_2_RC2 = 2577; -+ public static final int V1_16_2 = 2578; -+ public static final int V1_16_3_RC1 = 2579; -+ public static final int V1_16_3 = 2580; -+ public static final int V1_16_4_PRE1 = 2581; -+ public static final int V1_16_4_PRE2 = 2582; -+ public static final int V1_16_4_RC1 = 2583; -+ public static final int V1_16_4 = 2584; -+ public static final int V1_16_5_RC1 = 2585; -+ public static final int V1_16_5 = 2586; -+ public static final int V20W45A = 2681; -+ public static final int V20W46A = 2682; -+ public static final int V20W48A = 2683; -+ public static final int V20W49A = 2685; -+ public static final int V20W51A = 2687; -+ public static final int V21W03A = 2689; -+ public static final int V21W05A = 2690; -+ public static final int V21W05B = 2692; -+ public static final int V21W06A = 2694; -+ public static final int V21W07A = 2695; -+ public static final int V21W08A = 2697; -+ public static final int V21W08B = 2698; -+ public static final int V21W10A = 2699; -+ public static final int V21W11A = 2703; -+ public static final int V21W13A = 2705; -+ public static final int V21W14A = 2706; -+ public static final int V21W15A = 2709; -+ public static final int V21W16A = 2711; -+ public static final int V21W17A = 2712; -+ public static final int V21W18A = 2713; -+ public static final int V21W19A = 2714; -+ public static final int V21W20A = 2715; -+ public static final int V1_17_PRE1 = 2716; -+ public static final int V1_17_PRE2 = 2718; -+ public static final int V1_17_PRE3 = 2719; -+ public static final int V1_17_PRE4 = 2720; -+ public static final int V1_17_PRE5 = 2721; -+ public static final int V1_17_RC1 = 2722; -+ public static final int V1_17_RC2 = 2723; -+ public static final int V1_17 = 2724; -+ public static final int V1_17_1_PRE1 = 2725; -+ public static final int V1_17_1_PRE2 = 2726; -+ public static final int V1_17_1_PRE3 = 2727; -+ public static final int V1_17_1_RC1 = 2728; -+ public static final int V1_17_1_RC2 = 2729; -+ public static final int V1_17_1 = 2730; -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a30b6648bbd384dc21a3dd90e0896542c227daab ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java -@@ -0,0 +1,35 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.advancements; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.ArrayList; -+import java.util.function.Function; -+ -+public final class ConverterAbstractAdvancementsRename { -+ -+ private ConverterAbstractAdvancementsRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ MCTypeRegistry.ADVANCEMENTS.addStructureConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ for (final String key : new ArrayList<>(data.keys())) { -+ final String updated = renamer.apply(key); -+ if (updated != null) { -+ final Object value = data.getGeneric(key); -+ data.remove(key); -+ data.setGeneric(updated, value); -+ } -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/blockname/ConverterAbstractBlockRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/blockname/ConverterAbstractBlockRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..53fd133647aecb0390d78300f59f616a83445433 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/blockname/ConverterAbstractBlockRename.java -@@ -0,0 +1,74 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.blockname; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.function.Function; -+ -+public final class ConverterAbstractBlockRename { -+ -+ private ConverterAbstractBlockRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ ConverterAbstractStringValueTypeRename.register(version, subVersion, MCTypeRegistry.BLOCK_NAME, renamer); -+ MCTypeRegistry.BLOCK_STATE.addStructureConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String name = data.getString("Name"); -+ if (name != null) { -+ final String converted = renamer.apply(name); -+ if (converted != null) { -+ data.setString("Name", converted); -+ } -+ } -+ return null; -+ } -+ }); -+ } -+ -+ public static void registerAndFixJigsaw(final int version, final Function renamer) { -+ registerAndFixJigsaw(version, 0, renamer); -+ } -+ -+ public static void registerAndFixJigsaw(final int version, final int subVersion, final Function renamer) { -+ register(version, subVersion, renamer); -+ // TODO check on update, minecraft:jigsaw can change -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:jigsaw", new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String finalState = data.getString("final_state"); -+ if (finalState == null || finalState.isEmpty()) { -+ return null; -+ } -+ -+ final int nbtStart1 = finalState.indexOf('['); -+ final int nbtStart2 = finalState.indexOf('{'); -+ int stateNameEnd = finalState.length(); -+ if (nbtStart1 > 0) { -+ stateNameEnd = Math.min(stateNameEnd, nbtStart1); -+ } -+ -+ if (nbtStart2 > 0) { -+ stateNameEnd = Math.min(stateNameEnd, nbtStart2); -+ } -+ -+ final String blockStateName = finalState.substring(0, stateNameEnd); -+ final String converted = renamer.apply(blockStateName); -+ if (converted == null) { -+ return null; -+ } -+ -+ final String convertedState = converted.concat(finalState.substring(stateNameEnd)); -+ data.setString("final_state", convertedState); -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/chunk/ConverterFlattenChunk.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/chunk/ConverterFlattenChunk.java -new file mode 100644 -index 0000000000000000000000000000000000000000..64226434a38dc5e4a9103c61aa8f9c20bce9550c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/chunk/ConverterFlattenChunk.java -@@ -0,0 +1,1016 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.chunk; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperBlockFlatteningV1450; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperItemNameV102; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.mojang.datafixers.DataFixUtils; -+import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; -+import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -+import it.unimi.dsi.fastutil.ints.IntArrayList; -+import it.unimi.dsi.fastutil.ints.IntIterator; -+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; -+import net.minecraft.util.datafix.PackedBitStorage; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import java.util.Arrays; -+import java.util.BitSet; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.Map; -+import java.util.Objects; -+ -+import static it.unimi.dsi.fastutil.HashCommon.arraySize; -+ -+public final class ConverterFlattenChunk extends DataConverter, MapType> { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ static final BitSet VIRTUAL_SET = new BitSet(256); -+ static final BitSet IDS_NEEDING_FIX_SET = new BitSet(256); -+ -+ static { -+ IDS_NEEDING_FIX_SET.set(2); -+ IDS_NEEDING_FIX_SET.set(3); -+ IDS_NEEDING_FIX_SET.set(110); -+ IDS_NEEDING_FIX_SET.set(140); -+ IDS_NEEDING_FIX_SET.set(144); -+ IDS_NEEDING_FIX_SET.set(25); -+ IDS_NEEDING_FIX_SET.set(86); -+ IDS_NEEDING_FIX_SET.set(26); -+ IDS_NEEDING_FIX_SET.set(176); -+ IDS_NEEDING_FIX_SET.set(177); -+ IDS_NEEDING_FIX_SET.set(175); -+ IDS_NEEDING_FIX_SET.set(64); -+ IDS_NEEDING_FIX_SET.set(71); -+ IDS_NEEDING_FIX_SET.set(193); -+ IDS_NEEDING_FIX_SET.set(194); -+ IDS_NEEDING_FIX_SET.set(195); -+ IDS_NEEDING_FIX_SET.set(196); -+ IDS_NEEDING_FIX_SET.set(197); -+ -+ VIRTUAL_SET.set(54); -+ VIRTUAL_SET.set(146); -+ VIRTUAL_SET.set(25); -+ VIRTUAL_SET.set(26); -+ VIRTUAL_SET.set(51); -+ VIRTUAL_SET.set(53); -+ VIRTUAL_SET.set(67); -+ VIRTUAL_SET.set(108); -+ VIRTUAL_SET.set(109); -+ VIRTUAL_SET.set(114); -+ VIRTUAL_SET.set(128); -+ VIRTUAL_SET.set(134); -+ VIRTUAL_SET.set(135); -+ VIRTUAL_SET.set(136); -+ VIRTUAL_SET.set(156); -+ VIRTUAL_SET.set(163); -+ VIRTUAL_SET.set(164); -+ VIRTUAL_SET.set(180); -+ VIRTUAL_SET.set(203); -+ VIRTUAL_SET.set(55); -+ VIRTUAL_SET.set(85); -+ VIRTUAL_SET.set(113); -+ VIRTUAL_SET.set(188); -+ VIRTUAL_SET.set(189); -+ VIRTUAL_SET.set(190); -+ VIRTUAL_SET.set(191); -+ VIRTUAL_SET.set(192); -+ VIRTUAL_SET.set(93); -+ VIRTUAL_SET.set(94); -+ VIRTUAL_SET.set(101); -+ VIRTUAL_SET.set(102); -+ VIRTUAL_SET.set(160); -+ VIRTUAL_SET.set(106); -+ VIRTUAL_SET.set(107); -+ VIRTUAL_SET.set(183); -+ VIRTUAL_SET.set(184); -+ VIRTUAL_SET.set(185); -+ VIRTUAL_SET.set(186); -+ VIRTUAL_SET.set(187); -+ VIRTUAL_SET.set(132); -+ VIRTUAL_SET.set(139); -+ VIRTUAL_SET.set(199); -+ } -+ -+ static final boolean[] VIRTUAL = toBooleanArray(VIRTUAL_SET); -+ static final boolean[] IDS_NEEDING_FIX = toBooleanArray(IDS_NEEDING_FIX_SET); -+ -+ private static boolean[] toBooleanArray(final BitSet set) { -+ final boolean[] ret = new boolean[4096]; -+ for (int i = 0; i < 4096; ++i) { -+ ret[i] = set.get(i); -+ } -+ -+ return ret; -+ } -+ -+ static final MapType PUMPKIN = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:pumpkin'}"); -+ static final MapType SNOWY_PODZOL = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:podzol',Properties:{snowy:'true'}}"); -+ static final MapType SNOWY_GRASS = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:grass_block',Properties:{snowy:'true'}}"); -+ static final MapType SNOWY_MYCELIUM = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:mycelium',Properties:{snowy:'true'}}"); -+ static final MapType UPPER_SUNFLOWER = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:sunflower',Properties:{half:'upper'}}"); -+ static final MapType UPPER_LILAC = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:lilac',Properties:{half:'upper'}}"); -+ static final MapType UPPER_TALL_GRASS = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:tall_grass',Properties:{half:'upper'}}"); -+ static final MapType UPPER_LARGE_FERN = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:large_fern',Properties:{half:'upper'}}"); -+ static final MapType UPPER_ROSE_BUSH = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:rose_bush',Properties:{half:'upper'}}"); -+ static final MapType UPPER_PEONY = HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:peony',Properties:{half:'upper'}}"); -+ -+ static final Map> FLOWER_POT_MAP = new HashMap<>(); -+ static { -+ FLOWER_POT_MAP.put("minecraft:air0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:flower_pot'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_poppy'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower1", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_blue_orchid'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower2", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_allium'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower3", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_azure_bluet'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower4", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_red_tulip'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower5", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_orange_tulip'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower6", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_white_tulip'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower7", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_pink_tulip'}")); -+ FLOWER_POT_MAP.put("minecraft:red_flower8", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_oxeye_daisy'}")); -+ FLOWER_POT_MAP.put("minecraft:yellow_flower0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_dandelion'}")); -+ FLOWER_POT_MAP.put("minecraft:sapling0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_oak_sapling'}")); -+ FLOWER_POT_MAP.put("minecraft:sapling1", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_spruce_sapling'}")); -+ FLOWER_POT_MAP.put("minecraft:sapling2", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_birch_sapling'}")); -+ FLOWER_POT_MAP.put("minecraft:sapling3", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_jungle_sapling'}")); -+ FLOWER_POT_MAP.put("minecraft:sapling4", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_acacia_sapling'}")); -+ FLOWER_POT_MAP.put("minecraft:sapling5", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_dark_oak_sapling'}")); -+ FLOWER_POT_MAP.put("minecraft:red_mushroom0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_red_mushroom'}")); -+ FLOWER_POT_MAP.put("minecraft:brown_mushroom0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_brown_mushroom'}")); -+ FLOWER_POT_MAP.put("minecraft:deadbush0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_dead_bush'}")); -+ FLOWER_POT_MAP.put("minecraft:tallgrass2", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_fern'}")); -+ FLOWER_POT_MAP.put("minecraft:cactus0", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:potted_cactus'}")); // we change default to empty -+ } -+ -+ static final Map> SKULL_MAP = new HashMap<>(); -+ static { -+ mapSkull(SKULL_MAP, 0, "skeleton", "skull"); -+ mapSkull(SKULL_MAP, 1, "wither_skeleton", "skull"); -+ mapSkull(SKULL_MAP, 2, "zombie", "head"); -+ mapSkull(SKULL_MAP, 3, "player", "head"); -+ mapSkull(SKULL_MAP, 4, "creeper", "head"); -+ mapSkull(SKULL_MAP, 5, "dragon", "head"); -+ }; -+ -+ private static void mapSkull(final Map> into, final int oldId, final String newId, final String skullType) { -+ into.put(oldId + "north", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + newId + "_wall_" + skullType + "',Properties:{facing:'north'}}")); -+ into.put(oldId + "east", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + newId + "_wall_" + skullType + "',Properties:{facing:'east'}}")); -+ into.put(oldId + "south", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + newId + "_wall_" + skullType + "',Properties:{facing:'south'}}")); -+ into.put(oldId + "west", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + newId + "_wall_" + skullType + "',Properties:{facing:'west'}}")); -+ -+ for (int rotation = 0; rotation < 16; ++rotation) { -+ into.put(oldId + "" + rotation, -+ HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + newId + "_" + skullType + "',Properties:{rotation:'" + rotation + "'}}")); -+ } -+ } -+ -+ static final Map> DOOR_MAP = new HashMap<>(); -+ static { -+ mapDoor(DOOR_MAP, "oak_door", 1024); -+ mapDoor(DOOR_MAP, "iron_door", 1136); -+ mapDoor(DOOR_MAP, "spruce_door", 3088); -+ mapDoor(DOOR_MAP, "birch_door", 3104); -+ mapDoor(DOOR_MAP, "jungle_door", 3120); -+ mapDoor(DOOR_MAP, "acacia_door", 3136); -+ mapDoor(DOOR_MAP, "dark_oak_door", 3152); -+ }; -+ -+ private static void mapDoor(final Map> into, final String type, final int oldId) { -+ into.put("minecraft:" + type + "eastlowerleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "eastlowerleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "eastlowerlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "eastlowerlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "eastlowerrightfalsefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId))); -+ into.put("minecraft:" + type + "eastlowerrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "eastlowerrighttruefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 4))); -+ into.put("minecraft:" + type + "eastlowerrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "eastupperleftfalsefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 8))); -+ into.put("minecraft:" + type + "eastupperleftfalsetrue", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 10))); -+ into.put("minecraft:" + type + "eastupperlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "eastupperlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "eastupperrightfalsefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 9))); -+ into.put("minecraft:" + type + "eastupperrightfalsetrue", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 11))); -+ into.put("minecraft:" + type + "eastupperrighttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "eastupperrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "northlowerleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "northlowerleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "northlowerlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "northlowerlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "northlowerrightfalsefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 3))); -+ into.put("minecraft:" + type + "northlowerrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "northlowerrighttruefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 7))); -+ into.put("minecraft:" + type + "northlowerrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "northupperleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "northupperleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "northupperlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "northupperlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "northupperrightfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "northupperrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "northupperrighttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "northupperrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "southlowerleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "southlowerleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "southlowerlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "southlowerlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "southlowerrightfalsefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 1))); -+ into.put("minecraft:" + type + "southlowerrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "southlowerrighttruefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 5))); -+ into.put("minecraft:" + type + "southlowerrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "southupperleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "southupperleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "southupperlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "southupperlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "southupperrightfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "southupperrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "southupperrighttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "southupperrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "westlowerleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "westlowerleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "westlowerlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "westlowerlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "westlowerrightfalsefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 2))); -+ into.put("minecraft:" + type + "westlowerrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "westlowerrighttruefalse", Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(oldId + 6))); -+ into.put("minecraft:" + type + "westlowerrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "westupperleftfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "westupperleftfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "westupperlefttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "westupperlefttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}")); -+ into.put("minecraft:" + type + "westupperrightfalsefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}")); -+ into.put("minecraft:" + type + "westupperrightfalsetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}")); -+ into.put("minecraft:" + type + "westupperrighttruefalse", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}")); -+ into.put("minecraft:" + type + "westupperrighttruetrue", HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + type + "',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}")); -+ } -+ -+ static final Map> NOTE_BLOCK_MAP = new HashMap<>(); -+ static { -+ for(int note = 0; note < 26; ++note) { -+ NOTE_BLOCK_MAP.put("true" + note, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:note_block',Properties:{powered:'true',note:'" + note + "'}}")); -+ NOTE_BLOCK_MAP.put("false" + note, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:note_block',Properties:{powered:'false',note:'" + note + "'}}")); -+ } -+ } -+ -+ static final Int2ObjectOpenHashMap DYE_COLOR_MAP = new Int2ObjectOpenHashMap<>(); -+ static { -+ DYE_COLOR_MAP.put(0, "white"); -+ DYE_COLOR_MAP.put(1, "orange"); -+ DYE_COLOR_MAP.put(2, "magenta"); -+ DYE_COLOR_MAP.put(3, "light_blue"); -+ DYE_COLOR_MAP.put(4, "yellow"); -+ DYE_COLOR_MAP.put(5, "lime"); -+ DYE_COLOR_MAP.put(6, "pink"); -+ DYE_COLOR_MAP.put(7, "gray"); -+ DYE_COLOR_MAP.put(8, "light_gray"); -+ DYE_COLOR_MAP.put(9, "cyan"); -+ DYE_COLOR_MAP.put(10, "purple"); -+ DYE_COLOR_MAP.put(11, "blue"); -+ DYE_COLOR_MAP.put(12, "brown"); -+ DYE_COLOR_MAP.put(13, "green"); -+ DYE_COLOR_MAP.put(14, "red"); -+ DYE_COLOR_MAP.put(15, "black"); -+ } -+ -+ static final Map> BED_BLOCK_MAP = new HashMap<>(); -+ -+ static { -+ for (final Int2ObjectMap.Entry entry : DYE_COLOR_MAP.int2ObjectEntrySet()) { -+ if (!Objects.equals(entry.getValue(), "red")) { -+ addBeds(BED_BLOCK_MAP, entry.getIntKey(), entry.getValue()); -+ } -+ } -+ } -+ -+ private static void addBeds(final Map> into, final int colourId, final String colourName) { -+ into.put("southfalsefoot" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'south',occupied:'false',part:'foot'}}")); -+ into.put("westfalsefoot" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'west',occupied:'false',part:'foot'}}")); -+ into.put("northfalsefoot" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'north',occupied:'false',part:'foot'}}")); -+ into.put("eastfalsefoot" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'east',occupied:'false',part:'foot'}}")); -+ into.put("southfalsehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'south',occupied:'false',part:'head'}}")); -+ into.put("westfalsehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'west',occupied:'false',part:'head'}}")); -+ into.put("northfalsehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'north',occupied:'false',part:'head'}}")); -+ into.put("eastfalsehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'east',occupied:'false',part:'head'}}")); -+ into.put("southtruehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'south',occupied:'true',part:'head'}}")); -+ into.put("westtruehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'west',occupied:'true',part:'head'}}")); -+ into.put("northtruehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'north',occupied:'true',part:'head'}}")); -+ into.put("easttruehead" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_bed',Properties:{facing:'east',occupied:'true',part:'head'}}")); -+ } -+ -+ static final Map> BANNER_BLOCK_MAP = new HashMap<>(); -+ -+ static { -+ for (final Int2ObjectMap.Entry entry : DYE_COLOR_MAP.int2ObjectEntrySet()) { -+ if (!Objects.equals(entry.getValue(), "white")) { -+ addBanners(BANNER_BLOCK_MAP, 15 - entry.getIntKey(), entry.getValue()); -+ } -+ } -+ } -+ -+ private static void addBanners(final Map> into, final int colourId, final String colourName) { -+ for(int rotation = 0; rotation < 16; ++rotation) { -+ into.put("" + rotation + "_" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_banner',Properties:{rotation:'" + rotation + "'}}")); -+ } -+ -+ into.put("north_" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_wall_banner',Properties:{facing:'north'}}")); -+ into.put("south_" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_wall_banner',Properties:{facing:'south'}}")); -+ into.put("west_" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_wall_banner',Properties:{facing:'west'}}")); -+ into.put("east_" + colourId, HelperBlockFlatteningV1450.parseTag("{Name:'minecraft:" + colourName + "_wall_banner',Properties:{facing:'east'}}")); -+ } -+ -+ static final MapType AIR = Objects.requireNonNull(HelperBlockFlatteningV1450.getNBTForId(0)); -+ -+ public ConverterFlattenChunk() { -+ super(MCVersions.V17W47A, 1); -+ } -+ -+ static String getName(final MapType blockState) { -+ return blockState.getString("Name"); -+ } -+ -+ static String getProperty(final MapType blockState, final String propertyName) { -+ final MapType properties = blockState.getMap("Properties"); -+ if (properties == null) { -+ return ""; -+ } -+ -+ return properties.getString(propertyName, ""); -+ } -+ -+ static int getSideMask(final boolean noLeft, final boolean noRight, final boolean noBack, final boolean noForward) { -+ if (noBack) { -+ if (noRight) { -+ return 2; -+ } else if (noLeft) { -+ return 128; -+ } else { -+ return 1; -+ } -+ } else if (noForward) { -+ if (noLeft) { -+ return 32; -+ } else if (noRight) { -+ return 8; -+ } else { -+ return 16; -+ } -+ } else if (noRight) { -+ return 4; -+ } else if (noLeft) { -+ return 64; -+ } else { -+ return 0; -+ } -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ if (!level.hasKey("Sections", ObjectType.LIST)) { -+ return null; -+ } -+ -+ data.setMap("Level", new UpgradeChunk(level).writeBackToLevel()); -+ -+ return null; -+ } -+ -+ static enum Direction { -+ DOWN(AxisDirection.NEGATIVE, Axis.Y), -+ UP(AxisDirection.POSITIVE, Axis.Y), -+ NORTH(AxisDirection.NEGATIVE, Axis.Z), -+ SOUTH(AxisDirection.POSITIVE, Axis.Z), -+ WEST(AxisDirection.NEGATIVE, Axis.X), -+ EAST(AxisDirection.POSITIVE, Axis.X); -+ -+ private final Axis axis; -+ private final AxisDirection axisDirection; -+ -+ private Direction(final AxisDirection axisDirection, final Axis axis) { -+ this.axis = axis; -+ this.axisDirection = axisDirection; -+ } -+ -+ public AxisDirection getAxisDirection() { -+ return this.axisDirection; -+ } -+ -+ public Axis getAxis() { -+ return this.axis; -+ } -+ -+ public static enum AxisDirection { -+ POSITIVE(1), -+ NEGATIVE(-1); -+ -+ private final int step; -+ -+ private AxisDirection(final int step) { -+ this.step = step; -+ } -+ -+ public int getStep() { -+ return this.step; -+ } -+ } -+ -+ public static enum Axis { -+ X, Y, Z; -+ } -+ } -+ -+ static class DataLayer { -+ private final byte[] data; -+ -+ public DataLayer() { -+ this.data = new byte[2048]; -+ } -+ -+ public DataLayer(final byte[] data) { -+ this.data = data; -+ if (data.length != 2048) { -+ throw new IllegalArgumentException("ChunkNibbleArrays should be 2048 bytes not: " + data.length); -+ } -+ } -+ -+ public static DataLayer getOrNull(final byte[] data) { -+ return data == null ? null : new DataLayer(data); -+ } -+ -+ public static DataLayer getOrCreate(final byte[] data) { -+ return data == null ? new DataLayer() : new DataLayer(data); -+ } -+ -+ public int get(final int index) { -+ final byte value = this.data[index >>> 1]; -+ -+ // if we are an even index, we want lower 4 bits -+ // if we are an odd index, we want upper 4 bits -+ return ((value >>> ((index & 1) << 2)) & 0xF); -+ } -+ -+ public int get(final int x, final int y, final int z) { -+ final int index = y << 8 | z << 4 | x; -+ final byte value = this.data[index >>> 1]; -+ -+ // if we are an even index, we want lower 4 bits -+ // if we are an odd index, we want upper 4 bits -+ return ((value >>> ((index & 1) << 2)) & 0xF); -+ } -+ } -+ -+ static final class UpgradeChunk { -+ int sides; -+ -+ final Section[] sections = new Section[16]; -+ final MapType level; -+ final int blockX; -+ final int blockZ; -+ final Int2ObjectLinkedOpenHashMap> tileEntities = new Int2ObjectLinkedOpenHashMap<>(16); -+ -+ public UpgradeChunk(final MapType level) { -+ this.level = level; -+ this.blockX = level.getInt("xPos") << 4; -+ this.blockZ = level.getInt("zPos") << 4; -+ -+ final ListType tileEntities = level.getList("TileEntities", ObjectType.MAP); -+ if (tileEntities != null) { -+ for (int i = 0, len = tileEntities.size(); i < len; ++i) { -+ final MapType tileEntity = tileEntities.getMap(i); -+ -+ final int x = (tileEntity.getInt("x") - this.blockX) & 15; -+ final int y = tileEntity.getInt("y"); -+ final int z = (tileEntity.getInt("z") - this.blockZ) & 15; -+ final int index = (y << 8) | (z << 4) | x; -+ if (this.tileEntities.put(index, tileEntity) != null) { -+ LOGGER.warn("In chunk: {}x{} found a duplicate block entity at position (ConverterFlattenChunk): [{}, {}, {}]", this.blockX, this.blockZ, x, y, z); -+ } -+ } -+ } -+ -+ final boolean convertedFromAlphaFormat = level.getBoolean("convertedFromAlphaFormat"); -+ final ListType sections = level.getList("Sections", ObjectType.MAP); -+ if (sections != null) { -+ for (int i = 0, len = sections.size(); i < len; ++i) { -+ final MapType sectionData = sections.getMap(i); -+ final Section section = new Section(sectionData); -+ -+ if (section.y < 0 || section.y > 15) { -+ LOGGER.warn("In chunk: {}x{} found an invalid chunk section y (ConverterFlattenChunk): {}", this.blockX, this.blockZ, section.y); -+ continue; -+ } -+ -+ if (this.sections[section.y] != null) { -+ LOGGER.warn("In chunk: {}x{} found a duplicate chunk section (ConverterFlattenChunk): {}", this.blockX, this.blockZ, section.y); -+ } -+ -+ this.sides = section.upgrade(this.sides); -+ this.sections[section.y] = section; -+ } -+ } -+ -+ for (final Section section : this.sections) { -+ if (section == null) { -+ continue; -+ } -+ -+ final int yIndex = section.y << (8 + 4); -+ -+ for (final Iterator> iterator = section.toFix.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) { -+ final Int2ObjectMap.Entry fixEntry = iterator.next(); -+ final IntIterator positionIterator = fixEntry.getValue().iterator(); -+ switch (fixEntry.getIntKey()) { -+ case 2: { // grass block -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType blockState = this.getBlock(position); -+ if (!"minecraft:grass_block".equals(getName(blockState))) { -+ continue; -+ } -+ -+ final String blockAbove = getName(getBlock(relative(position, Direction.UP))); -+ if ("minecraft:snow".equals(blockAbove) || "minecraft:snow_layer".equals(blockAbove)) { -+ this.setBlock(position, SNOWY_GRASS); -+ } -+ } -+ break; -+ } -+ case 3: { // dirt -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType blockState = this.getBlock(position); -+ if (!"minecraft:podzol".equals(getName(blockState))) { -+ continue; -+ } -+ -+ final String blockAbove = getName(getBlock(relative(position, Direction.UP))); -+ if ("minecraft:snow".equals(blockAbove) || "minecraft:snow_layer".equals(blockAbove)) { -+ this.setBlock(position, SNOWY_PODZOL); -+ } -+ } -+ break; -+ } -+ case 25: { // note block -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType tile = this.removeBlockEntity(position); -+ if (tile != null) { -+ final String state = Boolean.toString(tile.getBoolean("powered")) + (byte) Math.min(Math.max(tile.getInt("note"), 0), 24); -+ this.setBlock(position, NOTE_BLOCK_MAP.getOrDefault(state, NOTE_BLOCK_MAP.get("false0"))); -+ } -+ } -+ break; -+ } -+ case 26: { // bed -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType tile = this.getBlockEntity(position); -+ -+ if (tile == null) { -+ continue; -+ } -+ -+ final MapType blockState = this.getBlock(position); -+ -+ final int colour = tile.getInt("color"); -+ if (colour != 14 && colour >= 0 && colour < 16) { -+ final String state = getProperty(blockState, "facing") + getProperty(blockState, "occupied") + getProperty(blockState, "part") + colour; -+ -+ final MapType update = BED_BLOCK_MAP.get(state); -+ if (update != null) { -+ this.setBlock(position, update); -+ } -+ } -+ } -+ break; -+ } -+ case 64: // oak door -+ case 71: // iron door -+ case 193: // spruce door -+ case 194: // birch door -+ case 195: // jungle door -+ case 196: // acacia door -+ case 197: { // dark oak door -+ // aka the door updater -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType blockState = this.getBlock(position); -+ if (!getName(blockState).endsWith("_door")) { -+ continue; -+ } -+ -+ if (!"lower".equals(getProperty(blockState, "half"))) { -+ continue; -+ } -+ -+ final int positionAbove = relative(position, Direction.UP); -+ final MapType blockStateAbove = this.getBlock(positionAbove); -+ -+ final String name = getName(blockState); -+ if (name.equals(getName(blockStateAbove))) { -+ final String facingBelow = getProperty(blockState, "facing"); -+ final String openBelow = getProperty(blockState, "open"); -+ final String hingeAbove = convertedFromAlphaFormat ? "left" : getProperty(blockStateAbove, "hinge"); -+ final String poweredAbove = convertedFromAlphaFormat ? "false" : getProperty(blockStateAbove, "powered"); -+ -+ this.setBlock(position, DOOR_MAP.get(name + facingBelow + "lower" + hingeAbove + openBelow + poweredAbove)); -+ this.setBlock(positionAbove, DOOR_MAP.get(name + facingBelow + "upper" + hingeAbove + openBelow + poweredAbove)); -+ } -+ } -+ break; -+ } -+ case 86: { // pumpkin -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType blockState = this.getBlock(position); -+ -+ // I guess this is some terrible hack to convert carved pumpkins from world gen into -+ // regular pumpkins? -+ -+ if ("minecraft:carved_pumpkin".equals(getName(blockState))) { -+ final String downName = getName(this.getBlock(relative(position, Direction.DOWN))); -+ if ("minecraft:grass_block".equals(downName) || "minecraft:dirt".equals(downName)) { -+ this.setBlock(position, PUMPKIN); -+ } -+ } -+ } -+ break; -+ } -+ case 110: { // mycelium -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType blockState = this.getBlock(position); -+ if ("minecraft:mycelium".equals(getName(blockState))) { -+ final String nameAbove = getName(this.getBlock(relative(position, Direction.UP))); -+ if ("minecraft:snow".equals(nameAbove) || "minecraft:snow_layer".equals(nameAbove)) { -+ this.setBlock(position, SNOWY_MYCELIUM); -+ } -+ } -+ } -+ break; -+ } -+ case 140: { // flower pot -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType tile = this.removeBlockEntity(position); -+ if (tile == null) { -+ continue; -+ } -+ -+ final String item; -+ if (tile.hasKey("Item", ObjectType.NUMBER)) { -+ // the item name converter should have migrated to number, however no legacy converter -+ // ever did this. so we can get data with versions above v102 (old worlds, converted prior to DFU) -+ // that didn't convert. so just do it here. -+ item = HelperItemNameV102.getNameFromId(tile.getInt("Item")); -+ } else { -+ item = tile.getString("Item", ""); -+ } -+ -+ final String state = item + tile.getInt("Data"); -+ this.setBlock(position, FLOWER_POT_MAP.getOrDefault(state, FLOWER_POT_MAP.get("minecraft:air0"))); -+ } -+ break; -+ } -+ case 144: { // mob head -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType tile = this.getBlockEntity(position); -+ if (tile == null) { -+ continue; -+ } -+ -+ final String typeString = Integer.toString(tile.getInt("SkullType")); -+ final String facing = getProperty(this.getBlock(position), "facing"); -+ final String state; -+ if (!"up".equals(facing) && !"down".equals(facing)) { -+ state = typeString + facing; -+ } else { -+ state = typeString + tile.getInt("Rot"); -+ } -+ -+ tile.remove("SkullType"); -+ tile.remove("facing"); -+ tile.remove("Rot"); -+ -+ this.setBlock(position, SKULL_MAP.getOrDefault(state, SKULL_MAP.get("0north"))); -+ } -+ break; -+ } -+ case 175: { // sunflower -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType blockState = this.getBlock(position); -+ if (!"upper".equals(getProperty(blockState, "half"))) { -+ continue; -+ } -+ -+ final MapType blockStateBelow = this.getBlock(relative(position, Direction.DOWN)); -+ final String nameBelow = getName(blockStateBelow); -+ switch (nameBelow) { -+ case "minecraft:sunflower": -+ this.setBlock(position, UPPER_SUNFLOWER); -+ break; -+ case "minecraft:lilac": -+ this.setBlock(position, UPPER_LILAC); -+ break; -+ case "minecraft:tall_grass": -+ this.setBlock(position, UPPER_TALL_GRASS); -+ break; -+ case "minecraft:large_fern": -+ this.setBlock(position, UPPER_LARGE_FERN); -+ break; -+ case "minecraft:rose_bush": -+ this.setBlock(position, UPPER_ROSE_BUSH); -+ break; -+ case "minecraft:peony": -+ this.setBlock(position, UPPER_PEONY); -+ break; -+ } -+ } -+ break; -+ } -+ case 176: // free standing banner -+ case 177: { // wall mounted banner -+ while (positionIterator.hasNext()) { -+ final int position = positionIterator.nextInt() | yIndex; -+ final MapType tile = this.getBlockEntity(position); -+ -+ if (tile == null) { -+ continue; -+ } -+ -+ final MapType blockState = this.getBlock(position); -+ -+ final int base = tile.getInt("Base"); -+ if (base != 15 && base >= 0 && base < 16) { -+ final String state = getProperty(blockState, fixEntry.getIntKey() == 176 ? "rotation" : "facing") + "_" + base; -+ final MapType update = BANNER_BLOCK_MAP.get(state); -+ if (update != null) { -+ this.setBlock(position, update); -+ } -+ } -+ } -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ private MapType getBlockEntity(final int index) { -+ return this.tileEntities.get(index); -+ } -+ -+ private MapType removeBlockEntity(final int index) { -+ return this.tileEntities.remove(index); -+ } -+ -+ public static int relative(final int index, final Direction direction) { -+ switch (direction.getAxis()) { -+ case X: -+ int j = (index & 15) + direction.getAxisDirection().getStep(); -+ return j >= 0 && j <= 15 ? index & -16 | j : -1; -+ case Y: -+ int k = (index >> 8) + direction.getAxisDirection().getStep(); -+ return k >= 0 && k <= 255 ? index & 255 | k << 8 : -1; -+ case Z: -+ int l = (index >> 4 & 15) + direction.getAxisDirection().getStep(); -+ return l >= 0 && l <= 15 ? index & -241 | l << 4 : -1; -+ default: -+ return -1; -+ } -+ } -+ -+ private void setBlock(final int index, final MapType blockState) { -+ if (index >= 0 && index <= 65535) { -+ final Section section = this.getSection(index); -+ if (section != null) { -+ section.setBlock(index & 4095, blockState); -+ } -+ } -+ } -+ -+ private Section getSection(final int index) { -+ final int y = index >> 12; -+ return y < this.sections.length ? this.sections[y] : null; -+ } -+ -+ public MapType getBlock(int i) { -+ if (i >= 0 && i <= 65535) { -+ final Section section = this.getSection(i); -+ return section == null ? AIR : section.getBlock(i & 4095); -+ } else { -+ return AIR; -+ } -+ } -+ -+ public MapType writeBackToLevel() { -+ if (this.tileEntities.isEmpty()) { -+ this.level.remove("TileEntities"); -+ } else { -+ final ListType tileEntities = Types.NBT.createEmptyList(); -+ this.tileEntities.values().forEach(tileEntities::addMap); -+ this.level.setList("TileEntities", tileEntities); -+ } -+ -+ final MapType indices = Types.NBT.createEmptyMap(); -+ final ListType sections = Types.NBT.createEmptyList(); -+ for (final Section section : this.sections) { -+ if (section == null) { -+ continue; -+ } -+ -+ sections.addMap(section.writeBackToSection()); -+ indices.setInts(Integer.toString(section.y), Arrays.copyOf(section.update.elements(), section.update.size())); -+ } -+ -+ this.level.setList("Sections", sections); -+ -+ final MapType upgradeData = Types.NBT.createEmptyMap(); -+ upgradeData.setByte("Sides", (byte)this.sides); -+ upgradeData.setMap("Indices", indices); -+ -+ this.level.setMap("UpgradeData", upgradeData); -+ -+ return this.level; -+ } -+ } -+ -+ static class Section { -+ final Palette palette = new Palette(); -+ -+ static final class Palette extends Reference2IntOpenHashMap> { -+ -+ final ListType paletteStates = Types.NBT.createEmptyList(); -+ -+ private int find(final MapType k) { -+ if (((k) == (null))) -+ return containsNullKey ? n : -(n + 1); -+ MapType curr; -+ final Object[] key = this.key; -+ int pos; -+ // The starting point. -+ if (((curr = (MapType)key[pos = (it.unimi.dsi.fastutil.HashCommon.mix(System.identityHashCode(k))) & mask]) == (null))) -+ return -(pos + 1); -+ if (((k) == (curr))) -+ return pos; -+ // There's always an unused entry. -+ while (true) { -+ if (((curr = (MapType)key[pos = (pos + 1) & mask]) == (null))) -+ return -(pos + 1); -+ if (((k) == (curr))) -+ return pos; -+ } -+ } -+ -+ private void insert(final int pos, final MapType k, final int v) { -+ if (pos == n) -+ containsNullKey = true; -+ ((Object[])key)[pos] = k; -+ value[pos] = v; -+ if (size++ >= maxFill) -+ rehash(arraySize(size + 1, f)); -+ } -+ -+ private MapType[] byId = new MapType[4]; -+ private MapType last = null; -+ -+ public int getOrCreateId(final MapType k) { -+ if (k == this.last) { -+ return this.size - 1; -+ } -+ final int pos = find(k); -+ if (pos >= 0) { -+ return this.value[pos]; -+ } -+ -+ final int insert = this.size; -+ MapType inPalette = k; -+ -+ if ("%%FILTER_ME%%".equals(getName(k))) { -+ inPalette = AIR; -+ } -+ -+ if (insert >= this.byId.length) { -+ this.byId = Arrays.copyOf(this.byId, this.byId.length * 2); -+ this.byId[insert] = k; -+ } else { -+ this.byId[insert] = k; -+ } -+ this.paletteStates.addMap(inPalette); -+ -+ this.last = k; -+ -+ this.insert(-pos - 1, k, insert); -+ -+ return insert; -+ } -+ -+ } -+ -+ final MapType section; -+ final boolean hasData; -+ final Int2ObjectLinkedOpenHashMap toFix = new Int2ObjectLinkedOpenHashMap<>(); -+ final IntArrayList update = new IntArrayList(); -+ final int y; -+ final int[] buffer = new int[4096]; -+ -+ public Section(final MapType section) { -+ this.section = section; -+ this.y = section.getInt("Y"); -+ this.hasData = section.hasKey("Blocks", ObjectType.BYTE_ARRAY); -+ } -+ -+ public MapType getBlock(final int index) { -+ if (index >= 0 && index <= 4095) { -+ final MapType state = this.palette.byId[this.buffer[index]]; -+ return state == null ? AIR : state; -+ } else { -+ return AIR; -+ } -+ } -+ -+ public void setBlock(final int index, final MapType blockState) { -+ this.buffer[index] = this.palette.getOrCreateId(blockState); -+ } -+ -+ public int upgrade(int sides) { -+ if (!this.hasData) { -+ return sides; -+ } -+ -+ final byte[] blocks = this.section.getBytes("Blocks"); -+ final DataLayer data = DataLayer.getOrNull(this.section.getBytes("Data")); -+ final DataLayer add = DataLayer.getOrNull(this.section.getBytes("Add")); -+ -+ this.palette.getOrCreateId(AIR); -+ -+ for (int index = 0; index < 4096; ++index) { -+ final int x = index & 15; -+ final int z = index >> 4 & 15; -+ -+ int blockStateId = (blocks[index] & 255) << 4; -+ if (data != null) { -+ blockStateId |= data.get(index); -+ } -+ if (add != null) { -+ blockStateId |= add.get(index) << 12; -+ } -+ if (IDS_NEEDING_FIX[blockStateId >>> 4]) { -+ this.addFix(blockStateId >>> 4, index); -+ } -+ -+ if (VIRTUAL[blockStateId >>> 4]) { -+ final int additionalSides = getSideMask(x == 0, x == 15, z == 0, z == 15); -+ if (additionalSides == 0) { -+ this.update.add(index); -+ } else { -+ sides |= additionalSides; -+ } -+ } -+ -+ this.setBlock(index, HelperBlockFlatteningV1450.getNBTForId(blockStateId)); -+ } -+ -+ return sides; -+ } -+ -+ private void addFix(final int block, final int index) { -+ this.toFix.computeIfAbsent(block, (final int keyInMap) -> { -+ return new IntArrayList(); -+ }).add(index); -+ } -+ -+ // Note: modifies the current section and returns it. -+ public MapType writeBackToSection() { -+ if (!this.hasData) { -+ return this.section; -+ } -+ -+ this.section.setList("Palette", this.palette.paletteStates.copy()); // deep copy to ensure palette compound tags are NOT shared -+ -+ final int bitSize = Math.max(4, DataFixUtils.ceillog2(this.palette.size())); -+ final PackedBitStorage packedIds = new PackedBitStorage(bitSize, 4096); -+ -+ for(int index = 0; index < this.buffer.length; ++index) { -+ packedIds.set(index, this.buffer[index]); -+ } -+ -+ this.section.setLongs("BlockStates", packedIds.getRaw()); -+ -+ this.section.remove("Blocks"); -+ this.section.remove("Data"); -+ this.section.remove("Add"); -+ -+ return this.section; -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/entity/ConverterAbstractEntityRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/entity/ConverterAbstractEntityRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..62b0761003b40cf84923d89ad77bc366a9fca98a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/entity/ConverterAbstractEntityRename.java -@@ -0,0 +1,39 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.entity; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.function.Function; -+ -+public final class ConverterAbstractEntityRename { -+ -+ private ConverterAbstractEntityRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(version) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String id = data.getString("id"); -+ if (id == null) { -+ return null; -+ } -+ -+ final String converted = renamer.apply(id); -+ -+ if (converted != null) { -+ data.setString("id", converted); -+ } -+ -+ return null; -+ } -+ }); -+ ConverterAbstractStringValueTypeRename.register(version, subVersion, MCTypeRegistry.ENTITY_NAME, renamer); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/ConverterAbstractStringValueTypeRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/ConverterAbstractStringValueTypeRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..89e887158ffc302f2b1b687493dbe2ebe2e449a9 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/ConverterAbstractStringValueTypeRename.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.helpers; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCValueType; -+ -+import java.util.function.Function; -+ -+public final class ConverterAbstractStringValueTypeRename { -+ -+ private ConverterAbstractStringValueTypeRename() {} -+ -+ public static void register(final int version, final MCValueType type, final Function renamer) { -+ register(version, 0, type, renamer); -+ } -+ public static void register(final int version, final int subVersion, final MCValueType type, final Function renamer) { -+ type.addConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public Object convert(final Object data, final long sourceVersion, final long toVersion) { -+ final String ret = (data instanceof String) ? renamer.apply((String)data) : null; -+ return ret == data ? null : ret; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperBlockFlatteningV1450.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperBlockFlatteningV1450.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a0b67038b026264882c04146ef79cb057eccd864 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperBlockFlatteningV1450.java -@@ -0,0 +1,1827 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.helpers; -+ -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.nbt.NBTMapType; -+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -+import net.minecraft.nbt.TagParser; -+import java.util.HashMap; -+import java.util.Map; -+ -+public final class HelperBlockFlatteningV1450 { -+ -+ protected static final MapType[] FLATTENED_BY_ID = new MapType[4096]; -+ protected static final MapType[] BLOCK_DEFAULTS = new MapType[4096]; -+ -+ private static final Object2IntOpenHashMap> ID_BY_OLD_NBT = new Object2IntOpenHashMap>(64, 0.7f) { -+ @Override -+ public int put(final MapType o, final int v) { -+ if (this.containsKey(o)) { -+ throw new RuntimeException("Already contains mapping for " + o); -+ } -+ -+ return super.put(o, v); -+ } -+ }; -+ static { -+ ID_BY_OLD_NBT.defaultReturnValue(-1); -+ } -+ -+ private static final Object2IntOpenHashMap ID_BY_OLD_NAME = new Object2IntOpenHashMap(64, 0.7f) { -+ @Override -+ public int put(final String o, final int v) { -+ if (this.containsKey(o)) { -+ throw new RuntimeException("Already contains mapping for " + o); -+ } -+ -+ return super.put(o, v); -+ } -+ }; -+ static { -+ ID_BY_OLD_NAME.defaultReturnValue(-1); -+ } -+ -+ // map used to ensure that each parsed block state contains no duplicates -+ protected static final Map, MapType> IDENTITY_ENSURE = new HashMap<>(); -+ -+ public static MapType parseTag(final String blockstate) { -+ try { -+ final MapType ret = new NBTMapType(TagParser.parseTag(blockstate.replace('\'', '"'))); -+ -+ final MapType identity = IDENTITY_ENSURE.putIfAbsent(ret, ret); -+ -+ return identity == null ? ret : identity; -+ } catch (final Exception ex) { -+ throw new RuntimeException("Exception parsing " + blockstate, ex); -+ } -+ } -+ -+ private static void register(final int id, final String flattened, final String... preFlattenings) { -+ final MapType flattenedNBT = parseTag(flattened); -+ if (FLATTENED_BY_ID[id] != null) { -+ throw new RuntimeException("Mapping already exists for id " + id); -+ } -+ FLATTENED_BY_ID[id] = flattenedNBT; -+ -+ // it's important that we register ids from smallest to largest, so that -+ // the default is going to be correct -+ final int block = id >> 4; -+ if (BLOCK_DEFAULTS[block] == null) { -+ BLOCK_DEFAULTS[block] = flattenedNBT; -+ } -+ -+ for (final String preFlattening : preFlattenings) { -+ final MapType preFlatteningNBT = parseTag(preFlattening); -+ final String name = preFlatteningNBT.getString("Name"); -+ if (name == null) { -+ throw new RuntimeException("Name does not exist for pre flattenings for id " + id); -+ } -+ -+ // putIfAbsent so we default to the lowest id, which is going to be the block default -+ ID_BY_OLD_NAME.putIfAbsent(name, id); -+ ID_BY_OLD_NBT.put(preFlatteningNBT, id); -+ } -+ } -+ -+ private static void finalizeMaps() { -+ for(int i = 0; i < FLATTENED_BY_ID.length; ++i) { -+ if (FLATTENED_BY_ID[i] == null) { -+ FLATTENED_BY_ID[i] = BLOCK_DEFAULTS[i >> 4]; -+ } -+ } -+ } -+ -+ public static MapType flattenNBT(final MapType old) { -+ final int id = ID_BY_OLD_NBT.getInt(old); -+ final MapType ret = getNBTForIdRaw(id); -+ -+ return ret == null ? old : ret; -+ } -+ -+ public static String getNewBlockName(final String old) { -+ final int id = ID_BY_OLD_NAME.getInt(old); -+ final MapType ret = getNBTForIdRaw(id); -+ return ret == null ? old : ret.getString("Name"); -+ } -+ -+ public static String getNameForId(final int block) { -+ final MapType nbt = getNBTForIdRaw(block); -+ return nbt == null ? "minecraft:air" : nbt.getString("Name"); -+ } -+ -+ protected static MapType getNBTForIdRaw(final int block) { -+ return block >= 0 && block < FLATTENED_BY_ID.length ? FLATTENED_BY_ID[block] : null; -+ } -+ -+ public static MapType getNBTForId(final int block) { -+ MapType ret = getNBTForIdRaw(block); -+ return ret == null ? FLATTENED_BY_ID[0] : ret; -+ } -+ -+ private HelperBlockFlatteningV1450() {} -+ -+ static { -+ ID_BY_OLD_NBT.defaultReturnValue(-1); -+ register(0, "{Name:'minecraft:air'}", "{Name:'minecraft:air'}"); -+ register(16, "{Name:'minecraft:stone'}", "{Name:'minecraft:stone',Properties:{variant:'stone'}}"); -+ register(17, "{Name:'minecraft:granite'}", "{Name:'minecraft:stone',Properties:{variant:'granite'}}"); -+ register(18, "{Name:'minecraft:polished_granite'}", "{Name:'minecraft:stone',Properties:{variant:'smooth_granite'}}"); -+ register(19, "{Name:'minecraft:diorite'}", "{Name:'minecraft:stone',Properties:{variant:'diorite'}}"); -+ register(20, "{Name:'minecraft:polished_diorite'}", "{Name:'minecraft:stone',Properties:{variant:'smooth_diorite'}}"); -+ register(21, "{Name:'minecraft:andesite'}", "{Name:'minecraft:stone',Properties:{variant:'andesite'}}"); -+ register(22, "{Name:'minecraft:polished_andesite'}", "{Name:'minecraft:stone',Properties:{variant:'smooth_andesite'}}"); -+ register(32, "{Name:'minecraft:grass_block',Properties:{snowy:'false'}}", "{Name:'minecraft:grass',Properties:{snowy:'false'}}", "{Name:'minecraft:grass',Properties:{snowy:'true'}}"); -+ register(48, "{Name:'minecraft:dirt'}", "{Name:'minecraft:dirt',Properties:{snowy:'false',variant:'dirt'}}", "{Name:'minecraft:dirt',Properties:{snowy:'true',variant:'dirt'}}"); -+ register(49, "{Name:'minecraft:coarse_dirt'}", "{Name:'minecraft:dirt',Properties:{snowy:'false',variant:'coarse_dirt'}}", "{Name:'minecraft:dirt',Properties:{snowy:'true',variant:'coarse_dirt'}}"); -+ register(50, "{Name:'minecraft:podzol',Properties:{snowy:'false'}}", "{Name:'minecraft:dirt',Properties:{snowy:'false',variant:'podzol'}}", "{Name:'minecraft:dirt',Properties:{snowy:'true',variant:'podzol'}}"); -+ register(64, "{Name:'minecraft:cobblestone'}", "{Name:'minecraft:cobblestone'}"); -+ register(80, "{Name:'minecraft:oak_planks'}", "{Name:'minecraft:planks',Properties:{variant:'oak'}}"); -+ register(81, "{Name:'minecraft:spruce_planks'}", "{Name:'minecraft:planks',Properties:{variant:'spruce'}}"); -+ register(82, "{Name:'minecraft:birch_planks'}", "{Name:'minecraft:planks',Properties:{variant:'birch'}}"); -+ register(83, "{Name:'minecraft:jungle_planks'}", "{Name:'minecraft:planks',Properties:{variant:'jungle'}}"); -+ register(84, "{Name:'minecraft:acacia_planks'}", "{Name:'minecraft:planks',Properties:{variant:'acacia'}}"); -+ register(85, "{Name:'minecraft:dark_oak_planks'}", "{Name:'minecraft:planks',Properties:{variant:'dark_oak'}}"); -+ register(96, "{Name:'minecraft:oak_sapling',Properties:{stage:'0'}}", "{Name:'minecraft:sapling',Properties:{stage:'0',type:'oak'}}"); -+ register(97, "{Name:'minecraft:spruce_sapling',Properties:{stage:'0'}}", "{Name:'minecraft:sapling',Properties:{stage:'0',type:'spruce'}}"); -+ register(98, "{Name:'minecraft:birch_sapling',Properties:{stage:'0'}}", "{Name:'minecraft:sapling',Properties:{stage:'0',type:'birch'}}"); -+ register(99, "{Name:'minecraft:jungle_sapling',Properties:{stage:'0'}}", "{Name:'minecraft:sapling',Properties:{stage:'0',type:'jungle'}}"); -+ register(100, "{Name:'minecraft:acacia_sapling',Properties:{stage:'0'}}", "{Name:'minecraft:sapling',Properties:{stage:'0',type:'acacia'}}"); -+ register(101, "{Name:'minecraft:dark_oak_sapling',Properties:{stage:'0'}}", "{Name:'minecraft:sapling',Properties:{stage:'0',type:'dark_oak'}}"); -+ register(104, "{Name:'minecraft:oak_sapling',Properties:{stage:'1'}}", "{Name:'minecraft:sapling',Properties:{stage:'1',type:'oak'}}"); -+ register(105, "{Name:'minecraft:spruce_sapling',Properties:{stage:'1'}}", "{Name:'minecraft:sapling',Properties:{stage:'1',type:'spruce'}}"); -+ register(106, "{Name:'minecraft:birch_sapling',Properties:{stage:'1'}}", "{Name:'minecraft:sapling',Properties:{stage:'1',type:'birch'}}"); -+ register(107, "{Name:'minecraft:jungle_sapling',Properties:{stage:'1'}}", "{Name:'minecraft:sapling',Properties:{stage:'1',type:'jungle'}}"); -+ register(108, "{Name:'minecraft:acacia_sapling',Properties:{stage:'1'}}", "{Name:'minecraft:sapling',Properties:{stage:'1',type:'acacia'}}"); -+ register(109, "{Name:'minecraft:dark_oak_sapling',Properties:{stage:'1'}}", "{Name:'minecraft:sapling',Properties:{stage:'1',type:'dark_oak'}}"); -+ register(112, "{Name:'minecraft:bedrock'}", "{Name:'minecraft:bedrock'}"); -+ register(128, "{Name:'minecraft:water',Properties:{level:'0'}}", "{Name:'minecraft:flowing_water',Properties:{level:'0'}}"); -+ register(129, "{Name:'minecraft:water',Properties:{level:'1'}}", "{Name:'minecraft:flowing_water',Properties:{level:'1'}}"); -+ register(130, "{Name:'minecraft:water',Properties:{level:'2'}}", "{Name:'minecraft:flowing_water',Properties:{level:'2'}}"); -+ register(131, "{Name:'minecraft:water',Properties:{level:'3'}}", "{Name:'minecraft:flowing_water',Properties:{level:'3'}}"); -+ register(132, "{Name:'minecraft:water',Properties:{level:'4'}}", "{Name:'minecraft:flowing_water',Properties:{level:'4'}}"); -+ register(133, "{Name:'minecraft:water',Properties:{level:'5'}}", "{Name:'minecraft:flowing_water',Properties:{level:'5'}}"); -+ register(134, "{Name:'minecraft:water',Properties:{level:'6'}}", "{Name:'minecraft:flowing_water',Properties:{level:'6'}}"); -+ register(135, "{Name:'minecraft:water',Properties:{level:'7'}}", "{Name:'minecraft:flowing_water',Properties:{level:'7'}}"); -+ register(136, "{Name:'minecraft:water',Properties:{level:'8'}}", "{Name:'minecraft:flowing_water',Properties:{level:'8'}}"); -+ register(137, "{Name:'minecraft:water',Properties:{level:'9'}}", "{Name:'minecraft:flowing_water',Properties:{level:'9'}}"); -+ register(138, "{Name:'minecraft:water',Properties:{level:'10'}}", "{Name:'minecraft:flowing_water',Properties:{level:'10'}}"); -+ register(139, "{Name:'minecraft:water',Properties:{level:'11'}}", "{Name:'minecraft:flowing_water',Properties:{level:'11'}}"); -+ register(140, "{Name:'minecraft:water',Properties:{level:'12'}}", "{Name:'minecraft:flowing_water',Properties:{level:'12'}}"); -+ register(141, "{Name:'minecraft:water',Properties:{level:'13'}}", "{Name:'minecraft:flowing_water',Properties:{level:'13'}}"); -+ register(142, "{Name:'minecraft:water',Properties:{level:'14'}}", "{Name:'minecraft:flowing_water',Properties:{level:'14'}}"); -+ register(143, "{Name:'minecraft:water',Properties:{level:'15'}}", "{Name:'minecraft:flowing_water',Properties:{level:'15'}}"); -+ register(144, "{Name:'minecraft:water',Properties:{level:'0'}}", "{Name:'minecraft:water',Properties:{level:'0'}}"); -+ register(145, "{Name:'minecraft:water',Properties:{level:'1'}}", "{Name:'minecraft:water',Properties:{level:'1'}}"); -+ register(146, "{Name:'minecraft:water',Properties:{level:'2'}}", "{Name:'minecraft:water',Properties:{level:'2'}}"); -+ register(147, "{Name:'minecraft:water',Properties:{level:'3'}}", "{Name:'minecraft:water',Properties:{level:'3'}}"); -+ register(148, "{Name:'minecraft:water',Properties:{level:'4'}}", "{Name:'minecraft:water',Properties:{level:'4'}}"); -+ register(149, "{Name:'minecraft:water',Properties:{level:'5'}}", "{Name:'minecraft:water',Properties:{level:'5'}}"); -+ register(150, "{Name:'minecraft:water',Properties:{level:'6'}}", "{Name:'minecraft:water',Properties:{level:'6'}}"); -+ register(151, "{Name:'minecraft:water',Properties:{level:'7'}}", "{Name:'minecraft:water',Properties:{level:'7'}}"); -+ register(152, "{Name:'minecraft:water',Properties:{level:'8'}}", "{Name:'minecraft:water',Properties:{level:'8'}}"); -+ register(153, "{Name:'minecraft:water',Properties:{level:'9'}}", "{Name:'minecraft:water',Properties:{level:'9'}}"); -+ register(154, "{Name:'minecraft:water',Properties:{level:'10'}}", "{Name:'minecraft:water',Properties:{level:'10'}}"); -+ register(155, "{Name:'minecraft:water',Properties:{level:'11'}}", "{Name:'minecraft:water',Properties:{level:'11'}}"); -+ register(156, "{Name:'minecraft:water',Properties:{level:'12'}}", "{Name:'minecraft:water',Properties:{level:'12'}}"); -+ register(157, "{Name:'minecraft:water',Properties:{level:'13'}}", "{Name:'minecraft:water',Properties:{level:'13'}}"); -+ register(158, "{Name:'minecraft:water',Properties:{level:'14'}}", "{Name:'minecraft:water',Properties:{level:'14'}}"); -+ register(159, "{Name:'minecraft:water',Properties:{level:'15'}}", "{Name:'minecraft:water',Properties:{level:'15'}}"); -+ register(160, "{Name:'minecraft:lava',Properties:{level:'0'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'0'}}"); -+ register(161, "{Name:'minecraft:lava',Properties:{level:'1'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'1'}}"); -+ register(162, "{Name:'minecraft:lava',Properties:{level:'2'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'2'}}"); -+ register(163, "{Name:'minecraft:lava',Properties:{level:'3'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'3'}}"); -+ register(164, "{Name:'minecraft:lava',Properties:{level:'4'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'4'}}"); -+ register(165, "{Name:'minecraft:lava',Properties:{level:'5'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'5'}}"); -+ register(166, "{Name:'minecraft:lava',Properties:{level:'6'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'6'}}"); -+ register(167, "{Name:'minecraft:lava',Properties:{level:'7'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'7'}}"); -+ register(168, "{Name:'minecraft:lava',Properties:{level:'8'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'8'}}"); -+ register(169, "{Name:'minecraft:lava',Properties:{level:'9'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'9'}}"); -+ register(170, "{Name:'minecraft:lava',Properties:{level:'10'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'10'}}"); -+ register(171, "{Name:'minecraft:lava',Properties:{level:'11'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'11'}}"); -+ register(172, "{Name:'minecraft:lava',Properties:{level:'12'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'12'}}"); -+ register(173, "{Name:'minecraft:lava',Properties:{level:'13'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'13'}}"); -+ register(174, "{Name:'minecraft:lava',Properties:{level:'14'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'14'}}"); -+ register(175, "{Name:'minecraft:lava',Properties:{level:'15'}}", "{Name:'minecraft:flowing_lava',Properties:{level:'15'}}"); -+ register(176, "{Name:'minecraft:lava',Properties:{level:'0'}}", "{Name:'minecraft:lava',Properties:{level:'0'}}"); -+ register(177, "{Name:'minecraft:lava',Properties:{level:'1'}}", "{Name:'minecraft:lava',Properties:{level:'1'}}"); -+ register(178, "{Name:'minecraft:lava',Properties:{level:'2'}}", "{Name:'minecraft:lava',Properties:{level:'2'}}"); -+ register(179, "{Name:'minecraft:lava',Properties:{level:'3'}}", "{Name:'minecraft:lava',Properties:{level:'3'}}"); -+ register(180, "{Name:'minecraft:lava',Properties:{level:'4'}}", "{Name:'minecraft:lava',Properties:{level:'4'}}"); -+ register(181, "{Name:'minecraft:lava',Properties:{level:'5'}}", "{Name:'minecraft:lava',Properties:{level:'5'}}"); -+ register(182, "{Name:'minecraft:lava',Properties:{level:'6'}}", "{Name:'minecraft:lava',Properties:{level:'6'}}"); -+ register(183, "{Name:'minecraft:lava',Properties:{level:'7'}}", "{Name:'minecraft:lava',Properties:{level:'7'}}"); -+ register(184, "{Name:'minecraft:lava',Properties:{level:'8'}}", "{Name:'minecraft:lava',Properties:{level:'8'}}"); -+ register(185, "{Name:'minecraft:lava',Properties:{level:'9'}}", "{Name:'minecraft:lava',Properties:{level:'9'}}"); -+ register(186, "{Name:'minecraft:lava',Properties:{level:'10'}}", "{Name:'minecraft:lava',Properties:{level:'10'}}"); -+ register(187, "{Name:'minecraft:lava',Properties:{level:'11'}}", "{Name:'minecraft:lava',Properties:{level:'11'}}"); -+ register(188, "{Name:'minecraft:lava',Properties:{level:'12'}}", "{Name:'minecraft:lava',Properties:{level:'12'}}"); -+ register(189, "{Name:'minecraft:lava',Properties:{level:'13'}}", "{Name:'minecraft:lava',Properties:{level:'13'}}"); -+ register(190, "{Name:'minecraft:lava',Properties:{level:'14'}}", "{Name:'minecraft:lava',Properties:{level:'14'}}"); -+ register(191, "{Name:'minecraft:lava',Properties:{level:'15'}}", "{Name:'minecraft:lava',Properties:{level:'15'}}"); -+ register(192, "{Name:'minecraft:sand'}", "{Name:'minecraft:sand',Properties:{variant:'sand'}}"); -+ register(193, "{Name:'minecraft:red_sand'}", "{Name:'minecraft:sand',Properties:{variant:'red_sand'}}"); -+ register(208, "{Name:'minecraft:gravel'}", "{Name:'minecraft:gravel'}"); -+ register(224, "{Name:'minecraft:gold_ore'}", "{Name:'minecraft:gold_ore'}"); -+ register(240, "{Name:'minecraft:iron_ore'}", "{Name:'minecraft:iron_ore'}"); -+ register(256, "{Name:'minecraft:coal_ore'}", "{Name:'minecraft:coal_ore'}"); -+ register(272, "{Name:'minecraft:oak_log',Properties:{axis:'y'}}", "{Name:'minecraft:log',Properties:{axis:'y',variant:'oak'}}"); -+ register(273, "{Name:'minecraft:spruce_log',Properties:{axis:'y'}}", "{Name:'minecraft:log',Properties:{axis:'y',variant:'spruce'}}"); -+ register(274, "{Name:'minecraft:birch_log',Properties:{axis:'y'}}", "{Name:'minecraft:log',Properties:{axis:'y',variant:'birch'}}"); -+ register(275, "{Name:'minecraft:jungle_log',Properties:{axis:'y'}}", "{Name:'minecraft:log',Properties:{axis:'y',variant:'jungle'}}"); -+ register(276, "{Name:'minecraft:oak_log',Properties:{axis:'x'}}", "{Name:'minecraft:log',Properties:{axis:'x',variant:'oak'}}"); -+ register(277, "{Name:'minecraft:spruce_log',Properties:{axis:'x'}}", "{Name:'minecraft:log',Properties:{axis:'x',variant:'spruce'}}"); -+ register(278, "{Name:'minecraft:birch_log',Properties:{axis:'x'}}", "{Name:'minecraft:log',Properties:{axis:'x',variant:'birch'}}"); -+ register(279, "{Name:'minecraft:jungle_log',Properties:{axis:'x'}}", "{Name:'minecraft:log',Properties:{axis:'x',variant:'jungle'}}"); -+ register(280, "{Name:'minecraft:oak_log',Properties:{axis:'z'}}", "{Name:'minecraft:log',Properties:{axis:'z',variant:'oak'}}"); -+ register(281, "{Name:'minecraft:spruce_log',Properties:{axis:'z'}}", "{Name:'minecraft:log',Properties:{axis:'z',variant:'spruce'}}"); -+ register(282, "{Name:'minecraft:birch_log',Properties:{axis:'z'}}", "{Name:'minecraft:log',Properties:{axis:'z',variant:'birch'}}"); -+ register(283, "{Name:'minecraft:jungle_log',Properties:{axis:'z'}}", "{Name:'minecraft:log',Properties:{axis:'z',variant:'jungle'}}"); -+ register(284, "{Name:'minecraft:oak_bark'}", "{Name:'minecraft:log',Properties:{axis:'none',variant:'oak'}}"); -+ register(285, "{Name:'minecraft:spruce_bark'}", "{Name:'minecraft:log',Properties:{axis:'none',variant:'spruce'}}"); -+ register(286, "{Name:'minecraft:birch_bark'}", "{Name:'minecraft:log',Properties:{axis:'none',variant:'birch'}}"); -+ register(287, "{Name:'minecraft:jungle_bark'}", "{Name:'minecraft:log',Properties:{axis:'none',variant:'jungle'}}"); -+ register(288, "{Name:'minecraft:oak_leaves',Properties:{check_decay:'false',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'true',variant:'oak'}}"); -+ register(289, "{Name:'minecraft:spruce_leaves',Properties:{check_decay:'false',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'true',variant:'spruce'}}"); -+ register(290, "{Name:'minecraft:birch_leaves',Properties:{check_decay:'false',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'true',variant:'birch'}}"); -+ register(291, "{Name:'minecraft:jungle_leaves',Properties:{check_decay:'false',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'true',variant:'jungle'}}"); -+ register(292, "{Name:'minecraft:oak_leaves',Properties:{check_decay:'false',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'false',variant:'oak'}}"); -+ register(293, "{Name:'minecraft:spruce_leaves',Properties:{check_decay:'false',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'false',variant:'spruce'}}"); -+ register(294, "{Name:'minecraft:birch_leaves',Properties:{check_decay:'false',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'false',variant:'birch'}}"); -+ register(295, "{Name:'minecraft:jungle_leaves',Properties:{check_decay:'false',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'false',decayable:'false',variant:'jungle'}}"); -+ register(296, "{Name:'minecraft:oak_leaves',Properties:{check_decay:'true',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'true',variant:'oak'}}"); -+ register(297, "{Name:'minecraft:spruce_leaves',Properties:{check_decay:'true',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'true',variant:'spruce'}}"); -+ register(298, "{Name:'minecraft:birch_leaves',Properties:{check_decay:'true',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'true',variant:'birch'}}"); -+ register(299, "{Name:'minecraft:jungle_leaves',Properties:{check_decay:'true',decayable:'true'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'true',variant:'jungle'}}"); -+ register(300, "{Name:'minecraft:oak_leaves',Properties:{check_decay:'true',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'false',variant:'oak'}}"); -+ register(301, "{Name:'minecraft:spruce_leaves',Properties:{check_decay:'true',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'false',variant:'spruce'}}"); -+ register(302, "{Name:'minecraft:birch_leaves',Properties:{check_decay:'true',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'false',variant:'birch'}}"); -+ register(303, "{Name:'minecraft:jungle_leaves',Properties:{check_decay:'true',decayable:'false'}}", "{Name:'minecraft:leaves',Properties:{check_decay:'true',decayable:'false',variant:'jungle'}}"); -+ register(304, "{Name:'minecraft:sponge'}", "{Name:'minecraft:sponge',Properties:{wet:'false'}}"); -+ register(305, "{Name:'minecraft:wet_sponge'}", "{Name:'minecraft:sponge',Properties:{wet:'true'}}"); -+ register(320, "{Name:'minecraft:glass'}", "{Name:'minecraft:glass'}"); -+ register(336, "{Name:'minecraft:lapis_ore'}", "{Name:'minecraft:lapis_ore'}"); -+ register(352, "{Name:'minecraft:lapis_block'}", "{Name:'minecraft:lapis_block'}"); -+ register(368, "{Name:'minecraft:dispenser',Properties:{facing:'down',triggered:'false'}}", "{Name:'minecraft:dispenser',Properties:{facing:'down',triggered:'false'}}"); -+ register(369, "{Name:'minecraft:dispenser',Properties:{facing:'up',triggered:'false'}}", "{Name:'minecraft:dispenser',Properties:{facing:'up',triggered:'false'}}"); -+ register(370, "{Name:'minecraft:dispenser',Properties:{facing:'north',triggered:'false'}}", "{Name:'minecraft:dispenser',Properties:{facing:'north',triggered:'false'}}"); -+ register(371, "{Name:'minecraft:dispenser',Properties:{facing:'south',triggered:'false'}}", "{Name:'minecraft:dispenser',Properties:{facing:'south',triggered:'false'}}"); -+ register(372, "{Name:'minecraft:dispenser',Properties:{facing:'west',triggered:'false'}}", "{Name:'minecraft:dispenser',Properties:{facing:'west',triggered:'false'}}"); -+ register(373, "{Name:'minecraft:dispenser',Properties:{facing:'east',triggered:'false'}}", "{Name:'minecraft:dispenser',Properties:{facing:'east',triggered:'false'}}"); -+ register(376, "{Name:'minecraft:dispenser',Properties:{facing:'down',triggered:'true'}}", "{Name:'minecraft:dispenser',Properties:{facing:'down',triggered:'true'}}"); -+ register(377, "{Name:'minecraft:dispenser',Properties:{facing:'up',triggered:'true'}}", "{Name:'minecraft:dispenser',Properties:{facing:'up',triggered:'true'}}"); -+ register(378, "{Name:'minecraft:dispenser',Properties:{facing:'north',triggered:'true'}}", "{Name:'minecraft:dispenser',Properties:{facing:'north',triggered:'true'}}"); -+ register(379, "{Name:'minecraft:dispenser',Properties:{facing:'south',triggered:'true'}}", "{Name:'minecraft:dispenser',Properties:{facing:'south',triggered:'true'}}"); -+ register(380, "{Name:'minecraft:dispenser',Properties:{facing:'west',triggered:'true'}}", "{Name:'minecraft:dispenser',Properties:{facing:'west',triggered:'true'}}"); -+ register(381, "{Name:'minecraft:dispenser',Properties:{facing:'east',triggered:'true'}}", "{Name:'minecraft:dispenser',Properties:{facing:'east',triggered:'true'}}"); -+ register(384, "{Name:'minecraft:sandstone'}", "{Name:'minecraft:sandstone',Properties:{type:'sandstone'}}"); -+ register(385, "{Name:'minecraft:chiseled_sandstone'}", "{Name:'minecraft:sandstone',Properties:{type:'chiseled_sandstone'}}"); -+ register(386, "{Name:'minecraft:cut_sandstone'}", "{Name:'minecraft:sandstone',Properties:{type:'smooth_sandstone'}}"); -+ register(400, "{Name:'minecraft:note_block'}", "{Name:'minecraft:noteblock'}"); -+ register(416, "{Name:'minecraft:red_bed',Properties:{facing:'south',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'south',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'south',occupied:'true',part:'foot'}}"); -+ register(417, "{Name:'minecraft:red_bed',Properties:{facing:'west',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'west',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'west',occupied:'true',part:'foot'}}"); -+ register(418, "{Name:'minecraft:red_bed',Properties:{facing:'north',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'north',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'north',occupied:'true',part:'foot'}}"); -+ register(419, "{Name:'minecraft:red_bed',Properties:{facing:'east',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'east',occupied:'false',part:'foot'}}", "{Name:'minecraft:bed',Properties:{facing:'east',occupied:'true',part:'foot'}}"); -+ register(424, "{Name:'minecraft:red_bed',Properties:{facing:'south',occupied:'false',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'south',occupied:'false',part:'head'}}"); -+ register(425, "{Name:'minecraft:red_bed',Properties:{facing:'west',occupied:'false',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'west',occupied:'false',part:'head'}}"); -+ register(426, "{Name:'minecraft:red_bed',Properties:{facing:'north',occupied:'false',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'north',occupied:'false',part:'head'}}"); -+ register(427, "{Name:'minecraft:red_bed',Properties:{facing:'east',occupied:'false',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'east',occupied:'false',part:'head'}}"); -+ register(428, "{Name:'minecraft:red_bed',Properties:{facing:'south',occupied:'true',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'south',occupied:'true',part:'head'}}"); -+ register(429, "{Name:'minecraft:red_bed',Properties:{facing:'west',occupied:'true',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'west',occupied:'true',part:'head'}}"); -+ register(430, "{Name:'minecraft:red_bed',Properties:{facing:'north',occupied:'true',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'north',occupied:'true',part:'head'}}"); -+ register(431, "{Name:'minecraft:red_bed',Properties:{facing:'east',occupied:'true',part:'head'}}", "{Name:'minecraft:bed',Properties:{facing:'east',occupied:'true',part:'head'}}"); -+ register(432, "{Name:'minecraft:powered_rail',Properties:{powered:'false',shape:'north_south'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'false',shape:'north_south'}}"); -+ register(433, "{Name:'minecraft:powered_rail',Properties:{powered:'false',shape:'east_west'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'false',shape:'east_west'}}"); -+ register(434, "{Name:'minecraft:powered_rail',Properties:{powered:'false',shape:'ascending_east'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'false',shape:'ascending_east'}}"); -+ register(435, "{Name:'minecraft:powered_rail',Properties:{powered:'false',shape:'ascending_west'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'false',shape:'ascending_west'}}"); -+ register(436, "{Name:'minecraft:powered_rail',Properties:{powered:'false',shape:'ascending_north'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'false',shape:'ascending_north'}}"); -+ register(437, "{Name:'minecraft:powered_rail',Properties:{powered:'false',shape:'ascending_south'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'false',shape:'ascending_south'}}"); -+ register(440, "{Name:'minecraft:powered_rail',Properties:{powered:'true',shape:'north_south'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'true',shape:'north_south'}}"); -+ register(441, "{Name:'minecraft:powered_rail',Properties:{powered:'true',shape:'east_west'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'true',shape:'east_west'}}"); -+ register(442, "{Name:'minecraft:powered_rail',Properties:{powered:'true',shape:'ascending_east'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'true',shape:'ascending_east'}}"); -+ register(443, "{Name:'minecraft:powered_rail',Properties:{powered:'true',shape:'ascending_west'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'true',shape:'ascending_west'}}"); -+ register(444, "{Name:'minecraft:powered_rail',Properties:{powered:'true',shape:'ascending_north'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'true',shape:'ascending_north'}}"); -+ register(445, "{Name:'minecraft:powered_rail',Properties:{powered:'true',shape:'ascending_south'}}", "{Name:'minecraft:golden_rail',Properties:{powered:'true',shape:'ascending_south'}}"); -+ register(448, "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'north_south'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'north_south'}}"); -+ register(449, "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'east_west'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'east_west'}}"); -+ register(450, "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_east'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_east'}}"); -+ register(451, "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_west'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_west'}}"); -+ register(452, "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_north'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_north'}}"); -+ register(453, "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_south'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'false',shape:'ascending_south'}}"); -+ register(456, "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'north_south'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'north_south'}}"); -+ register(457, "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'east_west'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'east_west'}}"); -+ register(458, "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_east'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_east'}}"); -+ register(459, "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_west'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_west'}}"); -+ register(460, "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_north'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_north'}}"); -+ register(461, "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_south'}}", "{Name:'minecraft:detector_rail',Properties:{powered:'true',shape:'ascending_south'}}"); -+ register(464, "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'down'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'down'}}"); -+ register(465, "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'up'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'up'}}"); -+ register(466, "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'north'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'north'}}"); -+ register(467, "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'south'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'south'}}"); -+ register(468, "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'west'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'west'}}"); -+ register(469, "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'east'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'false',facing:'east'}}"); -+ register(472, "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'down'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'down'}}"); -+ register(473, "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'up'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'up'}}"); -+ register(474, "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'north'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'north'}}"); -+ register(475, "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'south'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'south'}}"); -+ register(476, "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'west'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'west'}}"); -+ register(477, "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'east'}}", "{Name:'minecraft:sticky_piston',Properties:{extended:'true',facing:'east'}}"); -+ register(480, "{Name:'minecraft:cobweb'}", "{Name:'minecraft:web'}"); -+ register(496, "{Name:'minecraft:dead_bush'}", "{Name:'minecraft:tallgrass',Properties:{type:'dead_bush'}}"); -+ register(497, "{Name:'minecraft:grass'}", "{Name:'minecraft:tallgrass',Properties:{type:'tall_grass'}}"); -+ register(498, "{Name:'minecraft:fern'}", "{Name:'minecraft:tallgrass',Properties:{type:'fern'}}"); -+ register(512, "{Name:'minecraft:dead_bush'}", "{Name:'minecraft:deadbush'}"); -+ register(528, "{Name:'minecraft:piston',Properties:{extended:'false',facing:'down'}}", "{Name:'minecraft:piston',Properties:{extended:'false',facing:'down'}}"); -+ register(529, "{Name:'minecraft:piston',Properties:{extended:'false',facing:'up'}}", "{Name:'minecraft:piston',Properties:{extended:'false',facing:'up'}}"); -+ register(530, "{Name:'minecraft:piston',Properties:{extended:'false',facing:'north'}}", "{Name:'minecraft:piston',Properties:{extended:'false',facing:'north'}}"); -+ register(531, "{Name:'minecraft:piston',Properties:{extended:'false',facing:'south'}}", "{Name:'minecraft:piston',Properties:{extended:'false',facing:'south'}}"); -+ register(532, "{Name:'minecraft:piston',Properties:{extended:'false',facing:'west'}}", "{Name:'minecraft:piston',Properties:{extended:'false',facing:'west'}}"); -+ register(533, "{Name:'minecraft:piston',Properties:{extended:'false',facing:'east'}}", "{Name:'minecraft:piston',Properties:{extended:'false',facing:'east'}}"); -+ register(536, "{Name:'minecraft:piston',Properties:{extended:'true',facing:'down'}}", "{Name:'minecraft:piston',Properties:{extended:'true',facing:'down'}}"); -+ register(537, "{Name:'minecraft:piston',Properties:{extended:'true',facing:'up'}}", "{Name:'minecraft:piston',Properties:{extended:'true',facing:'up'}}"); -+ register(538, "{Name:'minecraft:piston',Properties:{extended:'true',facing:'north'}}", "{Name:'minecraft:piston',Properties:{extended:'true',facing:'north'}}"); -+ register(539, "{Name:'minecraft:piston',Properties:{extended:'true',facing:'south'}}", "{Name:'minecraft:piston',Properties:{extended:'true',facing:'south'}}"); -+ register(540, "{Name:'minecraft:piston',Properties:{extended:'true',facing:'west'}}", "{Name:'minecraft:piston',Properties:{extended:'true',facing:'west'}}"); -+ register(541, "{Name:'minecraft:piston',Properties:{extended:'true',facing:'east'}}", "{Name:'minecraft:piston',Properties:{extended:'true',facing:'east'}}"); -+ register(544, "{Name:'minecraft:piston_head',Properties:{facing:'down',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'down',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'down',short:'true',type:'normal'}}"); -+ register(545, "{Name:'minecraft:piston_head',Properties:{facing:'up',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'up',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'up',short:'true',type:'normal'}}"); -+ register(546, "{Name:'minecraft:piston_head',Properties:{facing:'north',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'north',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'north',short:'true',type:'normal'}}"); -+ register(547, "{Name:'minecraft:piston_head',Properties:{facing:'south',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'south',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'south',short:'true',type:'normal'}}"); -+ register(548, "{Name:'minecraft:piston_head',Properties:{facing:'west',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'west',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'west',short:'true',type:'normal'}}"); -+ register(549, "{Name:'minecraft:piston_head',Properties:{facing:'east',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'east',short:'false',type:'normal'}}", "{Name:'minecraft:piston_head',Properties:{facing:'east',short:'true',type:'normal'}}"); -+ register(552, "{Name:'minecraft:piston_head',Properties:{facing:'down',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'down',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'down',short:'true',type:'sticky'}}"); -+ register(553, "{Name:'minecraft:piston_head',Properties:{facing:'up',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'up',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'up',short:'true',type:'sticky'}}"); -+ register(554, "{Name:'minecraft:piston_head',Properties:{facing:'north',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'north',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'north',short:'true',type:'sticky'}}"); -+ register(555, "{Name:'minecraft:piston_head',Properties:{facing:'south',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'south',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'south',short:'true',type:'sticky'}}"); -+ register(556, "{Name:'minecraft:piston_head',Properties:{facing:'west',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'west',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'west',short:'true',type:'sticky'}}"); -+ register(557, "{Name:'minecraft:piston_head',Properties:{facing:'east',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'east',short:'false',type:'sticky'}}", "{Name:'minecraft:piston_head',Properties:{facing:'east',short:'true',type:'sticky'}}"); -+ register(560, "{Name:'minecraft:white_wool'}", "{Name:'minecraft:wool',Properties:{color:'white'}}"); -+ register(561, "{Name:'minecraft:orange_wool'}", "{Name:'minecraft:wool',Properties:{color:'orange'}}"); -+ register(562, "{Name:'minecraft:magenta_wool'}", "{Name:'minecraft:wool',Properties:{color:'magenta'}}"); -+ register(563, "{Name:'minecraft:light_blue_wool'}", "{Name:'minecraft:wool',Properties:{color:'light_blue'}}"); -+ register(564, "{Name:'minecraft:yellow_wool'}", "{Name:'minecraft:wool',Properties:{color:'yellow'}}"); -+ register(565, "{Name:'minecraft:lime_wool'}", "{Name:'minecraft:wool',Properties:{color:'lime'}}"); -+ register(566, "{Name:'minecraft:pink_wool'}", "{Name:'minecraft:wool',Properties:{color:'pink'}}"); -+ register(567, "{Name:'minecraft:gray_wool'}", "{Name:'minecraft:wool',Properties:{color:'gray'}}"); -+ register(568, "{Name:'minecraft:light_gray_wool'}", "{Name:'minecraft:wool',Properties:{color:'silver'}}"); -+ register(569, "{Name:'minecraft:cyan_wool'}", "{Name:'minecraft:wool',Properties:{color:'cyan'}}"); -+ register(570, "{Name:'minecraft:purple_wool'}", "{Name:'minecraft:wool',Properties:{color:'purple'}}"); -+ register(571, "{Name:'minecraft:blue_wool'}", "{Name:'minecraft:wool',Properties:{color:'blue'}}"); -+ register(572, "{Name:'minecraft:brown_wool'}", "{Name:'minecraft:wool',Properties:{color:'brown'}}"); -+ register(573, "{Name:'minecraft:green_wool'}", "{Name:'minecraft:wool',Properties:{color:'green'}}"); -+ register(574, "{Name:'minecraft:red_wool'}", "{Name:'minecraft:wool',Properties:{color:'red'}}"); -+ register(575, "{Name:'minecraft:black_wool'}", "{Name:'minecraft:wool',Properties:{color:'black'}}"); -+ register(576, "{Name:'minecraft:moving_piston',Properties:{facing:'down',type:'normal'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'down',type:'normal'}}"); -+ register(577, "{Name:'minecraft:moving_piston',Properties:{facing:'up',type:'normal'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'up',type:'normal'}}"); -+ register(578, "{Name:'minecraft:moving_piston',Properties:{facing:'north',type:'normal'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'north',type:'normal'}}"); -+ register(579, "{Name:'minecraft:moving_piston',Properties:{facing:'south',type:'normal'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'south',type:'normal'}}"); -+ register(580, "{Name:'minecraft:moving_piston',Properties:{facing:'west',type:'normal'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'west',type:'normal'}}"); -+ register(581, "{Name:'minecraft:moving_piston',Properties:{facing:'east',type:'normal'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'east',type:'normal'}}"); -+ register(584, "{Name:'minecraft:moving_piston',Properties:{facing:'down',type:'sticky'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'down',type:'sticky'}}"); -+ register(585, "{Name:'minecraft:moving_piston',Properties:{facing:'up',type:'sticky'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'up',type:'sticky'}}"); -+ register(586, "{Name:'minecraft:moving_piston',Properties:{facing:'north',type:'sticky'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'north',type:'sticky'}}"); -+ register(587, "{Name:'minecraft:moving_piston',Properties:{facing:'south',type:'sticky'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'south',type:'sticky'}}"); -+ register(588, "{Name:'minecraft:moving_piston',Properties:{facing:'west',type:'sticky'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'west',type:'sticky'}}"); -+ register(589, "{Name:'minecraft:moving_piston',Properties:{facing:'east',type:'sticky'}}", "{Name:'minecraft:piston_extension',Properties:{facing:'east',type:'sticky'}}"); -+ register(592, "{Name:'minecraft:dandelion'}", "{Name:'minecraft:yellow_flower',Properties:{type:'dandelion'}}"); -+ register(608, "{Name:'minecraft:poppy'}", "{Name:'minecraft:red_flower',Properties:{type:'poppy'}}"); -+ register(609, "{Name:'minecraft:blue_orchid'}", "{Name:'minecraft:red_flower',Properties:{type:'blue_orchid'}}"); -+ register(610, "{Name:'minecraft:allium'}", "{Name:'minecraft:red_flower',Properties:{type:'allium'}}"); -+ register(611, "{Name:'minecraft:azure_bluet'}", "{Name:'minecraft:red_flower',Properties:{type:'houstonia'}}"); -+ register(612, "{Name:'minecraft:red_tulip'}", "{Name:'minecraft:red_flower',Properties:{type:'red_tulip'}}"); -+ register(613, "{Name:'minecraft:orange_tulip'}", "{Name:'minecraft:red_flower',Properties:{type:'orange_tulip'}}"); -+ register(614, "{Name:'minecraft:white_tulip'}", "{Name:'minecraft:red_flower',Properties:{type:'white_tulip'}}"); -+ register(615, "{Name:'minecraft:pink_tulip'}", "{Name:'minecraft:red_flower',Properties:{type:'pink_tulip'}}"); -+ register(616, "{Name:'minecraft:oxeye_daisy'}", "{Name:'minecraft:red_flower',Properties:{type:'oxeye_daisy'}}"); -+ register(624, "{Name:'minecraft:brown_mushroom'}", "{Name:'minecraft:brown_mushroom'}"); -+ register(640, "{Name:'minecraft:red_mushroom'}", "{Name:'minecraft:red_mushroom'}"); -+ register(656, "{Name:'minecraft:gold_block'}", "{Name:'minecraft:gold_block'}"); -+ register(672, "{Name:'minecraft:iron_block'}", "{Name:'minecraft:iron_block'}"); -+ register(688, "{Name:'minecraft:stone_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'stone'}}"); -+ register(689, "{Name:'minecraft:sandstone_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'sandstone'}}"); -+ register(690, "{Name:'minecraft:petrified_oak_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'wood_old'}}"); -+ register(691, "{Name:'minecraft:cobblestone_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'cobblestone'}}"); -+ register(692, "{Name:'minecraft:brick_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'brick'}}"); -+ register(693, "{Name:'minecraft:stone_brick_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'stone_brick'}}"); -+ register(694, "{Name:'minecraft:nether_brick_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'nether_brick'}}"); -+ register(695, "{Name:'minecraft:quartz_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'false',variant:'quartz'}}"); -+ register(696, "{Name:'minecraft:smooth_stone'}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'stone'}}"); -+ register(697, "{Name:'minecraft:smooth_sandstone'}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'sandstone'}}"); -+ register(698, "{Name:'minecraft:petrified_oak_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'wood_old'}}"); -+ register(699, "{Name:'minecraft:cobblestone_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'cobblestone'}}"); -+ register(700, "{Name:'minecraft:brick_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'brick'}}"); -+ register(701, "{Name:'minecraft:stone_brick_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'stone_brick'}}"); -+ register(702, "{Name:'minecraft:nether_brick_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'nether_brick'}}"); -+ register(703, "{Name:'minecraft:smooth_quartz'}", "{Name:'minecraft:double_stone_slab',Properties:{seamless:'true',variant:'quartz'}}"); -+ register(704, "{Name:'minecraft:stone_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'stone'}}"); -+ register(705, "{Name:'minecraft:sandstone_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'sandstone'}}"); -+ register(706, "{Name:'minecraft:petrified_oak_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'wood_old'}}"); -+ register(707, "{Name:'minecraft:cobblestone_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'cobblestone'}}"); -+ register(708, "{Name:'minecraft:brick_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'brick'}}"); -+ register(709, "{Name:'minecraft:stone_brick_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'stone_brick'}}"); -+ register(710, "{Name:'minecraft:nether_brick_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'nether_brick'}}"); -+ register(711, "{Name:'minecraft:quartz_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab',Properties:{half:'bottom',variant:'quartz'}}"); -+ register(712, "{Name:'minecraft:stone_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'stone'}}"); -+ register(713, "{Name:'minecraft:sandstone_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'sandstone'}}"); -+ register(714, "{Name:'minecraft:petrified_oak_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'wood_old'}}"); -+ register(715, "{Name:'minecraft:cobblestone_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'cobblestone'}}"); -+ register(716, "{Name:'minecraft:brick_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'brick'}}"); -+ register(717, "{Name:'minecraft:stone_brick_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'stone_brick'}}"); -+ register(718, "{Name:'minecraft:nether_brick_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'nether_brick'}}"); -+ register(719, "{Name:'minecraft:quartz_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab',Properties:{half:'top',variant:'quartz'}}"); -+ register(720, "{Name:'minecraft:bricks'}", "{Name:'minecraft:brick_block'}"); -+ register(736, "{Name:'minecraft:tnt',Properties:{unstable:'false'}}", "{Name:'minecraft:tnt',Properties:{explode:'false'}}"); -+ register(737, "{Name:'minecraft:tnt',Properties:{unstable:'true'}}", "{Name:'minecraft:tnt',Properties:{explode:'true'}}"); -+ register(752, "{Name:'minecraft:bookshelf'}", "{Name:'minecraft:bookshelf'}"); -+ register(768, "{Name:'minecraft:mossy_cobblestone'}", "{Name:'minecraft:mossy_cobblestone'}"); -+ register(784, "{Name:'minecraft:obsidian'}", "{Name:'minecraft:obsidian'}"); -+ register(801, "{Name:'minecraft:wall_torch',Properties:{facing:'east'}}", "{Name:'minecraft:torch',Properties:{facing:'east'}}"); -+ register(802, "{Name:'minecraft:wall_torch',Properties:{facing:'west'}}", "{Name:'minecraft:torch',Properties:{facing:'west'}}"); -+ register(803, "{Name:'minecraft:wall_torch',Properties:{facing:'south'}}", "{Name:'minecraft:torch',Properties:{facing:'south'}}"); -+ register(804, "{Name:'minecraft:wall_torch',Properties:{facing:'north'}}", "{Name:'minecraft:torch',Properties:{facing:'north'}}"); -+ register(805, "{Name:'minecraft:torch'}", "{Name:'minecraft:torch',Properties:{facing:'up'}}"); -+ register(816, "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'0',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(817, "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'1',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(818, "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'2',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(819, "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'3',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(820, "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'4',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(821, "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'5',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(822, "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'6',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(823, "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'7',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(824, "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'8',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(825, "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'9',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(826, "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'10',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(827, "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'11',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(828, "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'12',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(829, "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'13',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(830, "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'14',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(831, "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:fire',Properties:{age:'15',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(832, "{Name:'minecraft:mob_spawner'}", "{Name:'minecraft:mob_spawner'}"); -+ register(848, "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(849, "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(850, "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(851, "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(852, "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(853, "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(854, "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(855, "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:oak_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(866, "{Name:'minecraft:chest',Properties:{facing:'north',type:'single'}}", "{Name:'minecraft:chest',Properties:{facing:'north'}}"); -+ register(867, "{Name:'minecraft:chest',Properties:{facing:'south',type:'single'}}", "{Name:'minecraft:chest',Properties:{facing:'south'}}"); -+ register(868, "{Name:'minecraft:chest',Properties:{facing:'west',type:'single'}}", "{Name:'minecraft:chest',Properties:{facing:'west'}}"); -+ register(869, "{Name:'minecraft:chest',Properties:{facing:'east',type:'single'}}", "{Name:'minecraft:chest',Properties:{facing:'east'}}"); -+ register(880, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'0',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'0',south:'up',west:'up'}}"); -+ register(881, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'1',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'1',south:'up',west:'up'}}"); -+ register(882, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'2',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'2',south:'up',west:'up'}}"); -+ register(883, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'3',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'3',south:'up',west:'up'}}"); -+ register(884, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'4',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'4',south:'up',west:'up'}}"); -+ register(885, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'5',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'5',south:'up',west:'up'}}"); -+ register(886, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'6',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'6',south:'up',west:'up'}}"); -+ register(887, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'7',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'7',south:'up',west:'up'}}"); -+ register(888, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'8',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'8',south:'up',west:'up'}}"); -+ register(889, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'9',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'9',south:'up',west:'up'}}"); -+ register(890, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'10',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'10',south:'up',west:'up'}}"); -+ register(891, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'11',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'11',south:'up',west:'up'}}"); -+ register(892, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'12',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'12',south:'up',west:'up'}}"); -+ register(893, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'13',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'13',south:'up',west:'up'}}"); -+ register(894, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'14',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'14',south:'up',west:'up'}}"); -+ register(895, "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'none',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'side',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'none',north:'up',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'none',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'side',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'side',north:'up',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'none',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'side',power:'15',south:'up',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'none',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'none',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'none',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'side',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'side',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'side',west:'up'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'up',west:'none'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'up',west:'side'}}", "{Name:'minecraft:redstone_wire',Properties:{east:'up',north:'up',power:'15',south:'up',west:'up'}}"); -+ register(896, "{Name:'minecraft:diamond_ore'}", "{Name:'minecraft:diamond_ore'}"); -+ register(912, "{Name:'minecraft:diamond_block'}", "{Name:'minecraft:diamond_block'}"); -+ register(928, "{Name:'minecraft:crafting_table'}", "{Name:'minecraft:crafting_table'}"); -+ register(944, "{Name:'minecraft:wheat',Properties:{age:'0'}}", "{Name:'minecraft:wheat',Properties:{age:'0'}}"); -+ register(945, "{Name:'minecraft:wheat',Properties:{age:'1'}}", "{Name:'minecraft:wheat',Properties:{age:'1'}}"); -+ register(946, "{Name:'minecraft:wheat',Properties:{age:'2'}}", "{Name:'minecraft:wheat',Properties:{age:'2'}}"); -+ register(947, "{Name:'minecraft:wheat',Properties:{age:'3'}}", "{Name:'minecraft:wheat',Properties:{age:'3'}}"); -+ register(948, "{Name:'minecraft:wheat',Properties:{age:'4'}}", "{Name:'minecraft:wheat',Properties:{age:'4'}}"); -+ register(949, "{Name:'minecraft:wheat',Properties:{age:'5'}}", "{Name:'minecraft:wheat',Properties:{age:'5'}}"); -+ register(950, "{Name:'minecraft:wheat',Properties:{age:'6'}}", "{Name:'minecraft:wheat',Properties:{age:'6'}}"); -+ register(951, "{Name:'minecraft:wheat',Properties:{age:'7'}}", "{Name:'minecraft:wheat',Properties:{age:'7'}}"); -+ register(960, "{Name:'minecraft:farmland',Properties:{moisture:'0'}}", "{Name:'minecraft:farmland',Properties:{moisture:'0'}}"); -+ register(961, "{Name:'minecraft:farmland',Properties:{moisture:'1'}}", "{Name:'minecraft:farmland',Properties:{moisture:'1'}}"); -+ register(962, "{Name:'minecraft:farmland',Properties:{moisture:'2'}}", "{Name:'minecraft:farmland',Properties:{moisture:'2'}}"); -+ register(963, "{Name:'minecraft:farmland',Properties:{moisture:'3'}}", "{Name:'minecraft:farmland',Properties:{moisture:'3'}}"); -+ register(964, "{Name:'minecraft:farmland',Properties:{moisture:'4'}}", "{Name:'minecraft:farmland',Properties:{moisture:'4'}}"); -+ register(965, "{Name:'minecraft:farmland',Properties:{moisture:'5'}}", "{Name:'minecraft:farmland',Properties:{moisture:'5'}}"); -+ register(966, "{Name:'minecraft:farmland',Properties:{moisture:'6'}}", "{Name:'minecraft:farmland',Properties:{moisture:'6'}}"); -+ register(967, "{Name:'minecraft:farmland',Properties:{moisture:'7'}}", "{Name:'minecraft:farmland',Properties:{moisture:'7'}}"); -+ register(978, "{Name:'minecraft:furnace',Properties:{facing:'north',lit:'false'}}", "{Name:'minecraft:furnace',Properties:{facing:'north'}}"); -+ register(979, "{Name:'minecraft:furnace',Properties:{facing:'south',lit:'false'}}", "{Name:'minecraft:furnace',Properties:{facing:'south'}}"); -+ register(980, "{Name:'minecraft:furnace',Properties:{facing:'west',lit:'false'}}", "{Name:'minecraft:furnace',Properties:{facing:'west'}}"); -+ register(981, "{Name:'minecraft:furnace',Properties:{facing:'east',lit:'false'}}", "{Name:'minecraft:furnace',Properties:{facing:'east'}}"); -+ register(994, "{Name:'minecraft:furnace',Properties:{facing:'north',lit:'true'}}", "{Name:'minecraft:lit_furnace',Properties:{facing:'north'}}"); -+ register(995, "{Name:'minecraft:furnace',Properties:{facing:'south',lit:'true'}}", "{Name:'minecraft:lit_furnace',Properties:{facing:'south'}}"); -+ register(996, "{Name:'minecraft:furnace',Properties:{facing:'west',lit:'true'}}", "{Name:'minecraft:lit_furnace',Properties:{facing:'west'}}"); -+ register(997, "{Name:'minecraft:furnace',Properties:{facing:'east',lit:'true'}}", "{Name:'minecraft:lit_furnace',Properties:{facing:'east'}}"); -+ register(1008, "{Name:'minecraft:sign',Properties:{rotation:'0'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'0'}}"); -+ register(1009, "{Name:'minecraft:sign',Properties:{rotation:'1'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'1'}}"); -+ register(1010, "{Name:'minecraft:sign',Properties:{rotation:'2'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'2'}}"); -+ register(1011, "{Name:'minecraft:sign',Properties:{rotation:'3'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'3'}}"); -+ register(1012, "{Name:'minecraft:sign',Properties:{rotation:'4'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'4'}}"); -+ register(1013, "{Name:'minecraft:sign',Properties:{rotation:'5'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'5'}}"); -+ register(1014, "{Name:'minecraft:sign',Properties:{rotation:'6'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'6'}}"); -+ register(1015, "{Name:'minecraft:sign',Properties:{rotation:'7'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'7'}}"); -+ register(1016, "{Name:'minecraft:sign',Properties:{rotation:'8'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'8'}}"); -+ register(1017, "{Name:'minecraft:sign',Properties:{rotation:'9'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'9'}}"); -+ register(1018, "{Name:'minecraft:sign',Properties:{rotation:'10'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'10'}}"); -+ register(1019, "{Name:'minecraft:sign',Properties:{rotation:'11'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'11'}}"); -+ register(1020, "{Name:'minecraft:sign',Properties:{rotation:'12'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'12'}}"); -+ register(1021, "{Name:'minecraft:sign',Properties:{rotation:'13'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'13'}}"); -+ register(1022, "{Name:'minecraft:sign',Properties:{rotation:'14'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'14'}}"); -+ register(1023, "{Name:'minecraft:sign',Properties:{rotation:'15'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'15'}}"); -+ register(1024, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1025, "{Name:'minecraft:oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1026, "{Name:'minecraft:oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1027, "{Name:'minecraft:oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1028, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1029, "{Name:'minecraft:oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1030, "{Name:'minecraft:oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1031, "{Name:'minecraft:oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1032, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1033, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(1034, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(1035, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:wooden_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(1036, "{Name:'minecraft:oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1037, "{Name:'minecraft:oak_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1038, "{Name:'minecraft:oak_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1039, "{Name:'minecraft:oak_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1042, "{Name:'minecraft:ladder',Properties:{facing:'north'}}", "{Name:'minecraft:ladder',Properties:{facing:'north'}}"); -+ register(1043, "{Name:'minecraft:ladder',Properties:{facing:'south'}}", "{Name:'minecraft:ladder',Properties:{facing:'south'}}"); -+ register(1044, "{Name:'minecraft:ladder',Properties:{facing:'west'}}", "{Name:'minecraft:ladder',Properties:{facing:'west'}}"); -+ register(1045, "{Name:'minecraft:ladder',Properties:{facing:'east'}}", "{Name:'minecraft:ladder',Properties:{facing:'east'}}"); -+ register(1056, "{Name:'minecraft:rail',Properties:{shape:'north_south'}}", "{Name:'minecraft:rail',Properties:{shape:'north_south'}}"); -+ register(1057, "{Name:'minecraft:rail',Properties:{shape:'east_west'}}", "{Name:'minecraft:rail',Properties:{shape:'east_west'}}"); -+ register(1058, "{Name:'minecraft:rail',Properties:{shape:'ascending_east'}}", "{Name:'minecraft:rail',Properties:{shape:'ascending_east'}}"); -+ register(1059, "{Name:'minecraft:rail',Properties:{shape:'ascending_west'}}", "{Name:'minecraft:rail',Properties:{shape:'ascending_west'}}"); -+ register(1060, "{Name:'minecraft:rail',Properties:{shape:'ascending_north'}}", "{Name:'minecraft:rail',Properties:{shape:'ascending_north'}}"); -+ register(1061, "{Name:'minecraft:rail',Properties:{shape:'ascending_south'}}", "{Name:'minecraft:rail',Properties:{shape:'ascending_south'}}"); -+ register(1062, "{Name:'minecraft:rail',Properties:{shape:'south_east'}}", "{Name:'minecraft:rail',Properties:{shape:'south_east'}}"); -+ register(1063, "{Name:'minecraft:rail',Properties:{shape:'south_west'}}", "{Name:'minecraft:rail',Properties:{shape:'south_west'}}"); -+ register(1064, "{Name:'minecraft:rail',Properties:{shape:'north_west'}}", "{Name:'minecraft:rail',Properties:{shape:'north_west'}}"); -+ register(1065, "{Name:'minecraft:rail',Properties:{shape:'north_east'}}", "{Name:'minecraft:rail',Properties:{shape:'north_east'}}"); -+ register(1072, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(1073, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(1074, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(1075, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(1076, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(1077, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(1078, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(1079, "{Name:'minecraft:cobblestone_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(1090, "{Name:'minecraft:wall_sign',Properties:{facing:'north'}}", "{Name:'minecraft:wall_sign',Properties:{facing:'north'}}"); -+ register(1091, "{Name:'minecraft:wall_sign',Properties:{facing:'south'}}", "{Name:'minecraft:wall_sign',Properties:{facing:'south'}}"); -+ register(1092, "{Name:'minecraft:wall_sign',Properties:{facing:'west'}}", "{Name:'minecraft:wall_sign',Properties:{facing:'west'}}"); -+ register(1093, "{Name:'minecraft:wall_sign',Properties:{facing:'east'}}", "{Name:'minecraft:wall_sign',Properties:{facing:'east'}}"); -+ register(1104, "{Name:'minecraft:lever',Properties:{face:'ceiling',facing:'west',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'down_x',powered:'false'}}"); -+ register(1105, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'east',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'east',powered:'false'}}"); -+ register(1106, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'west',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'west',powered:'false'}}"); -+ register(1107, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'south',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'south',powered:'false'}}"); -+ register(1108, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'north',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'north',powered:'false'}}"); -+ register(1109, "{Name:'minecraft:lever',Properties:{face:'floor',facing:'north',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'up_z',powered:'false'}}"); -+ register(1110, "{Name:'minecraft:lever',Properties:{face:'floor',facing:'west',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'up_x',powered:'false'}}"); -+ register(1111, "{Name:'minecraft:lever',Properties:{face:'ceiling',facing:'north',powered:'false'}}", "{Name:'minecraft:lever',Properties:{facing:'down_z',powered:'false'}}"); -+ register(1112, "{Name:'minecraft:lever',Properties:{face:'ceiling',facing:'west',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'down_x',powered:'true'}}"); -+ register(1113, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'east',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'east',powered:'true'}}"); -+ register(1114, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'west',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'west',powered:'true'}}"); -+ register(1115, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'south',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'south',powered:'true'}}"); -+ register(1116, "{Name:'minecraft:lever',Properties:{face:'wall',facing:'north',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'north',powered:'true'}}"); -+ register(1117, "{Name:'minecraft:lever',Properties:{face:'floor',facing:'north',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'up_z',powered:'true'}}"); -+ register(1118, "{Name:'minecraft:lever',Properties:{face:'floor',facing:'west',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'up_x',powered:'true'}}"); -+ register(1119, "{Name:'minecraft:lever',Properties:{face:'ceiling',facing:'north',powered:'true'}}", "{Name:'minecraft:lever',Properties:{facing:'down_z',powered:'true'}}"); -+ register(1120, "{Name:'minecraft:stone_pressure_plate',Properties:{powered:'false'}}", "{Name:'minecraft:stone_pressure_plate',Properties:{powered:'false'}}"); -+ register(1121, "{Name:'minecraft:stone_pressure_plate',Properties:{powered:'true'}}", "{Name:'minecraft:stone_pressure_plate',Properties:{powered:'true'}}"); -+ register(1136, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1137, "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1138, "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1139, "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(1140, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1141, "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1142, "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1143, "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(1144, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1145, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(1146, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(1147, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(1148, "{Name:'minecraft:iron_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1149, "{Name:'minecraft:iron_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1150, "{Name:'minecraft:iron_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1151, "{Name:'minecraft:iron_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(1152, "{Name:'minecraft:oak_pressure_plate',Properties:{powered:'false'}}", "{Name:'minecraft:wooden_pressure_plate',Properties:{powered:'false'}}"); -+ register(1153, "{Name:'minecraft:oak_pressure_plate',Properties:{powered:'true'}}", "{Name:'minecraft:wooden_pressure_plate',Properties:{powered:'true'}}"); -+ register(1168, "{Name:'minecraft:redstone_ore',Properties:{lit:'false'}}", "{Name:'minecraft:redstone_ore'}"); -+ register(1184, "{Name:'minecraft:redstone_ore',Properties:{lit:'true'}}", "{Name:'minecraft:lit_redstone_ore'}"); -+ register(1201, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'east',lit:'false'}}", "{Name:'minecraft:unlit_redstone_torch',Properties:{facing:'east'}}"); -+ register(1202, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'west',lit:'false'}}", "{Name:'minecraft:unlit_redstone_torch',Properties:{facing:'west'}}"); -+ register(1203, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'south',lit:'false'}}", "{Name:'minecraft:unlit_redstone_torch',Properties:{facing:'south'}}"); -+ register(1204, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'north',lit:'false'}}", "{Name:'minecraft:unlit_redstone_torch',Properties:{facing:'north'}}"); -+ register(1205, "{Name:'minecraft:redstone_torch',Properties:{lit:'false'}}", "{Name:'minecraft:unlit_redstone_torch',Properties:{facing:'up'}}"); -+ register(1217, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'east',lit:'true'}}", "{Name:'minecraft:redstone_torch',Properties:{facing:'east'}}"); -+ register(1218, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'west',lit:'true'}}", "{Name:'minecraft:redstone_torch',Properties:{facing:'west'}}"); -+ register(1219, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'south',lit:'true'}}", "{Name:'minecraft:redstone_torch',Properties:{facing:'south'}}"); -+ register(1220, "{Name:'minecraft:redstone_wall_torch',Properties:{facing:'north',lit:'true'}}", "{Name:'minecraft:redstone_torch',Properties:{facing:'north'}}"); -+ register(1221, "{Name:'minecraft:redstone_torch',Properties:{lit:'true'}}", "{Name:'minecraft:redstone_torch',Properties:{facing:'up'}}"); -+ register(1232, "{Name:'minecraft:stone_button',Properties:{face:'ceiling',facing:'north',powered:'false'}}", "{Name:'minecraft:stone_button',Properties:{facing:'down',powered:'false'}}"); -+ register(1233, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'east',powered:'false'}}", "{Name:'minecraft:stone_button',Properties:{facing:'east',powered:'false'}}"); -+ register(1234, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'west',powered:'false'}}", "{Name:'minecraft:stone_button',Properties:{facing:'west',powered:'false'}}"); -+ register(1235, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'south',powered:'false'}}", "{Name:'minecraft:stone_button',Properties:{facing:'south',powered:'false'}}"); -+ register(1236, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'north',powered:'false'}}", "{Name:'minecraft:stone_button',Properties:{facing:'north',powered:'false'}}"); -+ register(1237, "{Name:'minecraft:stone_button',Properties:{face:'floor',facing:'north',powered:'false'}}", "{Name:'minecraft:stone_button',Properties:{facing:'up',powered:'false'}}"); -+ register(1240, "{Name:'minecraft:stone_button',Properties:{face:'ceiling',facing:'north',powered:'true'}}", "{Name:'minecraft:stone_button',Properties:{facing:'down',powered:'true'}}"); -+ register(1241, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'east',powered:'true'}}", "{Name:'minecraft:stone_button',Properties:{facing:'east',powered:'true'}}"); -+ register(1242, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'west',powered:'true'}}", "{Name:'minecraft:stone_button',Properties:{facing:'west',powered:'true'}}"); -+ register(1243, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'south',powered:'true'}}", "{Name:'minecraft:stone_button',Properties:{facing:'south',powered:'true'}}"); -+ register(1244, "{Name:'minecraft:stone_button',Properties:{face:'wall',facing:'north',powered:'true'}}", "{Name:'minecraft:stone_button',Properties:{facing:'north',powered:'true'}}"); -+ register(1245, "{Name:'minecraft:stone_button',Properties:{face:'floor',facing:'north',powered:'true'}}", "{Name:'minecraft:stone_button',Properties:{facing:'up',powered:'true'}}"); -+ register(1248, "{Name:'minecraft:snow',Properties:{layers:'1'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'1'}}"); -+ register(1249, "{Name:'minecraft:snow',Properties:{layers:'2'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'2'}}"); -+ register(1250, "{Name:'minecraft:snow',Properties:{layers:'3'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'3'}}"); -+ register(1251, "{Name:'minecraft:snow',Properties:{layers:'4'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'4'}}"); -+ register(1252, "{Name:'minecraft:snow',Properties:{layers:'5'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'5'}}"); -+ register(1253, "{Name:'minecraft:snow',Properties:{layers:'6'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'6'}}"); -+ register(1254, "{Name:'minecraft:snow',Properties:{layers:'7'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'7'}}"); -+ register(1255, "{Name:'minecraft:snow',Properties:{layers:'8'}}", "{Name:'minecraft:snow_layer',Properties:{layers:'8'}}"); -+ register(1264, "{Name:'minecraft:ice'}", "{Name:'minecraft:ice'}"); -+ register(1280, "{Name:'minecraft:snow_block'}", "{Name:'minecraft:snow'}"); -+ register(1296, "{Name:'minecraft:cactus',Properties:{age:'0'}}", "{Name:'minecraft:cactus',Properties:{age:'0'}}"); -+ register(1297, "{Name:'minecraft:cactus',Properties:{age:'1'}}", "{Name:'minecraft:cactus',Properties:{age:'1'}}"); -+ register(1298, "{Name:'minecraft:cactus',Properties:{age:'2'}}", "{Name:'minecraft:cactus',Properties:{age:'2'}}"); -+ register(1299, "{Name:'minecraft:cactus',Properties:{age:'3'}}", "{Name:'minecraft:cactus',Properties:{age:'3'}}"); -+ register(1300, "{Name:'minecraft:cactus',Properties:{age:'4'}}", "{Name:'minecraft:cactus',Properties:{age:'4'}}"); -+ register(1301, "{Name:'minecraft:cactus',Properties:{age:'5'}}", "{Name:'minecraft:cactus',Properties:{age:'5'}}"); -+ register(1302, "{Name:'minecraft:cactus',Properties:{age:'6'}}", "{Name:'minecraft:cactus',Properties:{age:'6'}}"); -+ register(1303, "{Name:'minecraft:cactus',Properties:{age:'7'}}", "{Name:'minecraft:cactus',Properties:{age:'7'}}"); -+ register(1304, "{Name:'minecraft:cactus',Properties:{age:'8'}}", "{Name:'minecraft:cactus',Properties:{age:'8'}}"); -+ register(1305, "{Name:'minecraft:cactus',Properties:{age:'9'}}", "{Name:'minecraft:cactus',Properties:{age:'9'}}"); -+ register(1306, "{Name:'minecraft:cactus',Properties:{age:'10'}}", "{Name:'minecraft:cactus',Properties:{age:'10'}}"); -+ register(1307, "{Name:'minecraft:cactus',Properties:{age:'11'}}", "{Name:'minecraft:cactus',Properties:{age:'11'}}"); -+ register(1308, "{Name:'minecraft:cactus',Properties:{age:'12'}}", "{Name:'minecraft:cactus',Properties:{age:'12'}}"); -+ register(1309, "{Name:'minecraft:cactus',Properties:{age:'13'}}", "{Name:'minecraft:cactus',Properties:{age:'13'}}"); -+ register(1310, "{Name:'minecraft:cactus',Properties:{age:'14'}}", "{Name:'minecraft:cactus',Properties:{age:'14'}}"); -+ register(1311, "{Name:'minecraft:cactus',Properties:{age:'15'}}", "{Name:'minecraft:cactus',Properties:{age:'15'}}"); -+ register(1312, "{Name:'minecraft:clay'}", "{Name:'minecraft:clay'}"); -+ register(1328, "{Name:'minecraft:sugar_cane',Properties:{age:'0'}}", "{Name:'minecraft:reeds',Properties:{age:'0'}}"); -+ register(1329, "{Name:'minecraft:sugar_cane',Properties:{age:'1'}}", "{Name:'minecraft:reeds',Properties:{age:'1'}}"); -+ register(1330, "{Name:'minecraft:sugar_cane',Properties:{age:'2'}}", "{Name:'minecraft:reeds',Properties:{age:'2'}}"); -+ register(1331, "{Name:'minecraft:sugar_cane',Properties:{age:'3'}}", "{Name:'minecraft:reeds',Properties:{age:'3'}}"); -+ register(1332, "{Name:'minecraft:sugar_cane',Properties:{age:'4'}}", "{Name:'minecraft:reeds',Properties:{age:'4'}}"); -+ register(1333, "{Name:'minecraft:sugar_cane',Properties:{age:'5'}}", "{Name:'minecraft:reeds',Properties:{age:'5'}}"); -+ register(1334, "{Name:'minecraft:sugar_cane',Properties:{age:'6'}}", "{Name:'minecraft:reeds',Properties:{age:'6'}}"); -+ register(1335, "{Name:'minecraft:sugar_cane',Properties:{age:'7'}}", "{Name:'minecraft:reeds',Properties:{age:'7'}}"); -+ register(1336, "{Name:'minecraft:sugar_cane',Properties:{age:'8'}}", "{Name:'minecraft:reeds',Properties:{age:'8'}}"); -+ register(1337, "{Name:'minecraft:sugar_cane',Properties:{age:'9'}}", "{Name:'minecraft:reeds',Properties:{age:'9'}}"); -+ register(1338, "{Name:'minecraft:sugar_cane',Properties:{age:'10'}}", "{Name:'minecraft:reeds',Properties:{age:'10'}}"); -+ register(1339, "{Name:'minecraft:sugar_cane',Properties:{age:'11'}}", "{Name:'minecraft:reeds',Properties:{age:'11'}}"); -+ register(1340, "{Name:'minecraft:sugar_cane',Properties:{age:'12'}}", "{Name:'minecraft:reeds',Properties:{age:'12'}}"); -+ register(1341, "{Name:'minecraft:sugar_cane',Properties:{age:'13'}}", "{Name:'minecraft:reeds',Properties:{age:'13'}}"); -+ register(1342, "{Name:'minecraft:sugar_cane',Properties:{age:'14'}}", "{Name:'minecraft:reeds',Properties:{age:'14'}}"); -+ register(1343, "{Name:'minecraft:sugar_cane',Properties:{age:'15'}}", "{Name:'minecraft:reeds',Properties:{age:'15'}}"); -+ register(1344, "{Name:'minecraft:jukebox',Properties:{has_record:'false'}}", "{Name:'minecraft:jukebox',Properties:{has_record:'false'}}"); -+ register(1345, "{Name:'minecraft:jukebox',Properties:{has_record:'true'}}", "{Name:'minecraft:jukebox',Properties:{has_record:'true'}}"); -+ register(1360, "{Name:'minecraft:oak_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(1376, "{Name:'minecraft:carved_pumpkin',Properties:{facing:'south'}}", "{Name:'minecraft:pumpkin',Properties:{facing:'south'}}"); -+ register(1377, "{Name:'minecraft:carved_pumpkin',Properties:{facing:'west'}}", "{Name:'minecraft:pumpkin',Properties:{facing:'west'}}"); -+ register(1378, "{Name:'minecraft:carved_pumpkin',Properties:{facing:'north'}}", "{Name:'minecraft:pumpkin',Properties:{facing:'north'}}"); -+ register(1379, "{Name:'minecraft:carved_pumpkin',Properties:{facing:'east'}}", "{Name:'minecraft:pumpkin',Properties:{facing:'east'}}"); -+ register(1392, "{Name:'minecraft:netherrack'}", "{Name:'minecraft:netherrack'}"); -+ register(1408, "{Name:'minecraft:soul_sand'}", "{Name:'minecraft:soul_sand'}"); -+ register(1424, "{Name:'minecraft:glowstone'}", "{Name:'minecraft:glowstone'}"); -+ register(1441, "{Name:'minecraft:portal',Properties:{axis:'x'}}", "{Name:'minecraft:portal',Properties:{axis:'x'}}"); -+ register(1442, "{Name:'minecraft:portal',Properties:{axis:'z'}}", "{Name:'minecraft:portal',Properties:{axis:'z'}}"); -+ register(1456, "{Name:'minecraft:jack_o_lantern',Properties:{facing:'south'}}", "{Name:'minecraft:lit_pumpkin',Properties:{facing:'south'}}"); -+ register(1457, "{Name:'minecraft:jack_o_lantern',Properties:{facing:'west'}}", "{Name:'minecraft:lit_pumpkin',Properties:{facing:'west'}}"); -+ register(1458, "{Name:'minecraft:jack_o_lantern',Properties:{facing:'north'}}", "{Name:'minecraft:lit_pumpkin',Properties:{facing:'north'}}"); -+ register(1459, "{Name:'minecraft:jack_o_lantern',Properties:{facing:'east'}}", "{Name:'minecraft:lit_pumpkin',Properties:{facing:'east'}}"); -+ register(1472, "{Name:'minecraft:cake',Properties:{bites:'0'}}", "{Name:'minecraft:cake',Properties:{bites:'0'}}"); -+ register(1473, "{Name:'minecraft:cake',Properties:{bites:'1'}}", "{Name:'minecraft:cake',Properties:{bites:'1'}}"); -+ register(1474, "{Name:'minecraft:cake',Properties:{bites:'2'}}", "{Name:'minecraft:cake',Properties:{bites:'2'}}"); -+ register(1475, "{Name:'minecraft:cake',Properties:{bites:'3'}}", "{Name:'minecraft:cake',Properties:{bites:'3'}}"); -+ register(1476, "{Name:'minecraft:cake',Properties:{bites:'4'}}", "{Name:'minecraft:cake',Properties:{bites:'4'}}"); -+ register(1477, "{Name:'minecraft:cake',Properties:{bites:'5'}}", "{Name:'minecraft:cake',Properties:{bites:'5'}}"); -+ register(1478, "{Name:'minecraft:cake',Properties:{bites:'6'}}", "{Name:'minecraft:cake',Properties:{bites:'6'}}"); -+ register(1488, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'south',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'south',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'south',locked:'true'}}"); -+ register(1489, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'west',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'west',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'west',locked:'true'}}"); -+ register(1490, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'north',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'north',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'north',locked:'true'}}"); -+ register(1491, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'east',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'east',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'1',facing:'east',locked:'true'}}"); -+ register(1492, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'south',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'south',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'south',locked:'true'}}"); -+ register(1493, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'west',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'west',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'west',locked:'true'}}"); -+ register(1494, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'north',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'north',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'north',locked:'true'}}"); -+ register(1495, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'east',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'east',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'2',facing:'east',locked:'true'}}"); -+ register(1496, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'south',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'south',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'south',locked:'true'}}"); -+ register(1497, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'west',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'west',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'west',locked:'true'}}"); -+ register(1498, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'north',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'north',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'north',locked:'true'}}"); -+ register(1499, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'east',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'east',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'3',facing:'east',locked:'true'}}"); -+ register(1500, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'south',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'south',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'south',locked:'true'}}"); -+ register(1501, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'west',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'west',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'west',locked:'true'}}"); -+ register(1502, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'north',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'north',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'north',locked:'true'}}"); -+ register(1503, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'east',locked:'false',powered:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'east',locked:'false'}}", "{Name:'minecraft:unpowered_repeater',Properties:{delay:'4',facing:'east',locked:'true'}}"); -+ register(1504, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'south',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'south',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'south',locked:'true'}}"); -+ register(1505, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'west',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'west',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'west',locked:'true'}}"); -+ register(1506, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'north',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'north',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'north',locked:'true'}}"); -+ register(1507, "{Name:'minecraft:repeater',Properties:{delay:'1',facing:'east',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'east',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'1',facing:'east',locked:'true'}}"); -+ register(1508, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'south',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'south',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'south',locked:'true'}}"); -+ register(1509, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'west',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'west',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'west',locked:'true'}}"); -+ register(1510, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'north',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'north',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'north',locked:'true'}}"); -+ register(1511, "{Name:'minecraft:repeater',Properties:{delay:'2',facing:'east',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'east',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'2',facing:'east',locked:'true'}}"); -+ register(1512, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'south',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'south',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'south',locked:'true'}}"); -+ register(1513, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'west',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'west',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'west',locked:'true'}}"); -+ register(1514, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'north',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'north',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'north',locked:'true'}}"); -+ register(1515, "{Name:'minecraft:repeater',Properties:{delay:'3',facing:'east',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'east',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'3',facing:'east',locked:'true'}}"); -+ register(1516, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'south',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'south',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'south',locked:'true'}}"); -+ register(1517, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'west',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'west',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'west',locked:'true'}}"); -+ register(1518, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'north',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'north',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'north',locked:'true'}}"); -+ register(1519, "{Name:'minecraft:repeater',Properties:{delay:'4',facing:'east',locked:'false',powered:'true'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'east',locked:'false'}}", "{Name:'minecraft:powered_repeater',Properties:{delay:'4',facing:'east',locked:'true'}}"); -+ register(1520, "{Name:'minecraft:white_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'white'}}"); -+ register(1521, "{Name:'minecraft:orange_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'orange'}}"); -+ register(1522, "{Name:'minecraft:magenta_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'magenta'}}"); -+ register(1523, "{Name:'minecraft:light_blue_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'light_blue'}}"); -+ register(1524, "{Name:'minecraft:yellow_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'yellow'}}"); -+ register(1525, "{Name:'minecraft:lime_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'lime'}}"); -+ register(1526, "{Name:'minecraft:pink_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'pink'}}"); -+ register(1527, "{Name:'minecraft:gray_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'gray'}}"); -+ register(1528, "{Name:'minecraft:light_gray_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'silver'}}"); -+ register(1529, "{Name:'minecraft:cyan_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'cyan'}}"); -+ register(1530, "{Name:'minecraft:purple_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'purple'}}"); -+ register(1531, "{Name:'minecraft:blue_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'blue'}}"); -+ register(1532, "{Name:'minecraft:brown_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'brown'}}"); -+ register(1533, "{Name:'minecraft:green_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'green'}}"); -+ register(1534, "{Name:'minecraft:red_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'red'}}"); -+ register(1535, "{Name:'minecraft:black_stained_glass'}", "{Name:'minecraft:stained_glass',Properties:{color:'black'}}"); -+ register(1536, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'north',half:'bottom',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'north',half:'bottom',open:'false'}}"); -+ register(1537, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'south',half:'bottom',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'south',half:'bottom',open:'false'}}"); -+ register(1538, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'west',half:'bottom',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'west',half:'bottom',open:'false'}}"); -+ register(1539, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'east',half:'bottom',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'east',half:'bottom',open:'false'}}"); -+ register(1540, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'north',half:'bottom',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'north',half:'bottom',open:'true'}}"); -+ register(1541, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'south',half:'bottom',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'south',half:'bottom',open:'true'}}"); -+ register(1542, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'west',half:'bottom',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'west',half:'bottom',open:'true'}}"); -+ register(1543, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'east',half:'bottom',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'east',half:'bottom',open:'true'}}"); -+ register(1544, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'north',half:'top',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'north',half:'top',open:'false'}}"); -+ register(1545, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'south',half:'top',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'south',half:'top',open:'false'}}"); -+ register(1546, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'west',half:'top',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'west',half:'top',open:'false'}}"); -+ register(1547, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'east',half:'top',open:'false'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'east',half:'top',open:'false'}}"); -+ register(1548, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'north',half:'top',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'north',half:'top',open:'true'}}"); -+ register(1549, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'south',half:'top',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'south',half:'top',open:'true'}}"); -+ register(1550, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'west',half:'top',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'west',half:'top',open:'true'}}"); -+ register(1551, "{Name:'minecraft:oak_trapdoor',Properties:{facing:'east',half:'top',open:'true'}}", "{Name:'minecraft:trapdoor',Properties:{facing:'east',half:'top',open:'true'}}"); -+ register(1552, "{Name:'minecraft:infested_stone'}", "{Name:'minecraft:monster_egg',Properties:{variant:'stone'}}"); -+ register(1553, "{Name:'minecraft:infested_cobblestone'}", "{Name:'minecraft:monster_egg',Properties:{variant:'cobblestone'}}"); -+ register(1554, "{Name:'minecraft:infested_stone_bricks'}", "{Name:'minecraft:monster_egg',Properties:{variant:'stone_brick'}}"); -+ register(1555, "{Name:'minecraft:infested_mossy_stone_bricks'}", "{Name:'minecraft:monster_egg',Properties:{variant:'mossy_brick'}}"); -+ register(1556, "{Name:'minecraft:infested_cracked_stone_bricks'}", "{Name:'minecraft:monster_egg',Properties:{variant:'cracked_brick'}}"); -+ register(1557, "{Name:'minecraft:infested_chiseled_stone_bricks'}", "{Name:'minecraft:monster_egg',Properties:{variant:'chiseled_brick'}}"); -+ register(1568, "{Name:'minecraft:stone_bricks'}", "{Name:'minecraft:stonebrick',Properties:{variant:'stonebrick'}}"); -+ register(1569, "{Name:'minecraft:mossy_stone_bricks'}", "{Name:'minecraft:stonebrick',Properties:{variant:'mossy_stonebrick'}}"); -+ register(1570, "{Name:'minecraft:cracked_stone_bricks'}", "{Name:'minecraft:stonebrick',Properties:{variant:'cracked_stonebrick'}}"); -+ register(1571, "{Name:'minecraft:chiseled_stone_bricks'}", "{Name:'minecraft:stonebrick',Properties:{variant:'chiseled_stonebrick'}}"); -+ register(1584, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'all_inside'}}"); -+ register(1585, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'true',east:'false',south:'false',west:'true',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'north_west'}}"); -+ register(1586, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'true',east:'false',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'north'}}"); -+ register(1587, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'true',east:'true',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'north_east'}}"); -+ register(1588, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'true',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'west'}}"); -+ register(1589, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'center'}}"); -+ register(1590, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'true',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'east'}}"); -+ register(1591, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'true',west:'true',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'south_west'}}"); -+ register(1592, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'true',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'south'}}"); -+ register(1593, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'true',south:'true',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'south_east'}}"); -+ register(1594, "{Name:'minecraft:mushroom_stem',Properties:{north:'true',east:'true',south:'true',west:'true',up:'false',down:'false'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'stem'}}"); -+ register(1595, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}"); -+ register(1596, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}"); -+ register(1597, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}"); -+ register(1598, "{Name:'minecraft:brown_mushroom_block',Properties:{north:'true',east:'true',south:'true',west:'true',up:'true',down:'true'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'all_outside'}}"); -+ register(1599, "{Name:'minecraft:mushroom_stem',Properties:{north:'true',east:'true',south:'true',west:'true',up:'true',down:'true'}}", "{Name:'minecraft:brown_mushroom_block',Properties:{variant:'all_stem'}}"); -+ register(1600, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'all_inside'}}"); -+ register(1601, "{Name:'minecraft:red_mushroom_block',Properties:{north:'true',east:'false',south:'false',west:'true',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'north_west'}}"); -+ register(1602, "{Name:'minecraft:red_mushroom_block',Properties:{north:'true',east:'false',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'north'}}"); -+ register(1603, "{Name:'minecraft:red_mushroom_block',Properties:{north:'true',east:'true',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'north_east'}}"); -+ register(1604, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'true',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'west'}}"); -+ register(1605, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'center'}}"); -+ register(1606, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'true',south:'false',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'east'}}"); -+ register(1607, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'true',west:'true',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'south_west'}}"); -+ register(1608, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'true',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'south'}}"); -+ register(1609, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'true',south:'true',west:'false',up:'true',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'south_east'}}"); -+ register(1610, "{Name:'minecraft:mushroom_stem',Properties:{north:'true',east:'true',south:'true',west:'true',up:'false',down:'false'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'stem'}}"); -+ register(1611, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}"); -+ register(1612, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}"); -+ register(1613, "{Name:'minecraft:red_mushroom_block',Properties:{north:'false',east:'false',south:'false',west:'false',up:'false',down:'false'}}"); -+ register(1614, "{Name:'minecraft:red_mushroom_block',Properties:{north:'true',east:'true',south:'true',west:'true',up:'true',down:'true'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'all_outside'}}"); -+ register(1615, "{Name:'minecraft:mushroom_stem',Properties:{north:'true',east:'true',south:'true',west:'true',up:'true',down:'true'}}", "{Name:'minecraft:red_mushroom_block',Properties:{variant:'all_stem'}}"); -+ register(1616, "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:iron_bars',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(1632, "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:glass_pane',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(1648, "{Name:'minecraft:melon_block'}", "{Name:'minecraft:melon_block'}"); -+ register(1664, "{Name:'minecraft:pumpkin_stem',Properties:{age:'0'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'0',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'0',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'0',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'0',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'0',facing:'west'}}"); -+ register(1665, "{Name:'minecraft:pumpkin_stem',Properties:{age:'1'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'1',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'1',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'1',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'1',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'1',facing:'west'}}"); -+ register(1666, "{Name:'minecraft:pumpkin_stem',Properties:{age:'2'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'2',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'2',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'2',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'2',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'2',facing:'west'}}"); -+ register(1667, "{Name:'minecraft:pumpkin_stem',Properties:{age:'3'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'3',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'3',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'3',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'3',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'3',facing:'west'}}"); -+ register(1668, "{Name:'minecraft:pumpkin_stem',Properties:{age:'4'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'4',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'4',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'4',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'4',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'4',facing:'west'}}"); -+ register(1669, "{Name:'minecraft:pumpkin_stem',Properties:{age:'5'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'5',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'5',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'5',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'5',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'5',facing:'west'}}"); -+ register(1670, "{Name:'minecraft:pumpkin_stem',Properties:{age:'6'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'6',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'6',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'6',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'6',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'6',facing:'west'}}"); -+ register(1671, "{Name:'minecraft:pumpkin_stem',Properties:{age:'7'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'7',facing:'east'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'7',facing:'north'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'7',facing:'south'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'7',facing:'up'}}", "{Name:'minecraft:pumpkin_stem',Properties:{age:'7',facing:'west'}}"); -+ register(1680, "{Name:'minecraft:melon_stem',Properties:{age:'0'}}", "{Name:'minecraft:melon_stem',Properties:{age:'0',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'0',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'0',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'0',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'0',facing:'west'}}"); -+ register(1681, "{Name:'minecraft:melon_stem',Properties:{age:'1'}}", "{Name:'minecraft:melon_stem',Properties:{age:'1',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'1',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'1',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'1',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'1',facing:'west'}}"); -+ register(1682, "{Name:'minecraft:melon_stem',Properties:{age:'2'}}", "{Name:'minecraft:melon_stem',Properties:{age:'2',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'2',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'2',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'2',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'2',facing:'west'}}"); -+ register(1683, "{Name:'minecraft:melon_stem',Properties:{age:'3'}}", "{Name:'minecraft:melon_stem',Properties:{age:'3',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'3',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'3',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'3',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'3',facing:'west'}}"); -+ register(1684, "{Name:'minecraft:melon_stem',Properties:{age:'4'}}", "{Name:'minecraft:melon_stem',Properties:{age:'4',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'4',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'4',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'4',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'4',facing:'west'}}"); -+ register(1685, "{Name:'minecraft:melon_stem',Properties:{age:'5'}}", "{Name:'minecraft:melon_stem',Properties:{age:'5',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'5',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'5',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'5',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'5',facing:'west'}}"); -+ register(1686, "{Name:'minecraft:melon_stem',Properties:{age:'6'}}", "{Name:'minecraft:melon_stem',Properties:{age:'6',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'6',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'6',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'6',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'6',facing:'west'}}"); -+ register(1687, "{Name:'minecraft:melon_stem',Properties:{age:'7'}}", "{Name:'minecraft:melon_stem',Properties:{age:'7',facing:'east'}}", "{Name:'minecraft:melon_stem',Properties:{age:'7',facing:'north'}}", "{Name:'minecraft:melon_stem',Properties:{age:'7',facing:'south'}}", "{Name:'minecraft:melon_stem',Properties:{age:'7',facing:'up'}}", "{Name:'minecraft:melon_stem',Properties:{age:'7',facing:'west'}}"); -+ register(1696, "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'false',up:'true',west:'false'}}"); -+ register(1697, "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'true',up:'true',west:'false'}}"); -+ register(1698, "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'false',up:'true',west:'true'}}"); -+ register(1699, "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'false',south:'true',up:'true',west:'true'}}"); -+ register(1700, "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'false',up:'true',west:'false'}}"); -+ register(1701, "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'true',up:'true',west:'false'}}"); -+ register(1702, "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'false',up:'true',west:'true'}}"); -+ register(1703, "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'false',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(1704, "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'false',up:'true',west:'false'}}"); -+ register(1705, "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'true',up:'true',west:'false'}}"); -+ register(1706, "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'false',up:'true',west:'true'}}"); -+ register(1707, "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'false',south:'true',up:'true',west:'true'}}"); -+ register(1708, "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'false',up:'true',west:'false'}}"); -+ register(1709, "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'true',up:'true',west:'false'}}"); -+ register(1710, "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'false',up:'true',west:'true'}}"); -+ register(1711, "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:vine',Properties:{east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(1712, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'false'}}"); -+ register(1713, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'false'}}"); -+ register(1714, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'false'}}"); -+ register(1715, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'false'}}"); -+ register(1716, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'false'}}"); -+ register(1717, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'false'}}"); -+ register(1718, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'false'}}"); -+ register(1719, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'false'}}"); -+ register(1720, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'true'}}"); -+ register(1721, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'true'}}"); -+ register(1722, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'true'}}"); -+ register(1723, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'true'}}"); -+ register(1724, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'true'}}"); -+ register(1725, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'true'}}"); -+ register(1726, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'true'}}"); -+ register(1727, "{Name:'minecraft:oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'true'}}"); -+ register(1728, "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(1729, "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(1730, "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(1731, "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(1732, "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(1733, "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(1734, "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(1735, "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:brick_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(1744, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(1745, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(1746, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(1747, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(1748, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(1749, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(1750, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(1751, "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:stone_brick_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(1760, "{Name:'minecraft:mycelium',Properties:{snowy:'false'}}", "{Name:'minecraft:mycelium',Properties:{snowy:'false'}}", "{Name:'minecraft:mycelium',Properties:{snowy:'true'}}"); -+ register(1776, "{Name:'minecraft:lily_pad'}", "{Name:'minecraft:waterlily'}"); -+ register(1792, "{Name:'minecraft:nether_bricks'}", "{Name:'minecraft:nether_brick'}"); -+ register(1808, "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:nether_brick_fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(1824, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(1825, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(1826, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(1827, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(1828, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(1829, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(1830, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(1831, "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:nether_brick_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(1840, "{Name:'minecraft:nether_wart',Properties:{age:'0'}}", "{Name:'minecraft:nether_wart',Properties:{age:'0'}}"); -+ register(1841, "{Name:'minecraft:nether_wart',Properties:{age:'1'}}", "{Name:'minecraft:nether_wart',Properties:{age:'1'}}"); -+ register(1842, "{Name:'minecraft:nether_wart',Properties:{age:'2'}}", "{Name:'minecraft:nether_wart',Properties:{age:'2'}}"); -+ register(1843, "{Name:'minecraft:nether_wart',Properties:{age:'3'}}", "{Name:'minecraft:nether_wart',Properties:{age:'3'}}"); -+ register(1856, "{Name:'minecraft:enchanting_table'}", "{Name:'minecraft:enchanting_table'}"); -+ register(1872, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'false',has_bottle_2:'false'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'false',has_bottle_2:'false'}}"); -+ register(1873, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'false',has_bottle_2:'false'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'false',has_bottle_2:'false'}}"); -+ register(1874, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'true',has_bottle_2:'false'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'true',has_bottle_2:'false'}}"); -+ register(1875, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'true',has_bottle_2:'false'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'true',has_bottle_2:'false'}}"); -+ register(1876, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'false',has_bottle_2:'true'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'false',has_bottle_2:'true'}}"); -+ register(1877, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'false',has_bottle_2:'true'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'false',has_bottle_2:'true'}}"); -+ register(1878, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'true',has_bottle_2:'true'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'false',has_bottle_1:'true',has_bottle_2:'true'}}"); -+ register(1879, "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'true',has_bottle_2:'true'}}", "{Name:'minecraft:brewing_stand',Properties:{has_bottle_0:'true',has_bottle_1:'true',has_bottle_2:'true'}}"); -+ register(1888, "{Name:'minecraft:cauldron',Properties:{level:'0'}}", "{Name:'minecraft:cauldron',Properties:{level:'0'}}"); -+ register(1889, "{Name:'minecraft:cauldron',Properties:{level:'1'}}", "{Name:'minecraft:cauldron',Properties:{level:'1'}}"); -+ register(1890, "{Name:'minecraft:cauldron',Properties:{level:'2'}}", "{Name:'minecraft:cauldron',Properties:{level:'2'}}"); -+ register(1891, "{Name:'minecraft:cauldron',Properties:{level:'3'}}", "{Name:'minecraft:cauldron',Properties:{level:'3'}}"); -+ register(1904, "{Name:'minecraft:end_portal'}", "{Name:'minecraft:end_portal'}"); -+ register(1920, "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'south'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'south'}}"); -+ register(1921, "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'west'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'west'}}"); -+ register(1922, "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'north'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'north'}}"); -+ register(1923, "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'east'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'false',facing:'east'}}"); -+ register(1924, "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'south'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'south'}}"); -+ register(1925, "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'west'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'west'}}"); -+ register(1926, "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'north'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'north'}}"); -+ register(1927, "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'east'}}", "{Name:'minecraft:end_portal_frame',Properties:{eye:'true',facing:'east'}}"); -+ register(1936, "{Name:'minecraft:end_stone'}", "{Name:'minecraft:end_stone'}"); -+ register(1952, "{Name:'minecraft:dragon_egg'}", "{Name:'minecraft:dragon_egg'}"); -+ register(1968, "{Name:'minecraft:redstone_lamp',Properties:{lit:'false'}}", "{Name:'minecraft:redstone_lamp'}"); -+ register(1984, "{Name:'minecraft:redstone_lamp',Properties:{lit:'true'}}", "{Name:'minecraft:lit_redstone_lamp'}"); -+ register(2000, "{Name:'minecraft:oak_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_wooden_slab',Properties:{variant:'oak'}}"); -+ register(2001, "{Name:'minecraft:spruce_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_wooden_slab',Properties:{variant:'spruce'}}"); -+ register(2002, "{Name:'minecraft:birch_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_wooden_slab',Properties:{variant:'birch'}}"); -+ register(2003, "{Name:'minecraft:jungle_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_wooden_slab',Properties:{variant:'jungle'}}"); -+ register(2004, "{Name:'minecraft:acacia_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_wooden_slab',Properties:{variant:'acacia'}}"); -+ register(2005, "{Name:'minecraft:dark_oak_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_wooden_slab',Properties:{variant:'dark_oak'}}"); -+ register(2016, "{Name:'minecraft:oak_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'bottom',variant:'oak'}}"); -+ register(2017, "{Name:'minecraft:spruce_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'bottom',variant:'spruce'}}"); -+ register(2018, "{Name:'minecraft:birch_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'bottom',variant:'birch'}}"); -+ register(2019, "{Name:'minecraft:jungle_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'bottom',variant:'jungle'}}"); -+ register(2020, "{Name:'minecraft:acacia_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'bottom',variant:'acacia'}}"); -+ register(2021, "{Name:'minecraft:dark_oak_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'bottom',variant:'dark_oak'}}"); -+ register(2024, "{Name:'minecraft:oak_slab',Properties:{type:'top'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'top',variant:'oak'}}"); -+ register(2025, "{Name:'minecraft:spruce_slab',Properties:{type:'top'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'top',variant:'spruce'}}"); -+ register(2026, "{Name:'minecraft:birch_slab',Properties:{type:'top'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'top',variant:'birch'}}"); -+ register(2027, "{Name:'minecraft:jungle_slab',Properties:{type:'top'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'top',variant:'jungle'}}"); -+ register(2028, "{Name:'minecraft:acacia_slab',Properties:{type:'top'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'top',variant:'acacia'}}"); -+ register(2029, "{Name:'minecraft:dark_oak_slab',Properties:{type:'top'}}", "{Name:'minecraft:wooden_slab',Properties:{half:'top',variant:'dark_oak'}}"); -+ register(2032, "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'south'}}", "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'south'}}"); -+ register(2033, "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'west'}}", "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'west'}}"); -+ register(2034, "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'north'}}", "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'north'}}"); -+ register(2035, "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'east'}}", "{Name:'minecraft:cocoa',Properties:{age:'0',facing:'east'}}"); -+ register(2036, "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'south'}}", "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'south'}}"); -+ register(2037, "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'west'}}", "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'west'}}"); -+ register(2038, "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'north'}}", "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'north'}}"); -+ register(2039, "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'east'}}", "{Name:'minecraft:cocoa',Properties:{age:'1',facing:'east'}}"); -+ register(2040, "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'south'}}", "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'south'}}"); -+ register(2041, "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'west'}}", "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'west'}}"); -+ register(2042, "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'north'}}", "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'north'}}"); -+ register(2043, "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'east'}}", "{Name:'minecraft:cocoa',Properties:{age:'2',facing:'east'}}"); -+ register(2048, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2049, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2050, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2051, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2052, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2053, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2054, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2055, "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:sandstone_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2064, "{Name:'minecraft:emerald_ore'}", "{Name:'minecraft:emerald_ore'}"); -+ register(2082, "{Name:'minecraft:ender_chest',Properties:{facing:'north'}}", "{Name:'minecraft:ender_chest',Properties:{facing:'north'}}"); -+ register(2083, "{Name:'minecraft:ender_chest',Properties:{facing:'south'}}", "{Name:'minecraft:ender_chest',Properties:{facing:'south'}}"); -+ register(2084, "{Name:'minecraft:ender_chest',Properties:{facing:'west'}}", "{Name:'minecraft:ender_chest',Properties:{facing:'west'}}"); -+ register(2085, "{Name:'minecraft:ender_chest',Properties:{facing:'east'}}", "{Name:'minecraft:ender_chest',Properties:{facing:'east'}}"); -+ register(2096, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'south',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'south',powered:'false'}}"); -+ register(2097, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'west',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'west',powered:'false'}}"); -+ register(2098, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'north',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'north',powered:'false'}}"); -+ register(2099, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'east',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'east',powered:'false'}}"); -+ register(2100, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'south',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'south',powered:'false'}}"); -+ register(2101, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'west',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'west',powered:'false'}}"); -+ register(2102, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'north',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'north',powered:'false'}}"); -+ register(2103, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'east',powered:'false'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'east',powered:'false'}}"); -+ register(2104, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'south',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'south',powered:'true'}}"); -+ register(2105, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'west',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'west',powered:'true'}}"); -+ register(2106, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'north',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'north',powered:'true'}}"); -+ register(2107, "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'east',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'false',facing:'east',powered:'true'}}"); -+ register(2108, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'south',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'south',powered:'true'}}"); -+ register(2109, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'west',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'west',powered:'true'}}"); -+ register(2110, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'north',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'north',powered:'true'}}"); -+ register(2111, "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'east',powered:'true'}}", "{Name:'minecraft:tripwire_hook',Properties:{attached:'true',facing:'east',powered:'true'}}"); -+ register(2112, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'false',south:'true',west:'true'}}"); -+ register(2113, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'true',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'true',north:'true',powered:'true',south:'true',west:'true'}}"); -+ register(2114, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'false'}}"); -+ register(2115, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'false'}}"); -+ register(2116, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'false',south:'true',west:'true'}}"); -+ register(2117, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'true',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'true',north:'true',powered:'true',south:'true',west:'true'}}"); -+ register(2118, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'false',south:'false',west:'false'}}"); -+ register(2119, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'false',east:'false',north:'false',powered:'true',south:'false',west:'false'}}"); -+ register(2120, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'false',south:'true',west:'true'}}"); -+ register(2121, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'true',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'true',north:'true',powered:'true',south:'true',west:'true'}}"); -+ register(2122, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'false'}}"); -+ register(2123, "{Name:'minecraft:tripwire',Properties:{attached:'false',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'false'}}"); -+ register(2124, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'false',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'false',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'false',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'false',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'false',south:'true',west:'true'}}"); -+ register(2125, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'true',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'false',powered:'true',south:'true',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'true',south:'false',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'true',south:'false',west:'true'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'true',south:'true',west:'false'}}", "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'true',north:'true',powered:'true',south:'true',west:'true'}}"); -+ register(2126, "{Name:'minecraft:tripwire',Properties:{attached:'true',disarmed:'true',east:'false',north:'false',powered:'false',south:'false',west:'false'}}"); -+ register(2128, "{Name:'minecraft:emerald_block'}", "{Name:'minecraft:emerald_block'}"); -+ register(2144, "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2145, "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2146, "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2147, "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2148, "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2149, "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2150, "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2151, "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:spruce_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2160, "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2161, "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2162, "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2163, "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2164, "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2165, "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2166, "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2167, "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:birch_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2176, "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2177, "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2178, "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2179, "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2180, "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2181, "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2182, "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2183, "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:jungle_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2192, "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'down'}}", "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'down'}}"); -+ register(2193, "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'up'}}", "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'up'}}"); -+ register(2194, "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'north'}}", "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'north'}}"); -+ register(2195, "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'south'}}", "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'south'}}"); -+ register(2196, "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'west'}}", "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'west'}}"); -+ register(2197, "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'east'}}", "{Name:'minecraft:command_block',Properties:{conditional:'false',facing:'east'}}"); -+ register(2200, "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'down'}}", "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'down'}}"); -+ register(2201, "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'up'}}", "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'up'}}"); -+ register(2202, "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'north'}}", "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'north'}}"); -+ register(2203, "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'south'}}", "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'south'}}"); -+ register(2204, "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'west'}}", "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'west'}}"); -+ register(2205, "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'east'}}", "{Name:'minecraft:command_block',Properties:{conditional:'true',facing:'east'}}"); -+ register(2208, "{Name:'minecraft:beacon'}", "{Name:'minecraft:beacon'}"); -+ register(2224, "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'true',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'false',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'false',variant:'cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'true',variant:'cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'true',variant:'cobblestone',west:'true'}}"); -+ register(2225, "{Name:'minecraft:mossy_cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'false',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'false',south:'true',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'false',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'false',north:'true',south:'true',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'false',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'false',south:'true',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'false',up:'true',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'false',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'false',variant:'mossy_cobblestone',west:'true'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'true',variant:'mossy_cobblestone',west:'false'}}", "{Name:'minecraft:cobblestone_wall',Properties:{east:'true',north:'true',south:'true',up:'true',variant:'mossy_cobblestone',west:'true'}}"); -+ // There are a few changes made to flower pot here, notably handling how legacy data is handled. -+ // The TE itself should contain the target item and from there the proper state can be determined. However, there are -+ // blocks that do not contain a TE. So we need to make sure there is a default to fall on. -+ // I simply followed the legacy handling from BlockFlowerPot from 1.8.8 to find what legacy data mapped to what. -+ // It's better than defaulting everything to a cactus. -+ register(2240, "{Name:'minecraft:flower_pot'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'0'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'0'}}"); -+ register(2241, "{Name:'minecraft:potted_poppy'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'1'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'1'}}"); -+ register(2242, "{Name:'minecraft:potted_dandelion'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'2'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'2'}}"); -+ register(2243, "{Name:'minecraft:potted_oak_sapling'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'3'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'3'}}"); -+ register(2244, "{Name:'minecraft:potted_spruce_sapling'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'4'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'4'}}"); -+ register(2245, "{Name:'minecraft:potted_birch_sapling'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'5'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'5'}}"); -+ register(2246, "{Name:'minecraft:potted_jungle_sapling'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'6'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'6'}}"); -+ register(2247, "{Name:'minecraft:potted_red_mushroom'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'7'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'7'}}"); -+ register(2248, "{Name:'minecraft:potted_brown_mushroom'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'8'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'8'}}"); -+ register(2249, "{Name:'minecraft:potted_cactus'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'9'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'9'}}"); -+ register(2250, "{Name:'minecraft:potted_dead_bush'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'10'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'10'}}"); -+ register(2251, "{Name:'minecraft:potted_fern'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'11'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'11'}}"); -+ register(2252, "{Name:'minecraft:potted_acacia_sapling'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'12'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'12'}}"); -+ register(2253, "{Name:'minecraft:potted_dark_oak_sapling'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'13'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'13'}}"); -+ register(2254, "{Name:'minecraft:flower_pot'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'14'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'14'}}"); -+ register(2255, "{Name:'minecraft:flower_pot'}", "{Name:'minecraft:flower_pot',Properties:{contents:'acacia_sapling',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'allium',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'birch_sapling',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'blue_orchid',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'cactus',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dandelion',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dark_oak_sapling',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'dead_bush',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'empty',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'fern',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'houstonia',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'jungle_sapling',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_brown',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'mushroom_red',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oak_sapling',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'orange_tulip',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'oxeye_daisy',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'pink_tulip',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'red_tulip',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'rose',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'spruce_sapling',legacy_data:'15'}}", "{Name:'minecraft:flower_pot',Properties:{contents:'white_tulip',legacy_data:'15'}}"); -+ register(2256, "{Name:'minecraft:carrots',Properties:{age:'0'}}", "{Name:'minecraft:carrots',Properties:{age:'0'}}"); -+ register(2257, "{Name:'minecraft:carrots',Properties:{age:'1'}}", "{Name:'minecraft:carrots',Properties:{age:'1'}}"); -+ register(2258, "{Name:'minecraft:carrots',Properties:{age:'2'}}", "{Name:'minecraft:carrots',Properties:{age:'2'}}"); -+ register(2259, "{Name:'minecraft:carrots',Properties:{age:'3'}}", "{Name:'minecraft:carrots',Properties:{age:'3'}}"); -+ register(2260, "{Name:'minecraft:carrots',Properties:{age:'4'}}", "{Name:'minecraft:carrots',Properties:{age:'4'}}"); -+ register(2261, "{Name:'minecraft:carrots',Properties:{age:'5'}}", "{Name:'minecraft:carrots',Properties:{age:'5'}}"); -+ register(2262, "{Name:'minecraft:carrots',Properties:{age:'6'}}", "{Name:'minecraft:carrots',Properties:{age:'6'}}"); -+ register(2263, "{Name:'minecraft:carrots',Properties:{age:'7'}}", "{Name:'minecraft:carrots',Properties:{age:'7'}}"); -+ register(2272, "{Name:'minecraft:potatoes',Properties:{age:'0'}}", "{Name:'minecraft:potatoes',Properties:{age:'0'}}"); -+ register(2273, "{Name:'minecraft:potatoes',Properties:{age:'1'}}", "{Name:'minecraft:potatoes',Properties:{age:'1'}}"); -+ register(2274, "{Name:'minecraft:potatoes',Properties:{age:'2'}}", "{Name:'minecraft:potatoes',Properties:{age:'2'}}"); -+ register(2275, "{Name:'minecraft:potatoes',Properties:{age:'3'}}", "{Name:'minecraft:potatoes',Properties:{age:'3'}}"); -+ register(2276, "{Name:'minecraft:potatoes',Properties:{age:'4'}}", "{Name:'minecraft:potatoes',Properties:{age:'4'}}"); -+ register(2277, "{Name:'minecraft:potatoes',Properties:{age:'5'}}", "{Name:'minecraft:potatoes',Properties:{age:'5'}}"); -+ register(2278, "{Name:'minecraft:potatoes',Properties:{age:'6'}}", "{Name:'minecraft:potatoes',Properties:{age:'6'}}"); -+ register(2279, "{Name:'minecraft:potatoes',Properties:{age:'7'}}", "{Name:'minecraft:potatoes',Properties:{age:'7'}}"); -+ register(2288, "{Name:'minecraft:oak_button',Properties:{face:'ceiling',facing:'north',powered:'false'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'down',powered:'false'}}"); -+ register(2289, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'east',powered:'false'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'east',powered:'false'}}"); -+ register(2290, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'west',powered:'false'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'west',powered:'false'}}"); -+ register(2291, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'south',powered:'false'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'south',powered:'false'}}"); -+ register(2292, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'north',powered:'false'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'north',powered:'false'}}"); -+ register(2293, "{Name:'minecraft:oak_button',Properties:{face:'floor',facing:'north',powered:'false'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'up',powered:'false'}}"); -+ register(2296, "{Name:'minecraft:oak_button',Properties:{face:'ceiling',facing:'north',powered:'true'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'down',powered:'true'}}"); -+ register(2297, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'east',powered:'true'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'east',powered:'true'}}"); -+ register(2298, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'west',powered:'true'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'west',powered:'true'}}"); -+ register(2299, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'south',powered:'true'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'south',powered:'true'}}"); -+ register(2300, "{Name:'minecraft:oak_button',Properties:{face:'wall',facing:'north',powered:'true'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'north',powered:'true'}}"); -+ register(2301, "{Name:'minecraft:oak_button',Properties:{face:'floor',facing:'north',powered:'true'}}", "{Name:'minecraft:wooden_button',Properties:{facing:'up',powered:'true'}}"); -+ register(2304, "{Name:'%%FILTER_ME%%',Properties:{facing:'down',nodrop:'false'}}", "{Name:'minecraft:skull',Properties:{facing:'down',nodrop:'false'}}"); -+ register(2305, "{Name:'%%FILTER_ME%%',Properties:{facing:'up',nodrop:'false'}}", "{Name:'minecraft:skull',Properties:{facing:'up',nodrop:'false'}}"); -+ register(2306, "{Name:'%%FILTER_ME%%',Properties:{facing:'north',nodrop:'false'}}", "{Name:'minecraft:skull',Properties:{facing:'north',nodrop:'false'}}"); -+ register(2307, "{Name:'%%FILTER_ME%%',Properties:{facing:'south',nodrop:'false'}}", "{Name:'minecraft:skull',Properties:{facing:'south',nodrop:'false'}}"); -+ register(2308, "{Name:'%%FILTER_ME%%',Properties:{facing:'west',nodrop:'false'}}", "{Name:'minecraft:skull',Properties:{facing:'west',nodrop:'false'}}"); -+ register(2309, "{Name:'%%FILTER_ME%%',Properties:{facing:'east',nodrop:'false'}}", "{Name:'minecraft:skull',Properties:{facing:'east',nodrop:'false'}}"); -+ register(2312, "{Name:'%%FILTER_ME%%',Properties:{facing:'down',nodrop:'true'}}", "{Name:'minecraft:skull',Properties:{facing:'down',nodrop:'true'}}"); -+ register(2313, "{Name:'%%FILTER_ME%%',Properties:{facing:'up',nodrop:'true'}}", "{Name:'minecraft:skull',Properties:{facing:'up',nodrop:'true'}}"); -+ register(2314, "{Name:'%%FILTER_ME%%',Properties:{facing:'north',nodrop:'true'}}", "{Name:'minecraft:skull',Properties:{facing:'north',nodrop:'true'}}"); -+ register(2315, "{Name:'%%FILTER_ME%%',Properties:{facing:'south',nodrop:'true'}}", "{Name:'minecraft:skull',Properties:{facing:'south',nodrop:'true'}}"); -+ register(2316, "{Name:'%%FILTER_ME%%',Properties:{facing:'west',nodrop:'true'}}", "{Name:'minecraft:skull',Properties:{facing:'west',nodrop:'true'}}"); -+ register(2317, "{Name:'%%FILTER_ME%%',Properties:{facing:'east',nodrop:'true'}}", "{Name:'minecraft:skull',Properties:{facing:'east',nodrop:'true'}}"); -+ register(2320, "{Name:'minecraft:anvil',Properties:{facing:'south'}}", "{Name:'minecraft:anvil',Properties:{damage:'0',facing:'south'}}"); -+ register(2321, "{Name:'minecraft:anvil',Properties:{facing:'west'}}", "{Name:'minecraft:anvil',Properties:{damage:'0',facing:'west'}}"); -+ register(2322, "{Name:'minecraft:anvil',Properties:{facing:'north'}}", "{Name:'minecraft:anvil',Properties:{damage:'0',facing:'north'}}"); -+ register(2323, "{Name:'minecraft:anvil',Properties:{facing:'east'}}", "{Name:'minecraft:anvil',Properties:{damage:'0',facing:'east'}}"); -+ register(2324, "{Name:'minecraft:chipped_anvil',Properties:{facing:'south'}}", "{Name:'minecraft:anvil',Properties:{damage:'1',facing:'south'}}"); -+ register(2325, "{Name:'minecraft:chipped_anvil',Properties:{facing:'west'}}", "{Name:'minecraft:anvil',Properties:{damage:'1',facing:'west'}}"); -+ register(2326, "{Name:'minecraft:chipped_anvil',Properties:{facing:'north'}}", "{Name:'minecraft:anvil',Properties:{damage:'1',facing:'north'}}"); -+ register(2327, "{Name:'minecraft:chipped_anvil',Properties:{facing:'east'}}", "{Name:'minecraft:anvil',Properties:{damage:'1',facing:'east'}}"); -+ register(2328, "{Name:'minecraft:damaged_anvil',Properties:{facing:'south'}}", "{Name:'minecraft:anvil',Properties:{damage:'2',facing:'south'}}"); -+ register(2329, "{Name:'minecraft:damaged_anvil',Properties:{facing:'west'}}", "{Name:'minecraft:anvil',Properties:{damage:'2',facing:'west'}}"); -+ register(2330, "{Name:'minecraft:damaged_anvil',Properties:{facing:'north'}}", "{Name:'minecraft:anvil',Properties:{damage:'2',facing:'north'}}"); -+ register(2331, "{Name:'minecraft:damaged_anvil',Properties:{facing:'east'}}", "{Name:'minecraft:anvil',Properties:{damage:'2',facing:'east'}}"); -+ register(2338, "{Name:'minecraft:trapped_chest',Properties:{facing:'north',type:'single'}}", "{Name:'minecraft:trapped_chest',Properties:{facing:'north'}}"); -+ register(2339, "{Name:'minecraft:trapped_chest',Properties:{facing:'south',type:'single'}}", "{Name:'minecraft:trapped_chest',Properties:{facing:'south'}}"); -+ register(2340, "{Name:'minecraft:trapped_chest',Properties:{facing:'west',type:'single'}}", "{Name:'minecraft:trapped_chest',Properties:{facing:'west'}}"); -+ register(2341, "{Name:'minecraft:trapped_chest',Properties:{facing:'east',type:'single'}}", "{Name:'minecraft:trapped_chest',Properties:{facing:'east'}}"); -+ register(2352, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'0'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'0'}}"); -+ register(2353, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'1'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'1'}}"); -+ register(2354, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'2'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'2'}}"); -+ register(2355, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'3'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'3'}}"); -+ register(2356, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'4'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'4'}}"); -+ register(2357, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'5'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'5'}}"); -+ register(2358, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'6'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'6'}}"); -+ register(2359, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'7'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'7'}}"); -+ register(2360, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'8'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'8'}}"); -+ register(2361, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'9'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'9'}}"); -+ register(2362, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'10'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'10'}}"); -+ register(2363, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'11'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'11'}}"); -+ register(2364, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'12'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'12'}}"); -+ register(2365, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'13'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'13'}}"); -+ register(2366, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'14'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'14'}}"); -+ register(2367, "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'15'}}", "{Name:'minecraft:light_weighted_pressure_plate',Properties:{power:'15'}}"); -+ register(2368, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'0'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'0'}}"); -+ register(2369, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'1'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'1'}}"); -+ register(2370, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'2'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'2'}}"); -+ register(2371, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'3'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'3'}}"); -+ register(2372, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'4'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'4'}}"); -+ register(2373, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'5'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'5'}}"); -+ register(2374, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'6'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'6'}}"); -+ register(2375, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'7'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'7'}}"); -+ register(2376, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'8'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'8'}}"); -+ register(2377, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'9'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'9'}}"); -+ register(2378, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'10'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'10'}}"); -+ register(2379, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'11'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'11'}}"); -+ register(2380, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'12'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'12'}}"); -+ register(2381, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'13'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'13'}}"); -+ register(2382, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'14'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'14'}}"); -+ register(2383, "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'15'}}", "{Name:'minecraft:heavy_weighted_pressure_plate',Properties:{power:'15'}}"); -+ register(2384, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'compare',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'south',mode:'compare',powered:'false'}}"); -+ register(2385, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'compare',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'west',mode:'compare',powered:'false'}}"); -+ register(2386, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'compare',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'north',mode:'compare',powered:'false'}}"); -+ register(2387, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'compare',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'east',mode:'compare',powered:'false'}}"); -+ register(2388, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'subtract',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'south',mode:'subtract',powered:'false'}}"); -+ register(2389, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'subtract',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'west',mode:'subtract',powered:'false'}}"); -+ register(2390, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'subtract',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'north',mode:'subtract',powered:'false'}}"); -+ register(2391, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'subtract',powered:'false'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'east',mode:'subtract',powered:'false'}}"); -+ register(2392, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'compare',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'south',mode:'compare',powered:'true'}}"); -+ register(2393, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'compare',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'west',mode:'compare',powered:'true'}}"); -+ register(2394, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'compare',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'north',mode:'compare',powered:'true'}}"); -+ register(2395, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'compare',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'east',mode:'compare',powered:'true'}}"); -+ register(2396, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'subtract',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'south',mode:'subtract',powered:'true'}}"); -+ register(2397, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'subtract',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'west',mode:'subtract',powered:'true'}}"); -+ register(2398, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'subtract',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'north',mode:'subtract',powered:'true'}}"); -+ register(2399, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'subtract',powered:'true'}}", "{Name:'minecraft:unpowered_comparator',Properties:{facing:'east',mode:'subtract',powered:'true'}}"); -+ register(2400, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'compare',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'south',mode:'compare',powered:'false'}}"); -+ register(2401, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'compare',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'west',mode:'compare',powered:'false'}}"); -+ register(2402, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'compare',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'north',mode:'compare',powered:'false'}}"); -+ register(2403, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'compare',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'east',mode:'compare',powered:'false'}}"); -+ register(2404, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'subtract',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'south',mode:'subtract',powered:'false'}}"); -+ register(2405, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'subtract',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'west',mode:'subtract',powered:'false'}}"); -+ register(2406, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'subtract',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'north',mode:'subtract',powered:'false'}}"); -+ register(2407, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'subtract',powered:'false'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'east',mode:'subtract',powered:'false'}}"); -+ register(2408, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'compare',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'south',mode:'compare',powered:'true'}}"); -+ register(2409, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'compare',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'west',mode:'compare',powered:'true'}}"); -+ register(2410, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'compare',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'north',mode:'compare',powered:'true'}}"); -+ register(2411, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'compare',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'east',mode:'compare',powered:'true'}}"); -+ register(2412, "{Name:'minecraft:comparator',Properties:{facing:'south',mode:'subtract',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'south',mode:'subtract',powered:'true'}}"); -+ register(2413, "{Name:'minecraft:comparator',Properties:{facing:'west',mode:'subtract',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'west',mode:'subtract',powered:'true'}}"); -+ register(2414, "{Name:'minecraft:comparator',Properties:{facing:'north',mode:'subtract',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'north',mode:'subtract',powered:'true'}}"); -+ register(2415, "{Name:'minecraft:comparator',Properties:{facing:'east',mode:'subtract',powered:'true'}}", "{Name:'minecraft:powered_comparator',Properties:{facing:'east',mode:'subtract',powered:'true'}}"); -+ register(2416, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'0'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'0'}}"); -+ register(2417, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'1'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'1'}}"); -+ register(2418, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'2'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'2'}}"); -+ register(2419, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'3'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'3'}}"); -+ register(2420, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'4'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'4'}}"); -+ register(2421, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'5'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'5'}}"); -+ register(2422, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'6'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'6'}}"); -+ register(2423, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'7'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'7'}}"); -+ register(2424, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'8'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'8'}}"); -+ register(2425, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'9'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'9'}}"); -+ register(2426, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'10'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'10'}}"); -+ register(2427, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'11'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'11'}}"); -+ register(2428, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'12'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'12'}}"); -+ register(2429, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'13'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'13'}}"); -+ register(2430, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'14'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'14'}}"); -+ register(2431, "{Name:'minecraft:daylight_detector',Properties:{inverted:'false',power:'15'}}", "{Name:'minecraft:daylight_detector',Properties:{power:'15'}}"); -+ register(2432, "{Name:'minecraft:redstone_block'}", "{Name:'minecraft:redstone_block'}"); -+ register(2448, "{Name:'minecraft:nether_quartz_ore'}", "{Name:'minecraft:quartz_ore'}"); -+ register(2464, "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'down'}}", "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'down'}}"); -+ register(2466, "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'north'}}", "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'north'}}"); -+ register(2467, "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'south'}}", "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'south'}}"); -+ register(2468, "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'west'}}", "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'west'}}"); -+ register(2469, "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'east'}}", "{Name:'minecraft:hopper',Properties:{enabled:'true',facing:'east'}}"); -+ register(2472, "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'down'}}", "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'down'}}"); -+ register(2474, "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'north'}}", "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'north'}}"); -+ register(2475, "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'south'}}", "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'south'}}"); -+ register(2476, "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'west'}}", "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'west'}}"); -+ register(2477, "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'east'}}", "{Name:'minecraft:hopper',Properties:{enabled:'false',facing:'east'}}"); -+ register(2480, "{Name:'minecraft:quartz_block'}", "{Name:'minecraft:quartz_block',Properties:{variant:'default'}}"); -+ register(2481, "{Name:'minecraft:chiseled_quartz_block'}", "{Name:'minecraft:quartz_block',Properties:{variant:'chiseled'}}"); -+ register(2482, "{Name:'minecraft:quartz_pillar',Properties:{axis:'y'}}", "{Name:'minecraft:quartz_block',Properties:{variant:'lines_y'}}"); -+ register(2483, "{Name:'minecraft:quartz_pillar',Properties:{axis:'x'}}", "{Name:'minecraft:quartz_block',Properties:{variant:'lines_x'}}"); -+ register(2484, "{Name:'minecraft:quartz_pillar',Properties:{axis:'z'}}", "{Name:'minecraft:quartz_block',Properties:{variant:'lines_z'}}"); -+ register(2496, "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2497, "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2498, "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2499, "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2500, "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2501, "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2502, "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2503, "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:quartz_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2512, "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'north_south'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'north_south'}}"); -+ register(2513, "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'east_west'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'east_west'}}"); -+ register(2514, "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_east'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_east'}}"); -+ register(2515, "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_west'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_west'}}"); -+ register(2516, "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_north'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_north'}}"); -+ register(2517, "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_south'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'false',shape:'ascending_south'}}"); -+ register(2520, "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'north_south'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'north_south'}}"); -+ register(2521, "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'east_west'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'east_west'}}"); -+ register(2522, "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_east'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_east'}}"); -+ register(2523, "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_west'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_west'}}"); -+ register(2524, "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_north'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_north'}}"); -+ register(2525, "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_south'}}", "{Name:'minecraft:activator_rail',Properties:{powered:'true',shape:'ascending_south'}}"); -+ register(2528, "{Name:'minecraft:dropper',Properties:{facing:'down',triggered:'false'}}", "{Name:'minecraft:dropper',Properties:{facing:'down',triggered:'false'}}"); -+ register(2529, "{Name:'minecraft:dropper',Properties:{facing:'up',triggered:'false'}}", "{Name:'minecraft:dropper',Properties:{facing:'up',triggered:'false'}}"); -+ register(2530, "{Name:'minecraft:dropper',Properties:{facing:'north',triggered:'false'}}", "{Name:'minecraft:dropper',Properties:{facing:'north',triggered:'false'}}"); -+ register(2531, "{Name:'minecraft:dropper',Properties:{facing:'south',triggered:'false'}}", "{Name:'minecraft:dropper',Properties:{facing:'south',triggered:'false'}}"); -+ register(2532, "{Name:'minecraft:dropper',Properties:{facing:'west',triggered:'false'}}", "{Name:'minecraft:dropper',Properties:{facing:'west',triggered:'false'}}"); -+ register(2533, "{Name:'minecraft:dropper',Properties:{facing:'east',triggered:'false'}}", "{Name:'minecraft:dropper',Properties:{facing:'east',triggered:'false'}}"); -+ register(2536, "{Name:'minecraft:dropper',Properties:{facing:'down',triggered:'true'}}", "{Name:'minecraft:dropper',Properties:{facing:'down',triggered:'true'}}"); -+ register(2537, "{Name:'minecraft:dropper',Properties:{facing:'up',triggered:'true'}}", "{Name:'minecraft:dropper',Properties:{facing:'up',triggered:'true'}}"); -+ register(2538, "{Name:'minecraft:dropper',Properties:{facing:'north',triggered:'true'}}", "{Name:'minecraft:dropper',Properties:{facing:'north',triggered:'true'}}"); -+ register(2539, "{Name:'minecraft:dropper',Properties:{facing:'south',triggered:'true'}}", "{Name:'minecraft:dropper',Properties:{facing:'south',triggered:'true'}}"); -+ register(2540, "{Name:'minecraft:dropper',Properties:{facing:'west',triggered:'true'}}", "{Name:'minecraft:dropper',Properties:{facing:'west',triggered:'true'}}"); -+ register(2541, "{Name:'minecraft:dropper',Properties:{facing:'east',triggered:'true'}}", "{Name:'minecraft:dropper',Properties:{facing:'east',triggered:'true'}}"); -+ register(2544, "{Name:'minecraft:white_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'white'}}"); -+ register(2545, "{Name:'minecraft:orange_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'orange'}}"); -+ register(2546, "{Name:'minecraft:magenta_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'magenta'}}"); -+ register(2547, "{Name:'minecraft:light_blue_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'light_blue'}}"); -+ register(2548, "{Name:'minecraft:yellow_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'yellow'}}"); -+ register(2549, "{Name:'minecraft:lime_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'lime'}}"); -+ register(2550, "{Name:'minecraft:pink_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'pink'}}"); -+ register(2551, "{Name:'minecraft:gray_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'gray'}}"); -+ register(2552, "{Name:'minecraft:light_gray_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'silver'}}"); -+ register(2553, "{Name:'minecraft:cyan_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'cyan'}}"); -+ register(2554, "{Name:'minecraft:purple_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'purple'}}"); -+ register(2555, "{Name:'minecraft:blue_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'blue'}}"); -+ register(2556, "{Name:'minecraft:brown_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'brown'}}"); -+ register(2557, "{Name:'minecraft:green_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'green'}}"); -+ register(2558, "{Name:'minecraft:red_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'red'}}"); -+ register(2559, "{Name:'minecraft:black_terracotta'}", "{Name:'minecraft:stained_hardened_clay',Properties:{color:'black'}}"); -+ register(2560, "{Name:'minecraft:white_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'white',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2561, "{Name:'minecraft:orange_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'orange',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2562, "{Name:'minecraft:magenta_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'magenta',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2563, "{Name:'minecraft:light_blue_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'light_blue',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2564, "{Name:'minecraft:yellow_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'yellow',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2565, "{Name:'minecraft:lime_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'lime',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2566, "{Name:'minecraft:pink_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'pink',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2567, "{Name:'minecraft:gray_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'gray',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2568, "{Name:'minecraft:light_gray_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'silver',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2569, "{Name:'minecraft:cyan_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'cyan',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2570, "{Name:'minecraft:purple_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'purple',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2571, "{Name:'minecraft:blue_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'blue',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2572, "{Name:'minecraft:brown_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'brown',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2573, "{Name:'minecraft:green_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'green',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2574, "{Name:'minecraft:red_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'red',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2575, "{Name:'minecraft:black_stained_glass_pane',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:stained_glass_pane',Properties:{color:'black',east:'true',north:'true',south:'true',west:'true'}}"); -+ register(2576, "{Name:'minecraft:acacia_leaves',Properties:{check_decay:'false',decayable:'true'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'false',decayable:'true',variant:'acacia'}}"); -+ register(2577, "{Name:'minecraft:dark_oak_leaves',Properties:{check_decay:'false',decayable:'true'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'false',decayable:'true',variant:'dark_oak'}}"); -+ register(2580, "{Name:'minecraft:acacia_leaves',Properties:{check_decay:'false',decayable:'false'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'false',decayable:'false',variant:'acacia'}}"); -+ register(2581, "{Name:'minecraft:dark_oak_leaves',Properties:{check_decay:'false',decayable:'false'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'false',decayable:'false',variant:'dark_oak'}}"); -+ register(2584, "{Name:'minecraft:acacia_leaves',Properties:{check_decay:'true',decayable:'true'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'true',decayable:'true',variant:'acacia'}}"); -+ register(2585, "{Name:'minecraft:dark_oak_leaves',Properties:{check_decay:'true',decayable:'true'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'true',decayable:'true',variant:'dark_oak'}}"); -+ register(2588, "{Name:'minecraft:acacia_leaves',Properties:{check_decay:'true',decayable:'false'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'true',decayable:'false',variant:'acacia'}}"); -+ register(2589, "{Name:'minecraft:dark_oak_leaves',Properties:{check_decay:'true',decayable:'false'}}", "{Name:'minecraft:leaves2',Properties:{check_decay:'true',decayable:'false',variant:'dark_oak'}}"); -+ register(2592, "{Name:'minecraft:acacia_log',Properties:{axis:'y'}}", "{Name:'minecraft:log2',Properties:{axis:'y',variant:'acacia'}}"); -+ register(2593, "{Name:'minecraft:dark_oak_log',Properties:{axis:'y'}}", "{Name:'minecraft:log2',Properties:{axis:'y',variant:'dark_oak'}}"); -+ register(2596, "{Name:'minecraft:acacia_log',Properties:{axis:'x'}}", "{Name:'minecraft:log2',Properties:{axis:'x',variant:'acacia'}}"); -+ register(2597, "{Name:'minecraft:dark_oak_log',Properties:{axis:'x'}}", "{Name:'minecraft:log2',Properties:{axis:'x',variant:'dark_oak'}}"); -+ register(2600, "{Name:'minecraft:acacia_log',Properties:{axis:'z'}}", "{Name:'minecraft:log2',Properties:{axis:'z',variant:'acacia'}}"); -+ register(2601, "{Name:'minecraft:dark_oak_log',Properties:{axis:'z'}}", "{Name:'minecraft:log2',Properties:{axis:'z',variant:'dark_oak'}}"); -+ register(2604, "{Name:'minecraft:acacia_bark'}", "{Name:'minecraft:log2',Properties:{axis:'none',variant:'acacia'}}"); -+ register(2605, "{Name:'minecraft:dark_oak_bark'}", "{Name:'minecraft:log2',Properties:{axis:'none',variant:'dark_oak'}}"); -+ register(2608, "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2609, "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2610, "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2611, "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2612, "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2613, "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2614, "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2615, "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:acacia_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2624, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2625, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2626, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2627, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2628, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2629, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2630, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2631, "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:dark_oak_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2640, "{Name:'minecraft:slime_block'}", "{Name:'minecraft:slime'}"); -+ register(2656, "{Name:'minecraft:barrier'}", "{Name:'minecraft:barrier'}"); -+ register(2672, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'bottom',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'bottom',open:'false'}}"); -+ register(2673, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'bottom',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'bottom',open:'false'}}"); -+ register(2674, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'bottom',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'bottom',open:'false'}}"); -+ register(2675, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'bottom',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'bottom',open:'false'}}"); -+ register(2676, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'bottom',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'bottom',open:'true'}}"); -+ register(2677, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'bottom',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'bottom',open:'true'}}"); -+ register(2678, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'bottom',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'bottom',open:'true'}}"); -+ register(2679, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'bottom',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'bottom',open:'true'}}"); -+ register(2680, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'top',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'top',open:'false'}}"); -+ register(2681, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'top',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'top',open:'false'}}"); -+ register(2682, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'top',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'top',open:'false'}}"); -+ register(2683, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'top',open:'false'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'top',open:'false'}}"); -+ register(2684, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'top',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'north',half:'top',open:'true'}}"); -+ register(2685, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'top',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'south',half:'top',open:'true'}}"); -+ register(2686, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'top',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'west',half:'top',open:'true'}}"); -+ register(2687, "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'top',open:'true'}}", "{Name:'minecraft:iron_trapdoor',Properties:{facing:'east',half:'top',open:'true'}}"); -+ register(2688, "{Name:'minecraft:prismarine'}", "{Name:'minecraft:prismarine',Properties:{variant:'prismarine'}}"); -+ register(2689, "{Name:'minecraft:prismarine_bricks'}", "{Name:'minecraft:prismarine',Properties:{variant:'prismarine_bricks'}}"); -+ register(2690, "{Name:'minecraft:dark_prismarine'}", "{Name:'minecraft:prismarine',Properties:{variant:'dark_prismarine'}}"); -+ register(2704, "{Name:'minecraft:sea_lantern'}", "{Name:'minecraft:sea_lantern'}"); -+ register(2720, "{Name:'minecraft:hay_block',Properties:{axis:'y'}}", "{Name:'minecraft:hay_block',Properties:{axis:'y'}}"); -+ register(2724, "{Name:'minecraft:hay_block',Properties:{axis:'x'}}", "{Name:'minecraft:hay_block',Properties:{axis:'x'}}"); -+ register(2728, "{Name:'minecraft:hay_block',Properties:{axis:'z'}}", "{Name:'minecraft:hay_block',Properties:{axis:'z'}}"); -+ register(2736, "{Name:'minecraft:white_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'white'}}"); -+ register(2737, "{Name:'minecraft:orange_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'orange'}}"); -+ register(2738, "{Name:'minecraft:magenta_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'magenta'}}"); -+ register(2739, "{Name:'minecraft:light_blue_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'light_blue'}}"); -+ register(2740, "{Name:'minecraft:yellow_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'yellow'}}"); -+ register(2741, "{Name:'minecraft:lime_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'lime'}}"); -+ register(2742, "{Name:'minecraft:pink_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'pink'}}"); -+ register(2743, "{Name:'minecraft:gray_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'gray'}}"); -+ register(2744, "{Name:'minecraft:light_gray_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'silver'}}"); -+ register(2745, "{Name:'minecraft:cyan_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'cyan'}}"); -+ register(2746, "{Name:'minecraft:purple_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'purple'}}"); -+ register(2747, "{Name:'minecraft:blue_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'blue'}}"); -+ register(2748, "{Name:'minecraft:brown_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'brown'}}"); -+ register(2749, "{Name:'minecraft:green_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'green'}}"); -+ register(2750, "{Name:'minecraft:red_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'red'}}"); -+ register(2751, "{Name:'minecraft:black_carpet'}", "{Name:'minecraft:carpet',Properties:{color:'black'}}"); -+ register(2752, "{Name:'minecraft:terracotta'}", "{Name:'minecraft:hardened_clay'}"); -+ register(2768, "{Name:'minecraft:coal_block'}", "{Name:'minecraft:coal_block'}"); -+ register(2784, "{Name:'minecraft:packed_ice'}", "{Name:'minecraft:packed_ice'}"); -+ register(2800, "{Name:'minecraft:sunflower',Properties:{half:'lower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'lower',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'lower',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'lower',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'lower',variant:'sunflower'}}"); -+ register(2801, "{Name:'minecraft:lilac',Properties:{half:'lower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'lower',variant:'syringa'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'lower',variant:'syringa'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'lower',variant:'syringa'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'lower',variant:'syringa'}}"); -+ register(2802, "{Name:'minecraft:tall_grass',Properties:{half:'lower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'lower',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'lower',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'lower',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'lower',variant:'double_grass'}}"); -+ register(2803, "{Name:'minecraft:large_fern',Properties:{half:'lower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'lower',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'lower',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'lower',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'lower',variant:'double_fern'}}"); -+ register(2804, "{Name:'minecraft:rose_bush',Properties:{half:'lower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'lower',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'lower',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'lower',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'lower',variant:'double_rose'}}"); -+ register(2805, "{Name:'minecraft:peony',Properties:{half:'lower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'lower',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'lower',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'lower',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'lower',variant:'paeonia'}}"); -+ register(2808, "{Name:'minecraft:peony',Properties:{half:'upper'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'upper',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'upper',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'upper',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'upper',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'upper',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'south',half:'upper',variant:'syringa'}}"); -+ register(2809, "{Name:'minecraft:peony',Properties:{half:'upper'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'upper',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'upper',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'upper',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'upper',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'upper',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'west',half:'upper',variant:'syringa'}}"); -+ register(2810, "{Name:'minecraft:peony',Properties:{half:'upper'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'upper',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'upper',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'upper',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'upper',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'upper',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'north',half:'upper',variant:'syringa'}}"); -+ register(2811, "{Name:'minecraft:peony',Properties:{half:'upper'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'upper',variant:'double_fern'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'upper',variant:'double_grass'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'upper',variant:'double_rose'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'upper',variant:'paeonia'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'upper',variant:'sunflower'}}", "{Name:'minecraft:double_plant',Properties:{facing:'east',half:'upper',variant:'syringa'}}"); -+ register(2816, "{Name:'minecraft:white_banner',Properties:{rotation:'0'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'0'}}"); -+ register(2817, "{Name:'minecraft:white_banner',Properties:{rotation:'1'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'1'}}"); -+ register(2818, "{Name:'minecraft:white_banner',Properties:{rotation:'2'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'2'}}"); -+ register(2819, "{Name:'minecraft:white_banner',Properties:{rotation:'3'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'3'}}"); -+ register(2820, "{Name:'minecraft:white_banner',Properties:{rotation:'4'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'4'}}"); -+ register(2821, "{Name:'minecraft:white_banner',Properties:{rotation:'5'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'5'}}"); -+ register(2822, "{Name:'minecraft:white_banner',Properties:{rotation:'6'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'6'}}"); -+ register(2823, "{Name:'minecraft:white_banner',Properties:{rotation:'7'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'7'}}"); -+ register(2824, "{Name:'minecraft:white_banner',Properties:{rotation:'8'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'8'}}"); -+ register(2825, "{Name:'minecraft:white_banner',Properties:{rotation:'9'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'9'}}"); -+ register(2826, "{Name:'minecraft:white_banner',Properties:{rotation:'10'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'10'}}"); -+ register(2827, "{Name:'minecraft:white_banner',Properties:{rotation:'11'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'11'}}"); -+ register(2828, "{Name:'minecraft:white_banner',Properties:{rotation:'12'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'12'}}"); -+ register(2829, "{Name:'minecraft:white_banner',Properties:{rotation:'13'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'13'}}"); -+ register(2830, "{Name:'minecraft:white_banner',Properties:{rotation:'14'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'14'}}"); -+ register(2831, "{Name:'minecraft:white_banner',Properties:{rotation:'15'}}", "{Name:'minecraft:standing_banner',Properties:{rotation:'15'}}"); -+ register(2834, "{Name:'minecraft:white_wall_banner',Properties:{facing:'north'}}", "{Name:'minecraft:wall_banner',Properties:{facing:'north'}}"); -+ register(2835, "{Name:'minecraft:white_wall_banner',Properties:{facing:'south'}}", "{Name:'minecraft:wall_banner',Properties:{facing:'south'}}"); -+ register(2836, "{Name:'minecraft:white_wall_banner',Properties:{facing:'west'}}", "{Name:'minecraft:wall_banner',Properties:{facing:'west'}}"); -+ register(2837, "{Name:'minecraft:white_wall_banner',Properties:{facing:'east'}}", "{Name:'minecraft:wall_banner',Properties:{facing:'east'}}"); -+ register(2848, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'0'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'0'}}"); -+ register(2849, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'1'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'1'}}"); -+ register(2850, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'2'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'2'}}"); -+ register(2851, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'3'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'3'}}"); -+ register(2852, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'4'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'4'}}"); -+ register(2853, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'5'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'5'}}"); -+ register(2854, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'6'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'6'}}"); -+ register(2855, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'7'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'7'}}"); -+ register(2856, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'8'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'8'}}"); -+ register(2857, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'9'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'9'}}"); -+ register(2858, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'10'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'10'}}"); -+ register(2859, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'11'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'11'}}"); -+ register(2860, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'12'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'12'}}"); -+ register(2861, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'13'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'13'}}"); -+ register(2862, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'14'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'14'}}"); -+ register(2863, "{Name:'minecraft:daylight_detector',Properties:{inverted:'true',power:'15'}}", "{Name:'minecraft:daylight_detector_inverted',Properties:{power:'15'}}"); -+ register(2864, "{Name:'minecraft:red_sandstone'}", "{Name:'minecraft:red_sandstone',Properties:{type:'red_sandstone'}}"); -+ register(2865, "{Name:'minecraft:chiseled_red_sandstone'}", "{Name:'minecraft:red_sandstone',Properties:{type:'chiseled_red_sandstone'}}"); -+ register(2866, "{Name:'minecraft:cut_red_sandstone'}", "{Name:'minecraft:red_sandstone',Properties:{type:'smooth_red_sandstone'}}"); -+ register(2880, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(2881, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(2882, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(2883, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(2884, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(2885, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(2886, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(2887, "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:red_sandstone_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(2896, "{Name:'minecraft:red_sandstone_slab',Properties:{type:'double'}}", "{Name:'minecraft:double_stone_slab2',Properties:{seamless:'false',variant:'red_sandstone'}}"); -+ register(2904, "{Name:'minecraft:smooth_red_sandstone'}", "{Name:'minecraft:double_stone_slab2',Properties:{seamless:'true',variant:'red_sandstone'}}"); -+ register(2912, "{Name:'minecraft:red_sandstone_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:stone_slab2',Properties:{half:'bottom',variant:'red_sandstone'}}"); -+ register(2920, "{Name:'minecraft:red_sandstone_slab',Properties:{type:'top'}}", "{Name:'minecraft:stone_slab2',Properties:{half:'top',variant:'red_sandstone'}}"); -+ register(2928, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2929, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2930, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2931, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2932, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2933, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2934, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2935, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2936, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2937, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2938, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2939, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2940, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2941, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2942, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2943, "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2944, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2945, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2946, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2947, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2948, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2949, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2950, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2951, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2952, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2953, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2954, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2955, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2956, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2957, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2958, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2959, "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:birch_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2960, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2961, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2962, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2963, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2964, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2965, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2966, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2967, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2968, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2969, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2970, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2971, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2972, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2973, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2974, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2975, "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2976, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2977, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2978, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2979, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2980, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2981, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2982, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2983, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2984, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2985, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2986, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2987, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'true'}}"); -+ register(2988, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2989, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2990, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2991, "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'true'}}"); -+ register(2992, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2993, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2994, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2995, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'false'}}"); -+ register(2996, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2997, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2998, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'false'}}"); -+ register(2999, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'false'}}"); -+ register(3000, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'true',open:'false',powered:'true'}}"); -+ register(3001, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'true',open:'false',powered:'true'}}"); -+ register(3002, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'true',open:'false',powered:'true'}}"); -+ register(3003, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'true',open:'false',powered:'true'}}"); -+ register(3004, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'south',in_wall:'true',open:'true',powered:'true'}}"); -+ register(3005, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'west',in_wall:'true',open:'true',powered:'true'}}"); -+ register(3006, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'north',in_wall:'true',open:'true',powered:'true'}}"); -+ register(3007, "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'false',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_fence_gate',Properties:{facing:'east',in_wall:'true',open:'true',powered:'true'}}"); -+ register(3008, "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:spruce_fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(3024, "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:birch_fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(3040, "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:jungle_fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(3056, "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:dark_oak_fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(3072, "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'false',north:'true',south:'true',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'false',south:'false',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'false',south:'false',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'false',south:'true',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'false',south:'true',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'true',south:'false',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'true',south:'false',west:'true'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'true',south:'true',west:'false'}}", "{Name:'minecraft:acacia_fence',Properties:{east:'true',north:'true',south:'true',west:'true'}}"); -+ register(3088, "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3089, "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3090, "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3091, "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3092, "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3093, "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3094, "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3095, "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3096, "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(3097, "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(3098, "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(3099, "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:spruce_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(3104, "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3105, "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3106, "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3107, "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3108, "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3109, "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3110, "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3111, "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3112, "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(3113, "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(3114, "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(3115, "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:birch_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(3120, "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3121, "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3122, "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3123, "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3124, "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3125, "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3126, "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3127, "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3128, "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(3129, "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(3130, "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(3131, "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:jungle_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(3136, "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3137, "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3138, "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3139, "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3140, "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3141, "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3142, "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3143, "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3144, "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(3145, "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(3146, "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(3147, "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:acacia_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(3152, "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3153, "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3154, "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3155, "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'false',powered:'true'}}"); -+ register(3156, "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3157, "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3158, "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3159, "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'lower',hinge:'right',open:'true',powered:'true'}}"); -+ register(3160, "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'false'}}"); -+ register(3161, "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'false'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'false'}}"); -+ register(3162, "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'left',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'left',open:'true',powered:'true'}}"); -+ register(3163, "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'east',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'north',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'south',half:'upper',hinge:'right',open:'true',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'false',powered:'true'}}", "{Name:'minecraft:dark_oak_door',Properties:{facing:'west',half:'upper',hinge:'right',open:'true',powered:'true'}}"); -+ register(3168, "{Name:'minecraft:end_rod',Properties:{facing:'down'}}", "{Name:'minecraft:end_rod',Properties:{facing:'down'}}"); -+ register(3169, "{Name:'minecraft:end_rod',Properties:{facing:'up'}}", "{Name:'minecraft:end_rod',Properties:{facing:'up'}}"); -+ register(3170, "{Name:'minecraft:end_rod',Properties:{facing:'north'}}", "{Name:'minecraft:end_rod',Properties:{facing:'north'}}"); -+ register(3171, "{Name:'minecraft:end_rod',Properties:{facing:'south'}}", "{Name:'minecraft:end_rod',Properties:{facing:'south'}}"); -+ register(3172, "{Name:'minecraft:end_rod',Properties:{facing:'west'}}", "{Name:'minecraft:end_rod',Properties:{facing:'west'}}"); -+ register(3173, "{Name:'minecraft:end_rod',Properties:{facing:'east'}}", "{Name:'minecraft:end_rod',Properties:{facing:'east'}}"); -+ register(3184, "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'false',east:'true',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'false',north:'true',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'false',south:'true',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'false',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'false',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'false',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'false',up:'true',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'true',up:'false',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'true',up:'false',west:'true'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'true',up:'true',west:'false'}}", "{Name:'minecraft:chorus_plant',Properties:{down:'true',east:'true',north:'true',south:'true',up:'true',west:'true'}}"); -+ register(3200, "{Name:'minecraft:chorus_flower',Properties:{age:'0'}}", "{Name:'minecraft:chorus_flower',Properties:{age:'0'}}"); -+ register(3201, "{Name:'minecraft:chorus_flower',Properties:{age:'1'}}", "{Name:'minecraft:chorus_flower',Properties:{age:'1'}}"); -+ register(3202, "{Name:'minecraft:chorus_flower',Properties:{age:'2'}}", "{Name:'minecraft:chorus_flower',Properties:{age:'2'}}"); -+ register(3203, "{Name:'minecraft:chorus_flower',Properties:{age:'3'}}", "{Name:'minecraft:chorus_flower',Properties:{age:'3'}}"); -+ register(3204, "{Name:'minecraft:chorus_flower',Properties:{age:'4'}}", "{Name:'minecraft:chorus_flower',Properties:{age:'4'}}"); -+ register(3205, "{Name:'minecraft:chorus_flower',Properties:{age:'5'}}", "{Name:'minecraft:chorus_flower',Properties:{age:'5'}}"); -+ register(3216, "{Name:'minecraft:purpur_block'}", "{Name:'minecraft:purpur_block'}"); -+ register(3232, "{Name:'minecraft:purpur_pillar',Properties:{axis:'y'}}", "{Name:'minecraft:purpur_pillar',Properties:{axis:'y'}}"); -+ register(3236, "{Name:'minecraft:purpur_pillar',Properties:{axis:'x'}}", "{Name:'minecraft:purpur_pillar',Properties:{axis:'x'}}"); -+ register(3240, "{Name:'minecraft:purpur_pillar',Properties:{axis:'z'}}", "{Name:'minecraft:purpur_pillar',Properties:{axis:'z'}}"); -+ register(3248, "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'bottom',shape:'straight'}}"); -+ register(3249, "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'bottom',shape:'straight'}}"); -+ register(3250, "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'bottom',shape:'straight'}}"); -+ register(3251, "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'bottom',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'bottom',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'bottom',shape:'straight'}}"); -+ register(3252, "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'top',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'top',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'top',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'top',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'east',half:'top',shape:'straight'}}"); -+ register(3253, "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'top',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'top',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'top',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'top',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'west',half:'top',shape:'straight'}}"); -+ register(3254, "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'top',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'top',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'top',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'top',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'south',half:'top',shape:'straight'}}"); -+ register(3255, "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'top',shape:'inner_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'top',shape:'inner_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'top',shape:'outer_left'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'top',shape:'outer_right'}}", "{Name:'minecraft:purpur_stairs',Properties:{facing:'north',half:'top',shape:'straight'}}"); -+ register(3264, "{Name:'minecraft:purpur_slab',Properties:{type:'double'}}", "{Name:'minecraft:purpur_double_slab',Properties:{variant:'default'}}"); -+ register(3280, "{Name:'minecraft:purpur_slab',Properties:{type:'bottom'}}", "{Name:'minecraft:purpur_slab',Properties:{half:'bottom',variant:'default'}}"); -+ register(3288, "{Name:'minecraft:purpur_slab',Properties:{type:'top'}}", "{Name:'minecraft:purpur_slab',Properties:{half:'top',variant:'default'}}"); -+ register(3296, "{Name:'minecraft:end_stone_bricks'}", "{Name:'minecraft:end_bricks'}"); -+ register(3312, "{Name:'minecraft:beetroots',Properties:{age:'0'}}", "{Name:'minecraft:beetroots',Properties:{age:'0'}}"); -+ register(3313, "{Name:'minecraft:beetroots',Properties:{age:'1'}}", "{Name:'minecraft:beetroots',Properties:{age:'1'}}"); -+ register(3314, "{Name:'minecraft:beetroots',Properties:{age:'2'}}", "{Name:'minecraft:beetroots',Properties:{age:'2'}}"); -+ register(3315, "{Name:'minecraft:beetroots',Properties:{age:'3'}}", "{Name:'minecraft:beetroots',Properties:{age:'3'}}"); -+ register(3328, "{Name:'minecraft:grass_path'}", "{Name:'minecraft:grass_path'}"); -+ register(3344, "{Name:'minecraft:end_gateway'}", "{Name:'minecraft:end_gateway'}"); -+ register(3360, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'down'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'down'}}"); -+ register(3361, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'up'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'up'}}"); -+ register(3362, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'north'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'north'}}"); -+ register(3363, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'south'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'south'}}"); -+ register(3364, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'west'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'west'}}"); -+ register(3365, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'east'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'false',facing:'east'}}"); -+ register(3368, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'down'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'down'}}"); -+ register(3369, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'up'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'up'}}"); -+ register(3370, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'north'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'north'}}"); -+ register(3371, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'south'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'south'}}"); -+ register(3372, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'west'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'west'}}"); -+ register(3373, "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'east'}}", "{Name:'minecraft:repeating_command_block',Properties:{conditional:'true',facing:'east'}}"); -+ register(3376, "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'down'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'down'}}"); -+ register(3377, "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'up'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'up'}}"); -+ register(3378, "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'north'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'north'}}"); -+ register(3379, "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'south'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'south'}}"); -+ register(3380, "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'west'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'west'}}"); -+ register(3381, "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'east'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'false',facing:'east'}}"); -+ register(3384, "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'down'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'down'}}"); -+ register(3385, "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'up'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'up'}}"); -+ register(3386, "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'north'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'north'}}"); -+ register(3387, "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'south'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'south'}}"); -+ register(3388, "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'west'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'west'}}"); -+ register(3389, "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'east'}}", "{Name:'minecraft:chain_command_block',Properties:{conditional:'true',facing:'east'}}"); -+ register(3392, "{Name:'minecraft:frosted_ice',Properties:{age:'0'}}", "{Name:'minecraft:frosted_ice',Properties:{age:'0'}}"); -+ register(3393, "{Name:'minecraft:frosted_ice',Properties:{age:'1'}}", "{Name:'minecraft:frosted_ice',Properties:{age:'1'}}"); -+ register(3394, "{Name:'minecraft:frosted_ice',Properties:{age:'2'}}", "{Name:'minecraft:frosted_ice',Properties:{age:'2'}}"); -+ register(3395, "{Name:'minecraft:frosted_ice',Properties:{age:'3'}}", "{Name:'minecraft:frosted_ice',Properties:{age:'3'}}"); -+ register(3408, "{Name:'minecraft:magma_block'}", "{Name:'minecraft:magma'}"); -+ register(3424, "{Name:'minecraft:nether_wart_block'}", "{Name:'minecraft:nether_wart_block'}"); -+ register(3440, "{Name:'minecraft:red_nether_bricks'}", "{Name:'minecraft:red_nether_brick'}"); -+ register(3456, "{Name:'minecraft:bone_block',Properties:{axis:'y'}}", "{Name:'minecraft:bone_block',Properties:{axis:'y'}}"); -+ register(3460, "{Name:'minecraft:bone_block',Properties:{axis:'x'}}", "{Name:'minecraft:bone_block',Properties:{axis:'x'}}"); -+ register(3464, "{Name:'minecraft:bone_block',Properties:{axis:'z'}}", "{Name:'minecraft:bone_block',Properties:{axis:'z'}}"); -+ register(3472, "{Name:'minecraft:structure_void'}", "{Name:'minecraft:structure_void'}"); -+ register(3488, "{Name:'minecraft:observer',Properties:{facing:'down',powered:'false'}}", "{Name:'minecraft:observer',Properties:{facing:'down',powered:'false'}}"); -+ register(3489, "{Name:'minecraft:observer',Properties:{facing:'up',powered:'false'}}", "{Name:'minecraft:observer',Properties:{facing:'up',powered:'false'}}"); -+ register(3490, "{Name:'minecraft:observer',Properties:{facing:'north',powered:'false'}}", "{Name:'minecraft:observer',Properties:{facing:'north',powered:'false'}}"); -+ register(3491, "{Name:'minecraft:observer',Properties:{facing:'south',powered:'false'}}", "{Name:'minecraft:observer',Properties:{facing:'south',powered:'false'}}"); -+ register(3492, "{Name:'minecraft:observer',Properties:{facing:'west',powered:'false'}}", "{Name:'minecraft:observer',Properties:{facing:'west',powered:'false'}}"); -+ register(3493, "{Name:'minecraft:observer',Properties:{facing:'east',powered:'false'}}", "{Name:'minecraft:observer',Properties:{facing:'east',powered:'false'}}"); -+ register(3496, "{Name:'minecraft:observer',Properties:{facing:'down',powered:'true'}}", "{Name:'minecraft:observer',Properties:{facing:'down',powered:'true'}}"); -+ register(3497, "{Name:'minecraft:observer',Properties:{facing:'up',powered:'true'}}", "{Name:'minecraft:observer',Properties:{facing:'up',powered:'true'}}"); -+ register(3498, "{Name:'minecraft:observer',Properties:{facing:'north',powered:'true'}}", "{Name:'minecraft:observer',Properties:{facing:'north',powered:'true'}}"); -+ register(3499, "{Name:'minecraft:observer',Properties:{facing:'south',powered:'true'}}", "{Name:'minecraft:observer',Properties:{facing:'south',powered:'true'}}"); -+ register(3500, "{Name:'minecraft:observer',Properties:{facing:'west',powered:'true'}}", "{Name:'minecraft:observer',Properties:{facing:'west',powered:'true'}}"); -+ register(3501, "{Name:'minecraft:observer',Properties:{facing:'east',powered:'true'}}", "{Name:'minecraft:observer',Properties:{facing:'east',powered:'true'}}"); -+ register(3504, "{Name:'minecraft:white_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:white_shulker_box',Properties:{facing:'down'}}"); -+ register(3505, "{Name:'minecraft:white_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:white_shulker_box',Properties:{facing:'up'}}"); -+ register(3506, "{Name:'minecraft:white_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:white_shulker_box',Properties:{facing:'north'}}"); -+ register(3507, "{Name:'minecraft:white_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:white_shulker_box',Properties:{facing:'south'}}"); -+ register(3508, "{Name:'minecraft:white_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:white_shulker_box',Properties:{facing:'west'}}"); -+ register(3509, "{Name:'minecraft:white_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:white_shulker_box',Properties:{facing:'east'}}"); -+ register(3520, "{Name:'minecraft:orange_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:orange_shulker_box',Properties:{facing:'down'}}"); -+ register(3521, "{Name:'minecraft:orange_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:orange_shulker_box',Properties:{facing:'up'}}"); -+ register(3522, "{Name:'minecraft:orange_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:orange_shulker_box',Properties:{facing:'north'}}"); -+ register(3523, "{Name:'minecraft:orange_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:orange_shulker_box',Properties:{facing:'south'}}"); -+ register(3524, "{Name:'minecraft:orange_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:orange_shulker_box',Properties:{facing:'west'}}"); -+ register(3525, "{Name:'minecraft:orange_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:orange_shulker_box',Properties:{facing:'east'}}"); -+ register(3536, "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'down'}}"); -+ register(3537, "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'up'}}"); -+ register(3538, "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'north'}}"); -+ register(3539, "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'south'}}"); -+ register(3540, "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'west'}}"); -+ register(3541, "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:magenta_shulker_box',Properties:{facing:'east'}}"); -+ register(3552, "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'down'}}"); -+ register(3553, "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'up'}}"); -+ register(3554, "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'north'}}"); -+ register(3555, "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'south'}}"); -+ register(3556, "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'west'}}"); -+ register(3557, "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:light_blue_shulker_box',Properties:{facing:'east'}}"); -+ register(3568, "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'down'}}"); -+ register(3569, "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'up'}}"); -+ register(3570, "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'north'}}"); -+ register(3571, "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'south'}}"); -+ register(3572, "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'west'}}"); -+ register(3573, "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:yellow_shulker_box',Properties:{facing:'east'}}"); -+ register(3584, "{Name:'minecraft:lime_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:lime_shulker_box',Properties:{facing:'down'}}"); -+ register(3585, "{Name:'minecraft:lime_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:lime_shulker_box',Properties:{facing:'up'}}"); -+ register(3586, "{Name:'minecraft:lime_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:lime_shulker_box',Properties:{facing:'north'}}"); -+ register(3587, "{Name:'minecraft:lime_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:lime_shulker_box',Properties:{facing:'south'}}"); -+ register(3588, "{Name:'minecraft:lime_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:lime_shulker_box',Properties:{facing:'west'}}"); -+ register(3589, "{Name:'minecraft:lime_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:lime_shulker_box',Properties:{facing:'east'}}"); -+ register(3600, "{Name:'minecraft:pink_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:pink_shulker_box',Properties:{facing:'down'}}"); -+ register(3601, "{Name:'minecraft:pink_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:pink_shulker_box',Properties:{facing:'up'}}"); -+ register(3602, "{Name:'minecraft:pink_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:pink_shulker_box',Properties:{facing:'north'}}"); -+ register(3603, "{Name:'minecraft:pink_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:pink_shulker_box',Properties:{facing:'south'}}"); -+ register(3604, "{Name:'minecraft:pink_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:pink_shulker_box',Properties:{facing:'west'}}"); -+ register(3605, "{Name:'minecraft:pink_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:pink_shulker_box',Properties:{facing:'east'}}"); -+ register(3616, "{Name:'minecraft:gray_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:gray_shulker_box',Properties:{facing:'down'}}"); -+ register(3617, "{Name:'minecraft:gray_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:gray_shulker_box',Properties:{facing:'up'}}"); -+ register(3618, "{Name:'minecraft:gray_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:gray_shulker_box',Properties:{facing:'north'}}"); -+ register(3619, "{Name:'minecraft:gray_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:gray_shulker_box',Properties:{facing:'south'}}"); -+ register(3620, "{Name:'minecraft:gray_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:gray_shulker_box',Properties:{facing:'west'}}"); -+ register(3621, "{Name:'minecraft:gray_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:gray_shulker_box',Properties:{facing:'east'}}"); -+ register(3632, "{Name:'minecraft:light_gray_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:silver_shulker_box',Properties:{facing:'down'}}"); -+ register(3633, "{Name:'minecraft:light_gray_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:silver_shulker_box',Properties:{facing:'up'}}"); -+ register(3634, "{Name:'minecraft:light_gray_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:silver_shulker_box',Properties:{facing:'north'}}"); -+ register(3635, "{Name:'minecraft:light_gray_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:silver_shulker_box',Properties:{facing:'south'}}"); -+ register(3636, "{Name:'minecraft:light_gray_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:silver_shulker_box',Properties:{facing:'west'}}"); -+ register(3637, "{Name:'minecraft:light_gray_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:silver_shulker_box',Properties:{facing:'east'}}"); -+ register(3648, "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'down'}}"); -+ register(3649, "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'up'}}"); -+ register(3650, "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'north'}}"); -+ register(3651, "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'south'}}"); -+ register(3652, "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'west'}}"); -+ register(3653, "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:cyan_shulker_box',Properties:{facing:'east'}}"); -+ register(3664, "{Name:'minecraft:purple_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:purple_shulker_box',Properties:{facing:'down'}}"); -+ register(3665, "{Name:'minecraft:purple_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:purple_shulker_box',Properties:{facing:'up'}}"); -+ register(3666, "{Name:'minecraft:purple_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:purple_shulker_box',Properties:{facing:'north'}}"); -+ register(3667, "{Name:'minecraft:purple_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:purple_shulker_box',Properties:{facing:'south'}}"); -+ register(3668, "{Name:'minecraft:purple_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:purple_shulker_box',Properties:{facing:'west'}}"); -+ register(3669, "{Name:'minecraft:purple_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:purple_shulker_box',Properties:{facing:'east'}}"); -+ register(3680, "{Name:'minecraft:blue_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:blue_shulker_box',Properties:{facing:'down'}}"); -+ register(3681, "{Name:'minecraft:blue_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:blue_shulker_box',Properties:{facing:'up'}}"); -+ register(3682, "{Name:'minecraft:blue_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:blue_shulker_box',Properties:{facing:'north'}}"); -+ register(3683, "{Name:'minecraft:blue_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:blue_shulker_box',Properties:{facing:'south'}}"); -+ register(3684, "{Name:'minecraft:blue_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:blue_shulker_box',Properties:{facing:'west'}}"); -+ register(3685, "{Name:'minecraft:blue_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:blue_shulker_box',Properties:{facing:'east'}}"); -+ register(3696, "{Name:'minecraft:brown_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:brown_shulker_box',Properties:{facing:'down'}}"); -+ register(3697, "{Name:'minecraft:brown_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:brown_shulker_box',Properties:{facing:'up'}}"); -+ register(3698, "{Name:'minecraft:brown_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:brown_shulker_box',Properties:{facing:'north'}}"); -+ register(3699, "{Name:'minecraft:brown_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:brown_shulker_box',Properties:{facing:'south'}}"); -+ register(3700, "{Name:'minecraft:brown_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:brown_shulker_box',Properties:{facing:'west'}}"); -+ register(3701, "{Name:'minecraft:brown_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:brown_shulker_box',Properties:{facing:'east'}}"); -+ register(3712, "{Name:'minecraft:green_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:green_shulker_box',Properties:{facing:'down'}}"); -+ register(3713, "{Name:'minecraft:green_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:green_shulker_box',Properties:{facing:'up'}}"); -+ register(3714, "{Name:'minecraft:green_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:green_shulker_box',Properties:{facing:'north'}}"); -+ register(3715, "{Name:'minecraft:green_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:green_shulker_box',Properties:{facing:'south'}}"); -+ register(3716, "{Name:'minecraft:green_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:green_shulker_box',Properties:{facing:'west'}}"); -+ register(3717, "{Name:'minecraft:green_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:green_shulker_box',Properties:{facing:'east'}}"); -+ register(3728, "{Name:'minecraft:red_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:red_shulker_box',Properties:{facing:'down'}}"); -+ register(3729, "{Name:'minecraft:red_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:red_shulker_box',Properties:{facing:'up'}}"); -+ register(3730, "{Name:'minecraft:red_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:red_shulker_box',Properties:{facing:'north'}}"); -+ register(3731, "{Name:'minecraft:red_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:red_shulker_box',Properties:{facing:'south'}}"); -+ register(3732, "{Name:'minecraft:red_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:red_shulker_box',Properties:{facing:'west'}}"); -+ register(3733, "{Name:'minecraft:red_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:red_shulker_box',Properties:{facing:'east'}}"); -+ register(3744, "{Name:'minecraft:black_shulker_box',Properties:{facing:'down'}}", "{Name:'minecraft:black_shulker_box',Properties:{facing:'down'}}"); -+ register(3745, "{Name:'minecraft:black_shulker_box',Properties:{facing:'up'}}", "{Name:'minecraft:black_shulker_box',Properties:{facing:'up'}}"); -+ register(3746, "{Name:'minecraft:black_shulker_box',Properties:{facing:'north'}}", "{Name:'minecraft:black_shulker_box',Properties:{facing:'north'}}"); -+ register(3747, "{Name:'minecraft:black_shulker_box',Properties:{facing:'south'}}", "{Name:'minecraft:black_shulker_box',Properties:{facing:'south'}}"); -+ register(3748, "{Name:'minecraft:black_shulker_box',Properties:{facing:'west'}}", "{Name:'minecraft:black_shulker_box',Properties:{facing:'west'}}"); -+ register(3749, "{Name:'minecraft:black_shulker_box',Properties:{facing:'east'}}", "{Name:'minecraft:black_shulker_box',Properties:{facing:'east'}}"); -+ register(3760, "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3761, "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3762, "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3763, "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:white_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3776, "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3777, "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3778, "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3779, "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:orange_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3792, "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3793, "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3794, "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3795, "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:magenta_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3808, "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3809, "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3810, "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3811, "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:light_blue_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3824, "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3825, "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3826, "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3827, "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:yellow_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3840, "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3841, "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3842, "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3843, "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:lime_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3856, "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3857, "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3858, "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3859, "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:pink_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3872, "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3873, "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3874, "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3875, "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:gray_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3888, "{Name:'minecraft:light_gray_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:silver_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3889, "{Name:'minecraft:light_gray_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:silver_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3890, "{Name:'minecraft:light_gray_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:silver_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3891, "{Name:'minecraft:light_gray_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:silver_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3904, "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3905, "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3906, "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3907, "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:cyan_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3920, "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3921, "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3922, "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3923, "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:purple_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3936, "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3937, "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3938, "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3939, "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:blue_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3952, "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3953, "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3954, "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3955, "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:brown_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3968, "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3969, "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3970, "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3971, "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:green_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(3984, "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(3985, "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(3986, "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(3987, "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:red_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(4000, "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'south'}}", "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'south'}}"); -+ register(4001, "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'west'}}", "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'west'}}"); -+ register(4002, "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'north'}}", "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'north'}}"); -+ register(4003, "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'east'}}", "{Name:'minecraft:black_glazed_terracotta',Properties:{facing:'east'}}"); -+ register(4016, "{Name:'minecraft:white_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'white'}}"); -+ register(4017, "{Name:'minecraft:orange_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'orange'}}"); -+ register(4018, "{Name:'minecraft:magenta_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'magenta'}}"); -+ register(4019, "{Name:'minecraft:light_blue_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'light_blue'}}"); -+ register(4020, "{Name:'minecraft:yellow_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'yellow'}}"); -+ register(4021, "{Name:'minecraft:lime_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'lime'}}"); -+ register(4022, "{Name:'minecraft:pink_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'pink'}}"); -+ register(4023, "{Name:'minecraft:gray_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'gray'}}"); -+ register(4024, "{Name:'minecraft:light_gray_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'silver'}}"); -+ register(4025, "{Name:'minecraft:cyan_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'cyan'}}"); -+ register(4026, "{Name:'minecraft:purple_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'purple'}}"); -+ register(4027, "{Name:'minecraft:blue_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'blue'}}"); -+ register(4028, "{Name:'minecraft:brown_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'brown'}}"); -+ register(4029, "{Name:'minecraft:green_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'green'}}"); -+ register(4030, "{Name:'minecraft:red_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'red'}}"); -+ register(4031, "{Name:'minecraft:black_concrete'}", "{Name:'minecraft:concrete',Properties:{color:'black'}}"); -+ register(4032, "{Name:'minecraft:white_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'white'}}"); -+ register(4033, "{Name:'minecraft:orange_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'orange'}}"); -+ register(4034, "{Name:'minecraft:magenta_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'magenta'}}"); -+ register(4035, "{Name:'minecraft:light_blue_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'light_blue'}}"); -+ register(4036, "{Name:'minecraft:yellow_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'yellow'}}"); -+ register(4037, "{Name:'minecraft:lime_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'lime'}}"); -+ register(4038, "{Name:'minecraft:pink_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'pink'}}"); -+ register(4039, "{Name:'minecraft:gray_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'gray'}}"); -+ register(4040, "{Name:'minecraft:light_gray_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'silver'}}"); -+ register(4041, "{Name:'minecraft:cyan_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'cyan'}}"); -+ register(4042, "{Name:'minecraft:purple_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'purple'}}"); -+ register(4043, "{Name:'minecraft:blue_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'blue'}}"); -+ register(4044, "{Name:'minecraft:brown_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'brown'}}"); -+ register(4045, "{Name:'minecraft:green_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'green'}}"); -+ register(4046, "{Name:'minecraft:red_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'red'}}"); -+ register(4047, "{Name:'minecraft:black_concrete_powder'}", "{Name:'minecraft:concrete_powder',Properties:{color:'black'}}"); -+ register(4080, "{Name:'minecraft:structure_block',Properties:{mode:'save'}}", "{Name:'minecraft:structure_block',Properties:{mode:'save'}}"); -+ register(4081, "{Name:'minecraft:structure_block',Properties:{mode:'load'}}", "{Name:'minecraft:structure_block',Properties:{mode:'load'}}"); -+ register(4082, "{Name:'minecraft:structure_block',Properties:{mode:'corner'}}", "{Name:'minecraft:structure_block',Properties:{mode:'corner'}}"); -+ register(4083, "{Name:'minecraft:structure_block',Properties:{mode:'data'}}", "{Name:'minecraft:structure_block',Properties:{mode:'data'}}"); -+ finalizeMaps(); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperItemNameV102.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperItemNameV102.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f7a9dedd0b49ed068089cb9efe4050fba6db15d7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperItemNameV102.java -@@ -0,0 +1,533 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.helpers; -+ -+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -+ -+public final class HelperItemNameV102 { -+ -+ // This class is responsible for mapping the id -> string update in itemstacks and potions -+ -+ private static final Int2ObjectOpenHashMap ITEM_NAMES = new Int2ObjectOpenHashMap() { -+ @Override -+ public String put(final int k, final String o) { -+ final String ret = super.put(k, o); -+ -+ if (ret != null) { -+ throw new IllegalStateException("Mapping already exists for " + k + ": prev: " + ret + ", new: " + o); -+ } -+ -+ return ret; -+ } -+ }; -+ -+ static { -+ ITEM_NAMES.put(0, "minecraft:air"); -+ ITEM_NAMES.put(1, "minecraft:stone"); -+ ITEM_NAMES.put(2, "minecraft:grass"); -+ ITEM_NAMES.put(3, "minecraft:dirt"); -+ ITEM_NAMES.put(4, "minecraft:cobblestone"); -+ ITEM_NAMES.put(5, "minecraft:planks"); -+ ITEM_NAMES.put(6, "minecraft:sapling"); -+ ITEM_NAMES.put(7, "minecraft:bedrock"); -+ ITEM_NAMES.put(8, "minecraft:flowing_water"); -+ ITEM_NAMES.put(9, "minecraft:water"); -+ ITEM_NAMES.put(10, "minecraft:flowing_lava"); -+ ITEM_NAMES.put(11, "minecraft:lava"); -+ ITEM_NAMES.put(12, "minecraft:sand"); -+ ITEM_NAMES.put(13, "minecraft:gravel"); -+ ITEM_NAMES.put(14, "minecraft:gold_ore"); -+ ITEM_NAMES.put(15, "minecraft:iron_ore"); -+ ITEM_NAMES.put(16, "minecraft:coal_ore"); -+ ITEM_NAMES.put(17, "minecraft:log"); -+ ITEM_NAMES.put(18, "minecraft:leaves"); -+ ITEM_NAMES.put(19, "minecraft:sponge"); -+ ITEM_NAMES.put(20, "minecraft:glass"); -+ ITEM_NAMES.put(21, "minecraft:lapis_ore"); -+ ITEM_NAMES.put(22, "minecraft:lapis_block"); -+ ITEM_NAMES.put(23, "minecraft:dispenser"); -+ ITEM_NAMES.put(24, "minecraft:sandstone"); -+ ITEM_NAMES.put(25, "minecraft:noteblock"); -+ ITEM_NAMES.put(27, "minecraft:golden_rail"); -+ ITEM_NAMES.put(28, "minecraft:detector_rail"); -+ ITEM_NAMES.put(29, "minecraft:sticky_piston"); -+ ITEM_NAMES.put(30, "minecraft:web"); -+ ITEM_NAMES.put(31, "minecraft:tallgrass"); -+ ITEM_NAMES.put(32, "minecraft:deadbush"); -+ ITEM_NAMES.put(33, "minecraft:piston"); -+ ITEM_NAMES.put(35, "minecraft:wool"); -+ ITEM_NAMES.put(37, "minecraft:yellow_flower"); -+ ITEM_NAMES.put(38, "minecraft:red_flower"); -+ ITEM_NAMES.put(39, "minecraft:brown_mushroom"); -+ ITEM_NAMES.put(40, "minecraft:red_mushroom"); -+ ITEM_NAMES.put(41, "minecraft:gold_block"); -+ ITEM_NAMES.put(42, "minecraft:iron_block"); -+ ITEM_NAMES.put(43, "minecraft:double_stone_slab"); -+ ITEM_NAMES.put(44, "minecraft:stone_slab"); -+ ITEM_NAMES.put(45, "minecraft:brick_block"); -+ ITEM_NAMES.put(46, "minecraft:tnt"); -+ ITEM_NAMES.put(47, "minecraft:bookshelf"); -+ ITEM_NAMES.put(48, "minecraft:mossy_cobblestone"); -+ ITEM_NAMES.put(49, "minecraft:obsidian"); -+ ITEM_NAMES.put(50, "minecraft:torch"); -+ ITEM_NAMES.put(51, "minecraft:fire"); -+ ITEM_NAMES.put(52, "minecraft:mob_spawner"); -+ ITEM_NAMES.put(53, "minecraft:oak_stairs"); -+ ITEM_NAMES.put(54, "minecraft:chest"); -+ ITEM_NAMES.put(56, "minecraft:diamond_ore"); -+ ITEM_NAMES.put(57, "minecraft:diamond_block"); -+ ITEM_NAMES.put(58, "minecraft:crafting_table"); -+ ITEM_NAMES.put(60, "minecraft:farmland"); -+ ITEM_NAMES.put(61, "minecraft:furnace"); -+ ITEM_NAMES.put(62, "minecraft:lit_furnace"); -+ ITEM_NAMES.put(65, "minecraft:ladder"); -+ ITEM_NAMES.put(66, "minecraft:rail"); -+ ITEM_NAMES.put(67, "minecraft:stone_stairs"); -+ ITEM_NAMES.put(69, "minecraft:lever"); -+ ITEM_NAMES.put(70, "minecraft:stone_pressure_plate"); -+ ITEM_NAMES.put(72, "minecraft:wooden_pressure_plate"); -+ ITEM_NAMES.put(73, "minecraft:redstone_ore"); -+ ITEM_NAMES.put(76, "minecraft:redstone_torch"); -+ ITEM_NAMES.put(77, "minecraft:stone_button"); -+ ITEM_NAMES.put(78, "minecraft:snow_layer"); -+ ITEM_NAMES.put(79, "minecraft:ice"); -+ ITEM_NAMES.put(80, "minecraft:snow"); -+ ITEM_NAMES.put(81, "minecraft:cactus"); -+ ITEM_NAMES.put(82, "minecraft:clay"); -+ ITEM_NAMES.put(84, "minecraft:jukebox"); -+ ITEM_NAMES.put(85, "minecraft:fence"); -+ ITEM_NAMES.put(86, "minecraft:pumpkin"); -+ ITEM_NAMES.put(87, "minecraft:netherrack"); -+ ITEM_NAMES.put(88, "minecraft:soul_sand"); -+ ITEM_NAMES.put(89, "minecraft:glowstone"); -+ ITEM_NAMES.put(90, "minecraft:portal"); -+ ITEM_NAMES.put(91, "minecraft:lit_pumpkin"); -+ ITEM_NAMES.put(95, "minecraft:stained_glass"); -+ ITEM_NAMES.put(96, "minecraft:trapdoor"); -+ ITEM_NAMES.put(97, "minecraft:monster_egg"); -+ ITEM_NAMES.put(98, "minecraft:stonebrick"); -+ ITEM_NAMES.put(99, "minecraft:brown_mushroom_block"); -+ ITEM_NAMES.put(100, "minecraft:red_mushroom_block"); -+ ITEM_NAMES.put(101, "minecraft:iron_bars"); -+ ITEM_NAMES.put(102, "minecraft:glass_pane"); -+ ITEM_NAMES.put(103, "minecraft:melon_block"); -+ ITEM_NAMES.put(106, "minecraft:vine"); -+ ITEM_NAMES.put(107, "minecraft:fence_gate"); -+ ITEM_NAMES.put(108, "minecraft:brick_stairs"); -+ ITEM_NAMES.put(109, "minecraft:stone_brick_stairs"); -+ ITEM_NAMES.put(110, "minecraft:mycelium"); -+ ITEM_NAMES.put(111, "minecraft:waterlily"); -+ ITEM_NAMES.put(112, "minecraft:nether_brick"); -+ ITEM_NAMES.put(113, "minecraft:nether_brick_fence"); -+ ITEM_NAMES.put(114, "minecraft:nether_brick_stairs"); -+ ITEM_NAMES.put(116, "minecraft:enchanting_table"); -+ ITEM_NAMES.put(119, "minecraft:end_portal"); -+ ITEM_NAMES.put(120, "minecraft:end_portal_frame"); -+ ITEM_NAMES.put(121, "minecraft:end_stone"); -+ ITEM_NAMES.put(122, "minecraft:dragon_egg"); -+ ITEM_NAMES.put(123, "minecraft:redstone_lamp"); -+ ITEM_NAMES.put(125, "minecraft:double_wooden_slab"); -+ ITEM_NAMES.put(126, "minecraft:wooden_slab"); -+ ITEM_NAMES.put(127, "minecraft:cocoa"); -+ ITEM_NAMES.put(128, "minecraft:sandstone_stairs"); -+ ITEM_NAMES.put(129, "minecraft:emerald_ore"); -+ ITEM_NAMES.put(130, "minecraft:ender_chest"); -+ ITEM_NAMES.put(131, "minecraft:tripwire_hook"); -+ ITEM_NAMES.put(133, "minecraft:emerald_block"); -+ ITEM_NAMES.put(134, "minecraft:spruce_stairs"); -+ ITEM_NAMES.put(135, "minecraft:birch_stairs"); -+ ITEM_NAMES.put(136, "minecraft:jungle_stairs"); -+ ITEM_NAMES.put(137, "minecraft:command_block"); -+ ITEM_NAMES.put(138, "minecraft:beacon"); -+ ITEM_NAMES.put(139, "minecraft:cobblestone_wall"); -+ ITEM_NAMES.put(141, "minecraft:carrots"); -+ ITEM_NAMES.put(142, "minecraft:potatoes"); -+ ITEM_NAMES.put(143, "minecraft:wooden_button"); -+ ITEM_NAMES.put(145, "minecraft:anvil"); -+ ITEM_NAMES.put(146, "minecraft:trapped_chest"); -+ ITEM_NAMES.put(147, "minecraft:light_weighted_pressure_plate"); -+ ITEM_NAMES.put(148, "minecraft:heavy_weighted_pressure_plate"); -+ ITEM_NAMES.put(151, "minecraft:daylight_detector"); -+ ITEM_NAMES.put(152, "minecraft:redstone_block"); -+ ITEM_NAMES.put(153, "minecraft:quartz_ore"); -+ ITEM_NAMES.put(154, "minecraft:hopper"); -+ ITEM_NAMES.put(155, "minecraft:quartz_block"); -+ ITEM_NAMES.put(156, "minecraft:quartz_stairs"); -+ ITEM_NAMES.put(157, "minecraft:activator_rail"); -+ ITEM_NAMES.put(158, "minecraft:dropper"); -+ ITEM_NAMES.put(159, "minecraft:stained_hardened_clay"); -+ ITEM_NAMES.put(160, "minecraft:stained_glass_pane"); -+ ITEM_NAMES.put(161, "minecraft:leaves2"); -+ ITEM_NAMES.put(162, "minecraft:log2"); -+ ITEM_NAMES.put(163, "minecraft:acacia_stairs"); -+ ITEM_NAMES.put(164, "minecraft:dark_oak_stairs"); -+ ITEM_NAMES.put(170, "minecraft:hay_block"); -+ ITEM_NAMES.put(171, "minecraft:carpet"); -+ ITEM_NAMES.put(172, "minecraft:hardened_clay"); -+ ITEM_NAMES.put(173, "minecraft:coal_block"); -+ ITEM_NAMES.put(174, "minecraft:packed_ice"); -+ ITEM_NAMES.put(175, "minecraft:double_plant"); -+ ITEM_NAMES.put(256, "minecraft:iron_shovel"); -+ ITEM_NAMES.put(257, "minecraft:iron_pickaxe"); -+ ITEM_NAMES.put(258, "minecraft:iron_axe"); -+ ITEM_NAMES.put(259, "minecraft:flint_and_steel"); -+ ITEM_NAMES.put(260, "minecraft:apple"); -+ ITEM_NAMES.put(261, "minecraft:bow"); -+ ITEM_NAMES.put(262, "minecraft:arrow"); -+ ITEM_NAMES.put(263, "minecraft:coal"); -+ ITEM_NAMES.put(264, "minecraft:diamond"); -+ ITEM_NAMES.put(265, "minecraft:iron_ingot"); -+ ITEM_NAMES.put(266, "minecraft:gold_ingot"); -+ ITEM_NAMES.put(267, "minecraft:iron_sword"); -+ ITEM_NAMES.put(268, "minecraft:wooden_sword"); -+ ITEM_NAMES.put(269, "minecraft:wooden_shovel"); -+ ITEM_NAMES.put(270, "minecraft:wooden_pickaxe"); -+ ITEM_NAMES.put(271, "minecraft:wooden_axe"); -+ ITEM_NAMES.put(272, "minecraft:stone_sword"); -+ ITEM_NAMES.put(273, "minecraft:stone_shovel"); -+ ITEM_NAMES.put(274, "minecraft:stone_pickaxe"); -+ ITEM_NAMES.put(275, "minecraft:stone_axe"); -+ ITEM_NAMES.put(276, "minecraft:diamond_sword"); -+ ITEM_NAMES.put(277, "minecraft:diamond_shovel"); -+ ITEM_NAMES.put(278, "minecraft:diamond_pickaxe"); -+ ITEM_NAMES.put(279, "minecraft:diamond_axe"); -+ ITEM_NAMES.put(280, "minecraft:stick"); -+ ITEM_NAMES.put(281, "minecraft:bowl"); -+ ITEM_NAMES.put(282, "minecraft:mushroom_stew"); -+ ITEM_NAMES.put(283, "minecraft:golden_sword"); -+ ITEM_NAMES.put(284, "minecraft:golden_shovel"); -+ ITEM_NAMES.put(285, "minecraft:golden_pickaxe"); -+ ITEM_NAMES.put(286, "minecraft:golden_axe"); -+ ITEM_NAMES.put(287, "minecraft:string"); -+ ITEM_NAMES.put(288, "minecraft:feather"); -+ ITEM_NAMES.put(289, "minecraft:gunpowder"); -+ ITEM_NAMES.put(290, "minecraft:wooden_hoe"); -+ ITEM_NAMES.put(291, "minecraft:stone_hoe"); -+ ITEM_NAMES.put(292, "minecraft:iron_hoe"); -+ ITEM_NAMES.put(293, "minecraft:diamond_hoe"); -+ ITEM_NAMES.put(294, "minecraft:golden_hoe"); -+ ITEM_NAMES.put(295, "minecraft:wheat_seeds"); -+ ITEM_NAMES.put(296, "minecraft:wheat"); -+ ITEM_NAMES.put(297, "minecraft:bread"); -+ ITEM_NAMES.put(298, "minecraft:leather_helmet"); -+ ITEM_NAMES.put(299, "minecraft:leather_chestplate"); -+ ITEM_NAMES.put(300, "minecraft:leather_leggings"); -+ ITEM_NAMES.put(301, "minecraft:leather_boots"); -+ ITEM_NAMES.put(302, "minecraft:chainmail_helmet"); -+ ITEM_NAMES.put(303, "minecraft:chainmail_chestplate"); -+ ITEM_NAMES.put(304, "minecraft:chainmail_leggings"); -+ ITEM_NAMES.put(305, "minecraft:chainmail_boots"); -+ ITEM_NAMES.put(306, "minecraft:iron_helmet"); -+ ITEM_NAMES.put(307, "minecraft:iron_chestplate"); -+ ITEM_NAMES.put(308, "minecraft:iron_leggings"); -+ ITEM_NAMES.put(309, "minecraft:iron_boots"); -+ ITEM_NAMES.put(310, "minecraft:diamond_helmet"); -+ ITEM_NAMES.put(311, "minecraft:diamond_chestplate"); -+ ITEM_NAMES.put(312, "minecraft:diamond_leggings"); -+ ITEM_NAMES.put(313, "minecraft:diamond_boots"); -+ ITEM_NAMES.put(314, "minecraft:golden_helmet"); -+ ITEM_NAMES.put(315, "minecraft:golden_chestplate"); -+ ITEM_NAMES.put(316, "minecraft:golden_leggings"); -+ ITEM_NAMES.put(317, "minecraft:golden_boots"); -+ ITEM_NAMES.put(318, "minecraft:flint"); -+ ITEM_NAMES.put(319, "minecraft:porkchop"); -+ ITEM_NAMES.put(320, "minecraft:cooked_porkchop"); -+ ITEM_NAMES.put(321, "minecraft:painting"); -+ ITEM_NAMES.put(322, "minecraft:golden_apple"); -+ ITEM_NAMES.put(323, "minecraft:sign"); -+ ITEM_NAMES.put(324, "minecraft:wooden_door"); -+ ITEM_NAMES.put(325, "minecraft:bucket"); -+ ITEM_NAMES.put(326, "minecraft:water_bucket"); -+ ITEM_NAMES.put(327, "minecraft:lava_bucket"); -+ ITEM_NAMES.put(328, "minecraft:minecart"); -+ ITEM_NAMES.put(329, "minecraft:saddle"); -+ ITEM_NAMES.put(330, "minecraft:iron_door"); -+ ITEM_NAMES.put(331, "minecraft:redstone"); -+ ITEM_NAMES.put(332, "minecraft:snowball"); -+ ITEM_NAMES.put(333, "minecraft:boat"); -+ ITEM_NAMES.put(334, "minecraft:leather"); -+ ITEM_NAMES.put(335, "minecraft:milk_bucket"); -+ ITEM_NAMES.put(336, "minecraft:brick"); -+ ITEM_NAMES.put(337, "minecraft:clay_ball"); -+ ITEM_NAMES.put(338, "minecraft:reeds"); -+ ITEM_NAMES.put(339, "minecraft:paper"); -+ ITEM_NAMES.put(340, "minecraft:book"); -+ ITEM_NAMES.put(341, "minecraft:slime_ball"); -+ ITEM_NAMES.put(342, "minecraft:chest_minecart"); -+ ITEM_NAMES.put(343, "minecraft:furnace_minecart"); -+ ITEM_NAMES.put(344, "minecraft:egg"); -+ ITEM_NAMES.put(345, "minecraft:compass"); -+ ITEM_NAMES.put(346, "minecraft:fishing_rod"); -+ ITEM_NAMES.put(347, "minecraft:clock"); -+ ITEM_NAMES.put(348, "minecraft:glowstone_dust"); -+ ITEM_NAMES.put(349, "minecraft:fish"); -+ ITEM_NAMES.put(350, "minecraft:cooked_fished"); -+ ITEM_NAMES.put(351, "minecraft:dye"); -+ ITEM_NAMES.put(352, "minecraft:bone"); -+ ITEM_NAMES.put(353, "minecraft:sugar"); -+ ITEM_NAMES.put(354, "minecraft:cake"); -+ ITEM_NAMES.put(355, "minecraft:bed"); -+ ITEM_NAMES.put(356, "minecraft:repeater"); -+ ITEM_NAMES.put(357, "minecraft:cookie"); -+ ITEM_NAMES.put(358, "minecraft:filled_map"); -+ ITEM_NAMES.put(359, "minecraft:shears"); -+ ITEM_NAMES.put(360, "minecraft:melon"); -+ ITEM_NAMES.put(361, "minecraft:pumpkin_seeds"); -+ ITEM_NAMES.put(362, "minecraft:melon_seeds"); -+ ITEM_NAMES.put(363, "minecraft:beef"); -+ ITEM_NAMES.put(364, "minecraft:cooked_beef"); -+ ITEM_NAMES.put(365, "minecraft:chicken"); -+ ITEM_NAMES.put(366, "minecraft:cooked_chicken"); -+ ITEM_NAMES.put(367, "minecraft:rotten_flesh"); -+ ITEM_NAMES.put(368, "minecraft:ender_pearl"); -+ ITEM_NAMES.put(369, "minecraft:blaze_rod"); -+ ITEM_NAMES.put(370, "minecraft:ghast_tear"); -+ ITEM_NAMES.put(371, "minecraft:gold_nugget"); -+ ITEM_NAMES.put(372, "minecraft:nether_wart"); -+ ITEM_NAMES.put(373, "minecraft:potion"); -+ ITEM_NAMES.put(374, "minecraft:glass_bottle"); -+ ITEM_NAMES.put(375, "minecraft:spider_eye"); -+ ITEM_NAMES.put(376, "minecraft:fermented_spider_eye"); -+ ITEM_NAMES.put(377, "minecraft:blaze_powder"); -+ ITEM_NAMES.put(378, "minecraft:magma_cream"); -+ ITEM_NAMES.put(379, "minecraft:brewing_stand"); -+ ITEM_NAMES.put(380, "minecraft:cauldron"); -+ ITEM_NAMES.put(381, "minecraft:ender_eye"); -+ ITEM_NAMES.put(382, "minecraft:speckled_melon"); -+ ITEM_NAMES.put(383, "minecraft:spawn_egg"); -+ ITEM_NAMES.put(384, "minecraft:experience_bottle"); -+ ITEM_NAMES.put(385, "minecraft:fire_charge"); -+ ITEM_NAMES.put(386, "minecraft:writable_book"); -+ ITEM_NAMES.put(387, "minecraft:written_book"); -+ ITEM_NAMES.put(388, "minecraft:emerald"); -+ ITEM_NAMES.put(389, "minecraft:item_frame"); -+ ITEM_NAMES.put(390, "minecraft:flower_pot"); -+ ITEM_NAMES.put(391, "minecraft:carrot"); -+ ITEM_NAMES.put(392, "minecraft:potato"); -+ ITEM_NAMES.put(393, "minecraft:baked_potato"); -+ ITEM_NAMES.put(394, "minecraft:poisonous_potato"); -+ ITEM_NAMES.put(395, "minecraft:map"); -+ ITEM_NAMES.put(396, "minecraft:golden_carrot"); -+ ITEM_NAMES.put(397, "minecraft:skull"); -+ ITEM_NAMES.put(398, "minecraft:carrot_on_a_stick"); -+ ITEM_NAMES.put(399, "minecraft:nether_star"); -+ ITEM_NAMES.put(400, "minecraft:pumpkin_pie"); -+ ITEM_NAMES.put(401, "minecraft:fireworks"); -+ ITEM_NAMES.put(402, "minecraft:firework_charge"); -+ ITEM_NAMES.put(403, "minecraft:enchanted_book"); -+ ITEM_NAMES.put(404, "minecraft:comparator"); -+ ITEM_NAMES.put(405, "minecraft:netherbrick"); -+ ITEM_NAMES.put(406, "minecraft:quartz"); -+ ITEM_NAMES.put(407, "minecraft:tnt_minecart"); -+ ITEM_NAMES.put(408, "minecraft:hopper_minecart"); -+ ITEM_NAMES.put(417, "minecraft:iron_horse_armor"); -+ ITEM_NAMES.put(418, "minecraft:golden_horse_armor"); -+ ITEM_NAMES.put(419, "minecraft:diamond_horse_armor"); -+ ITEM_NAMES.put(420, "minecraft:lead"); -+ ITEM_NAMES.put(421, "minecraft:name_tag"); -+ ITEM_NAMES.put(422, "minecraft:command_block_minecart"); -+ ITEM_NAMES.put(2256, "minecraft:record_13"); -+ ITEM_NAMES.put(2257, "minecraft:record_cat"); -+ ITEM_NAMES.put(2258, "minecraft:record_blocks"); -+ ITEM_NAMES.put(2259, "minecraft:record_chirp"); -+ ITEM_NAMES.put(2260, "minecraft:record_far"); -+ ITEM_NAMES.put(2261, "minecraft:record_mall"); -+ ITEM_NAMES.put(2262, "minecraft:record_mellohi"); -+ ITEM_NAMES.put(2263, "minecraft:record_stal"); -+ ITEM_NAMES.put(2264, "minecraft:record_strad"); -+ ITEM_NAMES.put(2265, "minecraft:record_ward"); -+ ITEM_NAMES.put(2266, "minecraft:record_11"); -+ ITEM_NAMES.put(2267, "minecraft:record_wait"); -+ // https://github.com/starlis/empirecraft/commit/2da59d1901407fc0c135ef0458c0fe9b016570b3 -+ // It's likely that this is a result of old CB/Spigot behavior still writing ids into items as ints. -+ // These ids do not appear to be used by regular MC anyways, so I do not see the harm of porting it here. -+ // Extras can be added if needed -+ String[] extra = new String[4_000]; -+ // EMC start -+ extra[409] = "minecraft:prismarine_shard"; -+ extra[410] = "minecraft:prismarine_crystals"; -+ extra[411] = "minecraft:rabbit"; -+ extra[412] = "minecraft:cooked_rabbit"; -+ extra[413] = "minecraft:rabbit_stew"; -+ extra[414] = "minecraft:rabbit_foot"; -+ extra[415] = "minecraft:rabbit_hide"; -+ extra[416] = "minecraft:armor_stand"; -+ extra[423] = "minecraft:mutton"; -+ extra[424] = "minecraft:cooked_mutton"; -+ extra[425] = "minecraft:banner"; -+ extra[426] = "minecraft:end_crystal"; -+ extra[427] = "minecraft:spruce_door"; -+ extra[428] = "minecraft:birch_door"; -+ extra[429] = "minecraft:jungle_door"; -+ extra[430] = "minecraft:acacia_door"; -+ extra[431] = "minecraft:dark_oak_door"; -+ extra[432] = "minecraft:chorus_fruit"; -+ extra[433] = "minecraft:chorus_fruit_popped"; -+ extra[434] = "minecraft:beetroot"; -+ extra[435] = "minecraft:beetroot_seeds"; -+ extra[436] = "minecraft:beetroot_soup"; -+ extra[437] = "minecraft:dragon_breath"; -+ extra[438] = "minecraft:splash_potion"; -+ extra[439] = "minecraft:spectral_arrow"; -+ extra[440] = "minecraft:tipped_arrow"; -+ extra[441] = "minecraft:lingering_potion"; -+ extra[442] = "minecraft:shield"; -+ extra[443] = "minecraft:elytra"; -+ extra[444] = "minecraft:spruce_boat"; -+ extra[445] = "minecraft:birch_boat"; -+ extra[446] = "minecraft:jungle_boat"; -+ extra[447] = "minecraft:acacia_boat"; -+ extra[448] = "minecraft:dark_oak_boat"; -+ extra[449] = "minecraft:totem_of_undying"; -+ extra[450] = "minecraft:shulker_shell"; -+ extra[452] = "minecraft:iron_nugget"; -+ extra[453] = "minecraft:knowledge_book"; -+ // EMC end -+ -+ // dump extra into map -+ for (int i = 0; i < extra.length; ++i) { -+ if (extra[i] != null) { -+ ITEM_NAMES.put(i, extra[i]); -+ } -+ } -+ } -+ -+ private static final String[] POTION_NAMES = new String[128]; -+ static { -+ POTION_NAMES[0] = "minecraft:water"; -+ POTION_NAMES[1] = "minecraft:regeneration"; -+ POTION_NAMES[2] = "minecraft:swiftness"; -+ POTION_NAMES[3] = "minecraft:fire_resistance"; -+ POTION_NAMES[4] = "minecraft:poison"; -+ POTION_NAMES[5] = "minecraft:healing"; -+ POTION_NAMES[6] = "minecraft:night_vision"; -+ POTION_NAMES[7] = null; -+ POTION_NAMES[8] = "minecraft:weakness"; -+ POTION_NAMES[9] = "minecraft:strength"; -+ POTION_NAMES[10] = "minecraft:slowness"; -+ POTION_NAMES[11] = "minecraft:leaping"; -+ POTION_NAMES[12] = "minecraft:harming"; -+ POTION_NAMES[13] = "minecraft:water_breathing"; -+ POTION_NAMES[14] = "minecraft:invisibility"; -+ POTION_NAMES[15] = null; -+ POTION_NAMES[16] = "minecraft:awkward"; -+ POTION_NAMES[17] = "minecraft:regeneration"; -+ POTION_NAMES[18] = "minecraft:swiftness"; -+ POTION_NAMES[19] = "minecraft:fire_resistance"; -+ POTION_NAMES[20] = "minecraft:poison"; -+ POTION_NAMES[21] = "minecraft:healing"; -+ POTION_NAMES[22] = "minecraft:night_vision"; -+ POTION_NAMES[23] = null; -+ POTION_NAMES[24] = "minecraft:weakness"; -+ POTION_NAMES[25] = "minecraft:strength"; -+ POTION_NAMES[26] = "minecraft:slowness"; -+ POTION_NAMES[27] = "minecraft:leaping"; -+ POTION_NAMES[28] = "minecraft:harming"; -+ POTION_NAMES[29] = "minecraft:water_breathing"; -+ POTION_NAMES[30] = "minecraft:invisibility"; -+ POTION_NAMES[31] = null; -+ POTION_NAMES[32] = "minecraft:thick"; -+ POTION_NAMES[33] = "minecraft:strong_regeneration"; -+ POTION_NAMES[34] = "minecraft:strong_swiftness"; -+ POTION_NAMES[35] = "minecraft:fire_resistance"; -+ POTION_NAMES[36] = "minecraft:strong_poison"; -+ POTION_NAMES[37] = "minecraft:strong_healing"; -+ POTION_NAMES[38] = "minecraft:night_vision"; -+ POTION_NAMES[39] = null; -+ POTION_NAMES[40] = "minecraft:weakness"; -+ POTION_NAMES[41] = "minecraft:strong_strength"; -+ POTION_NAMES[42] = "minecraft:slowness"; -+ POTION_NAMES[43] = "minecraft:strong_leaping"; -+ POTION_NAMES[44] = "minecraft:strong_harming"; -+ POTION_NAMES[45] = "minecraft:water_breathing"; -+ POTION_NAMES[46] = "minecraft:invisibility"; -+ POTION_NAMES[47] = null; -+ POTION_NAMES[48] = null; -+ POTION_NAMES[49] = "minecraft:strong_regeneration"; -+ POTION_NAMES[50] = "minecraft:strong_swiftness"; -+ POTION_NAMES[51] = "minecraft:fire_resistance"; -+ POTION_NAMES[52] = "minecraft:strong_poison"; -+ POTION_NAMES[53] = "minecraft:strong_healing"; -+ POTION_NAMES[54] = "minecraft:night_vision"; -+ POTION_NAMES[55] = null; -+ POTION_NAMES[56] = "minecraft:weakness"; -+ POTION_NAMES[57] = "minecraft:strong_strength"; -+ POTION_NAMES[58] = "minecraft:slowness"; -+ POTION_NAMES[59] = "minecraft:strong_leaping"; -+ POTION_NAMES[60] = "minecraft:strong_harming"; -+ POTION_NAMES[61] = "minecraft:water_breathing"; -+ POTION_NAMES[62] = "minecraft:invisibility"; -+ POTION_NAMES[63] = null; -+ POTION_NAMES[64] = "minecraft:mundane"; -+ POTION_NAMES[65] = "minecraft:long_regeneration"; -+ POTION_NAMES[66] = "minecraft:long_swiftness"; -+ POTION_NAMES[67] = "minecraft:long_fire_resistance"; -+ POTION_NAMES[68] = "minecraft:long_poison"; -+ POTION_NAMES[69] = "minecraft:healing"; -+ POTION_NAMES[70] = "minecraft:long_night_vision"; -+ POTION_NAMES[71] = null; -+ POTION_NAMES[72] = "minecraft:long_weakness"; -+ POTION_NAMES[73] = "minecraft:long_strength"; -+ POTION_NAMES[74] = "minecraft:long_slowness"; -+ POTION_NAMES[75] = "minecraft:long_leaping"; -+ POTION_NAMES[76] = "minecraft:harming"; -+ POTION_NAMES[77] = "minecraft:long_water_breathing"; -+ POTION_NAMES[78] = "minecraft:long_invisibility"; -+ POTION_NAMES[79] = null; -+ POTION_NAMES[80] = "minecraft:awkward"; -+ POTION_NAMES[81] = "minecraft:long_regeneration"; -+ POTION_NAMES[82] = "minecraft:long_swiftness"; -+ POTION_NAMES[83] = "minecraft:long_fire_resistance"; -+ POTION_NAMES[84] = "minecraft:long_poison"; -+ POTION_NAMES[85] = "minecraft:healing"; -+ POTION_NAMES[86] = "minecraft:long_night_vision"; -+ POTION_NAMES[87] = null; -+ POTION_NAMES[88] = "minecraft:long_weakness"; -+ POTION_NAMES[89] = "minecraft:long_strength"; -+ POTION_NAMES[90] = "minecraft:long_slowness"; -+ POTION_NAMES[91] = "minecraft:long_leaping"; -+ POTION_NAMES[92] = "minecraft:harming"; -+ POTION_NAMES[93] = "minecraft:long_water_breathing"; -+ POTION_NAMES[94] = "minecraft:long_invisibility"; -+ POTION_NAMES[95] = null; -+ POTION_NAMES[96] = "minecraft:thick"; -+ POTION_NAMES[97] = "minecraft:regeneration"; -+ POTION_NAMES[98] = "minecraft:swiftness"; -+ POTION_NAMES[99] = "minecraft:long_fire_resistance"; -+ POTION_NAMES[100] = "minecraft:poison"; -+ POTION_NAMES[101] = "minecraft:strong_healing"; -+ POTION_NAMES[102] = "minecraft:long_night_vision"; -+ POTION_NAMES[103] = null; -+ POTION_NAMES[104] = "minecraft:long_weakness"; -+ POTION_NAMES[105] = "minecraft:strength"; -+ POTION_NAMES[106] = "minecraft:long_slowness"; -+ POTION_NAMES[107] = "minecraft:leaping"; -+ POTION_NAMES[108] = "minecraft:strong_harming"; -+ POTION_NAMES[109] = "minecraft:long_water_breathing"; -+ POTION_NAMES[110] = "minecraft:long_invisibility"; -+ POTION_NAMES[111] = null; -+ POTION_NAMES[112] = null; -+ POTION_NAMES[113] = "minecraft:regeneration"; -+ POTION_NAMES[114] = "minecraft:swiftness"; -+ POTION_NAMES[115] = "minecraft:long_fire_resistance"; -+ POTION_NAMES[116] = "minecraft:poison"; -+ POTION_NAMES[117] = "minecraft:strong_healing"; -+ POTION_NAMES[118] = "minecraft:long_night_vision"; -+ POTION_NAMES[119] = null; -+ POTION_NAMES[120] = "minecraft:long_weakness"; -+ POTION_NAMES[121] = "minecraft:strength"; -+ POTION_NAMES[122] = "minecraft:long_slowness"; -+ POTION_NAMES[123] = "minecraft:leaping"; -+ POTION_NAMES[124] = "minecraft:strong_harming"; -+ POTION_NAMES[125] = "minecraft:long_water_breathing"; -+ POTION_NAMES[126] = "minecraft:long_invisibility"; -+ POTION_NAMES[127] = null; -+ } -+ -+ // ret is nullable, you are supposed to log when it does not exist, NOT HIDE IT! -+ public static String getNameFromId(final int id) { -+ return ITEM_NAMES.get(id); -+ } -+ -+ public static String getPotionNameFromId(final short id) { -+ return POTION_NAMES[id & 127]; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperSpawnEggNameV105.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperSpawnEggNameV105.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5008c6d28b7f9b730bfaf257a264edcb45c78487 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/HelperSpawnEggNameV105.java -@@ -0,0 +1,79 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.helpers; -+ -+public final class HelperSpawnEggNameV105 { -+ -+ private static final String[] ID_TO_STRING = new String[256]; -+ static { -+ ID_TO_STRING[1] = "Item"; -+ ID_TO_STRING[2] = "XPOrb"; -+ ID_TO_STRING[7] = "ThrownEgg"; -+ ID_TO_STRING[8] = "LeashKnot"; -+ ID_TO_STRING[9] = "Painting"; -+ ID_TO_STRING[10] = "Arrow"; -+ ID_TO_STRING[11] = "Snowball"; -+ ID_TO_STRING[12] = "Fireball"; -+ ID_TO_STRING[13] = "SmallFireball"; -+ ID_TO_STRING[14] = "ThrownEnderpearl"; -+ ID_TO_STRING[15] = "EyeOfEnderSignal"; -+ ID_TO_STRING[16] = "ThrownPotion"; -+ ID_TO_STRING[17] = "ThrownExpBottle"; -+ ID_TO_STRING[18] = "ItemFrame"; -+ ID_TO_STRING[19] = "WitherSkull"; -+ ID_TO_STRING[20] = "PrimedTnt"; -+ ID_TO_STRING[21] = "FallingSand"; -+ ID_TO_STRING[22] = "FireworksRocketEntity"; -+ ID_TO_STRING[23] = "TippedArrow"; -+ ID_TO_STRING[24] = "SpectralArrow"; -+ ID_TO_STRING[25] = "ShulkerBullet"; -+ ID_TO_STRING[26] = "DragonFireball"; -+ ID_TO_STRING[30] = "ArmorStand"; -+ ID_TO_STRING[41] = "Boat"; -+ ID_TO_STRING[42] = "MinecartRideable"; -+ ID_TO_STRING[43] = "MinecartChest"; -+ ID_TO_STRING[44] = "MinecartFurnace"; -+ ID_TO_STRING[45] = "MinecartTNT"; -+ ID_TO_STRING[46] = "MinecartHopper"; -+ ID_TO_STRING[47] = "MinecartSpawner"; -+ ID_TO_STRING[40] = "MinecartCommandBlock"; -+ ID_TO_STRING[48] = "Mob"; -+ ID_TO_STRING[49] = "Monster"; -+ ID_TO_STRING[50] = "Creeper"; -+ ID_TO_STRING[51] = "Skeleton"; -+ ID_TO_STRING[52] = "Spider"; -+ ID_TO_STRING[53] = "Giant"; -+ ID_TO_STRING[54] = "Zombie"; -+ ID_TO_STRING[55] = "Slime"; -+ ID_TO_STRING[56] = "Ghast"; -+ ID_TO_STRING[57] = "PigZombie"; -+ ID_TO_STRING[58] = "Enderman"; -+ ID_TO_STRING[59] = "CaveSpider"; -+ ID_TO_STRING[60] = "Silverfish"; -+ ID_TO_STRING[61] = "Blaze"; -+ ID_TO_STRING[62] = "LavaSlime"; -+ ID_TO_STRING[63] = "EnderDragon"; -+ ID_TO_STRING[64] = "WitherBoss"; -+ ID_TO_STRING[65] = "Bat"; -+ ID_TO_STRING[66] = "Witch"; -+ ID_TO_STRING[67] = "Endermite"; -+ ID_TO_STRING[68] = "Guardian"; -+ ID_TO_STRING[69] = "Shulker"; -+ ID_TO_STRING[90] = "Pig"; -+ ID_TO_STRING[91] = "Sheep"; -+ ID_TO_STRING[92] = "Cow"; -+ ID_TO_STRING[93] = "Chicken"; -+ ID_TO_STRING[94] = "Squid"; -+ ID_TO_STRING[95] = "Wolf"; -+ ID_TO_STRING[96] = "MushroomCow"; -+ ID_TO_STRING[97] = "SnowMan"; -+ ID_TO_STRING[98] = "Ozelot"; -+ ID_TO_STRING[99] = "VillagerGolem"; -+ ID_TO_STRING[100] = "EntityHorse"; -+ ID_TO_STRING[101] = "Rabbit"; -+ ID_TO_STRING[120] = "Villager"; -+ ID_TO_STRING[200] = "EnderCrystal"; -+ } -+ -+ public static String getSpawnNameFromId(final short id) { -+ return ID_TO_STRING[id & 255]; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemname/ConverterAbstractItemRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemname/ConverterAbstractItemRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..94569f0ccff0d3a09eafd4ba73572d9db0a0ac5b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemname/ConverterAbstractItemRename.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.itemname; -+ -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import java.util.function.Function; -+ -+public final class ConverterAbstractItemRename { -+ -+ private ConverterAbstractItemRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ ConverterAbstractStringValueTypeRename.register(version, subVersion, MCTypeRegistry.ITEM_NAME, renamer); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterFlattenItemStack.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterFlattenItemStack.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6767354bb1ac4f4a996b8b4a17e03014b27e98ca ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterFlattenItemStack.java -@@ -0,0 +1,459 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.itemstack; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+ -+import java.util.Arrays; -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.Map; -+import java.util.Set; -+ -+public final class ConverterFlattenItemStack extends DataConverter, MapType> { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ // Map of "id.damage" -> "flattened id" -+ private static final Map FLATTEN_MAP = new HashMap<>(); -+ static { -+ FLATTEN_MAP.put("minecraft:stone.0", "minecraft:stone"); -+ FLATTEN_MAP.put("minecraft:stone.1", "minecraft:granite"); -+ FLATTEN_MAP.put("minecraft:stone.2", "minecraft:polished_granite"); -+ FLATTEN_MAP.put("minecraft:stone.3", "minecraft:diorite"); -+ FLATTEN_MAP.put("minecraft:stone.4", "minecraft:polished_diorite"); -+ FLATTEN_MAP.put("minecraft:stone.5", "minecraft:andesite"); -+ FLATTEN_MAP.put("minecraft:stone.6", "minecraft:polished_andesite"); -+ FLATTEN_MAP.put("minecraft:dirt.0", "minecraft:dirt"); -+ FLATTEN_MAP.put("minecraft:dirt.1", "minecraft:coarse_dirt"); -+ FLATTEN_MAP.put("minecraft:dirt.2", "minecraft:podzol"); -+ FLATTEN_MAP.put("minecraft:leaves.0", "minecraft:oak_leaves"); -+ FLATTEN_MAP.put("minecraft:leaves.1", "minecraft:spruce_leaves"); -+ FLATTEN_MAP.put("minecraft:leaves.2", "minecraft:birch_leaves"); -+ FLATTEN_MAP.put("minecraft:leaves.3", "minecraft:jungle_leaves"); -+ FLATTEN_MAP.put("minecraft:leaves2.0", "minecraft:acacia_leaves"); -+ FLATTEN_MAP.put("minecraft:leaves2.1", "minecraft:dark_oak_leaves"); -+ FLATTEN_MAP.put("minecraft:log.0", "minecraft:oak_log"); -+ FLATTEN_MAP.put("minecraft:log.1", "minecraft:spruce_log"); -+ FLATTEN_MAP.put("minecraft:log.2", "minecraft:birch_log"); -+ FLATTEN_MAP.put("minecraft:log.3", "minecraft:jungle_log"); -+ FLATTEN_MAP.put("minecraft:log2.0", "minecraft:acacia_log"); -+ FLATTEN_MAP.put("minecraft:log2.1", "minecraft:dark_oak_log"); -+ FLATTEN_MAP.put("minecraft:sapling.0", "minecraft:oak_sapling"); -+ FLATTEN_MAP.put("minecraft:sapling.1", "minecraft:spruce_sapling"); -+ FLATTEN_MAP.put("minecraft:sapling.2", "minecraft:birch_sapling"); -+ FLATTEN_MAP.put("minecraft:sapling.3", "minecraft:jungle_sapling"); -+ FLATTEN_MAP.put("minecraft:sapling.4", "minecraft:acacia_sapling"); -+ FLATTEN_MAP.put("minecraft:sapling.5", "minecraft:dark_oak_sapling"); -+ FLATTEN_MAP.put("minecraft:planks.0", "minecraft:oak_planks"); -+ FLATTEN_MAP.put("minecraft:planks.1", "minecraft:spruce_planks"); -+ FLATTEN_MAP.put("minecraft:planks.2", "minecraft:birch_planks"); -+ FLATTEN_MAP.put("minecraft:planks.3", "minecraft:jungle_planks"); -+ FLATTEN_MAP.put("minecraft:planks.4", "minecraft:acacia_planks"); -+ FLATTEN_MAP.put("minecraft:planks.5", "minecraft:dark_oak_planks"); -+ FLATTEN_MAP.put("minecraft:sand.0", "minecraft:sand"); -+ FLATTEN_MAP.put("minecraft:sand.1", "minecraft:red_sand"); -+ FLATTEN_MAP.put("minecraft:quartz_block.0", "minecraft:quartz_block"); -+ FLATTEN_MAP.put("minecraft:quartz_block.1", "minecraft:chiseled_quartz_block"); -+ FLATTEN_MAP.put("minecraft:quartz_block.2", "minecraft:quartz_pillar"); -+ FLATTEN_MAP.put("minecraft:anvil.0", "minecraft:anvil"); -+ FLATTEN_MAP.put("minecraft:anvil.1", "minecraft:chipped_anvil"); -+ FLATTEN_MAP.put("minecraft:anvil.2", "minecraft:damaged_anvil"); -+ FLATTEN_MAP.put("minecraft:wool.0", "minecraft:white_wool"); -+ FLATTEN_MAP.put("minecraft:wool.1", "minecraft:orange_wool"); -+ FLATTEN_MAP.put("minecraft:wool.2", "minecraft:magenta_wool"); -+ FLATTEN_MAP.put("minecraft:wool.3", "minecraft:light_blue_wool"); -+ FLATTEN_MAP.put("minecraft:wool.4", "minecraft:yellow_wool"); -+ FLATTEN_MAP.put("minecraft:wool.5", "minecraft:lime_wool"); -+ FLATTEN_MAP.put("minecraft:wool.6", "minecraft:pink_wool"); -+ FLATTEN_MAP.put("minecraft:wool.7", "minecraft:gray_wool"); -+ FLATTEN_MAP.put("minecraft:wool.8", "minecraft:light_gray_wool"); -+ FLATTEN_MAP.put("minecraft:wool.9", "minecraft:cyan_wool"); -+ FLATTEN_MAP.put("minecraft:wool.10", "minecraft:purple_wool"); -+ FLATTEN_MAP.put("minecraft:wool.11", "minecraft:blue_wool"); -+ FLATTEN_MAP.put("minecraft:wool.12", "minecraft:brown_wool"); -+ FLATTEN_MAP.put("minecraft:wool.13", "minecraft:green_wool"); -+ FLATTEN_MAP.put("minecraft:wool.14", "minecraft:red_wool"); -+ FLATTEN_MAP.put("minecraft:wool.15", "minecraft:black_wool"); -+ FLATTEN_MAP.put("minecraft:carpet.0", "minecraft:white_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.1", "minecraft:orange_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.2", "minecraft:magenta_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.3", "minecraft:light_blue_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.4", "minecraft:yellow_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.5", "minecraft:lime_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.6", "minecraft:pink_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.7", "minecraft:gray_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.8", "minecraft:light_gray_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.9", "minecraft:cyan_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.10", "minecraft:purple_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.11", "minecraft:blue_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.12", "minecraft:brown_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.13", "minecraft:green_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.14", "minecraft:red_carpet"); -+ FLATTEN_MAP.put("minecraft:carpet.15", "minecraft:black_carpet"); -+ FLATTEN_MAP.put("minecraft:hardened_clay.0", "minecraft:terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.0", "minecraft:white_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.1", "minecraft:orange_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.2", "minecraft:magenta_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.3", "minecraft:light_blue_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.4", "minecraft:yellow_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.5", "minecraft:lime_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.6", "minecraft:pink_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.7", "minecraft:gray_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.8", "minecraft:light_gray_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.9", "minecraft:cyan_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.10", "minecraft:purple_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.11", "minecraft:blue_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.12", "minecraft:brown_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.13", "minecraft:green_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.14", "minecraft:red_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_hardened_clay.15", "minecraft:black_terracotta"); -+ FLATTEN_MAP.put("minecraft:silver_glazed_terracotta.0", "minecraft:light_gray_glazed_terracotta"); -+ FLATTEN_MAP.put("minecraft:stained_glass.0", "minecraft:white_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.1", "minecraft:orange_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.2", "minecraft:magenta_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.3", "minecraft:light_blue_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.4", "minecraft:yellow_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.5", "minecraft:lime_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.6", "minecraft:pink_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.7", "minecraft:gray_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.8", "minecraft:light_gray_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.9", "minecraft:cyan_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.10", "minecraft:purple_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.11", "minecraft:blue_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.12", "minecraft:brown_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.13", "minecraft:green_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.14", "minecraft:red_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass.15", "minecraft:black_stained_glass"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.0", "minecraft:white_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.1", "minecraft:orange_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.2", "minecraft:magenta_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.3", "minecraft:light_blue_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.4", "minecraft:yellow_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.5", "minecraft:lime_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.6", "minecraft:pink_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.7", "minecraft:gray_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.8", "minecraft:light_gray_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.9", "minecraft:cyan_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.10", "minecraft:purple_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.11", "minecraft:blue_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.12", "minecraft:brown_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.13", "minecraft:green_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.14", "minecraft:red_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:stained_glass_pane.15", "minecraft:black_stained_glass_pane"); -+ FLATTEN_MAP.put("minecraft:prismarine.0", "minecraft:prismarine"); -+ FLATTEN_MAP.put("minecraft:prismarine.1", "minecraft:prismarine_bricks"); -+ FLATTEN_MAP.put("minecraft:prismarine.2", "minecraft:dark_prismarine"); -+ FLATTEN_MAP.put("minecraft:concrete.0", "minecraft:white_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.1", "minecraft:orange_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.2", "minecraft:magenta_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.3", "minecraft:light_blue_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.4", "minecraft:yellow_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.5", "minecraft:lime_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.6", "minecraft:pink_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.7", "minecraft:gray_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.8", "minecraft:light_gray_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.9", "minecraft:cyan_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.10", "minecraft:purple_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.11", "minecraft:blue_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.12", "minecraft:brown_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.13", "minecraft:green_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.14", "minecraft:red_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete.15", "minecraft:black_concrete"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.0", "minecraft:white_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.1", "minecraft:orange_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.2", "minecraft:magenta_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.3", "minecraft:light_blue_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.4", "minecraft:yellow_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.5", "minecraft:lime_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.6", "minecraft:pink_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.7", "minecraft:gray_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.8", "minecraft:light_gray_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.9", "minecraft:cyan_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.10", "minecraft:purple_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.11", "minecraft:blue_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.12", "minecraft:brown_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.13", "minecraft:green_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.14", "minecraft:red_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:concrete_powder.15", "minecraft:black_concrete_powder"); -+ FLATTEN_MAP.put("minecraft:cobblestone_wall.0", "minecraft:cobblestone_wall"); -+ FLATTEN_MAP.put("minecraft:cobblestone_wall.1", "minecraft:mossy_cobblestone_wall"); -+ FLATTEN_MAP.put("minecraft:sandstone.0", "minecraft:sandstone"); -+ FLATTEN_MAP.put("minecraft:sandstone.1", "minecraft:chiseled_sandstone"); -+ FLATTEN_MAP.put("minecraft:sandstone.2", "minecraft:cut_sandstone"); -+ FLATTEN_MAP.put("minecraft:red_sandstone.0", "minecraft:red_sandstone"); -+ FLATTEN_MAP.put("minecraft:red_sandstone.1", "minecraft:chiseled_red_sandstone"); -+ FLATTEN_MAP.put("minecraft:red_sandstone.2", "minecraft:cut_red_sandstone"); -+ FLATTEN_MAP.put("minecraft:stonebrick.0", "minecraft:stone_bricks"); -+ FLATTEN_MAP.put("minecraft:stonebrick.1", "minecraft:mossy_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:stonebrick.2", "minecraft:cracked_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:stonebrick.3", "minecraft:chiseled_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:monster_egg.0", "minecraft:infested_stone"); -+ FLATTEN_MAP.put("minecraft:monster_egg.1", "minecraft:infested_cobblestone"); -+ FLATTEN_MAP.put("minecraft:monster_egg.2", "minecraft:infested_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:monster_egg.3", "minecraft:infested_mossy_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:monster_egg.4", "minecraft:infested_cracked_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:monster_egg.5", "minecraft:infested_chiseled_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:yellow_flower.0", "minecraft:dandelion"); -+ FLATTEN_MAP.put("minecraft:red_flower.0", "minecraft:poppy"); -+ FLATTEN_MAP.put("minecraft:red_flower.1", "minecraft:blue_orchid"); -+ FLATTEN_MAP.put("minecraft:red_flower.2", "minecraft:allium"); -+ FLATTEN_MAP.put("minecraft:red_flower.3", "minecraft:azure_bluet"); -+ FLATTEN_MAP.put("minecraft:red_flower.4", "minecraft:red_tulip"); -+ FLATTEN_MAP.put("minecraft:red_flower.5", "minecraft:orange_tulip"); -+ FLATTEN_MAP.put("minecraft:red_flower.6", "minecraft:white_tulip"); -+ FLATTEN_MAP.put("minecraft:red_flower.7", "minecraft:pink_tulip"); -+ FLATTEN_MAP.put("minecraft:red_flower.8", "minecraft:oxeye_daisy"); -+ FLATTEN_MAP.put("minecraft:double_plant.0", "minecraft:sunflower"); -+ FLATTEN_MAP.put("minecraft:double_plant.1", "minecraft:lilac"); -+ FLATTEN_MAP.put("minecraft:double_plant.2", "minecraft:tall_grass"); -+ FLATTEN_MAP.put("minecraft:double_plant.3", "minecraft:large_fern"); -+ FLATTEN_MAP.put("minecraft:double_plant.4", "minecraft:rose_bush"); -+ FLATTEN_MAP.put("minecraft:double_plant.5", "minecraft:peony"); -+ FLATTEN_MAP.put("minecraft:deadbush.0", "minecraft:dead_bush"); -+ FLATTEN_MAP.put("minecraft:tallgrass.0", "minecraft:dead_bush"); -+ FLATTEN_MAP.put("minecraft:tallgrass.1", "minecraft:grass"); -+ FLATTEN_MAP.put("minecraft:tallgrass.2", "minecraft:fern"); -+ FLATTEN_MAP.put("minecraft:sponge.0", "minecraft:sponge"); -+ FLATTEN_MAP.put("minecraft:sponge.1", "minecraft:wet_sponge"); -+ FLATTEN_MAP.put("minecraft:purpur_slab.0", "minecraft:purpur_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.0", "minecraft:stone_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.1", "minecraft:sandstone_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.2", "minecraft:petrified_oak_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.3", "minecraft:cobblestone_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.4", "minecraft:brick_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.5", "minecraft:stone_brick_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.6", "minecraft:nether_brick_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab.7", "minecraft:quartz_slab"); -+ FLATTEN_MAP.put("minecraft:stone_slab2.0", "minecraft:red_sandstone_slab"); -+ FLATTEN_MAP.put("minecraft:wooden_slab.0", "minecraft:oak_slab"); -+ FLATTEN_MAP.put("minecraft:wooden_slab.1", "minecraft:spruce_slab"); -+ FLATTEN_MAP.put("minecraft:wooden_slab.2", "minecraft:birch_slab"); -+ FLATTEN_MAP.put("minecraft:wooden_slab.3", "minecraft:jungle_slab"); -+ FLATTEN_MAP.put("minecraft:wooden_slab.4", "minecraft:acacia_slab"); -+ FLATTEN_MAP.put("minecraft:wooden_slab.5", "minecraft:dark_oak_slab"); -+ FLATTEN_MAP.put("minecraft:coal.0", "minecraft:coal"); -+ FLATTEN_MAP.put("minecraft:coal.1", "minecraft:charcoal"); -+ FLATTEN_MAP.put("minecraft:fish.0", "minecraft:cod"); -+ FLATTEN_MAP.put("minecraft:fish.1", "minecraft:salmon"); -+ FLATTEN_MAP.put("minecraft:fish.2", "minecraft:clownfish"); -+ FLATTEN_MAP.put("minecraft:fish.3", "minecraft:pufferfish"); -+ FLATTEN_MAP.put("minecraft:cooked_fish.0", "minecraft:cooked_cod"); -+ FLATTEN_MAP.put("minecraft:cooked_fish.1", "minecraft:cooked_salmon"); -+ FLATTEN_MAP.put("minecraft:skull.0", "minecraft:skeleton_skull"); -+ FLATTEN_MAP.put("minecraft:skull.1", "minecraft:wither_skeleton_skull"); -+ FLATTEN_MAP.put("minecraft:skull.2", "minecraft:zombie_head"); -+ FLATTEN_MAP.put("minecraft:skull.3", "minecraft:player_head"); -+ FLATTEN_MAP.put("minecraft:skull.4", "minecraft:creeper_head"); -+ FLATTEN_MAP.put("minecraft:skull.5", "minecraft:dragon_head"); -+ FLATTEN_MAP.put("minecraft:golden_apple.0", "minecraft:golden_apple"); -+ FLATTEN_MAP.put("minecraft:golden_apple.1", "minecraft:enchanted_golden_apple"); -+ FLATTEN_MAP.put("minecraft:fireworks.0", "minecraft:firework_rocket"); -+ FLATTEN_MAP.put("minecraft:firework_charge.0", "minecraft:firework_star"); -+ FLATTEN_MAP.put("minecraft:dye.0", "minecraft:ink_sac"); -+ FLATTEN_MAP.put("minecraft:dye.1", "minecraft:rose_red"); -+ FLATTEN_MAP.put("minecraft:dye.2", "minecraft:cactus_green"); -+ FLATTEN_MAP.put("minecraft:dye.3", "minecraft:cocoa_beans"); -+ FLATTEN_MAP.put("minecraft:dye.4", "minecraft:lapis_lazuli"); -+ FLATTEN_MAP.put("minecraft:dye.5", "minecraft:purple_dye"); -+ FLATTEN_MAP.put("minecraft:dye.6", "minecraft:cyan_dye"); -+ FLATTEN_MAP.put("minecraft:dye.7", "minecraft:light_gray_dye"); -+ FLATTEN_MAP.put("minecraft:dye.8", "minecraft:gray_dye"); -+ FLATTEN_MAP.put("minecraft:dye.9", "minecraft:pink_dye"); -+ FLATTEN_MAP.put("minecraft:dye.10", "minecraft:lime_dye"); -+ FLATTEN_MAP.put("minecraft:dye.11", "minecraft:dandelion_yellow"); -+ FLATTEN_MAP.put("minecraft:dye.12", "minecraft:light_blue_dye"); -+ FLATTEN_MAP.put("minecraft:dye.13", "minecraft:magenta_dye"); -+ FLATTEN_MAP.put("minecraft:dye.14", "minecraft:orange_dye"); -+ FLATTEN_MAP.put("minecraft:dye.15", "minecraft:bone_meal"); -+ FLATTEN_MAP.put("minecraft:silver_shulker_box.0", "minecraft:light_gray_shulker_box"); -+ FLATTEN_MAP.put("minecraft:fence.0", "minecraft:oak_fence"); -+ FLATTEN_MAP.put("minecraft:fence_gate.0", "minecraft:oak_fence_gate"); -+ FLATTEN_MAP.put("minecraft:wooden_door.0", "minecraft:oak_door"); -+ FLATTEN_MAP.put("minecraft:boat.0", "minecraft:oak_boat"); -+ FLATTEN_MAP.put("minecraft:lit_pumpkin.0", "minecraft:jack_o_lantern"); -+ FLATTEN_MAP.put("minecraft:pumpkin.0", "minecraft:carved_pumpkin"); -+ FLATTEN_MAP.put("minecraft:trapdoor.0", "minecraft:oak_trapdoor"); -+ FLATTEN_MAP.put("minecraft:nether_brick.0", "minecraft:nether_bricks"); -+ FLATTEN_MAP.put("minecraft:red_nether_brick.0", "minecraft:red_nether_bricks"); -+ FLATTEN_MAP.put("minecraft:netherbrick.0", "minecraft:nether_brick"); -+ FLATTEN_MAP.put("minecraft:wooden_button.0", "minecraft:oak_button"); -+ FLATTEN_MAP.put("minecraft:wooden_pressure_plate.0", "minecraft:oak_pressure_plate"); -+ FLATTEN_MAP.put("minecraft:noteblock.0", "minecraft:note_block"); -+ FLATTEN_MAP.put("minecraft:bed.0", "minecraft:white_bed"); -+ FLATTEN_MAP.put("minecraft:bed.1", "minecraft:orange_bed"); -+ FLATTEN_MAP.put("minecraft:bed.2", "minecraft:magenta_bed"); -+ FLATTEN_MAP.put("minecraft:bed.3", "minecraft:light_blue_bed"); -+ FLATTEN_MAP.put("minecraft:bed.4", "minecraft:yellow_bed"); -+ FLATTEN_MAP.put("minecraft:bed.5", "minecraft:lime_bed"); -+ FLATTEN_MAP.put("minecraft:bed.6", "minecraft:pink_bed"); -+ FLATTEN_MAP.put("minecraft:bed.7", "minecraft:gray_bed"); -+ FLATTEN_MAP.put("minecraft:bed.8", "minecraft:light_gray_bed"); -+ FLATTEN_MAP.put("minecraft:bed.9", "minecraft:cyan_bed"); -+ FLATTEN_MAP.put("minecraft:bed.10", "minecraft:purple_bed"); -+ FLATTEN_MAP.put("minecraft:bed.11", "minecraft:blue_bed"); -+ FLATTEN_MAP.put("minecraft:bed.12", "minecraft:brown_bed"); -+ FLATTEN_MAP.put("minecraft:bed.13", "minecraft:green_bed"); -+ FLATTEN_MAP.put("minecraft:bed.14", "minecraft:red_bed"); -+ FLATTEN_MAP.put("minecraft:bed.15", "minecraft:black_bed"); -+ FLATTEN_MAP.put("minecraft:banner.15", "minecraft:white_banner"); -+ FLATTEN_MAP.put("minecraft:banner.14", "minecraft:orange_banner"); -+ FLATTEN_MAP.put("minecraft:banner.13", "minecraft:magenta_banner"); -+ FLATTEN_MAP.put("minecraft:banner.12", "minecraft:light_blue_banner"); -+ FLATTEN_MAP.put("minecraft:banner.11", "minecraft:yellow_banner"); -+ FLATTEN_MAP.put("minecraft:banner.10", "minecraft:lime_banner"); -+ FLATTEN_MAP.put("minecraft:banner.9", "minecraft:pink_banner"); -+ FLATTEN_MAP.put("minecraft:banner.8", "minecraft:gray_banner"); -+ FLATTEN_MAP.put("minecraft:banner.7", "minecraft:light_gray_banner"); -+ FLATTEN_MAP.put("minecraft:banner.6", "minecraft:cyan_banner"); -+ FLATTEN_MAP.put("minecraft:banner.5", "minecraft:purple_banner"); -+ FLATTEN_MAP.put("minecraft:banner.4", "minecraft:blue_banner"); -+ FLATTEN_MAP.put("minecraft:banner.3", "minecraft:brown_banner"); -+ FLATTEN_MAP.put("minecraft:banner.2", "minecraft:green_banner"); -+ FLATTEN_MAP.put("minecraft:banner.1", "minecraft:red_banner"); -+ FLATTEN_MAP.put("minecraft:banner.0", "minecraft:black_banner"); -+ FLATTEN_MAP.put("minecraft:grass.0", "minecraft:grass_block"); -+ FLATTEN_MAP.put("minecraft:brick_block.0", "minecraft:bricks"); -+ FLATTEN_MAP.put("minecraft:end_bricks.0", "minecraft:end_stone_bricks"); -+ FLATTEN_MAP.put("minecraft:golden_rail.0", "minecraft:powered_rail"); -+ FLATTEN_MAP.put("minecraft:magma.0", "minecraft:magma_block"); -+ FLATTEN_MAP.put("minecraft:quartz_ore.0", "minecraft:nether_quartz_ore"); -+ FLATTEN_MAP.put("minecraft:reeds.0", "minecraft:sugar_cane"); -+ FLATTEN_MAP.put("minecraft:slime.0", "minecraft:slime_block"); -+ FLATTEN_MAP.put("minecraft:stone_stairs.0", "minecraft:cobblestone_stairs"); -+ FLATTEN_MAP.put("minecraft:waterlily.0", "minecraft:lily_pad"); -+ FLATTEN_MAP.put("minecraft:web.0", "minecraft:cobweb"); -+ FLATTEN_MAP.put("minecraft:snow.0", "minecraft:snow_block"); -+ FLATTEN_MAP.put("minecraft:snow_layer.0", "minecraft:snow"); -+ FLATTEN_MAP.put("minecraft:record_11.0", "minecraft:music_disc_11"); -+ FLATTEN_MAP.put("minecraft:record_13.0", "minecraft:music_disc_13"); -+ FLATTEN_MAP.put("minecraft:record_blocks.0", "minecraft:music_disc_blocks"); -+ FLATTEN_MAP.put("minecraft:record_cat.0", "minecraft:music_disc_cat"); -+ FLATTEN_MAP.put("minecraft:record_chirp.0", "minecraft:music_disc_chirp"); -+ FLATTEN_MAP.put("minecraft:record_far.0", "minecraft:music_disc_far"); -+ FLATTEN_MAP.put("minecraft:record_mall.0", "minecraft:music_disc_mall"); -+ FLATTEN_MAP.put("minecraft:record_mellohi.0", "minecraft:music_disc_mellohi"); -+ FLATTEN_MAP.put("minecraft:record_stal.0", "minecraft:music_disc_stal"); -+ FLATTEN_MAP.put("minecraft:record_strad.0", "minecraft:music_disc_strad"); -+ FLATTEN_MAP.put("minecraft:record_wait.0", "minecraft:music_disc_wait"); -+ FLATTEN_MAP.put("minecraft:record_ward.0", "minecraft:music_disc_ward"); -+ } -+ -+ // maps out ids requiring flattening -+ private static final Set IDS_REQUIRING_FLATTENING = new HashSet<>(); -+ static { -+ for (final String key : FLATTEN_MAP.keySet()) { -+ IDS_REQUIRING_FLATTENING.add(key.substring(0, key.indexOf('.'))); -+ } -+ } -+ -+ // Damage tag is moved from the ItemStack base tag to the ItemStack tag, and we only want to migrate that -+ // for items that actually require it for damage purposes (Remember, old damage was used to differentiate item types) -+ // It should be noted that this ID set should not be included in the flattening map, because damage for these items -+ // is actual damage and not a subtype specifier -+ private static final Set ITEMS_WITH_DAMAGE = new HashSet<>(Arrays.asList( -+ "minecraft:bow", -+ "minecraft:carrot_on_a_stick", -+ "minecraft:chainmail_boots", -+ "minecraft:chainmail_chestplate", -+ "minecraft:chainmail_helmet", -+ "minecraft:chainmail_leggings", -+ "minecraft:diamond_axe", -+ "minecraft:diamond_boots", -+ "minecraft:diamond_chestplate", -+ "minecraft:diamond_helmet", -+ "minecraft:diamond_hoe", -+ "minecraft:diamond_leggings", -+ "minecraft:diamond_pickaxe", -+ "minecraft:diamond_shovel", -+ "minecraft:diamond_sword", -+ "minecraft:elytra", -+ "minecraft:fishing_rod", -+ "minecraft:flint_and_steel", -+ "minecraft:golden_axe", -+ "minecraft:golden_boots", -+ "minecraft:golden_chestplate", -+ "minecraft:golden_helmet", -+ "minecraft:golden_hoe", -+ "minecraft:golden_leggings", -+ "minecraft:golden_pickaxe", -+ "minecraft:golden_shovel", -+ "minecraft:golden_sword", -+ "minecraft:iron_axe", -+ "minecraft:iron_boots", -+ "minecraft:iron_chestplate", -+ "minecraft:iron_helmet", -+ "minecraft:iron_hoe", -+ "minecraft:iron_leggings", -+ "minecraft:iron_pickaxe", -+ "minecraft:iron_shovel", -+ "minecraft:iron_sword", -+ "minecraft:leather_boots", -+ "minecraft:leather_chestplate", -+ "minecraft:leather_helmet", -+ "minecraft:leather_leggings", -+ "minecraft:shears", -+ "minecraft:shield", -+ "minecraft:stone_axe", -+ "minecraft:stone_hoe", -+ "minecraft:stone_pickaxe", -+ "minecraft:stone_shovel", -+ "minecraft:stone_sword", -+ "minecraft:wooden_axe", -+ "minecraft:wooden_hoe", -+ "minecraft:wooden_pickaxe", -+ "minecraft:wooden_shovel", -+ "minecraft:wooden_sword" -+ )); -+ -+ public ConverterFlattenItemStack() { -+ super(MCVersions.V17W47A, 4); -+ } -+ -+ public static String flattenItem(final String oldName, final int data) { -+ if (IDS_REQUIRING_FLATTENING.contains(oldName)) { -+ final String flattened = FLATTEN_MAP.get(oldName + '.' + data); -+ return flattened == null ? FLATTEN_MAP.get(oldName.concat(".0")) : flattened; -+ } else { -+ return null; -+ } -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String id = data.getString("id"); -+ -+ if (id == null) { -+ return null; -+ } -+ -+ final int damage = data.getInt("Damage"); -+ data.remove("Damage"); -+ -+ if (IDS_REQUIRING_FLATTENING.contains(id)) { -+ String remap = FLATTEN_MAP.get(id + '.' + damage); -+ if (remap == null) { -+ remap = FLATTEN_MAP.get(id.concat(".0")); -+ // this shouldn't be null -+ } -+ if (remap != null) { -+ data.setString("id", remap); -+ } else { -+ LOGGER.warn("Item '" + id + "' requires flattening but found no mapping for it! (ConverterFlattenItemStack)"); -+ } -+ } else if (damage != 0 && ITEMS_WITH_DAMAGE.contains(id)) { -+ // migrate damage -+ MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ tag = Types.NBT.createEmptyMap(); -+ data.setMap("tag", tag); -+ } -+ tag.setInt("Damage", damage); -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterFlattenSpawnEgg.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterFlattenSpawnEgg.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a3b56a45f79fcddcd68c4a628e20f1229a17a645 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterFlattenSpawnEgg.java -@@ -0,0 +1,84 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.itemstack; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.HashMap; -+import java.util.Map; -+ -+public final class ConverterFlattenSpawnEgg extends DataConverter, MapType> { -+ -+ private static final Map ENTITY_ID_TO_NEW_EGG_ID = new HashMap<>(); -+ static { -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:bat", "minecraft:bat_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:blaze", "minecraft:blaze_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:cave_spider", "minecraft:cave_spider_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:chicken", "minecraft:chicken_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:cow", "minecraft:cow_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:creeper", "minecraft:creeper_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:donkey", "minecraft:donkey_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:elder_guardian", "minecraft:elder_guardian_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:enderman", "minecraft:enderman_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:endermite", "minecraft:endermite_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:evocation_illager", "minecraft:evocation_illager_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:ghast", "minecraft:ghast_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:guardian", "minecraft:guardian_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:horse", "minecraft:horse_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:husk", "minecraft:husk_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:llama", "minecraft:llama_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:magma_cube", "minecraft:magma_cube_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:mooshroom", "minecraft:mooshroom_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:mule", "minecraft:mule_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:ocelot", "minecraft:ocelot_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:pufferfish", "minecraft:pufferfish_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:parrot", "minecraft:parrot_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:pig", "minecraft:pig_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:polar_bear", "minecraft:polar_bear_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:rabbit", "minecraft:rabbit_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:sheep", "minecraft:sheep_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:shulker", "minecraft:shulker_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:silverfish", "minecraft:silverfish_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:skeleton", "minecraft:skeleton_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:skeleton_horse", "minecraft:skeleton_horse_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:slime", "minecraft:slime_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:spider", "minecraft:spider_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:squid", "minecraft:squid_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:stray", "minecraft:stray_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:turtle", "minecraft:turtle_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:vex", "minecraft:vex_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:villager", "minecraft:villager_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:vindication_illager", "minecraft:vindication_illager_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:witch", "minecraft:witch_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:wither_skeleton", "minecraft:wither_skeleton_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:wolf", "minecraft:wolf_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:zombie", "minecraft:zombie_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:zombie_horse", "minecraft:zombie_horse_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:zombie_pigman", "minecraft:zombie_pigman_spawn_egg"); -+ ENTITY_ID_TO_NEW_EGG_ID.put("minecraft:zombie_villager", "minecraft:zombie_villager_spawn_egg"); -+ } -+ -+ public ConverterFlattenSpawnEgg() { -+ super(MCVersions.V17W47A,5); -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final MapType entityTag = tag.getMap("EntityTag"); -+ if (entityTag == null) { -+ return null; -+ } -+ -+ final String id = entityTag.getString("id"); -+ if (id != null) { -+ data.setString("id", ENTITY_ID_TO_NEW_EGG_ID.getOrDefault(id, "minecraft:pig_spawn_egg")); -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/options/ConverterAbstractOptionsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/options/ConverterAbstractOptionsRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..36a24666ea471ea3b6f7a3386cd541544fb3faca ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/options/ConverterAbstractOptionsRename.java -@@ -0,0 +1,34 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.options; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.ArrayList; -+import java.util.function.Function; -+ -+public final class ConverterAbstractOptionsRename { -+ -+ private ConverterAbstractOptionsRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ for (final String key : new ArrayList<>(data.keys())) { -+ final String updated = renamer.apply(key); -+ if (updated != null) { -+ data.setGeneric(updated, data.getGeneric(key)); -+ data.remove(key); -+ } -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/poi/ConverterAbstractPOIRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/poi/ConverterAbstractPOIRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..18df676b66200a9400158cd7ef75b9ed2edf382a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/poi/ConverterAbstractPOIRename.java -@@ -0,0 +1,54 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.poi; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+import java.util.function.Function; -+ -+public final class ConverterAbstractPOIRename { -+ -+ private ConverterAbstractPOIRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ MCTypeRegistry.POI_CHUNK.addStructureConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType sections = data.getMap("Sections"); -+ if (sections == null) { -+ return null; -+ } -+ -+ for (final String key : sections.keys()) { -+ final MapType section = sections.getMap(key); -+ -+ final ListType records = section.getList("Records", ObjectType.MAP); -+ -+ if (records == null) { -+ continue; -+ } -+ -+ for (int i = 0, len = records.size(); i < len; ++i) { -+ final MapType record = records.getMap(i); -+ -+ final String type = record.getString("type"); -+ if (type != null) { -+ final String converted = renamer.apply(type); -+ if (converted != null) { -+ record.setString("type", converted); -+ } -+ } -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/recipe/ConverterAbstractRecipeRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/recipe/ConverterAbstractRecipeRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8f35cbbd78a629712f9ae3cd5d180269f015a11d ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/recipe/ConverterAbstractRecipeRename.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.recipe; -+ -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import java.util.function.Function; -+ -+public final class ConverterAbstractRecipeRename { -+ -+ private ConverterAbstractRecipeRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ ConverterAbstractStringValueTypeRename.register(version, subVersion, MCTypeRegistry.RECIPE, renamer); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterAbstractStatsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterAbstractStatsRename.java -new file mode 100644 -index 0000000000000000000000000000000000000000..415e7ab80e9432d7f77d020249a850a47789c79e ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterAbstractStatsRename.java -@@ -0,0 +1,76 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.stats; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.ArrayList; -+import java.util.function.Function; -+ -+public final class ConverterAbstractStatsRename { -+ -+ private ConverterAbstractStatsRename() {} -+ -+ public static void register(final int version, final Function renamer) { -+ register(version, 0, renamer); -+ } -+ -+ public static void register(final int version, final int subVersion, final Function renamer) { -+ MCTypeRegistry.OBJECTIVE.addStructureConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType criteriaType = data.getMap("CriteriaType"); -+ if (criteriaType == null) { -+ return null; -+ } -+ -+ final String type = criteriaType.getString("type"); -+ if (!"minecraft:custom".equals(type)) { -+ return null; -+ } -+ -+ final String id = criteriaType.getString("id"); -+ if (id == null) { -+ return null; -+ } -+ -+ final String rename = renamer.apply(id); -+ if (rename != null) { -+ criteriaType.setString("id", rename); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.STATS.addStructureConverter(new DataConverter<>(version, subVersion) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType stats = data.getMap("stats"); -+ -+ if (stats == null) { -+ return null; -+ } -+ -+ final MapType custom = stats.getMap("minecraft:custom"); -+ if (custom == null) { -+ return null; -+ } -+ -+ for (final String key : new ArrayList<>(custom.keys())) { -+ final String rename = renamer.apply(key); -+ if (rename == null) { -+ continue; -+ } -+ -+ final Object value = custom.getGeneric(key); -+ custom.remove(key); -+ -+ custom.setGeneric(rename, value); -+ } -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterFlattenStats.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterFlattenStats.java -new file mode 100644 -index 0000000000000000000000000000000000000000..99d2c2c84820295be1f8bb0b43784e58f51a46dd ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterFlattenStats.java -@@ -0,0 +1,94 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.stats; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperBlockFlatteningV1450; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemstack.ConverterFlattenItemStack; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.google.common.collect.ImmutableMap; -+import com.google.common.collect.ImmutableSet; -+import org.apache.commons.lang3.StringUtils; -+import java.util.Map; -+import java.util.Set; -+ -+public final class ConverterFlattenStats extends DataConverter, MapType> { -+ -+ private static final Set SKIP = ImmutableSet.builder().add("stat.craftItem.minecraft.spawn_egg").add("stat.useItem.minecraft.spawn_egg").add("stat.breakItem.minecraft.spawn_egg").add("stat.pickup.minecraft.spawn_egg").add("stat.drop.minecraft.spawn_egg").build(); -+ private static final Map CUSTOM_MAP = ImmutableMap.builder().put("stat.leaveGame", "minecraft:leave_game").put("stat.playOneMinute", "minecraft:play_one_minute").put("stat.timeSinceDeath", "minecraft:time_since_death").put("stat.sneakTime", "minecraft:sneak_time").put("stat.walkOneCm", "minecraft:walk_one_cm").put("stat.crouchOneCm", "minecraft:crouch_one_cm").put("stat.sprintOneCm", "minecraft:sprint_one_cm").put("stat.swimOneCm", "minecraft:swim_one_cm").put("stat.fallOneCm", "minecraft:fall_one_cm").put("stat.climbOneCm", "minecraft:climb_one_cm").put("stat.flyOneCm", "minecraft:fly_one_cm").put("stat.diveOneCm", "minecraft:dive_one_cm").put("stat.minecartOneCm", "minecraft:minecart_one_cm").put("stat.boatOneCm", "minecraft:boat_one_cm").put("stat.pigOneCm", "minecraft:pig_one_cm").put("stat.horseOneCm", "minecraft:horse_one_cm").put("stat.aviateOneCm", "minecraft:aviate_one_cm").put("stat.jump", "minecraft:jump").put("stat.drop", "minecraft:drop").put("stat.damageDealt", "minecraft:damage_dealt").put("stat.damageTaken", "minecraft:damage_taken").put("stat.deaths", "minecraft:deaths").put("stat.mobKills", "minecraft:mob_kills").put("stat.animalsBred", "minecraft:animals_bred").put("stat.playerKills", "minecraft:player_kills").put("stat.fishCaught", "minecraft:fish_caught").put("stat.talkedToVillager", "minecraft:talked_to_villager").put("stat.tradedWithVillager", "minecraft:traded_with_villager").put("stat.cakeSlicesEaten", "minecraft:eat_cake_slice").put("stat.cauldronFilled", "minecraft:fill_cauldron").put("stat.cauldronUsed", "minecraft:use_cauldron").put("stat.armorCleaned", "minecraft:clean_armor").put("stat.bannerCleaned", "minecraft:clean_banner").put("stat.brewingstandInteraction", "minecraft:interact_with_brewingstand").put("stat.beaconInteraction", "minecraft:interact_with_beacon").put("stat.dropperInspected", "minecraft:inspect_dropper").put("stat.hopperInspected", "minecraft:inspect_hopper").put("stat.dispenserInspected", "minecraft:inspect_dispenser").put("stat.noteblockPlayed", "minecraft:play_noteblock").put("stat.noteblockTuned", "minecraft:tune_noteblock").put("stat.flowerPotted", "minecraft:pot_flower").put("stat.trappedChestTriggered", "minecraft:trigger_trapped_chest").put("stat.enderchestOpened", "minecraft:open_enderchest").put("stat.itemEnchanted", "minecraft:enchant_item").put("stat.recordPlayed", "minecraft:play_record").put("stat.furnaceInteraction", "minecraft:interact_with_furnace").put("stat.craftingTableInteraction", "minecraft:interact_with_crafting_table").put("stat.chestOpened", "minecraft:open_chest").put("stat.sleepInBed", "minecraft:sleep_in_bed").put("stat.shulkerBoxOpened", "minecraft:open_shulker_box").build(); -+ private static final Map ITEM_KEYS = ImmutableMap.builder().put("stat.craftItem", "minecraft:crafted").put("stat.useItem", "minecraft:used").put("stat.breakItem", "minecraft:broken").put("stat.pickup", "minecraft:picked_up").put("stat.drop", "minecraft:dropped").build(); -+ private static final Map ENTITY_KEYS = ImmutableMap.builder().put("stat.entityKilledBy", "minecraft:killed_by").put("stat.killEntity", "minecraft:killed").build(); -+ private static final Map ENTITIES = ImmutableMap.builder().put("Bat", "minecraft:bat").put("Blaze", "minecraft:blaze").put("CaveSpider", "minecraft:cave_spider").put("Chicken", "minecraft:chicken").put("Cow", "minecraft:cow").put("Creeper", "minecraft:creeper").put("Donkey", "minecraft:donkey").put("ElderGuardian", "minecraft:elder_guardian").put("Enderman", "minecraft:enderman").put("Endermite", "minecraft:endermite").put("EvocationIllager", "minecraft:evocation_illager").put("Ghast", "minecraft:ghast").put("Guardian", "minecraft:guardian").put("Horse", "minecraft:horse").put("Husk", "minecraft:husk").put("Llama", "minecraft:llama").put("LavaSlime", "minecraft:magma_cube").put("MushroomCow", "minecraft:mooshroom").put("Mule", "minecraft:mule").put("Ozelot", "minecraft:ocelot").put("Parrot", "minecraft:parrot").put("Pig", "minecraft:pig").put("PolarBear", "minecraft:polar_bear").put("Rabbit", "minecraft:rabbit").put("Sheep", "minecraft:sheep").put("Shulker", "minecraft:shulker").put("Silverfish", "minecraft:silverfish").put("SkeletonHorse", "minecraft:skeleton_horse").put("Skeleton", "minecraft:skeleton").put("Slime", "minecraft:slime").put("Spider", "minecraft:spider").put("Squid", "minecraft:squid").put("Stray", "minecraft:stray").put("Vex", "minecraft:vex").put("Villager", "minecraft:villager").put("VindicationIllager", "minecraft:vindication_illager").put("Witch", "minecraft:witch").put("WitherSkeleton", "minecraft:wither_skeleton").put("Wolf", "minecraft:wolf").put("ZombieHorse", "minecraft:zombie_horse").put("PigZombie", "minecraft:zombie_pigman").put("ZombieVillager", "minecraft:zombie_villager").put("Zombie", "minecraft:zombie").build(); -+ -+ public ConverterFlattenStats() { -+ super(MCVersions.V17W47A, 6); -+ } -+ -+ private static String upgradeItem(final String itemName) { -+ return ConverterFlattenItemStack.flattenItem(itemName, 0); -+ } -+ -+ private static String upgradeBlock(final String block) { -+ return HelperBlockFlatteningV1450.getNewBlockName(block); -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType stats = Types.NBT.createEmptyMap(); -+ -+ for (final String statKey : data.keys()) { -+ final Number value = data.getNumber(statKey); -+ if (value == null) { -+ continue; -+ } -+ -+ if (SKIP.contains(statKey)) { -+ continue; -+ } -+ -+ final String statType; -+ final String newStatKey; -+ -+ if (CUSTOM_MAP.containsKey(statKey)) { -+ statType = "minecraft:custom"; -+ newStatKey = CUSTOM_MAP.get(statKey); -+ } else { -+ final int i = StringUtils.ordinalIndexOf(statKey, ".", 2); -+ if (i < 0) { -+ continue; -+ } -+ -+ final String key = statKey.substring(0, i); -+ -+ if ("stat.mineBlock".equals(key)) { -+ statType = "minecraft:mined"; -+ newStatKey = upgradeBlock(statKey.substring(i + 1).replace('.', ':')); -+ } else if (ITEM_KEYS.containsKey(key)) { -+ statType = ITEM_KEYS.get(key); -+ final String item = statKey.substring(i + 1).replace('.', ':'); -+ final String upgradedItem = upgradeItem(item); -+ newStatKey = upgradedItem == null ? item : upgradedItem; -+ } else if (ENTITY_KEYS.containsKey(key)) { -+ statType = ENTITY_KEYS.get(key); -+ final String entity = statKey.substring(i + 1).replace('.', ':'); -+ newStatKey = ENTITIES.getOrDefault(entity, entity); -+ } else { -+ continue; -+ } -+ } -+ -+ MapType statTypeMap = stats.getMap(statType); -+ if (statTypeMap == null) { -+ stats.setMap(statType, statTypeMap = Types.NBT.createEmptyMap()); -+ } -+ -+ statTypeMap.setGeneric(newStatKey, value); -+ } -+ -+ data.clear(); -+ -+ data.setMap("stats", stats); -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/tileentity/ConverterFlattenTileEntity.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/tileentity/ConverterFlattenTileEntity.java -new file mode 100644 -index 0000000000000000000000000000000000000000..19ba9f881a82ace675d0c97d652c88063c1c8402 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/tileentity/ConverterFlattenTileEntity.java -@@ -0,0 +1,371 @@ -+package ca.spottedleaf.dataconverter.minecraft.converters.tileentity; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperBlockFlatteningV1450; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+import java.util.HashMap; -+import java.util.Map; -+ -+public final class ConverterFlattenTileEntity extends DataConverter, MapType> { -+ -+ private static final Map BLOCK_NAME_TO_ID = new HashMap<>(); -+ static { -+ BLOCK_NAME_TO_ID.put("minecraft:air", 0); -+ BLOCK_NAME_TO_ID.put("minecraft:stone", 1); -+ BLOCK_NAME_TO_ID.put("minecraft:grass", 2); -+ BLOCK_NAME_TO_ID.put("minecraft:dirt", 3); -+ BLOCK_NAME_TO_ID.put("minecraft:cobblestone", 4); -+ BLOCK_NAME_TO_ID.put("minecraft:planks", 5); -+ BLOCK_NAME_TO_ID.put("minecraft:sapling", 6); -+ BLOCK_NAME_TO_ID.put("minecraft:bedrock", 7); -+ BLOCK_NAME_TO_ID.put("minecraft:flowing_water", 8); -+ BLOCK_NAME_TO_ID.put("minecraft:water", 9); -+ BLOCK_NAME_TO_ID.put("minecraft:flowing_lava", 10); -+ BLOCK_NAME_TO_ID.put("minecraft:lava", 11); -+ BLOCK_NAME_TO_ID.put("minecraft:sand", 12); -+ BLOCK_NAME_TO_ID.put("minecraft:gravel", 13); -+ BLOCK_NAME_TO_ID.put("minecraft:gold_ore", 14); -+ BLOCK_NAME_TO_ID.put("minecraft:iron_ore", 15); -+ BLOCK_NAME_TO_ID.put("minecraft:coal_ore", 16); -+ BLOCK_NAME_TO_ID.put("minecraft:log", 17); -+ BLOCK_NAME_TO_ID.put("minecraft:leaves", 18); -+ BLOCK_NAME_TO_ID.put("minecraft:sponge", 19); -+ BLOCK_NAME_TO_ID.put("minecraft:glass", 20); -+ BLOCK_NAME_TO_ID.put("minecraft:lapis_ore", 21); -+ BLOCK_NAME_TO_ID.put("minecraft:lapis_block", 22); -+ BLOCK_NAME_TO_ID.put("minecraft:dispenser", 23); -+ BLOCK_NAME_TO_ID.put("minecraft:sandstone", 24); -+ BLOCK_NAME_TO_ID.put("minecraft:noteblock", 25); -+ BLOCK_NAME_TO_ID.put("minecraft:bed", 26); -+ BLOCK_NAME_TO_ID.put("minecraft:golden_rail", 27); -+ BLOCK_NAME_TO_ID.put("minecraft:detector_rail", 28); -+ BLOCK_NAME_TO_ID.put("minecraft:sticky_piston", 29); -+ BLOCK_NAME_TO_ID.put("minecraft:web", 30); -+ BLOCK_NAME_TO_ID.put("minecraft:tallgrass", 31); -+ BLOCK_NAME_TO_ID.put("minecraft:deadbush", 32); -+ BLOCK_NAME_TO_ID.put("minecraft:piston", 33); -+ BLOCK_NAME_TO_ID.put("minecraft:piston_head", 34); -+ BLOCK_NAME_TO_ID.put("minecraft:wool", 35); -+ BLOCK_NAME_TO_ID.put("minecraft:piston_extension", 36); -+ BLOCK_NAME_TO_ID.put("minecraft:yellow_flower", 37); -+ BLOCK_NAME_TO_ID.put("minecraft:red_flower", 38); -+ BLOCK_NAME_TO_ID.put("minecraft:brown_mushroom", 39); -+ BLOCK_NAME_TO_ID.put("minecraft:red_mushroom", 40); -+ BLOCK_NAME_TO_ID.put("minecraft:gold_block", 41); -+ BLOCK_NAME_TO_ID.put("minecraft:iron_block", 42); -+ BLOCK_NAME_TO_ID.put("minecraft:double_stone_slab", 43); -+ BLOCK_NAME_TO_ID.put("minecraft:stone_slab", 44); -+ BLOCK_NAME_TO_ID.put("minecraft:brick_block", 45); -+ BLOCK_NAME_TO_ID.put("minecraft:tnt", 46); -+ BLOCK_NAME_TO_ID.put("minecraft:bookshelf", 47); -+ BLOCK_NAME_TO_ID.put("minecraft:mossy_cobblestone", 48); -+ BLOCK_NAME_TO_ID.put("minecraft:obsidian", 49); -+ BLOCK_NAME_TO_ID.put("minecraft:torch", 50); -+ BLOCK_NAME_TO_ID.put("minecraft:fire", 51); -+ BLOCK_NAME_TO_ID.put("minecraft:mob_spawner", 52); -+ BLOCK_NAME_TO_ID.put("minecraft:oak_stairs", 53); -+ BLOCK_NAME_TO_ID.put("minecraft:chest", 54); -+ BLOCK_NAME_TO_ID.put("minecraft:redstone_wire", 55); -+ BLOCK_NAME_TO_ID.put("minecraft:diamond_ore", 56); -+ BLOCK_NAME_TO_ID.put("minecraft:diamond_block", 57); -+ BLOCK_NAME_TO_ID.put("minecraft:crafting_table", 58); -+ BLOCK_NAME_TO_ID.put("minecraft:wheat", 59); -+ BLOCK_NAME_TO_ID.put("minecraft:farmland", 60); -+ BLOCK_NAME_TO_ID.put("minecraft:furnace", 61); -+ BLOCK_NAME_TO_ID.put("minecraft:lit_furnace", 62); -+ BLOCK_NAME_TO_ID.put("minecraft:standing_sign", 63); -+ BLOCK_NAME_TO_ID.put("minecraft:wooden_door", 64); -+ BLOCK_NAME_TO_ID.put("minecraft:ladder", 65); -+ BLOCK_NAME_TO_ID.put("minecraft:rail", 66); -+ BLOCK_NAME_TO_ID.put("minecraft:stone_stairs", 67); -+ BLOCK_NAME_TO_ID.put("minecraft:wall_sign", 68); -+ BLOCK_NAME_TO_ID.put("minecraft:lever", 69); -+ BLOCK_NAME_TO_ID.put("minecraft:stone_pressure_plate", 70); -+ BLOCK_NAME_TO_ID.put("minecraft:iron_door", 71); -+ BLOCK_NAME_TO_ID.put("minecraft:wooden_pressure_plate", 72); -+ BLOCK_NAME_TO_ID.put("minecraft:redstone_ore", 73); -+ BLOCK_NAME_TO_ID.put("minecraft:lit_redstone_ore", 74); -+ BLOCK_NAME_TO_ID.put("minecraft:unlit_redstone_torch", 75); -+ BLOCK_NAME_TO_ID.put("minecraft:redstone_torch", 76); -+ BLOCK_NAME_TO_ID.put("minecraft:stone_button", 77); -+ BLOCK_NAME_TO_ID.put("minecraft:snow_layer", 78); -+ BLOCK_NAME_TO_ID.put("minecraft:ice", 79); -+ BLOCK_NAME_TO_ID.put("minecraft:snow", 80); -+ BLOCK_NAME_TO_ID.put("minecraft:cactus", 81); -+ BLOCK_NAME_TO_ID.put("minecraft:clay", 82); -+ BLOCK_NAME_TO_ID.put("minecraft:reeds", 83); -+ BLOCK_NAME_TO_ID.put("minecraft:jukebox", 84); -+ BLOCK_NAME_TO_ID.put("minecraft:fence", 85); -+ BLOCK_NAME_TO_ID.put("minecraft:pumpkin", 86); -+ BLOCK_NAME_TO_ID.put("minecraft:netherrack", 87); -+ BLOCK_NAME_TO_ID.put("minecraft:soul_sand", 88); -+ BLOCK_NAME_TO_ID.put("minecraft:glowstone", 89); -+ BLOCK_NAME_TO_ID.put("minecraft:portal", 90); -+ BLOCK_NAME_TO_ID.put("minecraft:lit_pumpkin", 91); -+ BLOCK_NAME_TO_ID.put("minecraft:cake", 92); -+ BLOCK_NAME_TO_ID.put("minecraft:unpowered_repeater", 93); -+ BLOCK_NAME_TO_ID.put("minecraft:powered_repeater", 94); -+ BLOCK_NAME_TO_ID.put("minecraft:stained_glass", 95); -+ BLOCK_NAME_TO_ID.put("minecraft:trapdoor", 96); -+ BLOCK_NAME_TO_ID.put("minecraft:monster_egg", 97); -+ BLOCK_NAME_TO_ID.put("minecraft:stonebrick", 98); -+ BLOCK_NAME_TO_ID.put("minecraft:brown_mushroom_block", 99); -+ BLOCK_NAME_TO_ID.put("minecraft:red_mushroom_block", 100); -+ BLOCK_NAME_TO_ID.put("minecraft:iron_bars", 101); -+ BLOCK_NAME_TO_ID.put("minecraft:glass_pane", 102); -+ BLOCK_NAME_TO_ID.put("minecraft:melon_block", 103); -+ BLOCK_NAME_TO_ID.put("minecraft:pumpkin_stem", 104); -+ BLOCK_NAME_TO_ID.put("minecraft:melon_stem", 105); -+ BLOCK_NAME_TO_ID.put("minecraft:vine", 106); -+ BLOCK_NAME_TO_ID.put("minecraft:fence_gate", 107); -+ BLOCK_NAME_TO_ID.put("minecraft:brick_stairs", 108); -+ BLOCK_NAME_TO_ID.put("minecraft:stone_brick_stairs", 109); -+ BLOCK_NAME_TO_ID.put("minecraft:mycelium", 110); -+ BLOCK_NAME_TO_ID.put("minecraft:waterlily", 111); -+ BLOCK_NAME_TO_ID.put("minecraft:nether_brick", 112); -+ BLOCK_NAME_TO_ID.put("minecraft:nether_brick_fence", 113); -+ BLOCK_NAME_TO_ID.put("minecraft:nether_brick_stairs", 114); -+ BLOCK_NAME_TO_ID.put("minecraft:nether_wart", 115); -+ BLOCK_NAME_TO_ID.put("minecraft:enchanting_table", 116); -+ BLOCK_NAME_TO_ID.put("minecraft:brewing_stand", 117); -+ BLOCK_NAME_TO_ID.put("minecraft:cauldron", 118); -+ BLOCK_NAME_TO_ID.put("minecraft:end_portal", 119); -+ BLOCK_NAME_TO_ID.put("minecraft:end_portal_frame", 120); -+ BLOCK_NAME_TO_ID.put("minecraft:end_stone", 121); -+ BLOCK_NAME_TO_ID.put("minecraft:dragon_egg", 122); -+ BLOCK_NAME_TO_ID.put("minecraft:redstone_lamp", 123); -+ BLOCK_NAME_TO_ID.put("minecraft:lit_redstone_lamp", 124); -+ BLOCK_NAME_TO_ID.put("minecraft:double_wooden_slab", 125); -+ BLOCK_NAME_TO_ID.put("minecraft:wooden_slab", 126); -+ BLOCK_NAME_TO_ID.put("minecraft:cocoa", 127); -+ BLOCK_NAME_TO_ID.put("minecraft:sandstone_stairs", 128); -+ BLOCK_NAME_TO_ID.put("minecraft:emerald_ore", 129); -+ BLOCK_NAME_TO_ID.put("minecraft:ender_chest", 130); -+ BLOCK_NAME_TO_ID.put("minecraft:tripwire_hook", 131); -+ BLOCK_NAME_TO_ID.put("minecraft:tripwire", 132); -+ BLOCK_NAME_TO_ID.put("minecraft:emerald_block", 133); -+ BLOCK_NAME_TO_ID.put("minecraft:spruce_stairs", 134); -+ BLOCK_NAME_TO_ID.put("minecraft:birch_stairs", 135); -+ BLOCK_NAME_TO_ID.put("minecraft:jungle_stairs", 136); -+ BLOCK_NAME_TO_ID.put("minecraft:command_block", 137); -+ BLOCK_NAME_TO_ID.put("minecraft:beacon", 138); -+ BLOCK_NAME_TO_ID.put("minecraft:cobblestone_wall", 139); -+ BLOCK_NAME_TO_ID.put("minecraft:flower_pot", 140); -+ BLOCK_NAME_TO_ID.put("minecraft:carrots", 141); -+ BLOCK_NAME_TO_ID.put("minecraft:potatoes", 142); -+ BLOCK_NAME_TO_ID.put("minecraft:wooden_button", 143); -+ BLOCK_NAME_TO_ID.put("minecraft:skull", 144); -+ BLOCK_NAME_TO_ID.put("minecraft:anvil", 145); -+ BLOCK_NAME_TO_ID.put("minecraft:trapped_chest", 146); -+ BLOCK_NAME_TO_ID.put("minecraft:light_weighted_pressure_plate", 147); -+ BLOCK_NAME_TO_ID.put("minecraft:heavy_weighted_pressure_plate", 148); -+ BLOCK_NAME_TO_ID.put("minecraft:unpowered_comparator", 149); -+ BLOCK_NAME_TO_ID.put("minecraft:powered_comparator", 150); -+ BLOCK_NAME_TO_ID.put("minecraft:daylight_detector", 151); -+ BLOCK_NAME_TO_ID.put("minecraft:redstone_block", 152); -+ BLOCK_NAME_TO_ID.put("minecraft:quartz_ore", 153); -+ BLOCK_NAME_TO_ID.put("minecraft:hopper", 154); -+ BLOCK_NAME_TO_ID.put("minecraft:quartz_block", 155); -+ BLOCK_NAME_TO_ID.put("minecraft:quartz_stairs", 156); -+ BLOCK_NAME_TO_ID.put("minecraft:activator_rail", 157); -+ BLOCK_NAME_TO_ID.put("minecraft:dropper", 158); -+ BLOCK_NAME_TO_ID.put("minecraft:stained_hardened_clay", 159); -+ BLOCK_NAME_TO_ID.put("minecraft:stained_glass_pane", 160); -+ BLOCK_NAME_TO_ID.put("minecraft:leaves2", 161); -+ BLOCK_NAME_TO_ID.put("minecraft:log2", 162); -+ BLOCK_NAME_TO_ID.put("minecraft:acacia_stairs", 163); -+ BLOCK_NAME_TO_ID.put("minecraft:dark_oak_stairs", 164); -+ BLOCK_NAME_TO_ID.put("minecraft:slime", 165); -+ BLOCK_NAME_TO_ID.put("minecraft:barrier", 166); -+ BLOCK_NAME_TO_ID.put("minecraft:iron_trapdoor", 167); -+ BLOCK_NAME_TO_ID.put("minecraft:prismarine", 168); -+ BLOCK_NAME_TO_ID.put("minecraft:sea_lantern", 169); -+ BLOCK_NAME_TO_ID.put("minecraft:hay_block", 170); -+ BLOCK_NAME_TO_ID.put("minecraft:carpet", 171); -+ BLOCK_NAME_TO_ID.put("minecraft:hardened_clay", 172); -+ BLOCK_NAME_TO_ID.put("minecraft:coal_block", 173); -+ BLOCK_NAME_TO_ID.put("minecraft:packed_ice", 174); -+ BLOCK_NAME_TO_ID.put("minecraft:double_plant", 175); -+ BLOCK_NAME_TO_ID.put("minecraft:standing_banner", 176); -+ BLOCK_NAME_TO_ID.put("minecraft:wall_banner", 177); -+ BLOCK_NAME_TO_ID.put("minecraft:daylight_detector_inverted", 178); -+ BLOCK_NAME_TO_ID.put("minecraft:red_sandstone", 179); -+ BLOCK_NAME_TO_ID.put("minecraft:red_sandstone_stairs", 180); -+ BLOCK_NAME_TO_ID.put("minecraft:double_stone_slab2", 181); -+ BLOCK_NAME_TO_ID.put("minecraft:stone_slab2", 182); -+ BLOCK_NAME_TO_ID.put("minecraft:spruce_fence_gate", 183); -+ BLOCK_NAME_TO_ID.put("minecraft:birch_fence_gate", 184); -+ BLOCK_NAME_TO_ID.put("minecraft:jungle_fence_gate", 185); -+ BLOCK_NAME_TO_ID.put("minecraft:dark_oak_fence_gate", 186); -+ BLOCK_NAME_TO_ID.put("minecraft:acacia_fence_gate", 187); -+ BLOCK_NAME_TO_ID.put("minecraft:spruce_fence", 188); -+ BLOCK_NAME_TO_ID.put("minecraft:birch_fence", 189); -+ BLOCK_NAME_TO_ID.put("minecraft:jungle_fence", 190); -+ BLOCK_NAME_TO_ID.put("minecraft:dark_oak_fence", 191); -+ BLOCK_NAME_TO_ID.put("minecraft:acacia_fence", 192); -+ BLOCK_NAME_TO_ID.put("minecraft:spruce_door", 193); -+ BLOCK_NAME_TO_ID.put("minecraft:birch_door", 194); -+ BLOCK_NAME_TO_ID.put("minecraft:jungle_door", 195); -+ BLOCK_NAME_TO_ID.put("minecraft:acacia_door", 196); -+ BLOCK_NAME_TO_ID.put("minecraft:dark_oak_door", 197); -+ BLOCK_NAME_TO_ID.put("minecraft:end_rod", 198); -+ BLOCK_NAME_TO_ID.put("minecraft:chorus_plant", 199); -+ BLOCK_NAME_TO_ID.put("minecraft:chorus_flower", 200); -+ BLOCK_NAME_TO_ID.put("minecraft:purpur_block", 201); -+ BLOCK_NAME_TO_ID.put("minecraft:purpur_pillar", 202); -+ BLOCK_NAME_TO_ID.put("minecraft:purpur_stairs", 203); -+ BLOCK_NAME_TO_ID.put("minecraft:purpur_double_slab", 204); -+ BLOCK_NAME_TO_ID.put("minecraft:purpur_slab", 205); -+ BLOCK_NAME_TO_ID.put("minecraft:end_bricks", 206); -+ BLOCK_NAME_TO_ID.put("minecraft:beetroots", 207); -+ BLOCK_NAME_TO_ID.put("minecraft:grass_path", 208); -+ BLOCK_NAME_TO_ID.put("minecraft:end_gateway", 209); -+ BLOCK_NAME_TO_ID.put("minecraft:repeating_command_block", 210); -+ BLOCK_NAME_TO_ID.put("minecraft:chain_command_block", 211); -+ BLOCK_NAME_TO_ID.put("minecraft:frosted_ice", 212); -+ BLOCK_NAME_TO_ID.put("minecraft:magma", 213); -+ BLOCK_NAME_TO_ID.put("minecraft:nether_wart_block", 214); -+ BLOCK_NAME_TO_ID.put("minecraft:red_nether_brick", 215); -+ BLOCK_NAME_TO_ID.put("minecraft:bone_block", 216); -+ BLOCK_NAME_TO_ID.put("minecraft:structure_void", 217); -+ BLOCK_NAME_TO_ID.put("minecraft:observer", 218); -+ BLOCK_NAME_TO_ID.put("minecraft:white_shulker_box", 219); -+ BLOCK_NAME_TO_ID.put("minecraft:orange_shulker_box", 220); -+ BLOCK_NAME_TO_ID.put("minecraft:magenta_shulker_box", 221); -+ BLOCK_NAME_TO_ID.put("minecraft:light_blue_shulker_box", 222); -+ BLOCK_NAME_TO_ID.put("minecraft:yellow_shulker_box", 223); -+ BLOCK_NAME_TO_ID.put("minecraft:lime_shulker_box", 224); -+ BLOCK_NAME_TO_ID.put("minecraft:pink_shulker_box", 225); -+ BLOCK_NAME_TO_ID.put("minecraft:gray_shulker_box", 226); -+ BLOCK_NAME_TO_ID.put("minecraft:silver_shulker_box", 227); -+ BLOCK_NAME_TO_ID.put("minecraft:cyan_shulker_box", 228); -+ BLOCK_NAME_TO_ID.put("minecraft:purple_shulker_box", 229); -+ BLOCK_NAME_TO_ID.put("minecraft:blue_shulker_box", 230); -+ BLOCK_NAME_TO_ID.put("minecraft:brown_shulker_box", 231); -+ BLOCK_NAME_TO_ID.put("minecraft:green_shulker_box", 232); -+ BLOCK_NAME_TO_ID.put("minecraft:red_shulker_box", 233); -+ BLOCK_NAME_TO_ID.put("minecraft:black_shulker_box", 234); -+ BLOCK_NAME_TO_ID.put("minecraft:white_glazed_terracotta", 235); -+ BLOCK_NAME_TO_ID.put("minecraft:orange_glazed_terracotta", 236); -+ BLOCK_NAME_TO_ID.put("minecraft:magenta_glazed_terracotta", 237); -+ BLOCK_NAME_TO_ID.put("minecraft:light_blue_glazed_terracotta", 238); -+ BLOCK_NAME_TO_ID.put("minecraft:yellow_glazed_terracotta", 239); -+ BLOCK_NAME_TO_ID.put("minecraft:lime_glazed_terracotta", 240); -+ BLOCK_NAME_TO_ID.put("minecraft:pink_glazed_terracotta", 241); -+ BLOCK_NAME_TO_ID.put("minecraft:gray_glazed_terracotta", 242); -+ BLOCK_NAME_TO_ID.put("minecraft:silver_glazed_terracotta", 243); -+ BLOCK_NAME_TO_ID.put("minecraft:cyan_glazed_terracotta", 244); -+ BLOCK_NAME_TO_ID.put("minecraft:purple_glazed_terracotta", 245); -+ BLOCK_NAME_TO_ID.put("minecraft:blue_glazed_terracotta", 246); -+ BLOCK_NAME_TO_ID.put("minecraft:brown_glazed_terracotta", 247); -+ BLOCK_NAME_TO_ID.put("minecraft:green_glazed_terracotta", 248); -+ BLOCK_NAME_TO_ID.put("minecraft:red_glazed_terracotta", 249); -+ BLOCK_NAME_TO_ID.put("minecraft:black_glazed_terracotta", 250); -+ BLOCK_NAME_TO_ID.put("minecraft:concrete", 251); -+ BLOCK_NAME_TO_ID.put("minecraft:concrete_powder", 252); -+ BLOCK_NAME_TO_ID.put("minecraft:structure_block", 255); -+ } -+ -+ protected static final int VERSION = MCVersions.V17W47A; -+ -+ protected final String[] paths; -+ -+ public ConverterFlattenTileEntity(final String... paths) { -+ super(VERSION, 3); -+ this.paths = paths; -+ } -+ -+ private static void register(final String id, final String... paths) { -+ MCTypeRegistry.TILE_ENTITY.addConverterForId(id, new ConverterFlattenTileEntity(paths)); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:falling_block", new DataConverter<>(VERSION, 3) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int blockId; -+ if (data.hasKey("Block")) { -+ final Number id = data.getNumber("Block"); -+ if (id != null) { -+ blockId = id.intValue(); -+ } else { -+ blockId = getBlockId(data.getString("Block")); -+ } -+ } else { -+ final Number tileId = data.getNumber("TileID"); -+ if (tileId != null) { -+ blockId = tileId.intValue(); -+ } else { -+ blockId = data.getByte("Tile") & 255; -+ } -+ } -+ -+ final int blockData = data.getInt("Data") & 15; -+ -+ data.remove("Block"); // from type update -+ data.remove("Data"); -+ data.remove("TileID"); -+ data.remove("Tile"); -+ -+ // key is from type update -+ data.setMap("BlockState", HelperBlockFlatteningV1450.getNBTForId((blockId << 4) | blockData).copy()); // copy to avoid problems with later state datafixers -+ -+ return null; -+ } -+ }); -+ register("minecraft:enderman", "carried", "carriedData", "carriedBlockState"); -+ register("minecraft:arrow", "inTile", "inData", "inBlockState"); -+ register("minecraft:spectral_arrow", "inTile", "inData", "inBlockState"); -+ register("minecraft:egg", "inTile"); -+ register("minecraft:ender_pearl", "inTile"); -+ register("minecraft:fireball", "inTile"); -+ register("minecraft:potion", "inTile"); -+ register("minecraft:small_fireball", "inTile"); -+ register("minecraft:snowball", "inTile"); -+ register("minecraft:wither_skull", "inTile"); -+ register("minecraft:xp_bottle", "inTile"); -+ register("minecraft:commandblock_minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ register("minecraft:minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ register("minecraft:chest_minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ register("minecraft:furnace_minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ register("minecraft:tnt_minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ register("minecraft:hopper_minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ register("minecraft:spawner_minecart", "DisplayTile", "DisplayData", "DisplayState"); -+ } -+ -+ public static int getBlockId(final String block) { -+ final Integer ret = BLOCK_NAME_TO_ID.get(block); -+ return ret == null ? 0 : ret.intValue(); -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (this.paths.length == 1) { -+ data.remove(this.paths[0]); -+ return null; -+ } -+ final String idPath = this.paths[0]; -+ final String dataPath = this.paths[1]; -+ final String outputStatePath = this.paths[2]; -+ -+ final int blockId; -+ if (data.hasKey(idPath, ObjectType.NUMBER)) { -+ blockId = data.getInt(idPath); -+ } else { -+ blockId = getBlockId(data.getString(idPath)); -+ } -+ -+ final int blockData = data.getInt(dataPath) & 15; -+ -+ data.remove(idPath); // from type update -+ data.remove(dataPath); -+ -+ data.setMap(outputStatePath, HelperBlockFlatteningV1450.getNBTForId((blockId << 4) | blockData).copy()); // copy to avoid problems with later state datafixers -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/IDDataType.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/IDDataType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..60e3c59afab7596ea34224ab30da25ab6e89c63f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/IDDataType.java -@@ -0,0 +1,162 @@ -+package ca.spottedleaf.dataconverter.minecraft.datatypes; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataHook; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataWalker; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.util.Long2ObjectArraySortedMap; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+ -+public class IDDataType extends MCDataType { -+ -+ protected final Map>>> walkersById = new HashMap<>(); -+ -+ public IDDataType(final String name) { -+ super(name); -+ } -+ -+ public void addConverterForId(final String id, final DataConverter, MapType> converter) { -+ this.addStructureConverter(new DataConverter<>(converter.getToVersion(), converter.getVersionStep()) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!id.equals(data.getString("id"))) { -+ return null; -+ } -+ return converter.convert(data, sourceVersion, toVersion); -+ } -+ }); -+ } -+ -+ public void addWalker(final int minVersion, final String id, final DataWalker walker) { -+ this.addWalker(minVersion, 0, id, walker); -+ } -+ -+ public void addWalker(final int minVersion, final int versionStep, final String id, final DataWalker walker) { -+ this.walkersById.computeIfAbsent(id, (final String keyInMap) -> { -+ return new Long2ObjectArraySortedMap<>(); -+ }).computeIfAbsent(DataConverter.encodeVersions(minVersion, versionStep), (final long keyInMap) -> { -+ return new ArrayList<>(); -+ }).add(walker); -+ } -+ -+ public void copyWalkers(final int minVersion, final String fromId, final String toId) { -+ this.copyWalkers(minVersion, 0, fromId, toId); -+ } -+ -+ public void copyWalkers(final int minVersion, final int versionStep, final String fromId, final String toId) { -+ final long version = DataConverter.encodeVersions(minVersion, versionStep); -+ final Long2ObjectArraySortedMap>> walkersForId = this.walkersById.get(fromId); -+ if (walkersForId == null) { -+ return; -+ } -+ -+ final List> nearest = walkersForId.getFloor(version); -+ -+ if (nearest == null) { -+ return; -+ } -+ -+ for (final DataWalker walker : nearest) { -+ this.addWalker(minVersion, versionStep, toId, walker); -+ } -+ } -+ -+ @Override -+ public MapType convert(MapType data, final long fromVersion, final long toVersion) { -+ MapType ret = null; -+ -+ final List, MapType>> converters = this.structureConverters; -+ for (int i = 0, len = converters.size(); i < len; ++i) { -+ final DataConverter, MapType> converter = converters.get(i); -+ final long converterVersion = converter.getEncodedVersion(); -+ -+ if (converterVersion <= fromVersion) { -+ continue; -+ } -+ -+ if (converterVersion > toVersion) { -+ break; -+ } -+ -+ final List> hooks = this.structureHooks.getFloor(converterVersion); -+ -+ if (hooks != null) { -+ for (int k = 0, klen = hooks.size(); k < klen; ++k) { -+ final MapType replace = hooks.get(k).preHook(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ -+ final MapType replace = converter.convert(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ -+ if (hooks != null) { -+ for (int klen = hooks.size(), k = klen - 1; k >= 0; --k) { -+ final MapType postReplace = hooks.get(k).postHook(data, fromVersion, toVersion); -+ if (postReplace != null) { -+ ret = data = postReplace; -+ } -+ } -+ } -+ } -+ -+ final List> hooks = this.structureHooks.getFloor(toVersion); -+ -+ // run pre hooks -+ -+ if (hooks != null) { -+ for (int k = 0, klen = hooks.size(); k < klen; ++k) { -+ final MapType replace = hooks.get(k).preHook(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ -+ // run all walkers -+ -+ final List> walkers = this.structureWalkers.getFloor(toVersion); -+ if (walkers != null) { -+ for (int i = 0, len = walkers.size(); i < len; ++i) { -+ final MapType replace = walkers.get(i).walk(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ -+ final Long2ObjectArraySortedMap>> walkersByVersion = this.walkersById.get(data.getString("id")); -+ if (walkersByVersion != null) { -+ final List> walkersForId = walkersByVersion.getFloor(toVersion); -+ if (walkersForId != null) { -+ for (int i = 0, len = walkersForId.size(); i < len; ++i) { -+ final MapType replace = walkersForId.get(i).walk(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ } -+ -+ // run post hooks -+ -+ if (hooks != null) { -+ for (int klen = hooks.size(), k = klen - 1; k >= 0; --k) { -+ final MapType postReplace = hooks.get(k).postHook(data, fromVersion, toVersion); -+ if (postReplace != null) { -+ ret = data = postReplace; -+ } -+ } -+ } -+ -+ return ret; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCDataType.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCDataType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1c56ce02b76405b00ce737badd60d4cd3bfa9d11 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCDataType.java -@@ -0,0 +1,125 @@ -+package ca.spottedleaf.dataconverter.minecraft.datatypes; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataHook; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataType; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataWalker; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.util.Long2ObjectArraySortedMap; -+ -+import java.util.ArrayList; -+import java.util.List; -+ -+public class MCDataType extends DataType, MapType> { -+ -+ public final String name; -+ -+ protected final ArrayList, MapType>> structureConverters = new ArrayList<>(); -+ protected final Long2ObjectArraySortedMap>> structureWalkers = new Long2ObjectArraySortedMap<>(); -+ protected final Long2ObjectArraySortedMap>> structureHooks = new Long2ObjectArraySortedMap<>(); -+ -+ public MCDataType(final String name) { -+ this.name = name; -+ } -+ -+ public void addStructureConverter(final DataConverter, MapType> converter) { -+ this.structureConverters.add(converter); -+ this.structureConverters.sort(DataConverter.LOWEST_VERSION_COMPARATOR); -+ } -+ -+ public void addStructureWalker(final int minVersion, final DataWalker walker) { -+ this.addStructureWalker(minVersion, 0, walker); -+ } -+ -+ public void addStructureWalker(final int minVersion, final int versionStep, final DataWalker walker) { -+ this.structureWalkers.computeIfAbsent(DataConverter.encodeVersions(minVersion, versionStep), (final long keyInMap) -> { -+ return new ArrayList<>(); -+ }).add(walker); -+ } -+ -+ public void addStructureHook(final int minVersion, final DataHook hook) { -+ this.addStructureHook(minVersion, 0, hook); -+ } -+ -+ public void addStructureHook(final int minVersion, final int versionStep, final DataHook hook) { -+ this.structureHooks.computeIfAbsent(DataConverter.encodeVersions(minVersion, versionStep), (final long keyInMap) -> { -+ return new ArrayList<>(); -+ }).add(hook); -+ } -+ -+ @Override -+ public MapType convert(MapType data, final long fromVersion, final long toVersion) { -+ MapType ret = null; -+ -+ final List, MapType>> converters = this.structureConverters; -+ for (int i = 0, len = converters.size(); i < len; ++i) { -+ final DataConverter, MapType> converter = converters.get(i); -+ final long converterVersion = converter.getEncodedVersion(); -+ -+ if (converterVersion <= fromVersion) { -+ continue; -+ } -+ -+ if (converterVersion > toVersion) { -+ break; -+ } -+ -+ final List> hooks = this.structureHooks.getFloor(converterVersion); -+ -+ if (hooks != null) { -+ for (int k = 0, klen = hooks.size(); k < klen; ++k) { -+ final MapType replace = hooks.get(k).preHook(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ -+ final MapType replace = converter.convert(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ -+ if (hooks != null) { -+ for (int klen = hooks.size(), k = klen - 1; k >= 0; --k) { -+ final MapType postReplace = hooks.get(k).postHook(data, fromVersion, toVersion); -+ if (postReplace != null) { -+ ret = data = postReplace; -+ } -+ } -+ } -+ } -+ -+ final List> hooks = this.structureHooks.getFloor(toVersion); -+ -+ if (hooks != null) { -+ for (int k = 0, klen = hooks.size(); k < klen; ++k) { -+ final MapType replace = hooks.get(k).preHook(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ -+ final List> walkers = this.structureWalkers.getFloor(toVersion); -+ if (walkers != null) { -+ for (int i = 0, len = walkers.size(); i < len; ++i) { -+ final MapType replace = walkers.get(i).walk(data, fromVersion, toVersion); -+ if (replace != null) { -+ ret = data = replace; -+ } -+ } -+ } -+ -+ if (hooks != null) { -+ for (int klen = hooks.size(), k = klen - 1; k >= 0; --k) { -+ final MapType postReplace = hooks.get(k).postHook(data, fromVersion, toVersion); -+ if (postReplace != null) { -+ ret = data = postReplace; -+ } -+ } -+ } -+ -+ return ret; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2f5a9e04e3797673f49a035eebfedd1b90c81b07 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java -@@ -0,0 +1,316 @@ -+package ca.spottedleaf.dataconverter.minecraft.datatypes; -+ -+import ca.spottedleaf.dataconverter.minecraft.versions.V100; -+import ca.spottedleaf.dataconverter.minecraft.versions.V101; -+import ca.spottedleaf.dataconverter.minecraft.versions.V102; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1022; -+import ca.spottedleaf.dataconverter.minecraft.versions.V105; -+import ca.spottedleaf.dataconverter.minecraft.versions.V106; -+import ca.spottedleaf.dataconverter.minecraft.versions.V107; -+import ca.spottedleaf.dataconverter.minecraft.versions.V108; -+import ca.spottedleaf.dataconverter.minecraft.versions.V109; -+import ca.spottedleaf.dataconverter.minecraft.versions.V110; -+import ca.spottedleaf.dataconverter.minecraft.versions.V111; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1125; -+import ca.spottedleaf.dataconverter.minecraft.versions.V113; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1344; -+import ca.spottedleaf.dataconverter.minecraft.versions.V135; -+import ca.spottedleaf.dataconverter.minecraft.versions.V143; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1446; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1450; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1451; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1456; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1458; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1460; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1466; -+import ca.spottedleaf.dataconverter.minecraft.versions.V147; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1470; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1474; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1475; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1480; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1483; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1484; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1486; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1487; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1488; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1490; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1492; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1494; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1496; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1500; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1501; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1502; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1506; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1510; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1514; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1515; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1624; -+import ca.spottedleaf.dataconverter.minecraft.versions.V165; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1800; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1801; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1802; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1803; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1904; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1905; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1906; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1911; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1917; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1918; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1920; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1925; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1928; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1929; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1931; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1936; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1946; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1948; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1953; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1955; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1961; -+import ca.spottedleaf.dataconverter.minecraft.versions.V1963; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2100; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2202; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2209; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2211; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2218; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2501; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2502; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2503; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2505; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2508; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2509; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2511; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2514; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2516; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2518; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2519; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2522; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2523; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2527; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2528; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2529; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2531; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2533; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2535; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2550; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2551; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2552; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2553; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2558; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2568; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2671; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2679; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2680; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2686; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2688; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2690; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2691; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2696; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2700; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2701; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2702; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2707; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2710; -+import ca.spottedleaf.dataconverter.minecraft.versions.V2717; -+import ca.spottedleaf.dataconverter.minecraft.versions.V501; -+import ca.spottedleaf.dataconverter.minecraft.versions.V502; -+import ca.spottedleaf.dataconverter.minecraft.versions.V505; -+import ca.spottedleaf.dataconverter.minecraft.versions.V700; -+import ca.spottedleaf.dataconverter.minecraft.versions.V701; -+import ca.spottedleaf.dataconverter.minecraft.versions.V702; -+import ca.spottedleaf.dataconverter.minecraft.versions.V703; -+import ca.spottedleaf.dataconverter.minecraft.versions.V704; -+import ca.spottedleaf.dataconverter.minecraft.versions.V705; -+import ca.spottedleaf.dataconverter.minecraft.versions.V804; -+import ca.spottedleaf.dataconverter.minecraft.versions.V806; -+import ca.spottedleaf.dataconverter.minecraft.versions.V808; -+import ca.spottedleaf.dataconverter.minecraft.versions.V813; -+import ca.spottedleaf.dataconverter.minecraft.versions.V816; -+import ca.spottedleaf.dataconverter.minecraft.versions.V820; -+import ca.spottedleaf.dataconverter.minecraft.versions.V99; -+ -+public final class MCTypeRegistry { -+ -+ public static final MCDataType LEVEL = new MCDataType("Level"); -+ public static final MCDataType PLAYER = new MCDataType("Player"); -+ public static final MCDataType CHUNK = new MCDataType("Chunk"); -+ public static final MCDataType HOTBAR = new MCDataType("CreativeHotbar"); -+ public static final MCDataType OPTIONS = new MCDataType("Options"); -+ public static final MCDataType STRUCTURE = new MCDataType("Structure"); -+ public static final MCDataType STATS = new MCDataType("Stats"); -+ public static final MCDataType SAVED_DATA = new MCDataType("SavedData"); -+ public static final MCDataType ADVANCEMENTS = new MCDataType("Advancements"); -+ public static final MCDataType POI_CHUNK = new MCDataType("PoiChunk"); -+ public static final MCDataType ENTITY_CHUNK = new MCDataType("EntityChunk"); -+ public static final IDDataType TILE_ENTITY = new IDDataType("TileEntity"); -+ public static final IDDataType ITEM_STACK = new IDDataType("ItemStack"); -+ public static final MCDataType BLOCK_STATE = new MCDataType("BlockState"); -+ public static final MCValueType ENTITY_NAME = new MCValueType("EntityName"); -+ public static final IDDataType ENTITY = new IDDataType("Entity"); -+ public static final MCValueType BLOCK_NAME = new MCValueType("BlockName"); -+ public static final MCValueType ITEM_NAME = new MCValueType("ItemName"); -+ public static final MCDataType UNTAGGED_SPAWNER = new MCDataType("Spawner"); -+ public static final MCDataType STRUCTURE_FEATURE = new MCDataType("StructureFeature"); -+ public static final MCDataType OBJECTIVE = new MCDataType("Objective"); -+ public static final MCDataType TEAM = new MCDataType("Team"); -+ public static final MCValueType RECIPE = new MCValueType("RecipeName"); -+ public static final MCValueType BIOME = new MCValueType("Biome"); -+ public static final MCDataType WORLD_GEN_SETTINGS = new MCDataType("WorldGenSettings"); -+ -+ static { -+ // General notes: -+ // - Structure converters run before everything. -+ // - ID specific converters run after structure converters. -+ // - Structure walkers run after id specific converters. -+ // - ID specific walkers run after structure walkers. -+ -+ V99.register(); // all legacy data before converters existed -+ V100.register(); // first version with version id -+ V101.register(); -+ V102.register(); -+ V105.register(); -+ V106.register(); -+ V107.register(); -+ V108.register(); -+ V109.register(); -+ V110.register(); -+ V111.register(); -+ V113.register(); -+ V135.register(); -+ V143.register(); -+ V147.register(); -+ V165.register(); -+ V501.register(); -+ V502.register(); -+ V505.register(); -+ V700.register(); -+ V701.register(); -+ V702.register(); -+ V703.register(); -+ V704.register(); -+ V705.register(); -+ V804.register(); -+ V806.register(); -+ V808.register(); -+ V813.register(); -+ V816.register(); -+ V820.register(); -+ V1022.register(); -+ V1125.register(); -+ // END OF LEGACY DATA CONVERTERS -+ -+ // V1.13 -+ V1344.register(); -+ V1446.register(); -+ // START THE FLATTENING -+ V1450.register(); -+ V1451.register(); -+ // END THE FLATTENING -+ -+ V1456.register(); -+ V1458.register(); -+ V1460.register(); -+ V1466.register(); -+ V1470.register(); -+ V1474.register(); -+ V1475.register(); -+ V1480.register(); -+ // V1481 is adding simple block entity -+ V1483.register(); -+ V1484.register(); -+ V1486.register(); -+ V1487.register(); -+ V1488.register(); -+ V1490.register(); -+ V1492.register(); -+ V1494.register(); -+ V1496.register(); -+ V1500.register(); -+ V1501.register(); -+ V1502.register(); -+ V1506.register(); -+ V1510.register(); -+ V1514.register(); -+ V1515.register(); -+ V1624.register(); -+ // V1.14 -+ V1800.register(); -+ V1801.register(); -+ V1802.register(); -+ V1803.register(); -+ V1904.register(); -+ V1905.register(); -+ V1906.register(); -+ // V1909 is just adding a simple block entity (jigsaw) -+ V1911.register(); -+ V1917.register(); -+ V1918.register(); -+ V1920.register(); -+ V1925.register(); -+ V1928.register(); -+ V1929.register(); -+ V1931.register(); -+ V1936.register(); -+ V1946.register(); -+ V1948.register(); -+ V1953.register(); -+ V1955.register(); -+ V1961.register(); -+ V1963.register(); -+ // V1.15 -+ V2100.register(); -+ V2202.register(); -+ V2209.register(); -+ V2211.register(); -+ V2218.register(); -+ // V1.16 -+ V2501.register(); -+ V2502.register(); -+ V2503.register(); -+ V2505.register(); -+ V2508.register(); -+ V2509.register(); -+ V2511.register(); -+ V2514.register(); -+ V2516.register(); -+ V2518.register(); -+ V2519.register(); -+ V2522.register(); -+ V2523.register(); -+ V2527.register(); -+ V2528.register(); -+ V2529.register(); -+ V2531.register(); -+ V2533.register(); -+ V2535.register(); -+ V2550.register(); -+ V2551.register(); -+ V2552.register(); -+ V2553.register(); -+ V2558.register(); -+ V2568.register(); -+ // V1.17 -+ // WARN: Mojang registers V2671 under 2571, but that version predates 1.16.5? So it looks like a typo... -+ // I changed it to 2671, just so that it's after 1.16.5, but even then this looks misplaced... Thankfully this is -+ // the first datafixer, and all it does is add a walker, so I think even if the version here is just wrong it will -+ // work. -+ V2671.register(); -+ V2679.register(); -+ V2680.register(); -+ // V2684 is registering a simple tile entity (skulk sensor) -+ V2686.register(); -+ V2688.register(); -+ V2690.register(); -+ V2691.register(); -+ V2696.register(); -+ V2700.register(); -+ V2701.register(); -+ V2702.register(); -+ // In reference to V2671, why the fuck is goat being registered again? For this obvious reason, V2704 is absent. -+ V2707.register(); -+ V2710.register(); -+ V2717.register(); -+ } -+ -+ private MCTypeRegistry() {} -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCValueType.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCValueType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c74981675118762dfe317f5f58b6fd751f59e5f2 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCValueType.java -@@ -0,0 +1,48 @@ -+package ca.spottedleaf.dataconverter.minecraft.datatypes; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataType; -+ -+import java.util.ArrayList; -+import java.util.List; -+ -+public class MCValueType extends DataType { -+ -+ protected final ArrayList> converters = new ArrayList<>(); -+ public final String name; -+ -+ public MCValueType(final String name) { -+ this.name = name; -+ } -+ -+ public void addConverter(final DataConverter converter) { -+ this.converters.add(converter); -+ this.converters.sort(DataConverter.LOWEST_VERSION_COMPARATOR); -+ } -+ -+ @Override -+ public Object convert(final Object data, final long fromVersion, final long toVersion) { -+ Object ret = null; -+ final List> converters = this.converters; -+ -+ for (int i = 0, len = converters.size(); i < len; ++i) { -+ final DataConverter converter = converters.get(i); -+ final long converterVersion = converter.getEncodedVersion(); -+ -+ if (converterVersion <= fromVersion) { -+ continue; -+ } -+ -+ if (converterVersion > toVersion) { -+ break; -+ } -+ -+ final Object converted = converter.convert(ret == null ? data : ret, fromVersion, toVersion); -+ if (converted != null) { -+ ret = converted; -+ } -+ } -+ -+ return ret; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V100.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V100.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7e8f42eb57c12c885a1c17eafab1c9d9be4d8963 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V100.java -@@ -0,0 +1,159 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.block_name.DataWalkerBlockNames; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V100 { -+ -+ protected static final int VERSION = MCVersions.V15W32A; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType equipment = data.getList("Equipment", ObjectType.MAP); -+ data.remove("Equipment"); -+ -+ if (equipment != null) { -+ if (equipment.size() > 0 && data.getListUnchecked("HandItems") == null) { -+ final ListType handItems = Types.NBT.createEmptyList(); -+ data.setList("HandItems", handItems); -+ handItems.addMap(equipment.getMap(0)); -+ handItems.addMap(Types.NBT.createEmptyMap()); -+ } -+ -+ if (equipment.size() > 1 && data.getListUnchecked("ArmorItems") == null) { -+ final ListType armorItems = Types.NBT.createEmptyList(); -+ data.setList("ArmorItems", armorItems); -+ for (int i = 1; i < Math.min(equipment.size(), 5); ++i) { -+ armorItems.addMap(equipment.getMap(i)); -+ } -+ } -+ } -+ -+ final ListType dropChances = data.getList("DropChances", ObjectType.FLOAT); -+ data.remove("DropChances"); -+ -+ if (dropChances != null) { -+ if (data.getListUnchecked("HandDropChances") == null) { -+ final ListType handDropChances = Types.NBT.createEmptyList(); -+ data.setList("HandDropChances", handDropChances); -+ if (0 < dropChances.size()) { -+ handDropChances.addFloat(dropChances.getFloat(0)); -+ } else { -+ handDropChances.addFloat(0.0F); -+ } -+ handDropChances.addFloat(0.0F); -+ } -+ -+ if (data.getListUnchecked("ArmorDropChances") == null) { -+ final ListType armorDropChances = Types.NBT.createEmptyList(); -+ data.setList("ArmorDropChances", armorDropChances); -+ for (int i = 1; i < 5; ++i) { -+ if (i < dropChances.size()) { -+ armorDropChances.addFloat(dropChances.getFloat(i)); -+ } else { -+ armorDropChances.addFloat(0.0F); -+ } -+ } -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ registerMob("ArmorStand"); -+ registerMob("Creeper"); -+ registerMob("Skeleton"); -+ registerMob("Spider"); -+ registerMob("Giant"); -+ registerMob("Zombie"); -+ registerMob("Slime"); -+ registerMob("Ghast"); -+ registerMob("PigZombie"); -+ registerMob("Enderman"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Enderman", new DataWalkerBlockNames("carried")); -+ registerMob("CaveSpider"); -+ registerMob("Silverfish"); -+ registerMob("Blaze"); -+ registerMob("LavaSlime"); -+ registerMob("EnderDragon"); -+ registerMob("WitherBoss"); -+ registerMob("Bat"); -+ registerMob("Witch"); -+ registerMob("Endermite"); -+ registerMob("Guardian"); -+ registerMob("Pig"); -+ registerMob("Sheep"); -+ registerMob("Cow"); -+ registerMob("Chicken"); -+ registerMob("Squid"); -+ registerMob("Wolf"); -+ registerMob("MushroomCow"); -+ registerMob("SnowMan"); -+ registerMob("Ozelot"); -+ registerMob("VillagerGolem"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "EntityHorse", new DataWalkerItemLists("Items", "ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "EntityHorse", new DataWalkerItems("ArmorItem", "SaddleItem")); -+ registerMob("Rabbit"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Villager", (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Inventory", fromVersion, toVersion); -+ -+ final MapType offers = data.getMap("Offers"); -+ if (offers != null) { -+ final ListType recipes = offers.getList("Recipes", ObjectType.MAP); -+ if (recipes != null) { -+ for (int i = 0, len = recipes.size(); i < len; ++i) { -+ final MapType recipe = recipes.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buy", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buyB", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "sell", fromVersion, toVersion); -+ } -+ } -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "ArmorItems", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "HandItems", fromVersion, toVersion); -+ -+ return null; -+ }); -+ registerMob("Shulker"); -+ -+ MCTypeRegistry.STRUCTURE.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final ListType entities = data.getList("entities", ObjectType.MAP); -+ if (entities != null) { -+ for (int i = 0, len = entities.size(); i < len; ++i) { -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, entities.getMap(i), "nbt", fromVersion, toVersion); -+ } -+ } -+ -+ final ListType blocks = data.getList("blocks", ObjectType.MAP); -+ if (blocks != null) { -+ for (int i = 0, len = blocks.size(); i < len; ++i) { -+ WalkerUtils.convert(MCTypeRegistry.TILE_ENTITY, blocks.getMap(i), "nbt", fromVersion, toVersion); -+ } -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_STATE, data, "palette", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ private V100() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V101.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V101.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6f2291562931b074babee711c6f8b5009bcfdc5b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V101.java -@@ -0,0 +1,72 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.gson.JsonParseException; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.chat.TextComponent; -+import net.minecraft.util.GsonHelper; -+import net.minecraft.util.datafix.fixes.BlockEntitySignTextStrictJsonFix; -+ -+public final class V101 { -+ -+ protected static final int VERSION = MCVersions.V15W32A + 1; -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("Sign", new DataConverter, MapType>(VERSION) { -+ protected void updateLine(final MapType data, final String path) { -+ final String textString = data.getString(path); -+ if (textString == null || textString.isEmpty() || "null".equals(textString)) { -+ data.setString(path, Component.Serializer.toJson(TextComponent.EMPTY)); -+ return; -+ } -+ -+ Component component = null; -+ -+ if (textString.charAt(0) == '"' && textString.charAt(textString.length() - 1) == '"' -+ || textString.charAt(0) == '{' && textString.charAt(textString.length() - 1) == '}') { -+ try { -+ component = GsonHelper.fromJson(BlockEntitySignTextStrictJsonFix.GSON, textString, Component.class, true); -+ if (component == null) { -+ component = TextComponent.EMPTY; -+ } -+ } catch (final JsonParseException ignored) {} -+ -+ if (component == null) { -+ try { -+ component = Component.Serializer.fromJson(textString); -+ } catch (final JsonParseException ignored) {} -+ } -+ -+ if (component == null) { -+ try { -+ component = Component.Serializer.fromJsonLenient(textString); -+ } catch (final JsonParseException ignored) {} -+ } -+ -+ if (component == null) { -+ component = new TextComponent(textString); -+ } -+ } else { -+ component = new TextComponent(textString); -+ } -+ -+ data.setString(path, Component.Serializer.toJson(component)); -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ this.updateLine(data, "Text1"); -+ this.updateLine(data, "Text2"); -+ this.updateLine(data, "Text3"); -+ this.updateLine(data, "Text4"); -+ return null; -+ } -+ }); -+ } -+ -+ private V101() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V102.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V102.java -new file mode 100644 -index 0000000000000000000000000000000000000000..901ab9e9a4307c02a75784b2b12f4da833b0bd38 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V102.java -@@ -0,0 +1,84 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperItemNameV102; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+ -+public final class V102 { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final int VERSION = MCVersions.V15W32A + 2; -+ -+ public static void register() { -+ // V102 -> V15W32A + 2 -+ // V102 schema only modifies ITEM_STACK to have only a string ID, but our ITEM_NAME is generic (int or String) so we don't -+ // actually need to update the walker -+ -+ MCTypeRegistry.ITEM_NAME.addConverter(new DataConverter<>(VERSION) { -+ @Override -+ public Object convert(final Object data, final long sourceVersion, final long toVersion) { -+ if (!(data instanceof Number)) { -+ return null; -+ } -+ final int id = ((Number)data).intValue(); -+ final String remap = HelperItemNameV102.getNameFromId(id); -+ return remap == null ? HelperItemNameV102.getNameFromId(0) : remap; -+ } -+ }); -+ -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!data.hasKey("id", ObjectType.NUMBER)) { -+ return null; -+ } -+ -+ final int id = data.getInt("id"); -+ -+ String remap = HelperItemNameV102.getNameFromId(id); -+ if (remap == null) { -+ LOGGER.warn("Unknown legacy integer id (V102) " + id); -+ remap = HelperItemNameV102.getNameFromId(0); -+ } -+ -+ data.setString("id", remap); -+ -+ return null; -+ } -+ }); -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:potion", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final short damage = data.getShort("Damage"); -+ if (damage != 0) { -+ data.setShort("Damage", (short)0); -+ } -+ MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ tag = Types.NBT.createEmptyMap(); -+ data.setMap("tag", tag); -+ } -+ -+ if (!tag.hasKey("Potion", ObjectType.STRING)) { -+ String converted = HelperItemNameV102.getPotionNameFromId(damage); -+ tag.setString("Potion", converted == null ? "minecraft:water" : converted); -+ if ((damage & 16384) == 16384) { -+ data.setString("id", "minecraft:splash_potion"); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V102() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1022.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1022.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e251ead28d7d90937ae5871ffac489c1161e6e87 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1022.java -@@ -0,0 +1,45 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1022 { -+ -+ protected static final int VERSION = MCVersions.V17W06A; -+ -+ public static void register() { -+ MCTypeRegistry.PLAYER.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType rootVehicle = data.getMap("RootVehicle"); -+ if (rootVehicle != null) { -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, rootVehicle, "Entity", fromVersion, toVersion); -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Inventory", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "EnderItems", fromVersion, toVersion); -+ -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, data, "ShoulderEntityLeft", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, data, "ShoulderEntityRight", fromVersion, toVersion); -+ -+ final MapType recipeBook = data.getMap("recipeBook"); -+ if (recipeBook != null) { -+ WalkerUtils.convertList(MCTypeRegistry.RECIPE, recipeBook, "recipes", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.RECIPE, recipeBook, "toBeDisplayed", fromVersion, toVersion); -+ } -+ -+ return null; -+ }); -+ -+ MCTypeRegistry.HOTBAR.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ for (final String key : data.keys()) { -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, key, fromVersion, toVersion); -+ } -+ -+ return null; -+ }); -+ } -+ -+ private V1022() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V105.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V105.java -new file mode 100644 -index 0000000000000000000000000000000000000000..544f6a54041147a8c9ee3ff52c31c480a3696924 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V105.java -@@ -0,0 +1,49 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperSpawnEggNameV105; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V105 { -+ -+ protected static final int VERSION = MCVersions.V15W32C + 1; -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:spawn_egg", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ tag = Types.NBT.createEmptyMap(); -+ } -+ -+ final short damage = data.getShort("Damage"); -+ if (damage != 0) { -+ data.setShort("Damage", (short)0); -+ } -+ -+ MapType entityTag = tag.getMap("EntityTag"); -+ if (entityTag == null) { -+ entityTag = Types.NBT.createEmptyMap(); -+ } -+ -+ if (!entityTag.hasKey("id", ObjectType.STRING)) { -+ final String converted = HelperSpawnEggNameV105.getSpawnNameFromId(damage); -+ if (converted != null) { -+ entityTag.setString("id", converted); -+ tag.setMap("EntityTag", entityTag); -+ data.setMap("tag", tag); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V105() {} -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V106.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V106.java -new file mode 100644 -index 0000000000000000000000000000000000000000..951838b0f4f2b4ed82d707706ef15d779f3f41eb ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V106.java -@@ -0,0 +1,84 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V106 { -+ -+ protected static final int VERSION = MCVersions.V15W32C + 2; -+ -+ public static void register() { -+ // V106 -> V15W32C + 2 -+ -+ MCTypeRegistry.UNTAGGED_SPAWNER.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ // While all converters for spawners check the id for this version, we don't because spawners exist in minecarts. ooops! Loading a chunk -+ // with a minecart spawner from 1.7.10 in 1.16.5 vanilla will fail to convert! Clearly there was a mistake in how they -+ // used and applied spawner converters. In anycase, do not check the id - we are not guaranteed to be a tile -+ // entity. We can be a regular old minecart spawner. And we know we are a spawner because this is only called from data walkers. -+ -+ final String entityId = data.getString("EntityId"); -+ if (entityId != null) { -+ data.remove("EntityId"); -+ MapType spawnData = data.getMap("SpawnData"); -+ if (spawnData == null) { -+ spawnData = Types.NBT.createEmptyMap(); -+ data.setMap("SpawnData", spawnData); -+ } -+ spawnData.setString("id", entityId.isEmpty() ? "Pig" : entityId); -+ } -+ -+ final ListType spawnPotentials = data.getList("SpawnPotentials", ObjectType.MAP); -+ if (spawnPotentials != null) { -+ for (int i = 0, len = spawnPotentials.size(); i < len; ++i) { -+ // convert to standard entity format (it's not a coincidence a walker for spawners is only added -+ // in this version) -+ final MapType spawn = spawnPotentials.getMap(i); -+ final String spawnType = spawn.getString("Type"); -+ if (spawnType == null) { -+ continue; -+ } -+ spawn.remove("Type"); -+ -+ MapType properties = spawn.getMap("Properties"); -+ if (properties == null) { -+ properties = Types.NBT.createEmptyMap(); -+ } else { -+ spawn.remove("Properties"); -+ } -+ -+ properties.setString("id", spawnType); -+ -+ spawn.setMap("Entity", properties); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.UNTAGGED_SPAWNER.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final ListType spawnPotentials = data.getList("SpawnPotentials", ObjectType.MAP); -+ if (spawnPotentials != null) { -+ for (int i = 0, len = spawnPotentials.size(); i < len; ++i) { -+ final MapType spawnPotential = spawnPotentials.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, spawnPotential, "Entity", fromVersion, toVersion); -+ } -+ } -+ -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, data, "SpawnData", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ private V106() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V107.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V107.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aa8c8d22ee2a77604d923b62f5a93ede9b3f333f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V107.java -@@ -0,0 +1,44 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V107 { -+ -+ protected static final int VERSION = MCVersions.V15W32C + 3; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("Minecart", new DataConverter<>(VERSION) { -+ protected final String[] MINECART_IDS = new String[] { -+ "MinecartRideable", // 0 -+ "MinecartChest", // 1 -+ "MinecartFurnace", // 2 -+ "MinecartTNT", // 3 -+ "MinecartSpawner", // 4 -+ "MinecartHopper", // 5 -+ "MinecartCommandBlock" // 6 -+ }; -+ // Vanilla does not use all of the IDs here. The legacy (pre DFU) code does, so I'm going to use them. -+ // No harm in catching more cases here. -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ String newId = "MinecartRideable"; // dfl -+ final int type = data.getInt("Type"); -+ data.remove("Type"); -+ -+ if (type >= 0 && type < MINECART_IDS.length) { -+ newId = MINECART_IDS[type]; -+ } -+ data.setString("id", newId); -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V107() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V108.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V108.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2300f4db851510cfa3b8dd704b555e12bc4ea725 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V108.java -@@ -0,0 +1,47 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import java.util.UUID; -+ -+public final class V108 { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final int VERSION = MCVersions.V15W32C + 4; -+ -+ public static void register() { -+ // Convert String UUID into UUIDMost and UUIDLeast -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String uuidString = data.getString("UUID"); -+ -+ if (uuidString == null) { -+ return null; -+ } -+ data.remove("UUID"); -+ -+ final UUID uuid; -+ try { -+ uuid = UUID.fromString(uuidString); -+ } catch (final Exception ex) { -+ LOGGER.warn("Failed to parse UUID for legacy entity (V108): " + uuidString, ex); -+ return null; -+ } -+ -+ data.setLong("UUIDMost", uuid.getMostSignificantBits()); -+ data.setLong("UUIDLeast", uuid.getLeastSignificantBits()); -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V108() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V109.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V109.java -new file mode 100644 -index 0000000000000000000000000000000000000000..70e5d7ef6d8bc7ebdd7f8aac6926c0c8386e5826 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V109.java -@@ -0,0 +1,48 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.common.collect.Sets; -+import java.util.Set; -+ -+public final class V109 { -+ -+ protected static final int VERSION = MCVersions.V15W32C + 5; -+ -+ public static void register() { -+ // Converts health to be in float, and cleans up whatever the hell was going on with HealF and Health... -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ // Vanilla declares this exact field but leaves it unused. Not sure why, legacy conversion system checked if the ID matched. -+ // I'm going to leave it here unused as well, just in case it's needed in the future. -+ private final Set ENTITIES = Sets.newHashSet(new String[]{"ArmorStand", "Bat", "Blaze", "CaveSpider", "Chicken", "Cow", "Creeper", "EnderDragon", "Enderman", "Endermite", "EntityHorse", "Ghast", "Giant", "Guardian", "LavaSlime", "MushroomCow", "Ozelot", "Pig", "PigZombie", "Rabbit", "Sheep", "Shulker", "Silverfish", "Skeleton", "Slime", "SnowMan", "Spider", "Squid", "Villager", "VillagerGolem", "Witch", "WitherBoss", "Wolf", "Zombie"}); -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final Number healF = data.getNumber("HealF"); -+ final Number heal = data.getNumber("Health"); -+ -+ final float newHealth; -+ -+ if (healF != null) { -+ data.remove("HealF"); -+ newHealth = healF.floatValue(); -+ } else { -+ if (heal == null) { -+ return null; -+ } -+ -+ newHealth = heal.floatValue(); -+ } -+ -+ data.setFloat("Health", newHealth); -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V109() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V110.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V110.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7b8e302ffc33f8ba0d62ce90d38ae48cff385ff3 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V110.java -@@ -0,0 +1,39 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V110 { -+ -+ protected static final int VERSION = MCVersions.V15W32C + 6; -+ -+ public static void register() { -+ // Moves the Saddle boolean to be an actual saddle item. Note: The data walker for the SaddleItem exists -+ // in V99, it doesn't need to be added here. -+ MCTypeRegistry.ENTITY.addConverterForId("EntityHorse", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getByte("Saddle") == 0 || data.hasKey("SaddleItem", ObjectType.MAP)) { -+ return null; -+ } -+ -+ final MapType saddleItem = Types.NBT.createEmptyMap(); -+ data.remove("Saddle"); -+ data.setMap("SaddleItem", saddleItem); -+ -+ saddleItem.setString("id", "minecraft:saddle"); -+ saddleItem.setByte("Count", (byte)1); -+ saddleItem.setShort("Damage", (short)0); -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V110() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V111.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V111.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5bae7effda7761a3f2a0a2ce550d867cb2c18b99 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V111.java -@@ -0,0 +1,67 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V111 { -+ -+ protected static final int VERSION = MCVersions.V15W33B; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("Painting", new EntityRotationFix("Painting")); -+ MCTypeRegistry.ENTITY.addConverterForId("ItemFrame", new EntityRotationFix("ItemFrame")); -+ } -+ -+ private V111() {} -+ -+ protected static final class EntityRotationFix extends DataConverter, MapType> { -+ -+ private static final int[][] DIRECTIONS = new int[][] { -+ {0, 0, 1}, -+ {-1, 0, 0}, -+ {0, 0, -1}, -+ {1, 0, 0} -+ }; -+ -+ protected final String id; -+ -+ public EntityRotationFix(final String id) { -+ super(VERSION); -+ this.id = id; -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getNumber("Facing") != null) { -+ return null; -+ } -+ -+ final Number direction = data.getNumber("Direction"); -+ final int facing; -+ if (direction != null) { -+ data.remove("Direction"); -+ facing = direction.intValue() % DIRECTIONS.length; -+ final int[] offsets = DIRECTIONS[facing]; -+ data.setInt("TileX", data.getInt("TileX") + offsets[0]); -+ data.setInt("TileY", data.getInt("TileY") + offsets[1]); -+ data.setInt("TileZ", data.getInt("TileZ") + offsets[2]); -+ if ("ItemFrame".equals(data.getString("id"))) { -+ final Number rotation = data.getNumber("ItemRotation"); -+ if (rotation != null) { -+ data.setByte("ItemRotation", (byte)(rotation.byteValue() * 2)); -+ } -+ } -+ } else { -+ facing = data.getByte("Dir") % DIRECTIONS.length; -+ data.remove("Dir"); -+ } -+ -+ data.setByte("Facing", (byte)facing); -+ -+ return null; -+ } -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1125.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1125.java -new file mode 100644 -index 0000000000000000000000000000000000000000..dfda6f0a701918fca183db9f8be92a75c60d9716 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1125.java -@@ -0,0 +1,98 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V1125 { -+ -+ protected static final int VERSION = MCVersions.V17W15A; -+ protected static final int BED_BLOCK_ID = 416; -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ final int chunkX = level.getInt("xPos"); -+ final int chunkZ = level.getInt("zPos"); -+ -+ final ListType sections = level.getList("Sections", ObjectType.MAP); -+ if (sections == null) { -+ return null; -+ } -+ -+ ListType tileEntities = level.getList("TileEntities", ObjectType.MAP); -+ if (tileEntities == null) { -+ tileEntities = Types.NBT.createEmptyList(); -+ level.setList("TileEntities", tileEntities); -+ } -+ -+ for (int i = 0, len = sections.size(); i < len; ++i) { -+ final MapType section = sections.getMap(i); -+ -+ final byte sectionY = section.getByte("Y"); -+ final byte[] blocks = section.getBytes("Blocks"); -+ -+ if (blocks == null) { -+ continue; -+ } -+ -+ for (int blockIndex = 0; blockIndex < blocks.length; ++blockIndex) { -+ if (BED_BLOCK_ID != ((blocks[blockIndex] & 255) << 4)) { -+ continue; -+ } -+ -+ final int localX = blockIndex & 15; -+ final int localZ = (blockIndex >> 4) & 15; -+ final int localY = (blockIndex >> 8) & 15; -+ -+ final MapType newTile = Types.NBT.createEmptyMap(); -+ newTile.setString("id", "minecraft:bed"); -+ newTile.setInt("x", localX + (chunkX << 4)); -+ newTile.setInt("y", localY + (sectionY << 4)); -+ newTile.setInt("z", localZ + (chunkZ << 4)); -+ newTile.setShort("color", (short)14); // Red -+ -+ tileEntities.addMap(newTile); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:bed", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getShort("Damage") == 0) { -+ data.setShort("Damage", (short)14); // Red -+ } -+ -+ return null; -+ } -+ }); -+ -+ -+ MCTypeRegistry.ADVANCEMENTS.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convertKeys(MCTypeRegistry.BIOME, data.getMap("minecraft:adventure/adventuring_time"), "criteria", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ENTITY_NAME, data.getMap("minecraft:adventure/kill_a_mob"), "criteria", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ENTITY_NAME, data.getMap("minecraft:adventure/kill_all_mobs"), "criteria", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ENTITY_NAME, data.getMap("minecraft:adventure/bred_all_animals"), "criteria", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ private V1125() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V113.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V113.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3a200fd4b31e27f23579b29ff93e82853a8cc30b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V113.java -@@ -0,0 +1,41 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V113 { -+ -+ protected static final int VERSION = MCVersions.V15W33C + 1; -+ -+ public static void register() { -+ // Removes "HandDropChances" and "ArmorDropChances" if they're empty. -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ private void checkList(final MapType data, final String id, final int requiredLength) { -+ final ListType list = data.getList(id, ObjectType.FLOAT); -+ if (list != null && list.size() == requiredLength) { -+ for (int i = 0; i < requiredLength; ++i) { -+ if (list.getFloat(i) != 0.0F) { -+ return; -+ } -+ } -+ } -+ -+ data.remove(id); -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ this.checkList(data, "HandDropChances", 2); -+ this.checkList(data, "ArmorDropChances", 4); -+ return null; -+ } -+ }); -+ } -+ -+ private V113() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1344.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1344.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ac390a6111ba1a4aae3d5726747f60f4929fa254 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1344.java -@@ -0,0 +1,177 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -+ -+public final class V1344 { -+ -+ protected static final int VERSION = MCVersions.V1_12_2 + 1; -+ -+ private static final Int2ObjectOpenHashMap BUTTON_ID_TO_NAME = new Int2ObjectOpenHashMap<>(); -+ static { -+ BUTTON_ID_TO_NAME.put(0, "key.unknown"); -+ BUTTON_ID_TO_NAME.put(11, "key.0"); -+ BUTTON_ID_TO_NAME.put(2, "key.1"); -+ BUTTON_ID_TO_NAME.put(3, "key.2"); -+ BUTTON_ID_TO_NAME.put(4, "key.3"); -+ BUTTON_ID_TO_NAME.put(5, "key.4"); -+ BUTTON_ID_TO_NAME.put(6, "key.5"); -+ BUTTON_ID_TO_NAME.put(7, "key.6"); -+ BUTTON_ID_TO_NAME.put(8, "key.7"); -+ BUTTON_ID_TO_NAME.put(9, "key.8"); -+ BUTTON_ID_TO_NAME.put(10, "key.9"); -+ BUTTON_ID_TO_NAME.put(30, "key.a"); -+ BUTTON_ID_TO_NAME.put(40, "key.apostrophe"); -+ BUTTON_ID_TO_NAME.put(48, "key.b"); -+ BUTTON_ID_TO_NAME.put(43, "key.backslash"); -+ BUTTON_ID_TO_NAME.put(14, "key.backspace"); -+ BUTTON_ID_TO_NAME.put(46, "key.c"); -+ BUTTON_ID_TO_NAME.put(58, "key.caps.lock"); -+ BUTTON_ID_TO_NAME.put(51, "key.comma"); -+ BUTTON_ID_TO_NAME.put(32, "key.d"); -+ BUTTON_ID_TO_NAME.put(211, "key.delete"); -+ BUTTON_ID_TO_NAME.put(208, "key.down"); -+ BUTTON_ID_TO_NAME.put(18, "key.e"); -+ BUTTON_ID_TO_NAME.put(207, "key.end"); -+ BUTTON_ID_TO_NAME.put(28, "key.enter"); -+ BUTTON_ID_TO_NAME.put(13, "key.equal"); -+ BUTTON_ID_TO_NAME.put(1, "key.escape"); -+ BUTTON_ID_TO_NAME.put(33, "key.f"); -+ BUTTON_ID_TO_NAME.put(59, "key.f1"); -+ BUTTON_ID_TO_NAME.put(68, "key.f10"); -+ BUTTON_ID_TO_NAME.put(87, "key.f11"); -+ BUTTON_ID_TO_NAME.put(88, "key.f12"); -+ BUTTON_ID_TO_NAME.put(100, "key.f13"); -+ BUTTON_ID_TO_NAME.put(101, "key.f14"); -+ BUTTON_ID_TO_NAME.put(102, "key.f15"); -+ BUTTON_ID_TO_NAME.put(103, "key.f16"); -+ BUTTON_ID_TO_NAME.put(104, "key.f17"); -+ BUTTON_ID_TO_NAME.put(105, "key.f18"); -+ BUTTON_ID_TO_NAME.put(113, "key.f19"); -+ BUTTON_ID_TO_NAME.put(60, "key.f2"); -+ BUTTON_ID_TO_NAME.put(61, "key.f3"); -+ BUTTON_ID_TO_NAME.put(62, "key.f4"); -+ BUTTON_ID_TO_NAME.put(63, "key.f5"); -+ BUTTON_ID_TO_NAME.put(64, "key.f6"); -+ BUTTON_ID_TO_NAME.put(65, "key.f7"); -+ BUTTON_ID_TO_NAME.put(66, "key.f8"); -+ BUTTON_ID_TO_NAME.put(67, "key.f9"); -+ BUTTON_ID_TO_NAME.put(34, "key.g"); -+ BUTTON_ID_TO_NAME.put(41, "key.grave.accent"); -+ BUTTON_ID_TO_NAME.put(35, "key.h"); -+ BUTTON_ID_TO_NAME.put(199, "key.home"); -+ BUTTON_ID_TO_NAME.put(23, "key.i"); -+ BUTTON_ID_TO_NAME.put(210, "key.insert"); -+ BUTTON_ID_TO_NAME.put(36, "key.j"); -+ BUTTON_ID_TO_NAME.put(37, "key.k"); -+ BUTTON_ID_TO_NAME.put(82, "key.keypad.0"); -+ BUTTON_ID_TO_NAME.put(79, "key.keypad.1"); -+ BUTTON_ID_TO_NAME.put(80, "key.keypad.2"); -+ BUTTON_ID_TO_NAME.put(81, "key.keypad.3"); -+ BUTTON_ID_TO_NAME.put(75, "key.keypad.4"); -+ BUTTON_ID_TO_NAME.put(76, "key.keypad.5"); -+ BUTTON_ID_TO_NAME.put(77, "key.keypad.6"); -+ BUTTON_ID_TO_NAME.put(71, "key.keypad.7"); -+ BUTTON_ID_TO_NAME.put(72, "key.keypad.8"); -+ BUTTON_ID_TO_NAME.put(73, "key.keypad.9"); -+ BUTTON_ID_TO_NAME.put(78, "key.keypad.add"); -+ BUTTON_ID_TO_NAME.put(83, "key.keypad.decimal"); -+ BUTTON_ID_TO_NAME.put(181, "key.keypad.divide"); -+ BUTTON_ID_TO_NAME.put(156, "key.keypad.enter"); -+ BUTTON_ID_TO_NAME.put(141, "key.keypad.equal"); -+ BUTTON_ID_TO_NAME.put(55, "key.keypad.multiply"); -+ BUTTON_ID_TO_NAME.put(74, "key.keypad.subtract"); -+ BUTTON_ID_TO_NAME.put(38, "key.l"); -+ BUTTON_ID_TO_NAME.put(203, "key.left"); -+ BUTTON_ID_TO_NAME.put(56, "key.left.alt"); -+ BUTTON_ID_TO_NAME.put(26, "key.left.bracket"); -+ BUTTON_ID_TO_NAME.put(29, "key.left.control"); -+ BUTTON_ID_TO_NAME.put(42, "key.left.shift"); -+ BUTTON_ID_TO_NAME.put(219, "key.left.win"); -+ BUTTON_ID_TO_NAME.put(50, "key.m"); -+ BUTTON_ID_TO_NAME.put(12, "key.minus"); -+ BUTTON_ID_TO_NAME.put(49, "key.n"); -+ BUTTON_ID_TO_NAME.put(69, "key.num.lock"); -+ BUTTON_ID_TO_NAME.put(24, "key.o"); -+ BUTTON_ID_TO_NAME.put(25, "key.p"); -+ BUTTON_ID_TO_NAME.put(209, "key.page.down"); -+ BUTTON_ID_TO_NAME.put(201, "key.page.up"); -+ BUTTON_ID_TO_NAME.put(197, "key.pause"); -+ BUTTON_ID_TO_NAME.put(52, "key.period"); -+ BUTTON_ID_TO_NAME.put(183, "key.print.screen"); -+ BUTTON_ID_TO_NAME.put(16, "key.q"); -+ BUTTON_ID_TO_NAME.put(19, "key.r"); -+ BUTTON_ID_TO_NAME.put(205, "key.right"); -+ BUTTON_ID_TO_NAME.put(184, "key.right.alt"); -+ BUTTON_ID_TO_NAME.put(27, "key.right.bracket"); -+ BUTTON_ID_TO_NAME.put(157, "key.right.control"); -+ BUTTON_ID_TO_NAME.put(54, "key.right.shift"); -+ BUTTON_ID_TO_NAME.put(220, "key.right.win"); -+ BUTTON_ID_TO_NAME.put(31, "key.s"); -+ BUTTON_ID_TO_NAME.put(70, "key.scroll.lock"); -+ BUTTON_ID_TO_NAME.put(39, "key.semicolon"); -+ BUTTON_ID_TO_NAME.put(53, "key.slash"); -+ BUTTON_ID_TO_NAME.put(57, "key.space"); -+ BUTTON_ID_TO_NAME.put(20, "key.t"); -+ BUTTON_ID_TO_NAME.put(15, "key.tab"); -+ BUTTON_ID_TO_NAME.put(22, "key.u"); -+ BUTTON_ID_TO_NAME.put(200, "key.up"); -+ BUTTON_ID_TO_NAME.put(47, "key.v"); -+ BUTTON_ID_TO_NAME.put(17, "key.w"); -+ BUTTON_ID_TO_NAME.put(45, "key.x"); -+ BUTTON_ID_TO_NAME.put(21, "key.y"); -+ BUTTON_ID_TO_NAME.put(44, "key.z"); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ for (final String key : data.keys()) { -+ if (!key.startsWith("key_")) { -+ continue; -+ } -+ final String value = data.getString(key); -+ final int code; -+ try { -+ code = Integer.parseInt(value); -+ } catch (final NumberFormatException ex) { -+ continue; -+ } -+ -+ final String newEntry; -+ -+ if (code < 0) { -+ final int mouseCode = code + 100; -+ switch (mouseCode) { -+ case 0: -+ newEntry = "key.mouse.left"; -+ break; -+ case 1: -+ newEntry = "key.mouse.right"; -+ break; -+ case 2: -+ newEntry = "key.mouse.middle"; -+ break; -+ default: -+ newEntry = "key.mouse." + (mouseCode + 1); -+ break; -+ } -+ } else { -+ newEntry = BUTTON_ID_TO_NAME.getOrDefault(code, "key.unknown"); -+ } -+ -+ // No CMEs occur for existing entries in maps. -+ data.setString(key, newEntry); -+ } -+ return null; -+ } -+ }); -+ } -+ -+ private V1344() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V135.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V135.java -new file mode 100644 -index 0000000000000000000000000000000000000000..764a56fda5ee909ac47a0c1b3b581c8c26deb591 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V135.java -@@ -0,0 +1,61 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V135 { -+ -+ protected static final int VERSION = MCVersions.V15W40B + 1; -+ -+ public static void register() { -+ // In this update they changed the "Riding" value to be "Passengers", which is now a list. So it added -+ // support for multiple entities riding. Of course, Riding and Passenger are opposites - so it also will -+ // switch the data layout to be from highest rider to lowest rider, in terms of depth. -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(MapType data, final long sourceVersion, final long toVersion) { -+ MapType ret = null; -+ while (data.hasKey("Riding", ObjectType.MAP)) { -+ final MapType riding = data.getMap("Riding"); -+ data.remove("Riding"); -+ -+ final ListType passengers = Types.NBT.createEmptyList(); -+ riding.setList("Passengers", passengers); -+ passengers.addMap(data); -+ -+ ret = data = riding; -+ } -+ -+ return ret; -+ } -+ }); -+ -+ -+ MCTypeRegistry.PLAYER.addStructureWalker(VERSION, new DataWalkerItemLists("Inventory", "EnderItems")); -+ MCTypeRegistry.PLAYER.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType rootVehicle = data.getMap("RootVehicle"); -+ if (rootVehicle != null) { -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, rootVehicle, "Entity", fromVersion, toVersion); -+ } -+ -+ return null; -+ }); -+ -+ MCTypeRegistry.ENTITY.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convertList(MCTypeRegistry.ENTITY, data, "Passengers", fromVersion, toVersion); -+ -+ return null; -+ }); -+ -+ } -+ -+ private V135() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V143.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V143.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f76b5dbb09a1a5547363d54b57e934e962d2bed3 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V143.java -@@ -0,0 +1,26 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V143 { -+ -+ protected static final int VERSION = MCVersions.V15W44B; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("TippedArrow", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ data.setString("id", "Arrow"); -+ return null; -+ } -+ }); -+ } -+ -+ private V143() { -+ -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1446.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1446.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fc0ece569baed94bbf3cbbaa21a397fdc37e51e8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1446.java -@@ -0,0 +1,36 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1446 { -+ -+ protected static final int VERSION = MCVersions.V17W43B + 1; -+ -+ public static void register() { -+ MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ for (final String key : data.keys()) { -+ if (!key.startsWith("key_")) { -+ continue; -+ } -+ -+ final String value = data.getString(key); -+ -+ if (value.startsWith("key.mouse") || value.startsWith("scancode.")) { -+ continue; -+ } -+ -+ data.setString(key, "key.keyboard." + value.substring("key.".length())); -+ } -+ return null; -+ } -+ }); -+ } -+ -+ private V1446() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1450.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1450.java -new file mode 100644 -index 0000000000000000000000000000000000000000..711222cd33ee557b7f3d1f6ae73ad45d1caf6768 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1450.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperBlockFlatteningV1450; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1450 { -+ -+ protected static final int VERSION = MCVersions.V17W46A + 1; -+ -+ public static void register() { -+ MCTypeRegistry.BLOCK_STATE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType ret = HelperBlockFlatteningV1450.flattenNBT(data); -+ return ret == data ? null : ret.copy(); // copy to avoid problems with later state datafixers -+ } -+ }); -+ } -+ -+ private V1450() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1451.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1451.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a5525eb9ecd957d405bedb18c2119e471d689993 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1451.java -@@ -0,0 +1,510 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataHook; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.chunk.ConverterFlattenChunk; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperBlockFlatteningV1450; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperItemNameV102; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemstack.ConverterFlattenItemStack; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemstack.ConverterFlattenSpawnEgg; -+import ca.spottedleaf.dataconverter.minecraft.converters.stats.ConverterFlattenStats; -+import ca.spottedleaf.dataconverter.minecraft.converters.tileentity.ConverterFlattenTileEntity; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerTypePaths; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.minecraft.walkers.tile_entity.DataWalkerTileEntities; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.google.common.base.Splitter; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.util.datafix.fixes.BlockStateData; -+import net.minecraft.util.datafix.fixes.EntityBlockStateFix; -+import net.minecraft.util.datafix.schemas.NamespacedSchema; -+import org.apache.commons.lang3.math.NumberUtils; -+import java.util.Iterator; -+import java.util.List; -+import java.util.stream.Collectors; -+import java.util.stream.StreamSupport; -+ -+public final class V1451 { -+ -+ protected static final int VERSION = MCVersions.V17W47A; -+ -+ public static void register() { -+ // V0 -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, 0, "minecraft:trapped_chest", new DataWalkerItemLists("Items")); -+ -+ // V1 -+ MCTypeRegistry.CHUNK.addStructureConverter(new ConverterFlattenChunk()); -+ -+ MCTypeRegistry.CHUNK.addStructureWalker(VERSION, 1, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ENTITY, level, "Entities", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.TILE_ENTITY, level, "TileEntities", fromVersion, toVersion); -+ -+ final ListType tileTicks = level.getList("TileTicks", ObjectType.MAP); -+ if (tileTicks != null) { -+ for (int i = 0, len = tileTicks.size(); i < len; ++i) { -+ final MapType tileTick = tileTicks.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, tileTick, "i", fromVersion, toVersion); -+ } -+ } -+ -+ final ListType sections = level.getList("Sections", ObjectType.MAP); -+ if (sections != null) { -+ for (int i = 0, len = sections.size(); i < len; ++i) { -+ final MapType section = sections.getMap(i); -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_STATE, section, "Palette", fromVersion, toVersion); -+ } -+ } -+ -+ return null; -+ }); -+ -+ // V2 -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:piston", new DataConverter<>(VERSION, 2) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int blockId = data.getInt("blockId"); -+ final int blockData = data.getInt("blockData") & 15; -+ -+ data.remove("blockId"); -+ data.remove("blockData"); -+ -+ data.setMap("blockState", HelperBlockFlatteningV1450.getNBTForId((blockId << 4) | blockData).copy()); // copy to avoid problems with later state datafixers -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, 2, "minecraft:piston", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "blockState")); -+ -+ // V3 -+ ConverterFlattenTileEntity.register(); -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:filled_map", new DataConverter<>(VERSION, 3) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ tag = Types.NBT.createEmptyMap(); -+ data.setMap("tag", tag); -+ } -+ -+ if (!tag.hasKey("map", ObjectType.NUMBER)) { // This if is from CB. as usual, no documentation from CB. I'm guessing it just wants to avoid possibly overwriting it. seems fine. -+ tag.setInt("map", data.getInt("Damage")); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:potion", new DataWalkerItems("Potion")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:arrow", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "inBlockState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:enderman", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:enderman", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "carriedBlockState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:falling_block", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "BlockState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:falling_block", new DataWalkerTileEntities("TileEntityData")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:spectral_arrow", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "inBlockState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:chest_minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:chest_minecart", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:commandblock_minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:furnace_minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:hopper_minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:hopper_minecart", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:spawner_minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:spawner_minecart", MCTypeRegistry.UNTAGGED_SPAWNER::convert); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, 3, "minecraft:tnt_minecart", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "DisplayState")); -+ -+ // V4 -+ MCTypeRegistry.BLOCK_NAME.addConverter(new DataConverter<>(VERSION, 4) { -+ @Override -+ public Object convert(final Object data, final long sourceVersion, final long toVersion) { -+ if (data instanceof Number) { -+ return HelperBlockFlatteningV1450.getNameForId(((Number)data).intValue()); -+ } else if (data instanceof String) { -+ return HelperBlockFlatteningV1450.getNewBlockName(NamespacedSchema.ensureNamespaced((String)data)); -+ } -+ return null; -+ } -+ }); -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new ConverterFlattenItemStack()); -+ -+ // V5 -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:spawn_egg", new ConverterFlattenSpawnEgg()); -+ /* This datafixer has been disabled because the collar colour handler did not change from 1.12 -> 1.13 at all. -+ // So clearly somebody fucked up. This fixes wolf colours incorrectly converting between versions -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:wolf", new DataConverter<>(VERSION, 5) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final Number colour = data.getNumber("CollarColor"); -+ -+ if (colour != null) { -+ data.setByte("CollarColor", (byte)(15 - colour.intValue())); -+ } -+ -+ return null; -+ } -+ }); -+ */ -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:banner", new DataConverter<>(VERSION, 5) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final Number base = data.getNumber("Base"); -+ if (base != null) { -+ data.setInt("Base", 15 - base.intValue()); -+ } -+ -+ final ListType patterns = data.getList("Patterns", ObjectType.MAP); -+ if (patterns != null) { -+ for (int i = 0, len = patterns.size(); i < len; ++i) { -+ final MapType pattern = patterns.getMap(i); -+ final Number colour = pattern.getNumber("Color"); -+ if (colour != null) { -+ pattern.setInt("Color", 15 - colour.intValue()); -+ } -+ } -+ } -+ -+ return null; -+ } -+ }); -+ MCTypeRegistry.LEVEL.addStructureConverter(new DataConverter<>(VERSION, 5) { -+ private final Splitter SPLITTER = Splitter.on(';').limit(5); -+ private final Splitter LAYER_SPLITTER = Splitter.on(','); -+ private final Splitter OLD_AMOUNT_SPLITTER = Splitter.on('x').limit(2); -+ private final Splitter AMOUNT_SPLITTER = Splitter.on('*').limit(2); -+ private final Splitter BLOCK_SPLITTER = Splitter.on(':').limit(3); -+ -+ // idk man i just copy and pasted this one -+ private String fixGeneratorSettings(final String generatorSettings) { -+ if (generatorSettings.isEmpty()) { -+ return "minecraft:bedrock,2*minecraft:dirt,minecraft:grass_block;1;village"; -+ } else { -+ Iterator iterator = SPLITTER.split(generatorSettings).iterator(); -+ String string2 = (String)iterator.next(); -+ int j; -+ String string4; -+ if (iterator.hasNext()) { -+ j = NumberUtils.toInt(string2, 0); -+ string4 = (String)iterator.next(); -+ } else { -+ j = 0; -+ string4 = string2; -+ } -+ -+ if (j >= 0 && j <= 3) { -+ StringBuilder stringBuilder = new StringBuilder(); -+ Splitter splitter = j < 3 ? OLD_AMOUNT_SPLITTER : AMOUNT_SPLITTER; -+ stringBuilder.append((String) StreamSupport.stream(LAYER_SPLITTER.split(string4).spliterator(), false).map((stringx) -> { -+ List list = splitter.splitToList(stringx); -+ int k; -+ String string3; -+ if (list.size() == 2) { -+ k = NumberUtils.toInt((String)list.get(0)); -+ string3 = (String)list.get(1); -+ } else { -+ k = 1; -+ string3 = (String)list.get(0); -+ } -+ -+ List list2 = BLOCK_SPLITTER.splitToList(string3); -+ int l = ((String)list2.get(0)).equals("minecraft") ? 1 : 0; -+ String string5 = (String)list2.get(l); -+ int m = j == 3 ? EntityBlockStateFix.getBlockId("minecraft:" + string5) : NumberUtils.toInt(string5, 0); -+ int n = l + 1; -+ int o = list2.size() > n ? NumberUtils.toInt((String)list2.get(n), 0) : 0; -+ return (k == 1 ? "" : k + "*") + BlockStateData.getTag(m << 4 | o).get("Name").asString(""); -+ }).collect(Collectors.joining(","))); -+ -+ while(iterator.hasNext()) { -+ stringBuilder.append(';').append((String)iterator.next()); -+ } -+ -+ return stringBuilder.toString(); -+ } else { -+ return "minecraft:bedrock,2*minecraft:dirt,minecraft:grass_block;1;village"; -+ } -+ } -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!"flat".equalsIgnoreCase(data.getString("generatorName"))) { -+ return null; -+ } -+ -+ final String generatorOptions = data.getString("generatorOptions"); -+ if (generatorOptions == null) { -+ return null; -+ } -+ -+ data.setString("generatorOptions", this.fixGeneratorSettings(generatorOptions)); -+ -+ return null; -+ } -+ }); -+ -+ // V6 -+ MCTypeRegistry.STATS.addStructureConverter(new ConverterFlattenStats()); -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:jukebox", new DataConverter<>(VERSION, 6) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int record = data.getInt("Record"); -+ if (record <= 0) { -+ return null; -+ } -+ -+ data.remove("Record"); -+ -+ final String newItemId = ConverterFlattenItemStack.flattenItem(HelperItemNameV102.getNameFromId(record), 0); -+ if (newItemId == null) { -+ return null; -+ } -+ -+ final MapType recordItem = Types.NBT.createEmptyMap(); -+ recordItem.setString("id", newItemId); -+ recordItem.setByte("Count", (byte)1); -+ -+ data.setMap("RecordItem", recordItem); -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.STATS.addStructureWalker(VERSION, 6, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType stats = data.getMap("stats"); -+ if (stats == null) { -+ return null; -+ } -+ -+ WalkerUtils.convertKeys(MCTypeRegistry.BLOCK_NAME, stats, "minecraft:mined", fromVersion, toVersion); -+ -+ WalkerUtils.convertKeys(MCTypeRegistry.ITEM_NAME, stats, "minecraft:crafted", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ITEM_NAME, stats, "minecraft:used", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ITEM_NAME, stats, "minecraft:broken", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ITEM_NAME, stats, "minecraft:picked_up", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ITEM_NAME, stats, "minecraft:dropped", fromVersion, toVersion); -+ -+ WalkerUtils.convertKeys(MCTypeRegistry.ENTITY_NAME, stats, "minecraft:killed", fromVersion, toVersion); -+ WalkerUtils.convertKeys(MCTypeRegistry.ENTITY_NAME, stats, "minecraft:killed_by", fromVersion, toVersion); -+ -+ return null; -+ }); -+ -+ MCTypeRegistry.OBJECTIVE.addStructureHook(VERSION, 6, new DataHook<>() { -+ private static String packWithDot(final String string) { -+ final ResourceLocation resourceLocation = ResourceLocation.tryParse(string); -+ return resourceLocation != null ? resourceLocation.getNamespace() + "." + resourceLocation.getPath() : string; -+ } -+ -+ @Override -+ public MapType preHook(final MapType data, final long fromVersion, final long toVersion) { -+ // unpack -+ final String criteriaName = data.getString("CriteriaName"); -+ String type; -+ String id; -+ -+ if (criteriaName != null) { -+ final int index = criteriaName.indexOf(':'); -+ if (index < 0) { -+ type = "_special"; -+ id = criteriaName; -+ } else { -+ try { -+ type = ResourceLocation.of(criteriaName.substring(0, index), '.').toString(); -+ id = ResourceLocation.of(criteriaName.substring(index + 1), '.').toString(); -+ } catch (final Exception ex) { -+ type = "_special"; -+ id = criteriaName; -+ } -+ } -+ } else { -+ type = null; -+ id = null; -+ } -+ -+ if (type != null && id != null) { -+ final MapType criteriaType = Types.NBT.createEmptyMap(); -+ data.setMap("CriteriaType", criteriaType); -+ -+ criteriaType.setString("type", type); -+ criteriaType.setString("id", id); -+ } -+ -+ return null; -+ } -+ -+ @Override -+ public MapType postHook(final MapType data, final long fromVersion, final long toVersion) { -+ // repack -+ final MapType criteriaType = data.getMap("CriteriaType"); -+ -+ final String newName; -+ if (criteriaType == null) { -+ newName = null; -+ } else { -+ final String type = criteriaType.getString("type"); -+ final String id = criteriaType.getString("id"); -+ if (type != null && id != null) { -+ if ("_special".equals(type)) { -+ newName = id; -+ } else { -+ newName = packWithDot(type) + ":" + packWithDot(id); -+ } -+ } else { -+ newName = null; -+ } -+ } -+ -+ if (newName != null) { -+ data.remove("CriteriaType"); -+ data.setString("CriteriaName", newName); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.OBJECTIVE.addStructureWalker(VERSION, 6, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType criteriaType = data.getMap("CriteriaType"); -+ if (criteriaType == null) { -+ return null; -+ } -+ -+ final String type = criteriaType.getString("type"); -+ -+ if (type == null) { -+ return null; -+ } -+ -+ switch (type) { -+ case "minecraft:mined": { -+ WalkerUtils.convert(MCTypeRegistry.ITEM_NAME, criteriaType, "id", fromVersion, toVersion); -+ break; -+ } -+ -+ case "minecraft:crafted": -+ case "minecraft:used": -+ case "minecraft:broken": -+ case "minecraft:picked_up": -+ case "minecraft:dropped": { -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, criteriaType, "id", fromVersion, toVersion); -+ break; -+ } -+ -+ case "minecraft:killed": -+ case "minecraft:killed_by": { -+ WalkerUtils.convert(MCTypeRegistry.ENTITY_NAME, criteriaType, "id", fromVersion, toVersion); -+ break; -+ } -+ } -+ -+ return null; -+ }); -+ -+ -+ // V7 -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureConverter(new DataConverter<>(VERSION, 7) { -+ private void convertToBlockState(final MapType data, final String path) { -+ final Number number = data.getNumber(path); -+ if (number == null) { -+ return; -+ } -+ -+ data.setMap(path, HelperBlockFlatteningV1450.getNBTForId(number.intValue() << 4).copy()); // copy to avoid problems with later state datafixers -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType children = data.getList("Children", ObjectType.MAP); -+ if (children == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = children.size(); i < len; ++i) { -+ final MapType child = children.getMap(i); -+ -+ final String id = child.getString("id"); -+ -+ switch (id) { -+ case "ViF": -+ this.convertToBlockState(child, "CA"); -+ this.convertToBlockState(child, "CB"); -+ break; -+ case "ViDF": -+ this.convertToBlockState(child, "CA"); -+ this.convertToBlockState(child, "CB"); -+ this.convertToBlockState(child, "CC"); -+ this.convertToBlockState(child, "CD"); -+ break; -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ // convert villagers to trade with pumpkins and not the carved pumpkin -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", new DataConverter<>(VERSION, 7) { -+ private void convertPumpkin(final MapType data, final String path) { -+ final MapType item = data.getMap(path); -+ if (item == null) { -+ return; -+ } -+ -+ final String id = item.getString("id"); -+ -+ if (id.equals("minecraft:carved_pumpkin")) { -+ item.setString("id", "minecraft:pumpkin"); -+ } -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType offers = data.getMap("Offers"); -+ if (offers != null) { -+ final ListType recipes = offers.getList("Recipes", ObjectType.MAP); -+ if (recipes != null) { -+ for (int i = 0, len = recipes.size(); i < len; ++i) { -+ final MapType recipe = recipes.getMap(i); -+ -+ this.convertPumpkin(recipe, "buy"); -+ this.convertPumpkin(recipe, "buyB"); -+ this.convertPumpkin(recipe, "sell"); -+ } -+ } -+ } -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureWalker(VERSION, 7, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final ListType list = data.getList("Children", ObjectType.MAP); -+ if (list == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ final MapType child = list.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CA", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CB", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CC", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CD", fromVersion, toVersion); -+ } -+ -+ return null; -+ }); -+ } -+ -+ private V1451() {} -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1456.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1456.java -new file mode 100644 -index 0000000000000000000000000000000000000000..059ff11a4f41fb01638f400035809833c65cb771 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1456.java -@@ -0,0 +1,38 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1456 { -+ -+ protected static final int VERSION = MCVersions.V17W49B + 1; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:item_frame", new DataConverter<>(VERSION) { -+ private byte direction2dTo3d(final byte old) { -+ switch(old) { -+ case 0: -+ return 3; -+ case 1: -+ return 4; -+ case 2: -+ default: -+ return 2; -+ case 3: -+ return 5; -+ } -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ data.setByte("Facing", this.direction2dTo3d(data.getByte("Facing"))); -+ return null; -+ } -+ }); -+ } -+ -+ private V1456() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1458.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1458.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c247eb056fb168c6d096e45f2c92005b0dddd992 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1458.java -@@ -0,0 +1,92 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.chat.TextComponent; -+import net.minecraft.network.chat.TranslatableComponent; -+ -+public final class V1458 { -+ -+ protected static final int VERSION = MCVersions.V17W50A + 1; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if ("minecraft:commandblock_minecart".equals(data.getString("id"))) { -+ return null; -+ } -+ -+ final String customName = data.getString("CustomName"); -+ if (customName == null) { -+ return null; -+ } -+ -+ if (customName.isEmpty()) { -+ data.remove("CustomName"); -+ } else { -+ data.setString("CustomName", Component.Serializer.toJson(new TextComponent(customName))); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final MapType display = tag.getMap("display"); -+ if (display == null) { -+ return null; -+ } -+ -+ final String name = display.getString("Name"); -+ if (name != null) { -+ display.setString("Name", Component.Serializer.toJson(new TextComponent(name))); -+ } else { -+ final String localisedName = display.getString("LocName"); -+ if (localisedName != null) { -+ display.setString("Name", Component.Serializer.toJson(new TranslatableComponent(localisedName))); -+ display.remove("LocName"); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.TILE_ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if ("minecraft:command_block".equals(data.getString("id"))) { -+ return null; -+ } -+ -+ final String customName = data.getString("CustomName"); -+ if (customName == null) { -+ return null; -+ } -+ -+ if (customName.isEmpty()) { -+ data.remove("CustomName"); -+ } else { -+ data.setString("CustomName", Component.Serializer.toJson(new TextComponent(customName))); -+ } -+ -+ return null; -+ } -+ }); -+ -+ } -+ -+ private V1458() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1460.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1460.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f68b561b2bb750d5f632f17e538337fa38108472 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1460.java -@@ -0,0 +1,53 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.block_name.DataWalkerBlockNames; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+import net.minecraft.resources.ResourceLocation; -+import java.util.HashMap; -+import java.util.Locale; -+import java.util.Map; -+ -+public final class V1460 { -+ -+ private static final Map MOTIVE_REMAP = new HashMap<>(); -+ -+ static { -+ MOTIVE_REMAP.put("donkeykong", "donkey_kong"); -+ MOTIVE_REMAP.put("burningskull", "burning_skull"); -+ MOTIVE_REMAP.put("skullandroses", "skull_and_roses"); -+ }; -+ -+ protected static final int VERSION = MCVersions.V18W01A + 1; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ private static void registerThrowableProjectile(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerBlockNames("inTile")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:painting", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ String motive = data.getString("Motive"); -+ if (motive != null) { -+ motive = motive.toLowerCase(Locale.ROOT); -+ data.setString("Motive", new ResourceLocation(MOTIVE_REMAP.getOrDefault(motive, motive)).toString()); -+ } -+ return null; -+ } -+ }); -+ -+ // No idea why so many type redefines exist here in Vanilla. nothing about the data structure changed, it's literally a copy of -+ // the existing types. -+ } -+ -+ private V1460() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1466.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1466.java -new file mode 100644 -index 0000000000000000000000000000000000000000..25a221142aa2653c7d6b84fb0bf8aebd6f818624 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1466.java -@@ -0,0 +1,143 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V1466 { -+ -+ protected static final int VERSION = MCVersions.V18W06A; -+ -+ private static short packOffsetCoordinates(final int x, final int y, final int z) { -+ return (short)((x & 15) | ((y & 15) << 4) | ((z & 15) << 8)); -+ } -+ -+ public static void register() { -+ // There is a rather critical change I've made to this converter: changing the chunk status determination. -+ // In Vanilla, this is determined by whether the terrain has been populated and whether the chunk is lit. -+ // For reference, here is the full status progression (at the time of 18w06a): -+ // empty -> base -> carved -> decorated -> lighted -> mobs_spawned -> finalized -> fullchunk -> postprocessed -+ // So one of those must be picked. -+ // If the chunk is lit and terrain is populated, the Vanilla converter will set the status to "mobs_spawned." -+ // If it is anything else, it will be "empty" -+ // I've changed it to the following: if terrain is populated, it is set to at least decorated. If it is populated -+ // and lit, it is set to "mobs_spawned" -+ // But what if it is not populated? If it is not populated, ignore the lit field - obviously that's just broken. -+ // It can't be lit and not populated. -+ // Let's take a look at chunk generation logic for a chunk that is not populated, or even near a populated chunk. -+ // It actually will generate a chunk up to the "carved" stage. It generates the base terrain, (i.e using noise -+ // to figure out where stone is, dirt, grass) and it will generate caves. Nothing else though. No populators. -+ // So "carved" is the correct stage to use, not empty. Setting it to empty would clobber chunk data, when we don't -+ // need to. If it is populated, at least set it to decorated. If it is lit and populated, set it to mobs_spawned. Else, -+ // it is carved. -+ // This change also fixes the random light check "bug" (really this is Mojang's fault for fucking up the status conversion here) -+ // caused by spigot, which would not set the lit value for some chunks. Now those chunks will not be regenerated. -+ -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ final boolean terrainPopulated = level.getBoolean("TerrainPopulated"); -+ final boolean lightPopulated = level.getBoolean("LightPopulated") || level.getNumber("LightPopulated") != null; -+ final String newStatus = !terrainPopulated ? "carved" : (lightPopulated ? "mobs_spawned" : "decorated"); -+ -+ level.setString("Status", newStatus); -+ level.setBoolean("hasLegacyStructureData", true); -+ -+ // convert biome byte[] into int[] -+ final byte[] biomes = level.getBytes("Biomes"); -+ if (biomes != null) { -+ final int[] newBiomes = new int[256]; -+ for (int i = 0, len = Math.min(newBiomes.length, biomes.length); i < len; ++i) { -+ newBiomes[i] = biomes[i] & 255; -+ } -+ level.setInts("Biomes", newBiomes); -+ } -+ -+ // ProtoChunks have their own dedicated tick list, so we must convert the TileTicks to that. -+ final ListType ticks = level.getList("TileTicks", ObjectType.MAP); -+ if (ticks != null) { -+ final ListType sections = Types.NBT.createEmptyList(); -+ final ListType[] sectionAccess = new ListType[16]; -+ for (int i = 0; i < sectionAccess.length; ++i) { -+ sections.addList(sectionAccess[i] = Types.NBT.createEmptyList()); -+ } -+ level.setList("ToBeTicked", sections); -+ -+ for (int i = 0, len = ticks.size(); i < len; ++i) { -+ final MapType tick = ticks.getMap(i); -+ -+ final int x = tick.getInt("x"); -+ final int y = tick.getInt("y"); -+ final int z = tick.getInt("z"); -+ final short coordinate = packOffsetCoordinates(x, y, z); -+ -+ sectionAccess[y >> 4].addShort(coordinate); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ -+ MCTypeRegistry.CHUNK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ENTITY, level, "Entities", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.TILE_ENTITY, level, "TileEntities", fromVersion, toVersion); -+ -+ final ListType tileTicks = level.getList("TileTicks", ObjectType.MAP); -+ if (tileTicks != null) { -+ for (int i = 0, len = tileTicks.size(); i < len; ++i) { -+ final MapType tileTick = tileTicks.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, tileTick, "i", fromVersion, toVersion); -+ } -+ } -+ -+ final ListType sections = level.getList("Sections", ObjectType.MAP); -+ if (sections != null) { -+ for (int i = 0, len = sections.size(); i < len; ++i) { -+ final MapType section = sections.getMap(i); -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_STATE, section, "Palette", fromVersion, toVersion); -+ } -+ } -+ -+ WalkerUtils.convertValues(MCTypeRegistry.STRUCTURE_FEATURE, level.getMap("Structures"), "Starts", fromVersion, toVersion); -+ -+ return null; -+ }); -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final ListType list = data.getList("Children", ObjectType.MAP); -+ if (list != null) { -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ final MapType child = list.getMap(i); -+ -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CA", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CB", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CC", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_STATE, child, "CD", fromVersion, toVersion); -+ } -+ } -+ -+ WalkerUtils.convert(MCTypeRegistry.BIOME, data, "biome", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ private V1466() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V147.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V147.java -new file mode 100644 -index 0000000000000000000000000000000000000000..68dd3ce7709a998bc50a5080fe9c805b71a88365 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V147.java -@@ -0,0 +1,27 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V147 { -+ -+ protected static final int VERSION = MCVersions.V15W46A + 1; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("ArmorStand", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getBoolean("Silent") && !data.getBoolean("Marker")) { -+ data.remove("Silent"); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V147() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1470.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1470.java -new file mode 100644 -index 0000000000000000000000000000000000000000..669509286b18a173826938bae347c1aefffeed51 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1470.java -@@ -0,0 +1,31 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerTypePaths; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V1470 { -+ -+ protected static final int VERSION = MCVersions.V18W08A; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:turtle"); -+ registerMob("minecraft:cod_mob"); -+ registerMob("minecraft:tropical_fish"); -+ registerMob("minecraft:salmon_mob"); -+ registerMob("minecraft:puffer_fish"); -+ registerMob("minecraft:phantom"); -+ registerMob("minecraft:dolphin"); -+ registerMob("minecraft:drowned"); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:trident", new DataWalkerTypePaths<>(MCTypeRegistry.BLOCK_STATE, "inBlockState")); -+ } -+ -+ private V1470() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1474.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1474.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4883d416a96d30d68871e65644fe5053c5b7d8b8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1474.java -@@ -0,0 +1,35 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1474 { -+ -+ protected static final int VERSION = MCVersions.V18W10B; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:shulker", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getInt("Color") == 10) { -+ data.setByte("Color", (byte)16); -+ } -+ return null; -+ } -+ }); -+ ConverterAbstractBlockRename.register(VERSION, (final String old) -> { -+ return "minecraft:purple_shulker_box".equals(old) ? "minecraft:shulker_box" : null; -+ }); -+ ConverterAbstractItemRename.register(VERSION, (final String old) -> { -+ return "minecraft:purple_shulker_box".equals(old) ? "minecraft:shulker_box" : null; -+ }); -+ -+ } -+ -+ private V1474() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1475.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1475.java -new file mode 100644 -index 0000000000000000000000000000000000000000..40b64efb8717b2de0ff13af87bcc99119c9f7c9d ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1475.java -@@ -0,0 +1,21 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V1475 { -+ -+ protected static final int VERSION = MCVersions.V18W10B + 1; -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, -+ ImmutableMap.of( -+ "minecraft:flowing_water", "minecraft:water", -+ "minecraft:flowing_lava", "minecraft:lava" -+ )::get); -+ } -+ -+ private V1475() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1480.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1480.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e5373d4e6ca027749f634e9a508bd81b9b41ed3e ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1480.java -@@ -0,0 +1,42 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1480 { -+ -+ protected static final int VERSION = MCVersions.V18W14A + 1; -+ -+ public static final Map RENAMED_IDS = ImmutableMap.builder() -+ .put("minecraft:blue_coral", "minecraft:tube_coral_block") -+ .put("minecraft:pink_coral", "minecraft:brain_coral_block") -+ .put("minecraft:purple_coral", "minecraft:bubble_coral_block") -+ .put("minecraft:red_coral", "minecraft:fire_coral_block") -+ .put("minecraft:yellow_coral", "minecraft:horn_coral_block") -+ .put("minecraft:blue_coral_plant", "minecraft:tube_coral") -+ .put("minecraft:pink_coral_plant", "minecraft:brain_coral") -+ .put("minecraft:purple_coral_plant", "minecraft:bubble_coral") -+ .put("minecraft:red_coral_plant", "minecraft:fire_coral") -+ .put("minecraft:yellow_coral_plant", "minecraft:horn_coral") -+ .put("minecraft:blue_coral_fan", "minecraft:tube_coral_fan") -+ .put("minecraft:pink_coral_fan", "minecraft:brain_coral_fan") -+ .put("minecraft:purple_coral_fan", "minecraft:bubble_coral_fan") -+ .put("minecraft:red_coral_fan", "minecraft:fire_coral_fan") -+ .put("minecraft:yellow_coral_fan", "minecraft:horn_coral_fan") -+ .put("minecraft:blue_dead_coral", "minecraft:dead_tube_coral") -+ .put("minecraft:pink_dead_coral", "minecraft:dead_brain_coral") -+ .put("minecraft:purple_dead_coral", "minecraft:dead_bubble_coral") -+ .put("minecraft:red_dead_coral", "minecraft:dead_fire_coral") -+ .put("minecraft:yellow_dead_coral", "minecraft:dead_horn_coral") -+ .build(); -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, RENAMED_IDS::get); -+ ConverterAbstractItemRename.register(VERSION, RENAMED_IDS::get); -+ } -+ -+ private V1480() {} -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1483.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1483.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9437c6855427d96042a234d2724093a16e1b4030 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1483.java -@@ -0,0 +1,31 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.entity.ConverterAbstractEntityRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V1483 { -+ -+ protected static final int VERSION = MCVersions.V18W16A; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ ConverterAbstractEntityRename.register(VERSION, ImmutableMap.of( -+ "minecraft:puffer_fish", "minecraft:pufferfish" -+ )::get); -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:puffer_fish_spawn_egg", "minecraft:pufferfish_spawn_egg" -+ )::get); -+ -+ registerMob("minecraft:pufferfish"); -+ } -+ -+ private V1483() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1484.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1484.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f5b9c166304930e095bfc00e8f6b93edb706df48 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1484.java -@@ -0,0 +1,73 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1484 { -+ -+ protected static final int VERSION = MCVersions.V18W19A; -+ -+ public static void register() { -+ final Map renamed = ImmutableMap.of( -+ "minecraft:sea_grass", "minecraft:seagrass", -+ "minecraft:tall_sea_grass", "minecraft:tall_seagrass" -+ ); -+ -+ ConverterAbstractItemRename.register(VERSION, renamed::get); -+ ConverterAbstractBlockRename.register(VERSION, renamed::get); -+ -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ -+ if (level == null) { -+ return null; -+ } -+ -+ final MapType heightmaps = level.getMap("Heightmaps"); -+ -+ if (heightmaps == null) { -+ return null; -+ } -+ -+ final Object liquid = heightmaps.getGeneric("LIQUID"); -+ if (liquid != null) { -+ heightmaps.remove("LIQUID"); -+ heightmaps.setGeneric("WORLD_SURFACE_WG", liquid); -+ } -+ -+ final Object solid = heightmaps.getGeneric("SOLID"); -+ if (solid != null) { -+ heightmaps.remove("SOLID"); -+ heightmaps.setGeneric("OCEAN_FLOOR_WG", solid); -+ heightmaps.setGeneric("OCEAN_FLOOR", solid); -+ } -+ -+ final Object light = heightmaps.getGeneric("LIGHT"); -+ if (light != null) { -+ heightmaps.remove("LIGHT"); -+ heightmaps.setGeneric("LIGHT_BLOCKING", light); -+ } -+ -+ final Object rain = heightmaps.getGeneric("RAIN"); -+ if (rain != null) { -+ heightmaps.remove("RAIN"); -+ heightmaps.setGeneric("MOTION_BLOCKING", rain); -+ heightmaps.setGeneric("MOTION_BLOCKING_NO_LEAVES", rain); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V1484() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1486.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1486.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0500c1e3aba4d1458762021c9e4596330bf2b13d ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1486.java -@@ -0,0 +1,39 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.entity.ConverterAbstractEntityRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1486 { -+ -+ protected static final int VERSION = MCVersions.V18W19B + 1; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static final Map RENAMED_ENTITY_IDS = ImmutableMap.builder() -+ .put("minecraft:salmon_mob", "minecraft:salmon") -+ .put("minecraft:cod_mob", "minecraft:cod") -+ .build(); -+ public static final Map RENAMED_ITEM_IDS = ImmutableMap.builder() -+ .put("minecraft:salmon_mob_spawn_egg", "minecraft:salmon_spawn_egg") -+ .put("minecraft:cod_mob_spawn_egg", "minecraft:cod_spawn_egg") -+ .build(); -+ -+ -+ public static void register() { -+ registerMob("minecraft:cod"); -+ registerMob("minecraft:salmon"); -+ -+ ConverterAbstractEntityRename.register(VERSION, RENAMED_ENTITY_IDS::get); -+ ConverterAbstractItemRename.register(VERSION, RENAMED_ITEM_IDS::get); -+ } -+ -+ private V1486() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1487.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1487.java -new file mode 100644 -index 0000000000000000000000000000000000000000..dba4a64f61b27f1eb820e0e0a3fddb81517acc16 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1487.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1487 { -+ -+ protected static final int VERSION = MCVersions.V18W19B + 2; -+ -+ public static void register() { -+ final Map remap = ImmutableMap.of( -+ "minecraft:prismarine_bricks_slab", "minecraft:prismarine_brick_slab", -+ "minecraft:prismarine_bricks_stairs", "minecraft:prismarine_brick_stairs" -+ ); -+ -+ ConverterAbstractItemRename.register(VERSION, remap::get); -+ ConverterAbstractBlockRename.register(VERSION, remap::get); -+ } -+ -+ private V1487() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1488.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1488.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bd847cea21dfbaaef1809c2ca3f939a97fd3bae8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1488.java -@@ -0,0 +1,112 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.common.collect.ImmutableMap; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.chat.TextComponent; -+ -+public final class V1488 { -+ -+ protected static final int VERSION = MCVersions.V18W19B + 3; -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, ImmutableMap.of( -+ "minecraft:kelp_top", "minecraft:kelp", -+ "minecraft:kelp", "minecraft:kelp_plant" -+ )::get); -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:kelp_top", "minecraft:kelp" -+ )::get); -+ -+ // Don't ask me why in V1458 they wrote the converter to NOT do command blocks and THEN in THIS version -+ // to ONLY do command blocks. I don't know. -+ -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:command_block", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String customName = data.getString("CustomName"); -+ if (customName == null) { -+ return null; -+ } -+ -+ if (customName.isEmpty()) { -+ data.remove("CustomName"); -+ } else { -+ data.setString("CustomName", Component.Serializer.toJson(new TextComponent(customName))); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:commandblock_minecart", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String customName = data.getString("CustomName"); -+ if (customName == null) { -+ return null; -+ } -+ -+ if (customName.isEmpty()) { -+ data.remove("CustomName"); -+ } else { -+ data.setString("CustomName", Component.Serializer.toJson(new TextComponent(customName))); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType children = data.getList("Children", ObjectType.MAP); -+ boolean isIgloo; -+ if (children != null) { -+ isIgloo = true; -+ for (int i = 0, len = children.size(); i < len; ++i) { -+ if (!isIglooPiece(children.getMap(i))) { -+ isIgloo = false; -+ break; -+ } -+ } -+ } else { -+ isIgloo = false; -+ } -+ -+ if (isIgloo) { -+ data.remove("Children"); -+ data.setString("id", "Igloo"); -+ return null; -+ } -+ -+ if (children != null) { -+ for (int i = 0; i < children.size();) { -+ final MapType child = children.getMap(i); -+ if (isIglooPiece(child)) { -+ children.remove(i); -+ continue; -+ } -+ ++i; -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private static boolean isIglooPiece(final MapType piece) { -+ return "Iglu".equals(piece.getString("id")); -+ } -+ -+ private V1488() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1490.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1490.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cb3afa0634cb47cbd5b324a66d140375b1c23e07 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1490.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V1490 { -+ -+ protected static final int VERSION = MCVersions.V18W20A + 1; -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, ImmutableMap.of( -+ "minecraft:melon_block", "minecraft:melon" -+ )::get); -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:melon_block", "minecraft:melon", -+ "minecraft:melon", "minecraft:melon_slice", -+ "minecraft:speckled_melon", "minecraft:glistering_melon_slice" -+ )::get); -+ } -+ -+ private V1490() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1492.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1492.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4fe91970eb69d2cb8f80487d6995e4ab0027bdd4 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1492.java -@@ -0,0 +1,152 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.common.collect.ImmutableMap; -+import com.mojang.datafixers.util.Pair; -+ -+public final class V1492 { -+ -+ private static final ImmutableMap>> RENAMES = ImmutableMap.>>builder() -+ .put("EndCity", Pair.of( -+ "ECP", -+ ImmutableMap.builder() -+ .put("second_floor", "second_floor_1") -+ .put("third_floor", "third_floor_1") -+ .put("third_floor_c", "third_floor_2") -+ .build() -+ ) -+ ) -+ -+ .put("Mansion", Pair.of( -+ "WMP", -+ ImmutableMap.builder() -+ .put("carpet_south", "carpet_south_1") -+ .put("carpet_west", "carpet_west_1") -+ .put("indoors_door", "indoors_door_1") -+ .put("indoors_wall", "indoors_wall_1") -+ .build() -+ ) -+ ) -+ -+ .put("Igloo", Pair.of( -+ "Iglu", -+ ImmutableMap.builder() -+ .put("minecraft:igloo/igloo_bottom", "minecraft:igloo/bottom") -+ .put("minecraft:igloo/igloo_middle", "minecraft:igloo/middle") -+ .put("minecraft:igloo/igloo_top", "minecraft:igloo/top") -+ .build() -+ ) -+ ) -+ .put("Ocean_Ruin", Pair.of( -+ "ORP", -+ ImmutableMap.builder() -+ .put("minecraft:ruin/big_ruin1_brick", "minecraft:underwater_ruin/big_brick_1") -+ .put("minecraft:ruin/big_ruin2_brick", "minecraft:underwater_ruin/big_brick_2") -+ .put("minecraft:ruin/big_ruin3_brick", "minecraft:underwater_ruin/big_brick_3") -+ .put("minecraft:ruin/big_ruin8_brick", "minecraft:underwater_ruin/big_brick_8") -+ .put("minecraft:ruin/big_ruin1_cracked", "minecraft:underwater_ruin/big_cracked_1") -+ .put("minecraft:ruin/big_ruin2_cracked", "minecraft:underwater_ruin/big_cracked_2") -+ .put("minecraft:ruin/big_ruin3_cracked", "minecraft:underwater_ruin/big_cracked_3") -+ .put("minecraft:ruin/big_ruin8_cracked", "minecraft:underwater_ruin/big_cracked_8") -+ .put("minecraft:ruin/big_ruin1_mossy", "minecraft:underwater_ruin/big_mossy_1") -+ .put("minecraft:ruin/big_ruin2_mossy", "minecraft:underwater_ruin/big_mossy_2") -+ .put("minecraft:ruin/big_ruin3_mossy", "minecraft:underwater_ruin/big_mossy_3") -+ .put("minecraft:ruin/big_ruin8_mossy", "minecraft:underwater_ruin/big_mossy_8") -+ .put("minecraft:ruin/big_ruin_warm4", "minecraft:underwater_ruin/big_warm_4") -+ .put("minecraft:ruin/big_ruin_warm5", "minecraft:underwater_ruin/big_warm_5") -+ .put("minecraft:ruin/big_ruin_warm6", "minecraft:underwater_ruin/big_warm_6") -+ .put("minecraft:ruin/big_ruin_warm7", "minecraft:underwater_ruin/big_warm_7") -+ .put("minecraft:ruin/ruin1_brick", "minecraft:underwater_ruin/brick_1") -+ .put("minecraft:ruin/ruin2_brick", "minecraft:underwater_ruin/brick_2") -+ .put("minecraft:ruin/ruin3_brick", "minecraft:underwater_ruin/brick_3") -+ .put("minecraft:ruin/ruin4_brick", "minecraft:underwater_ruin/brick_4") -+ .put("minecraft:ruin/ruin5_brick", "minecraft:underwater_ruin/brick_5") -+ .put("minecraft:ruin/ruin6_brick", "minecraft:underwater_ruin/brick_6") -+ .put("minecraft:ruin/ruin7_brick", "minecraft:underwater_ruin/brick_7") -+ .put("minecraft:ruin/ruin8_brick", "minecraft:underwater_ruin/brick_8") -+ .put("minecraft:ruin/ruin1_cracked", "minecraft:underwater_ruin/cracked_1") -+ .put("minecraft:ruin/ruin2_cracked", "minecraft:underwater_ruin/cracked_2") -+ .put("minecraft:ruin/ruin3_cracked", "minecraft:underwater_ruin/cracked_3") -+ .put("minecraft:ruin/ruin4_cracked", "minecraft:underwater_ruin/cracked_4") -+ .put("minecraft:ruin/ruin5_cracked", "minecraft:underwater_ruin/cracked_5") -+ .put("minecraft:ruin/ruin6_cracked", "minecraft:underwater_ruin/cracked_6") -+ .put("minecraft:ruin/ruin7_cracked", "minecraft:underwater_ruin/cracked_7") -+ .put("minecraft:ruin/ruin8_cracked", "minecraft:underwater_ruin/cracked_8") -+ .put("minecraft:ruin/ruin1_mossy", "minecraft:underwater_ruin/mossy_1") -+ .put("minecraft:ruin/ruin2_mossy", "minecraft:underwater_ruin/mossy_2") -+ .put("minecraft:ruin/ruin3_mossy", "minecraft:underwater_ruin/mossy_3") -+ .put("minecraft:ruin/ruin4_mossy", "minecraft:underwater_ruin/mossy_4") -+ .put("minecraft:ruin/ruin5_mossy", "minecraft:underwater_ruin/mossy_5") -+ .put("minecraft:ruin/ruin6_mossy", "minecraft:underwater_ruin/mossy_6") -+ .put("minecraft:ruin/ruin7_mossy", "minecraft:underwater_ruin/mossy_7") -+ .put("minecraft:ruin/ruin8_mossy", "minecraft:underwater_ruin/mossy_8") -+ .put("minecraft:ruin/ruin_warm1", "minecraft:underwater_ruin/warm_1") -+ .put("minecraft:ruin/ruin_warm2", "minecraft:underwater_ruin/warm_2") -+ .put("minecraft:ruin/ruin_warm3", "minecraft:underwater_ruin/warm_3") -+ .put("minecraft:ruin/ruin_warm4", "minecraft:underwater_ruin/warm_4") -+ .put("minecraft:ruin/ruin_warm5", "minecraft:underwater_ruin/warm_5") -+ .put("minecraft:ruin/ruin_warm6", "minecraft:underwater_ruin/warm_6") -+ .put("minecraft:ruin/ruin_warm7", "minecraft:underwater_ruin/warm_7") -+ .put("minecraft:ruin/ruin_warm8", "minecraft:underwater_ruin/warm_8") -+ .put("minecraft:ruin/big_brick_1", "minecraft:underwater_ruin/big_brick_1") -+ .put("minecraft:ruin/big_brick_2", "minecraft:underwater_ruin/big_brick_2") -+ .put("minecraft:ruin/big_brick_3", "minecraft:underwater_ruin/big_brick_3") -+ .put("minecraft:ruin/big_brick_8", "minecraft:underwater_ruin/big_brick_8") -+ .put("minecraft:ruin/big_mossy_1", "minecraft:underwater_ruin/big_mossy_1") -+ .put("minecraft:ruin/big_mossy_2", "minecraft:underwater_ruin/big_mossy_2") -+ .put("minecraft:ruin/big_mossy_3", "minecraft:underwater_ruin/big_mossy_3") -+ .put("minecraft:ruin/big_mossy_8", "minecraft:underwater_ruin/big_mossy_8") -+ .put("minecraft:ruin/big_cracked_1", "minecraft:underwater_ruin/big_cracked_1") -+ .put("minecraft:ruin/big_cracked_2", "minecraft:underwater_ruin/big_cracked_2") -+ .put("minecraft:ruin/big_cracked_3", "minecraft:underwater_ruin/big_cracked_3") -+ .put("minecraft:ruin/big_cracked_8", "minecraft:underwater_ruin/big_cracked_8") -+ .put("minecraft:ruin/big_warm_4", "minecraft:underwater_ruin/big_warm_4") -+ .put("minecraft:ruin/big_warm_5", "minecraft:underwater_ruin/big_warm_5") -+ .put("minecraft:ruin/big_warm_6", "minecraft:underwater_ruin/big_warm_6") -+ .put("minecraft:ruin/big_warm_7", "minecraft:underwater_ruin/big_warm_7") -+ .build() -+ ) -+ ) -+ -+ .build(); -+ -+ protected static final int VERSION = MCVersions.V18W20B + 1; -+ -+ public static void register() { -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType children = data.getList("Children", ObjectType.MAP); -+ if (children == null) { -+ return null; -+ } -+ -+ final String id = data.getString("id"); -+ -+ final Pair> renames = RENAMES.get(id); -+ if (renames == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = children.size(); i < len; ++i) { -+ final MapType child = children.getMap(i); -+ -+ if (!renames.getFirst().equals(child.getString("id"))) { -+ final String template = child.getString("Template", ""); -+ child.setString("Template", renames.getSecond().getOrDefault(template, template)); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V1492() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1494.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1494.java -new file mode 100644 -index 0000000000000000000000000000000000000000..50411042a83d58c4c36768a8f5196b4b41b4d095 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1494.java -@@ -0,0 +1,89 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -+ -+public final class V1494 { -+ -+ protected static final int VERSION = MCVersions.V18W20C + 1; -+ -+ private static final Int2ObjectOpenHashMap ENCH_ID_TO_NAME = new Int2ObjectOpenHashMap<>(); -+ static { -+ ENCH_ID_TO_NAME.put(0, "minecraft:protection"); -+ ENCH_ID_TO_NAME.put(1, "minecraft:fire_protection"); -+ ENCH_ID_TO_NAME.put(2, "minecraft:feather_falling"); -+ ENCH_ID_TO_NAME.put(3, "minecraft:blast_protection"); -+ ENCH_ID_TO_NAME.put(4, "minecraft:projectile_protection"); -+ ENCH_ID_TO_NAME.put(5, "minecraft:respiration"); -+ ENCH_ID_TO_NAME.put(6, "minecraft:aqua_affinity"); -+ ENCH_ID_TO_NAME.put(7, "minecraft:thorns"); -+ ENCH_ID_TO_NAME.put(8, "minecraft:depth_strider"); -+ ENCH_ID_TO_NAME.put(9, "minecraft:frost_walker"); -+ ENCH_ID_TO_NAME.put(10, "minecraft:binding_curse"); -+ ENCH_ID_TO_NAME.put(16, "minecraft:sharpness"); -+ ENCH_ID_TO_NAME.put(17, "minecraft:smite"); -+ ENCH_ID_TO_NAME.put(18, "minecraft:bane_of_arthropods"); -+ ENCH_ID_TO_NAME.put(19, "minecraft:knockback"); -+ ENCH_ID_TO_NAME.put(20, "minecraft:fire_aspect"); -+ ENCH_ID_TO_NAME.put(21, "minecraft:looting"); -+ ENCH_ID_TO_NAME.put(22, "minecraft:sweeping"); -+ ENCH_ID_TO_NAME.put(32, "minecraft:efficiency"); -+ ENCH_ID_TO_NAME.put(33, "minecraft:silk_touch"); -+ ENCH_ID_TO_NAME.put(34, "minecraft:unbreaking"); -+ ENCH_ID_TO_NAME.put(35, "minecraft:fortune"); -+ ENCH_ID_TO_NAME.put(48, "minecraft:power"); -+ ENCH_ID_TO_NAME.put(49, "minecraft:punch"); -+ ENCH_ID_TO_NAME.put(50, "minecraft:flame"); -+ ENCH_ID_TO_NAME.put(51, "minecraft:infinity"); -+ ENCH_ID_TO_NAME.put(61, "minecraft:luck_of_the_sea"); -+ ENCH_ID_TO_NAME.put(62, "minecraft:lure"); -+ ENCH_ID_TO_NAME.put(65, "minecraft:loyalty"); -+ ENCH_ID_TO_NAME.put(66, "minecraft:impaling"); -+ ENCH_ID_TO_NAME.put(67, "minecraft:riptide"); -+ ENCH_ID_TO_NAME.put(68, "minecraft:channeling"); -+ ENCH_ID_TO_NAME.put(70, "minecraft:mending"); -+ ENCH_ID_TO_NAME.put(71, "minecraft:vanishing_curse"); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final ListType enchants = tag.getList("ench", ObjectType.MAP); -+ if (enchants != null) { -+ tag.remove("ench"); -+ tag.setList("Enchantments", enchants); -+ -+ for (int i = 0, len = enchants.size(); i < len; ++i) { -+ final MapType enchant = enchants.getMap(i); -+ enchant.setString("id", ENCH_ID_TO_NAME.getOrDefault(enchant.getInt("id"), "null")); -+ } -+ } -+ -+ final ListType storedEnchants = tag.getList("StoredEnchantments", ObjectType.MAP); -+ if (storedEnchants != null) { -+ for (int i = 0, len = storedEnchants.size(); i < len; ++i) { -+ final MapType enchant = storedEnchants.getMap(i); -+ enchant.setString("id", ENCH_ID_TO_NAME.getOrDefault(enchant.getInt("id"), "null")); -+ } -+ } -+ -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V1494() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1496.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1496.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c56d50c552d4609474f5b3b6b0b8be8b575764ea ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1496.java -@@ -0,0 +1,370 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.mojang.datafixers.DataFixUtils; -+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -+import it.unimi.dsi.fastutil.ints.IntIterator; -+import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -+import net.minecraft.util.datafix.PackedBitStorage; -+import java.util.Arrays; -+import java.util.HashSet; -+import java.util.Set; -+ -+public final class V1496 { -+ -+ private V1496() {} -+ -+ protected static final int VERSION = MCVersions.V18W21B; -+ -+ private static final int[][] DIRECTIONS = new int[][] { -+ new int[] {-1, 0, 0}, -+ new int[] {1, 0, 0}, -+ new int[] {0, -1, 0}, -+ new int[] {0, 1, 0}, -+ new int[] {0, 0, -1}, -+ new int[] {0, 0, 1} -+ }; -+ -+ private static final Object2IntOpenHashMap LEAVES_TO_ID = new Object2IntOpenHashMap<>(); -+ static { -+ LEAVES_TO_ID.put("minecraft:acacia_leaves", 0); -+ LEAVES_TO_ID.put("minecraft:birch_leaves", 1); -+ LEAVES_TO_ID.put("minecraft:dark_oak_leaves", 2); -+ LEAVES_TO_ID.put("minecraft:jungle_leaves", 3); -+ LEAVES_TO_ID.put("minecraft:oak_leaves", 4); -+ LEAVES_TO_ID.put("minecraft:spruce_leaves", 5); -+ } -+ -+ private static final Set LOGS = new HashSet<>( -+ Arrays.asList( -+ "minecraft:acacia_bark", -+ "minecraft:birch_bark", -+ "minecraft:dark_oak_bark", -+ "minecraft:jungle_bark", -+ "minecraft:oak_bark", -+ "minecraft:spruce_bark", -+ "minecraft:acacia_log", -+ "minecraft:birch_log", -+ "minecraft:dark_oak_log", -+ "minecraft:jungle_log", -+ "minecraft:oak_log", -+ "minecraft:spruce_log", -+ "minecraft:stripped_acacia_log", -+ "minecraft:stripped_birch_log", -+ "minecraft:stripped_dark_oak_log", -+ "minecraft:stripped_jungle_log", -+ "minecraft:stripped_oak_log", -+ "minecraft:stripped_spruce_log" -+ ) -+ ); -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ final ListType sectionsNBT = level.getList("Sections", ObjectType.MAP); -+ if (sectionsNBT == null) { -+ return null; -+ } -+ -+ int newSides = 0; -+ -+ final LeavesSection[] sections = new LeavesSection[16]; -+ boolean skippable = true; -+ for (int i = 0, len = sectionsNBT.size(); i < len; ++i) { -+ final LeavesSection section = new LeavesSection(sectionsNBT.getMap(i)); -+ sections[section.sectionY] = section; -+ -+ skippable &= section.isSkippable(); -+ } -+ -+ if (skippable) { -+ return null; -+ } -+ -+ final IntOpenHashSet[] positionsByDistance = new IntOpenHashSet[7]; -+ for (int i = 0; i < positionsByDistance.length; ++i) { -+ positionsByDistance[i] = new IntOpenHashSet(); -+ } -+ -+ for (final LeavesSection section : sections) { -+ if (section == null || section.isSkippable()) { -+ continue; -+ } -+ -+ for (int index = 0; index < 4096; ++index) { -+ final int block = section.getBlock(index); -+ if (section.isLog(block)) { -+ positionsByDistance[0].add(section.getSectionY() << 12 | index); -+ } else if (section.isLeaf(block)) { -+ int x = getX(index); -+ int z = getZ(index); -+ newSides |= getSideMask(x == 0, x == 15, z == 0, z == 15); -+ } -+ } -+ } -+ -+ // this is basically supposed to recalculate the distances, because a higher cap was added -+ for (int distance = 1; distance < 7; ++distance) { -+ final IntOpenHashSet positionsLess = positionsByDistance[distance - 1]; -+ final IntOpenHashSet positionsEqual = positionsByDistance[distance]; -+ -+ for (final IntIterator iterator = positionsLess.iterator(); iterator.hasNext();) { -+ final int position = iterator.nextInt(); -+ final int fromX = getX(position); -+ final int fromY = getY(position); -+ final int fromZ = getZ(position); -+ -+ for (final int[] direction : DIRECTIONS) { -+ final int toX = fromX + direction[0]; -+ final int toY = fromY + direction[1]; -+ final int toZ = fromZ + direction[2]; -+ -+ if (!(toX >= 0 && toX <= 15 && toZ >= 0 && toZ <= 15 && toY >= 0 && toY <= 255)) { -+ continue; -+ } -+ -+ final LeavesSection toSection = sections[toY >> 4]; -+ if (toSection == null || toSection.isSkippable()) { -+ continue; -+ } -+ -+ final int sectionLocalIndex = getIndex(toX, toY & 15, toZ); -+ final int toBlock = toSection.getBlock(sectionLocalIndex); -+ -+ if (toSection.isLeaf(toBlock)) { -+ final int newDistance = toSection.getDistance(toBlock); -+ if (newDistance > distance) { -+ toSection.setDistance(sectionLocalIndex, toBlock, distance); -+ positionsEqual.add(getIndex(toX, toY, toZ)); -+ } -+ } -+ } -+ } -+ } -+ -+ // done updating blocks, now just update the blockstates and palette -+ for (int i = 0, len = sectionsNBT.size(); i < len; ++i) { -+ final MapType sectionNBT = sectionsNBT.getMap(i); -+ final int y = sectionNBT.getInt("Y"); -+ final LeavesSection section = sections[y]; -+ -+ section.writeInto(sectionNBT); -+ } -+ -+ // if sides changed during process, update it now -+ if (newSides != 0) { -+ MapType upgradeData = level.getMap("UpgradeData"); -+ if (upgradeData == null) { -+ level.setMap("UpgradeData", upgradeData = Types.NBT.createEmptyMap()); -+ } -+ -+ upgradeData.setByte("Sides", (byte)(upgradeData.getByte("Sides") | newSides)); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ public static int getIndex(final int x, final int y, final int z) { -+ return y << 8 | z << 4 | x; -+ } -+ -+ public static int getX(final int index) { -+ return index & 15; -+ } -+ -+ public static int getY(final int index) { -+ return index >> 8 & 255; -+ } -+ -+ public static int getZ(final int index) { -+ return index >> 4 & 15; -+ } -+ -+ public static int getSideMask(final boolean noLeft, final boolean noRight, final boolean noBack, final boolean noForward) { -+ final int ret; -+ -+ if (noBack) { -+ if (noRight) { -+ ret = 2; -+ } else if (noLeft) { -+ ret = 128; -+ } else { -+ ret = 1; -+ } -+ } else if (noForward) { -+ if (noLeft) { -+ ret = 32; -+ } else if (noRight) { -+ ret = 8; -+ } else { -+ ret = 16; -+ } -+ } else if (noRight) { -+ ret = 4; -+ } else if (noLeft) { -+ ret = 64; -+ } else { -+ ret = 0; -+ } -+ -+ return ret; -+ } -+ -+ public abstract static class Section { -+ protected final ListType palette; -+ protected final int sectionY; -+ protected PackedBitStorage storage; -+ -+ public Section(final MapType section) { -+ this.palette = section.getList("Palette", ObjectType.MAP); -+ this.sectionY = section.getInt("Y"); -+ this.readStorage(section); -+ } -+ -+ protected void readStorage(final MapType section) { -+ if (this.initSkippable()) { -+ this.storage = null; -+ } else { -+ final long[] states = section.getLongs("BlockStates"); -+ final int bits = Math.max(4, DataFixUtils.ceillog2(this.palette.size())); -+ this.storage = new PackedBitStorage(bits, 4096, states); -+ } -+ } -+ -+ public void writeInto(final MapType section) { -+ if (this.isSkippable()) { -+ return; -+ } -+ -+ section.setList("Palette", this.palette); -+ section.setLongs("BlockStates", this.storage.getRaw()); -+ } -+ -+ public boolean isSkippable() { -+ return this.storage == null; -+ } -+ -+ public int getBlock(final int index) { -+ return this.storage.get(index); -+ } -+ -+ protected int getStateId(final String name, final boolean persistent, final int distance) { -+ return LEAVES_TO_ID.getInt(name) << 5 | (persistent ? 16 : 0) | distance; -+ } -+ -+ protected int getSectionY() { -+ return this.sectionY; -+ } -+ -+ protected abstract boolean initSkippable(); -+ } -+ -+ public static final class LeavesSection extends Section { -+ private IntOpenHashSet leaveIds; -+ private IntOpenHashSet logIds; -+ private Int2IntOpenHashMap stateToIdMap; -+ -+ public LeavesSection(final MapType section) { -+ super(section); -+ } -+ -+ @Override -+ protected boolean initSkippable() { -+ this.leaveIds = new IntOpenHashSet(); -+ this.logIds = new IntOpenHashSet(); -+ this.stateToIdMap = new Int2IntOpenHashMap(); -+ this.stateToIdMap.defaultReturnValue(-1); -+ -+ for(int i = 0; i < this.palette.size(); ++i) { -+ final MapType blockState = this.palette.getMap(i); -+ final String name = blockState.getString("Name", ""); -+ if (LEAVES_TO_ID.containsKey(name)) { -+ final MapType properties = blockState.getMap("Properties"); -+ final boolean notDecayable = properties != null && "false".equals(properties.getString("decayable")); -+ -+ this.leaveIds.add(i); -+ this.stateToIdMap.put(this.getStateId(name, notDecayable, 7), i); -+ this.palette.setMap(i, this.makeNewLeafTag(name, notDecayable, 7)); -+ } -+ -+ if (LOGS.contains(name)) { -+ this.logIds.add(i); -+ } -+ } -+ -+ return this.leaveIds.isEmpty() && this.logIds.isEmpty(); -+ } -+ -+ private MapType makeNewLeafTag(final String name, final boolean notDecayable, final int distance) { -+ final MapType properties = Types.NBT.createEmptyMap(); -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ ret.setString("Name", name); -+ ret.setMap("Properties", properties); -+ -+ properties.setString("persistent", Boolean.toString(notDecayable)); -+ properties.setString("distance", Integer.toString(distance)); -+ -+ return ret; -+ } -+ -+ public boolean isLog(final int id) { -+ return this.logIds.contains(id); -+ } -+ -+ public boolean isLeaf(final int id) { -+ return this.leaveIds.contains(id); -+ } -+ -+ // only call for logs or leaves, will throw otherwise! -+ private int getDistance(final int id) { -+ if (this.isLog(id)) { -+ return 0; -+ } -+ -+ return Integer.parseInt(this.palette.getMap(id).getMap("Properties").getString("distance")); -+ } -+ -+ private void setDistance(final int index, final int id, final int distance) { -+ final MapType state = this.palette.getMap(id); -+ final String name = state.getString("Name"); -+ final boolean persistent = "true".equals(state.getMap("Properties").getString("persistent")); -+ final int newState = this.getStateId(name, persistent, distance); -+ int newStateId; -+ if ((newStateId = this.stateToIdMap.get(newState)) == -1) { -+ newStateId = this.palette.size(); -+ this.leaveIds.add(newStateId); -+ this.stateToIdMap.put(newState, newStateId); -+ this.palette.addMap(this.makeNewLeafTag(name, persistent, distance)); -+ } -+ -+ if (1 << this.storage.getBits() <= newStateId) { -+ // need to widen storage -+ final PackedBitStorage newStorage = new PackedBitStorage(this.storage.getBits() + 1, 4096); -+ -+ for(int i = 0; i < 4096; ++i) { -+ newStorage.set(i, this.storage.get(i)); -+ } -+ -+ this.storage = newStorage; -+ } -+ -+ this.storage.set(index, newStateId); -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1500.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1500.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9208152e2a158470f37b0eb022478e8e5287c12b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1500.java -@@ -0,0 +1,24 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1500 { -+ -+ protected static final int VERSION = MCVersions.V18W22C + 1; -+ -+ private V1500() {} -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("DUMMY", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ data.setBoolean("keepPacked", true); -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1501.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1501.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c497faa60c37f30ceb0d7c394446d6074599c1b7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1501.java -@@ -0,0 +1,75 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.advancements.ConverterAbstractAdvancementsRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1501 { -+ -+ protected static final int VERSION = MCVersions.V1_13_PRE1; -+ -+ private static final Map RENAMES = ImmutableMap.builder() -+ .put("minecraft:recipes/brewing/speckled_melon", "minecraft:recipes/brewing/glistering_melon_slice") -+ .put("minecraft:recipes/building_blocks/black_stained_hardened_clay", "minecraft:recipes/building_blocks/black_terracotta") -+ .put("minecraft:recipes/building_blocks/blue_stained_hardened_clay", "minecraft:recipes/building_blocks/blue_terracotta") -+ .put("minecraft:recipes/building_blocks/brown_stained_hardened_clay", "minecraft:recipes/building_blocks/brown_terracotta") -+ .put("minecraft:recipes/building_blocks/cyan_stained_hardened_clay", "minecraft:recipes/building_blocks/cyan_terracotta") -+ .put("minecraft:recipes/building_blocks/gray_stained_hardened_clay", "minecraft:recipes/building_blocks/gray_terracotta") -+ .put("minecraft:recipes/building_blocks/green_stained_hardened_clay", "minecraft:recipes/building_blocks/green_terracotta") -+ .put("minecraft:recipes/building_blocks/light_blue_stained_hardened_clay", "minecraft:recipes/building_blocks/light_blue_terracotta") -+ .put("minecraft:recipes/building_blocks/light_gray_stained_hardened_clay", "minecraft:recipes/building_blocks/light_gray_terracotta") -+ .put("minecraft:recipes/building_blocks/lime_stained_hardened_clay", "minecraft:recipes/building_blocks/lime_terracotta") -+ .put("minecraft:recipes/building_blocks/magenta_stained_hardened_clay", "minecraft:recipes/building_blocks/magenta_terracotta") -+ .put("minecraft:recipes/building_blocks/orange_stained_hardened_clay", "minecraft:recipes/building_blocks/orange_terracotta") -+ .put("minecraft:recipes/building_blocks/pink_stained_hardened_clay", "minecraft:recipes/building_blocks/pink_terracotta") -+ .put("minecraft:recipes/building_blocks/purple_stained_hardened_clay", "minecraft:recipes/building_blocks/purple_terracotta") -+ .put("minecraft:recipes/building_blocks/red_stained_hardened_clay", "minecraft:recipes/building_blocks/red_terracotta") -+ .put("minecraft:recipes/building_blocks/white_stained_hardened_clay", "minecraft:recipes/building_blocks/white_terracotta") -+ .put("minecraft:recipes/building_blocks/yellow_stained_hardened_clay", "minecraft:recipes/building_blocks/yellow_terracotta") -+ .put("minecraft:recipes/building_blocks/acacia_wooden_slab", "minecraft:recipes/building_blocks/acacia_slab") -+ .put("minecraft:recipes/building_blocks/birch_wooden_slab", "minecraft:recipes/building_blocks/birch_slab") -+ .put("minecraft:recipes/building_blocks/dark_oak_wooden_slab", "minecraft:recipes/building_blocks/dark_oak_slab") -+ .put("minecraft:recipes/building_blocks/jungle_wooden_slab", "minecraft:recipes/building_blocks/jungle_slab") -+ .put("minecraft:recipes/building_blocks/oak_wooden_slab", "minecraft:recipes/building_blocks/oak_slab") -+ .put("minecraft:recipes/building_blocks/spruce_wooden_slab", "minecraft:recipes/building_blocks/spruce_slab") -+ .put("minecraft:recipes/building_blocks/brick_block", "minecraft:recipes/building_blocks/bricks") -+ .put("minecraft:recipes/building_blocks/chiseled_stonebrick", "minecraft:recipes/building_blocks/chiseled_stone_bricks") -+ .put("minecraft:recipes/building_blocks/end_bricks", "minecraft:recipes/building_blocks/end_stone_bricks") -+ .put("minecraft:recipes/building_blocks/lit_pumpkin", "minecraft:recipes/building_blocks/jack_o_lantern") -+ .put("minecraft:recipes/building_blocks/magma", "minecraft:recipes/building_blocks/magma_block") -+ .put("minecraft:recipes/building_blocks/melon_block", "minecraft:recipes/building_blocks/melon") -+ .put("minecraft:recipes/building_blocks/mossy_stonebrick", "minecraft:recipes/building_blocks/mossy_stone_bricks") -+ .put("minecraft:recipes/building_blocks/nether_brick", "minecraft:recipes/building_blocks/nether_bricks") -+ .put("minecraft:recipes/building_blocks/pillar_quartz_block", "minecraft:recipes/building_blocks/quartz_pillar") -+ .put("minecraft:recipes/building_blocks/red_nether_brick", "minecraft:recipes/building_blocks/red_nether_bricks") -+ .put("minecraft:recipes/building_blocks/snow", "minecraft:recipes/building_blocks/snow_block") -+ .put("minecraft:recipes/building_blocks/smooth_red_sandstone", "minecraft:recipes/building_blocks/cut_red_sandstone") -+ .put("minecraft:recipes/building_blocks/smooth_sandstone", "minecraft:recipes/building_blocks/cut_sandstone") -+ .put("minecraft:recipes/building_blocks/stonebrick", "minecraft:recipes/building_blocks/stone_bricks") -+ .put("minecraft:recipes/building_blocks/stone_stairs", "minecraft:recipes/building_blocks/cobblestone_stairs") -+ .put("minecraft:recipes/building_blocks/string_to_wool", "minecraft:recipes/building_blocks/white_wool_from_string") -+ .put("minecraft:recipes/decorations/fence", "minecraft:recipes/decorations/oak_fence") -+ .put("minecraft:recipes/decorations/purple_shulker_box", "minecraft:recipes/decorations/shulker_box") -+ .put("minecraft:recipes/decorations/slime", "minecraft:recipes/decorations/slime_block") -+ .put("minecraft:recipes/decorations/snow_layer", "minecraft:recipes/decorations/snow") -+ .put("minecraft:recipes/misc/bone_meal_from_block", "minecraft:recipes/misc/bone_meal_from_bone_block") -+ .put("minecraft:recipes/misc/bone_meal_from_bone", "minecraft:recipes/misc/bone_meal") -+ .put("minecraft:recipes/misc/gold_ingot_from_block", "minecraft:recipes/misc/gold_ingot_from_gold_block") -+ .put("minecraft:recipes/misc/iron_ingot_from_block", "minecraft:recipes/misc/iron_ingot_from_iron_block") -+ .put("minecraft:recipes/redstone/fence_gate", "minecraft:recipes/redstone/oak_fence_gate") -+ .put("minecraft:recipes/redstone/noteblock", "minecraft:recipes/redstone/note_block") -+ .put("minecraft:recipes/redstone/trapdoor", "minecraft:recipes/redstone/oak_trapdoor") -+ .put("minecraft:recipes/redstone/wooden_button", "minecraft:recipes/redstone/oak_button") -+ .put("minecraft:recipes/redstone/wooden_door", "minecraft:recipes/redstone/oak_door") -+ .put("minecraft:recipes/redstone/wooden_pressure_plate", "minecraft:recipes/redstone/oak_pressure_plate") -+ .put("minecraft:recipes/transportation/boat", "minecraft:recipes/transportation/oak_boat") -+ .put("minecraft:recipes/transportation/golden_rail", "minecraft:recipes/transportation/powered_rail") -+ .build(); -+ -+ private V1501() {} -+ -+ public static void register() { -+ ConverterAbstractAdvancementsRename.register(VERSION, RENAMES::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1502.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1502.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7db79b279a047ec5907a3fb2c6e1a75be14a2f68 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1502.java -@@ -0,0 +1,74 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.recipe.ConverterAbstractRecipeRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1502 { -+ -+ protected static final int VERSION = MCVersions.V1_13_PRE2; -+ -+ private static final Map RECIPES_UPDATES = ImmutableMap.builder() -+ .put("minecraft:acacia_wooden_slab", "minecraft:acacia_slab") -+ .put("minecraft:birch_wooden_slab", "minecraft:birch_slab") -+ .put("minecraft:black_stained_hardened_clay", "minecraft:black_terracotta") -+ .put("minecraft:blue_stained_hardened_clay", "minecraft:blue_terracotta") -+ .put("minecraft:boat", "minecraft:oak_boat") -+ .put("minecraft:bone_meal_from_block", "minecraft:bone_meal_from_bone_block") -+ .put("minecraft:bone_meal_from_bone", "minecraft:bone_meal") -+ .put("minecraft:brick_block", "minecraft:bricks") -+ .put("minecraft:brown_stained_hardened_clay", "minecraft:brown_terracotta") -+ .put("minecraft:chiseled_stonebrick", "minecraft:chiseled_stone_bricks") -+ .put("minecraft:cyan_stained_hardened_clay", "minecraft:cyan_terracotta") -+ .put("minecraft:dark_oak_wooden_slab", "minecraft:dark_oak_slab") -+ .put("minecraft:end_bricks", "minecraft:end_stone_bricks") -+ .put("minecraft:fence_gate", "minecraft:oak_fence_gate") -+ .put("minecraft:fence", "minecraft:oak_fence") -+ .put("minecraft:golden_rail", "minecraft:powered_rail") -+ .put("minecraft:gold_ingot_from_block", "minecraft:gold_ingot_from_gold_block") -+ .put("minecraft:gray_stained_hardened_clay", "minecraft:gray_terracotta") -+ .put("minecraft:green_stained_hardened_clay", "minecraft:green_terracotta") -+ .put("minecraft:iron_ingot_from_block", "minecraft:iron_ingot_from_iron_block") -+ .put("minecraft:jungle_wooden_slab", "minecraft:jungle_slab") -+ .put("minecraft:light_blue_stained_hardened_clay", "minecraft:light_blue_terracotta") -+ .put("minecraft:light_gray_stained_hardened_clay", "minecraft:light_gray_terracotta") -+ .put("minecraft:lime_stained_hardened_clay", "minecraft:lime_terracotta") -+ .put("minecraft:lit_pumpkin", "minecraft:jack_o_lantern") -+ .put("minecraft:magenta_stained_hardened_clay", "minecraft:magenta_terracotta") -+ .put("minecraft:magma", "minecraft:magma_block") -+ .put("minecraft:melon_block", "minecraft:melon") -+ .put("minecraft:mossy_stonebrick", "minecraft:mossy_stone_bricks") -+ .put("minecraft:noteblock", "minecraft:note_block") -+ .put("minecraft:oak_wooden_slab", "minecraft:oak_slab") -+ .put("minecraft:orange_stained_hardened_clay", "minecraft:orange_terracotta") -+ .put("minecraft:pillar_quartz_block", "minecraft:quartz_pillar") -+ .put("minecraft:pink_stained_hardened_clay", "minecraft:pink_terracotta") -+ .put("minecraft:purple_shulker_box", "minecraft:shulker_box") -+ .put("minecraft:purple_stained_hardened_clay", "minecraft:purple_terracotta") -+ .put("minecraft:red_nether_brick", "minecraft:red_nether_bricks") -+ .put("minecraft:red_stained_hardened_clay", "minecraft:red_terracotta") -+ .put("minecraft:slime", "minecraft:slime_block") -+ .put("minecraft:smooth_red_sandstone", "minecraft:cut_red_sandstone") -+ .put("minecraft:smooth_sandstone", "minecraft:cut_sandstone") -+ .put("minecraft:snow_layer", "minecraft:snow") -+ .put("minecraft:snow", "minecraft:snow_block") -+ .put("minecraft:speckled_melon", "minecraft:glistering_melon_slice") -+ .put("minecraft:spruce_wooden_slab", "minecraft:spruce_slab") -+ .put("minecraft:stonebrick", "minecraft:stone_bricks") -+ .put("minecraft:stone_stairs", "minecraft:cobblestone_stairs") -+ .put("minecraft:string_to_wool", "minecraft:white_wool_from_string") -+ .put("minecraft:trapdoor", "minecraft:oak_trapdoor") -+ .put("minecraft:white_stained_hardened_clay", "minecraft:white_terracotta") -+ .put("minecraft:wooden_button", "minecraft:oak_button") -+ .put("minecraft:wooden_door", "minecraft:oak_door") -+ .put("minecraft:wooden_pressure_plate", "minecraft:oak_pressure_plate") -+ .put("minecraft:yellow_stained_hardened_clay", "minecraft:yellow_terracotta") -+ .build(); -+ -+ private V1502() {} -+ -+ public static void register() { -+ ConverterAbstractRecipeRename.register(VERSION, RECIPES_UPDATES::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1506.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1506.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d67a44b7154825efd3e3fd50e0e708ef839866f7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1506.java -@@ -0,0 +1,219 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.json.JsonMapType; -+import ca.spottedleaf.dataconverter.types.json.JsonTypeUtil; -+import ca.spottedleaf.dataconverter.types.nbt.NBTMapType; -+import com.google.common.base.Splitter; -+import com.google.common.collect.ImmutableMap; -+import com.google.common.collect.Lists; -+import com.google.common.collect.Maps; -+import com.mojang.datafixers.util.Pair; -+import com.mojang.serialization.Dynamic; -+import com.mojang.serialization.DynamicOps; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.NbtOps; -+import net.minecraft.nbt.Tag; -+import net.minecraft.util.GsonHelper; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Locale; -+import java.util.Map; -+import java.util.stream.Collectors; -+ -+public final class V1506 { -+ -+ protected static final int VERSION = MCVersions.V1_13_PRE4 + 2; -+ -+ static final Map MAP = new HashMap<>(); -+ static { -+ MAP.put("0", "minecraft:ocean"); -+ MAP.put("1", "minecraft:plains"); -+ MAP.put("2", "minecraft:desert"); -+ MAP.put("3", "minecraft:mountains"); -+ MAP.put("4", "minecraft:forest"); -+ MAP.put("5", "minecraft:taiga"); -+ MAP.put("6", "minecraft:swamp"); -+ MAP.put("7", "minecraft:river"); -+ MAP.put("8", "minecraft:nether"); -+ MAP.put("9", "minecraft:the_end"); -+ MAP.put("10", "minecraft:frozen_ocean"); -+ MAP.put("11", "minecraft:frozen_river"); -+ MAP.put("12", "minecraft:snowy_tundra"); -+ MAP.put("13", "minecraft:snowy_mountains"); -+ MAP.put("14", "minecraft:mushroom_fields"); -+ MAP.put("15", "minecraft:mushroom_field_shore"); -+ MAP.put("16", "minecraft:beach"); -+ MAP.put("17", "minecraft:desert_hills"); -+ MAP.put("18", "minecraft:wooded_hills"); -+ MAP.put("19", "minecraft:taiga_hills"); -+ MAP.put("20", "minecraft:mountain_edge"); -+ MAP.put("21", "minecraft:jungle"); -+ MAP.put("22", "minecraft:jungle_hills"); -+ MAP.put("23", "minecraft:jungle_edge"); -+ MAP.put("24", "minecraft:deep_ocean"); -+ MAP.put("25", "minecraft:stone_shore"); -+ MAP.put("26", "minecraft:snowy_beach"); -+ MAP.put("27", "minecraft:birch_forest"); -+ MAP.put("28", "minecraft:birch_forest_hills"); -+ MAP.put("29", "minecraft:dark_forest"); -+ MAP.put("30", "minecraft:snowy_taiga"); -+ MAP.put("31", "minecraft:snowy_taiga_hills"); -+ MAP.put("32", "minecraft:giant_tree_taiga"); -+ MAP.put("33", "minecraft:giant_tree_taiga_hills"); -+ MAP.put("34", "minecraft:wooded_mountains"); -+ MAP.put("35", "minecraft:savanna"); -+ MAP.put("36", "minecraft:savanna_plateau"); -+ MAP.put("37", "minecraft:badlands"); -+ MAP.put("38", "minecraft:wooded_badlands_plateau"); -+ MAP.put("39", "minecraft:badlands_plateau"); -+ MAP.put("40", "minecraft:small_end_islands"); -+ MAP.put("41", "minecraft:end_midlands"); -+ MAP.put("42", "minecraft:end_highlands"); -+ MAP.put("43", "minecraft:end_barrens"); -+ MAP.put("44", "minecraft:warm_ocean"); -+ MAP.put("45", "minecraft:lukewarm_ocean"); -+ MAP.put("46", "minecraft:cold_ocean"); -+ MAP.put("47", "minecraft:deep_warm_ocean"); -+ MAP.put("48", "minecraft:deep_lukewarm_ocean"); -+ MAP.put("49", "minecraft:deep_cold_ocean"); -+ MAP.put("50", "minecraft:deep_frozen_ocean"); -+ MAP.put("127", "minecraft:the_void"); -+ MAP.put("129", "minecraft:sunflower_plains"); -+ MAP.put("130", "minecraft:desert_lakes"); -+ MAP.put("131", "minecraft:gravelly_mountains"); -+ MAP.put("132", "minecraft:flower_forest"); -+ MAP.put("133", "minecraft:taiga_mountains"); -+ MAP.put("134", "minecraft:swamp_hills"); -+ MAP.put("140", "minecraft:ice_spikes"); -+ MAP.put("149", "minecraft:modified_jungle"); -+ MAP.put("151", "minecraft:modified_jungle_edge"); -+ MAP.put("155", "minecraft:tall_birch_forest"); -+ MAP.put("156", "minecraft:tall_birch_hills"); -+ MAP.put("157", "minecraft:dark_forest_hills"); -+ MAP.put("158", "minecraft:snowy_taiga_mountains"); -+ MAP.put("160", "minecraft:giant_spruce_taiga"); -+ MAP.put("161", "minecraft:giant_spruce_taiga_hills"); -+ MAP.put("162", "minecraft:modified_gravelly_mountains"); -+ MAP.put("163", "minecraft:shattered_savanna"); -+ MAP.put("164", "minecraft:shattered_savanna_plateau"); -+ MAP.put("165", "minecraft:eroded_badlands"); -+ MAP.put("166", "minecraft:modified_wooded_badlands_plateau"); -+ MAP.put("167", "minecraft:modified_badlands_plateau"); -+ } -+ -+ private V1506() {} -+ -+ public static void register() { -+ MCTypeRegistry.LEVEL.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String generatorOptions = data.getString("generatorOptions"); -+ final String generatorName = data.getString("generatorName"); -+ if ("flat".equalsIgnoreCase(generatorName)) { -+ data.setMap("generatorOptions", V1506.convert(generatorOptions == null ? "" : generatorOptions)); -+ } else if ("buffet".equalsIgnoreCase(generatorName) && generatorOptions != null) { -+ data.setMap("generatorOptions", JsonTypeUtil.convertJsonToNBT(new JsonMapType(GsonHelper.parse(generatorName, true), false))); -+ } -+ return null; -+ } -+ }); -+ } -+ -+ private static MapType convert(final String param0) { -+ final Dynamic dynamic = convert(param0, NbtOps.INSTANCE); -+ -+ return new NBTMapType((CompoundTag)dynamic.getValue()); -+ } -+ -+ // Yeah I ain't touching that. This is basically magic value hell. -+ private static Dynamic convert(final String generatorSettings, final DynamicOps ops) { -+ final Iterator splitSettings = Splitter.on(';').split(generatorSettings).iterator(); -+ String biome = "minecraft:plains"; -+ final Map> structures = Maps.newHashMap(); -+ final List> layers; -+ if (!generatorSettings.isEmpty() && splitSettings.hasNext()) { -+ layers = getLayersInfoFromString(splitSettings.next()); -+ if (!layers.isEmpty()) { -+ // biome is next -+ if (splitSettings.hasNext()) { -+ biome = MAP.getOrDefault(splitSettings.next(), "minecraft:plains"); -+ } -+ -+ // structures is next -+ if (splitSettings.hasNext()) { -+ final String[] structuresSplit = splitSettings.next().toLowerCase(Locale.ROOT).split(","); -+ -+ for (final String structureString : structuresSplit) { -+ final String[] structureInfo = structureString.split("\\(", 2); -+ if (!structureInfo[0].isEmpty()) { -+ structures.put(structureInfo[0], Maps.newHashMap()); -+ if (structureInfo.length > 1 && structureInfo[1].endsWith(")") && structureInfo[1].length() > 1) { -+ // I can't even guess the mappings for these. Not worth my time, it will work regardless of the mappings -+ final String[] var7 = structureInfo[1].substring(0, structureInfo[1].length() - 1).split(" "); -+ -+ for (final String var8 : var7) { -+ String[] var9 = var8.split("=", 2); -+ if (var9.length == 2) { -+ structures.get(structureInfo[0]).put(var9[0], var9[1]); -+ } -+ } -+ } -+ } -+ } -+ } else { -+ structures.put("village", Maps.newHashMap()); -+ } -+ } -+ } else { -+ layers = Lists.newArrayList(); -+ layers.add(Pair.of(1, "minecraft:bedrock")); -+ layers.add(Pair.of(2, "minecraft:dirt")); -+ layers.add(Pair.of(1, "minecraft:grass_block")); -+ structures.put("village", Maps.newHashMap()); -+ } -+ -+ final T layerTag = ops.createList(layers.stream().map((param1x) -> ops.createMap(ImmutableMap.of(ops.createString("height"), ops.createInt(param1x.getFirst()), ops.createString("block"), ops.createString(param1x.getSecond()))))); -+ final T structuresTag = ops.createMap(structures.entrySet().stream().map((param1x) -> Pair.of(ops.createString(param1x.getKey().toLowerCase(Locale.ROOT)), ops.createMap(param1x.getValue().entrySet().stream().map((param1xx) -> Pair.of(ops.createString(param1xx.getKey()), ops.createString(param1xx.getValue()))).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))))).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); -+ return new Dynamic<>(ops, ops.createMap(ImmutableMap.of(ops.createString("layers"), layerTag, ops.createString("biome"), ops.createString(biome), ops.createString("structures"), structuresTag))); -+ } -+ -+ private static Pair getLayerInfoFromString(final String layerString) { -+ final String[] split = layerString.split("\\*", 2); -+ int layerCount; -+ if (split.length == 2) { -+ try { -+ layerCount = Integer.parseInt(split[0]); -+ } catch (final NumberFormatException ex) { -+ return null; -+ } -+ } else { -+ layerCount = 1; -+ } -+ -+ final String blockName = split[split.length - 1]; -+ return Pair.of(layerCount, blockName); -+ } -+ -+ private static List> getLayersInfoFromString(final String layersString) { -+ final List> ret = new ArrayList<>(); -+ final String[] layers = layersString.split(","); -+ -+ for (final String layerString : layers) { -+ final Pair layer = getLayerInfoFromString(layerString); -+ if (layer == null) { -+ return Collections.emptyList(); -+ } -+ -+ ret.add(layer); -+ } -+ -+ return ret; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1510.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1510.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9d480d35f0136d449f9cde1f595acd5fb6182fe9 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1510.java -@@ -0,0 +1,138 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.entity.ConverterAbstractEntityRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.recipe.ConverterAbstractRecipeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.common.collect.ImmutableMap; -+ -+import java.util.ArrayList; -+import java.util.Map; -+ -+public final class V1510 { -+ -+ public static final Map RENAMED_ENTITY_IDS = ImmutableMap.builder() -+ .put("minecraft:commandblock_minecart", "minecraft:command_block_minecart") -+ .put("minecraft:ender_crystal", "minecraft:end_crystal") -+ .put("minecraft:snowman", "minecraft:snow_golem") -+ .put("minecraft:evocation_illager", "minecraft:evoker") -+ .put("minecraft:evocation_fangs", "minecraft:evoker_fangs") -+ .put("minecraft:illusion_illager", "minecraft:illusioner") -+ .put("minecraft:vindication_illager", "minecraft:vindicator") -+ .put("minecraft:villager_golem", "minecraft:iron_golem") -+ .put("minecraft:xp_orb", "minecraft:experience_orb") -+ .put("minecraft:xp_bottle", "minecraft:experience_bottle") -+ .put("minecraft:eye_of_ender_signal", "minecraft:eye_of_ender") -+ .put("minecraft:fireworks_rocket", "minecraft:firework_rocket") -+ .build(); -+ -+ public static final Map RENAMED_BLOCKS = ImmutableMap.builder() -+ .put("minecraft:portal", "minecraft:nether_portal") -+ .put("minecraft:oak_bark", "minecraft:oak_wood") -+ .put("minecraft:spruce_bark", "minecraft:spruce_wood") -+ .put("minecraft:birch_bark", "minecraft:birch_wood") -+ .put("minecraft:jungle_bark", "minecraft:jungle_wood") -+ .put("minecraft:acacia_bark", "minecraft:acacia_wood") -+ .put("minecraft:dark_oak_bark", "minecraft:dark_oak_wood") -+ .put("minecraft:stripped_oak_bark", "minecraft:stripped_oak_wood") -+ .put("minecraft:stripped_spruce_bark", "minecraft:stripped_spruce_wood") -+ .put("minecraft:stripped_birch_bark", "minecraft:stripped_birch_wood") -+ .put("minecraft:stripped_jungle_bark", "minecraft:stripped_jungle_wood") -+ .put("minecraft:stripped_acacia_bark", "minecraft:stripped_acacia_wood") -+ .put("minecraft:stripped_dark_oak_bark", "minecraft:stripped_dark_oak_wood") -+ .put("minecraft:mob_spawner", "minecraft:spawner") -+ .build(); -+ -+ public static final Map RENAMED_ITEMS = ImmutableMap.builder() -+ .putAll(RENAMED_BLOCKS) -+ .put("minecraft:clownfish", "minecraft:tropical_fish") -+ .put("minecraft:chorus_fruit_popped", "minecraft:popped_chorus_fruit") -+ .put("minecraft:evocation_illager_spawn_egg", "minecraft:evoker_spawn_egg") -+ .put("minecraft:vindication_illager_spawn_egg", "minecraft:vindicator_spawn_egg") -+ .build(); -+ -+ private static final Map RECIPES_UPDATES = ImmutableMap.builder() -+ .put("minecraft:acacia_bark", "minecraft:acacia_wood") -+ .put("minecraft:birch_bark", "minecraft:birch_wood") -+ .put("minecraft:dark_oak_bark", "minecraft:dark_oak_wood") -+ .put("minecraft:jungle_bark", "minecraft:jungle_wood") -+ .put("minecraft:oak_bark", "minecraft:oak_wood") -+ .put("minecraft:spruce_bark", "minecraft:spruce_wood") -+ .build(); -+ -+ protected static final int VERSION = MCVersions.V1_13_PRE4 + 6; -+ -+ private V1510() {} -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, RENAMED_BLOCKS::get); -+ ConverterAbstractItemRename.register(VERSION, RENAMED_ITEMS::get); -+ ConverterAbstractRecipeRename.register(VERSION, RECIPES_UPDATES::get); -+ -+ ConverterAbstractEntityRename.register(VERSION, (String input) -> { -+ if (input.startsWith("minecraft:bred_")) { -+ input = "minecraft:".concat(input.substring("minecraft:bred_".length())); -+ } -+ -+ return RENAMED_ENTITY_IDS.get(input); -+ }); -+ -+ MCTypeRegistry.STATS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType stats = data.getMap("stats"); -+ if (stats == null) { -+ return null; -+ } -+ -+ final MapType custom = stats.getMap("minecraft:custom"); -+ -+ if (custom == null) { -+ return null; -+ } -+ -+ for (final String key : new ArrayList<>(custom.keys())) { -+ final String convert; -+ switch (key) { -+ case "minecraft:swim_one_cm": -+ convert = "minecraft:walk_on_water_one_cm"; -+ break; -+ case "minecraft:dive_one_cm": -+ convert = "minecraft:walk_under_water_one_cm"; -+ break; -+ default: -+ convert = null; -+ break; -+ } -+ -+ if (convert == null) { -+ continue; -+ } -+ -+ custom.setGeneric(convert, custom.getGeneric(key)); -+ custom.remove(key); -+ } -+ -+ return null; -+ } -+ }); -+ -+ -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:commandblock_minecart", "minecraft:command_block_minecart"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:ender_crystal", "minecraft:end_crystal"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:snowman", "minecraft:snow_golem"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:evocation_illager", "minecraft:evoker"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:evocation_fangs", "minecraft:evoker_fangs"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:illusion_illager", "minecraft:illusioner"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:vindication_illager", "minecraft:vindicator"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:villager_golem", "minecraft:iron_golem"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:xp_orb", "minecraft:experience_orb"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:xp_bottle", "minecraft:experience_bottle"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:eye_of_ender_signal", "minecraft:eye_of_ender"); -+ MCTypeRegistry.ENTITY.copyWalkers(VERSION, "minecraft:fireworks_rocket", "minecraft:firework_rocket"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1514.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1514.java -new file mode 100644 -index 0000000000000000000000000000000000000000..62feb7e81963f7aeea6332fbae3d71c2d9bf2b95 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1514.java -@@ -0,0 +1,70 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.chat.TextComponent; -+import net.minecraft.world.scores.criteria.ObjectiveCriteria; -+ -+public final class V1514 { -+ -+ protected static final int VERSION = MCVersions.V1_13_PRE7 + 1; -+ -+ private V1514() {} -+ -+ public static void register() { -+ MCTypeRegistry.OBJECTIVE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String displayName = data.getString("DisplayName"); -+ if (displayName == null) { -+ return null; -+ } -+ -+ final String update = Component.Serializer.toJson(new TextComponent(displayName)); -+ -+ data.setString("DisplayName", update); -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.TEAM.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String displayName = data.getString("DisplayName"); -+ if (displayName == null) { -+ return null; -+ } -+ -+ final String update = Component.Serializer.toJson(new TextComponent(displayName)); -+ -+ data.setString("DisplayName", update); -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.OBJECTIVE.addStructureConverter(new DataConverter<>(VERSION) { -+ private static ObjectiveCriteria.RenderType getRenderType(String string) { -+ return string.equals("health") ? ObjectiveCriteria.RenderType.HEARTS : ObjectiveCriteria.RenderType.INTEGER; -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String renderType = data.getString("RenderType"); -+ if (renderType != null) { -+ return null; -+ } -+ -+ final String criteriaName = data.getString("CriteriaName", ""); -+ -+ data.setString("RenderType", getRenderType(criteriaName).getId()); -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1515.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1515.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8f7a2ff2d5a154f667da35215f0e1d0756dbe2a0 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1515.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1515 { -+ -+ protected static final int VERSION = MCVersions.V1_13_PRE7 + 2; -+ -+ public static final Map RENAMED_BLOCK_IDS = ImmutableMap.builder() -+ .put("minecraft:tube_coral_fan", "minecraft:tube_coral_wall_fan") -+ .put("minecraft:brain_coral_fan", "minecraft:brain_coral_wall_fan") -+ .put("minecraft:bubble_coral_fan", "minecraft:bubble_coral_wall_fan") -+ .put("minecraft:fire_coral_fan", "minecraft:fire_coral_wall_fan") -+ .put("minecraft:horn_coral_fan", "minecraft:horn_coral_wall_fan") -+ .build(); -+ -+ private V1515() {} -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, RENAMED_BLOCK_IDS::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1624.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1624.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fc236f356067295a74e6d74e5e10ac099fc8ffa4 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1624.java -@@ -0,0 +1,110 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+ -+public final class V1624 { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final int VERSION = MCVersions.V18W32A + 1; -+ -+ private V1624() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ -+ if (level == null) { -+ return null; -+ } -+ -+ final ListType sections = level.getList("Sections", ObjectType.MAP); -+ if (sections == null) { -+ return null; -+ } -+ -+ final IntOpenHashSet positionsToLook = new IntOpenHashSet(); -+ -+ for (int i = 0, len = sections.size(); i < len; ++i) { -+ final TrappedChestSection section = new TrappedChestSection(sections.getMap(i)); -+ if (section.isSkippable()) { -+ continue; -+ } -+ -+ for (int index = 0; index < 4096; ++index) { -+ if (section.isTrappedChest(section.getBlock(index))) { -+ positionsToLook.add(section.getSectionY() << 12 | index); -+ } -+ } -+ } -+ -+ final int chunkX = level.getInt("xPos"); -+ final int chunkZ = level.getInt("zPos"); -+ -+ final ListType tileEntities = level.getList("TileEntities", ObjectType.MAP); -+ -+ if (tileEntities != null) { -+ for (int i = 0, len = tileEntities.size(); i < len; ++i) { -+ final MapType tile = tileEntities.getMap(i); -+ -+ final int x = tile.getInt("x"); -+ final int y = tile.getInt("y"); -+ final int z = tile.getInt("z"); -+ -+ final int index = V1496.getIndex(x - (chunkX << 4), y, z - (chunkZ << 4)); -+ if (!positionsToLook.contains(index)) { -+ continue; -+ } -+ -+ final String id = tile.getString("id"); -+ if (!"minecraft:chest".equals(id)) { -+ LOGGER.warn("Block Entity ({},{},{}) was expected to be a chest (V1624)", x, y, z); -+ } -+ -+ tile.setString("id", "minecraft:trapped_chest"); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ public static final class TrappedChestSection extends V1496.Section { -+ -+ private IntOpenHashSet chestIds; -+ -+ public TrappedChestSection(final MapType section) { -+ super(section); -+ } -+ -+ @Override -+ protected boolean initSkippable() { -+ this.chestIds = new IntOpenHashSet(); -+ -+ for (int i = 0; i < this.palette.size(); ++i) { -+ final MapType blockState = this.palette.getMap(i); -+ final String name = blockState.getString("Name"); -+ if ("minecraft:trapped_chest".equals(name)) { -+ this.chestIds.add(i); -+ } -+ } -+ -+ return this.chestIds.isEmpty(); -+ } -+ -+ public boolean isTrappedChest(final int id) { -+ return this.chestIds.contains(id); -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V165.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V165.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e94facc0dde06d0abbf415cce3cc0f31207900df ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V165.java -@@ -0,0 +1,79 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.gson.JsonParseException; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.chat.TextComponent; -+import net.minecraft.util.GsonHelper; -+import net.minecraft.util.datafix.fixes.BlockEntitySignTextStrictJsonFix; -+import org.apache.commons.lang3.StringUtils; -+ -+public final class V165 { -+ -+ protected static final int VERSION = MCVersions.V1_9_PRE2; -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final ListType pages = tag.getList("pages", ObjectType.STRING); -+ if (pages == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = pages.size(); i < len; ++i) { -+ final String page = pages.getString(i); -+ Component component = null; -+ -+ if (!"null".equals(page) && !StringUtils.isEmpty(page)) { -+ if (page.charAt(0) == '"' && page.charAt(page.length() - 1) == '"' || page.charAt(0) == '{' && page.charAt(page.length() - 1) == '}') { -+ try { -+ component = GsonHelper.fromJson(BlockEntitySignTextStrictJsonFix.GSON, page, Component.class, true); -+ if (component == null) { -+ component = TextComponent.EMPTY; -+ } -+ } catch (final JsonParseException ignored) {} -+ -+ if (component == null) { -+ try { -+ component = Component.Serializer.fromJson(page); -+ } catch (final JsonParseException ignored) {} -+ } -+ -+ if (component == null) { -+ try { -+ component = Component.Serializer.fromJsonLenient(page); -+ } catch (JsonParseException ignored) {} -+ } -+ -+ if (component == null) { -+ component = new TextComponent(page); -+ } -+ } else { -+ component = new TextComponent(page); -+ } -+ } else { -+ component = TextComponent.EMPTY; -+ } -+ -+ pages.setString(i, Component.Serializer.toJson(component)); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V165() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1800.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1800.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1362a7917243715305650c197a8e7e5689bcfe4a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1800.java -@@ -0,0 +1,33 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1800 { -+ -+ protected static final int VERSION = MCVersions.V1_13_2 + 169; -+ -+ public static final Map RENAMED_ITEM_IDS = ImmutableMap.builder() -+ .put("minecraft:cactus_green", "minecraft:green_dye") -+ .put("minecraft:rose_red", "minecraft:red_dye") -+ .put("minecraft:dandelion_yellow", "minecraft:yellow_dye") -+ .build(); -+ -+ private V1800() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, RENAMED_ITEM_IDS::get); -+ -+ registerMob("minecraft:panda"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:pillager", new DataWalkerItemLists("Inventory", "ArmorItems", "HandItems")); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1801.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1801.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a4e2fa4ed6ede8d1783b5591ef1b5ebf3cd28bf0 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1801.java -@@ -0,0 +1,21 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V1801 { -+ -+ protected static final int VERSION = MCVersions.V1_13_2 + 170; -+ -+ private V1801() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:illager_beast"); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1802.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1802.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cd5110ef3c18662871020456b60edfb3aeb67166 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1802.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V1802 { -+ -+ protected static final int VERSION = MCVersions.V1_13_2 + 171; -+ -+ private V1802() {} -+ -+ public static void register() { -+ ConverterAbstractBlockRename.register(VERSION, ImmutableMap.of( -+ "minecraft:stone_slab", "minecraft:smooth_stone_slab", -+ "minecraft:sign", "minecraft:oak_sign", "minecraft:wall_sign", "minecraft:oak_wall_sign" -+ )::get); -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:stone_slab", "minecraft:smooth_stone_slab", -+ "minecraft:sign", "minecraft:oak_sign" -+ )::get); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1803.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1803.java -new file mode 100644 -index 0000000000000000000000000000000000000000..87d156b6b6066b4c312608d82e5d7d6b0c01abc7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1803.java -@@ -0,0 +1,48 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.chat.TextComponent; -+ -+public final class V1803 { -+ -+ protected static final int VERSION = MCVersions.V1_13_2 + 172; -+ -+ private V1803() {} -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ -+ if (tag == null) { -+ return null; -+ } -+ -+ final MapType display = tag.getMap("display"); -+ -+ if (display == null) { -+ return null; -+ } -+ -+ final ListType lore = display.getList("Lore", ObjectType.STRING); -+ if (lore == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = lore.size(); i < len; ++i) { -+ lore.setString(i, Component.Serializer.toJson(new TextComponent(lore.getString(i)))); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1904.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1904.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a8ac14b43f4f1cd65f1ecaf8223f2245d5540f51 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1904.java -@@ -0,0 +1,42 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1904 { -+ -+ protected static final int VERSION = MCVersions.V18W43C + 1; -+ -+ private V1904() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:ocelot", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int catType = data.getInt("CatType"); -+ -+ if (catType == 0) { -+ final String owner = data.getString("Owner"); -+ final String ownerUUID = data.getString("OwnerUUID"); -+ if ((owner != null && owner.length() > 0) || (ownerUUID != null && ownerUUID.length() > 0)) { -+ data.setBoolean("Trusting", true); -+ } -+ } else if (catType > 0 && catType < 4) { -+ data.setString("id", "minecraft:cat"); -+ } -+ -+ return null; -+ } -+ }); -+ registerMob("minecraft:cat"); -+ } -+ -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1905.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1905.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2eeec0d9cbd35ff20ba239ea7fd9c2f52f7e4f9e ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1905.java -@@ -0,0 +1,35 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1905 { -+ -+ protected static final int VERSION = MCVersions.V18W43C + 2; -+ -+ private V1905() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ -+ if (level == null) { -+ return null; -+ } -+ -+ final String status = level.getString("Status"); -+ -+ if ("postprocessed".equals(status)) { -+ level.setString("Status", "fullchunk"); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1906.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1906.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6358c2e0861a3743a3ea6d46a644870892256a79 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1906.java -@@ -0,0 +1,21 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+ -+public final class V1906 { -+ -+ protected static final int VERSION = MCVersions.V18W43C + 3; -+ -+ private V1906() {} -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:barrel", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:smoker", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:blast_furnace", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:lectern", new DataWalkerItems("Book")); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1911.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1911.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b9cc2e4a2ae42e12ccf4e0b634fd74d3aad317ab ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1911.java -@@ -0,0 +1,48 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V1911 { -+ -+ protected static final int VERSION = MCVersions.V18W46A + 1; -+ -+ private static final Map CHUNK_STATUS_REMAP = ImmutableMap.builder() -+ .put("structure_references", "empty") -+ .put("biomes", "empty") -+ .put("base", "surface") -+ .put("carved", "carvers") -+ .put("liquid_carved", "liquid_carvers") -+ .put("decorated", "features") -+ .put("lighted", "light") -+ .put("mobs_spawned", "spawn") -+ .put("finalized", "heightmaps") -+ .put("fullchunk", "full") -+ .build(); -+ -+ -+ private V1911() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ -+ if (level == null) { -+ return null; -+ } -+ -+ final String status = level.getString("Status", "empty"); -+ level.setString("Status", CHUNK_STATUS_REMAP.getOrDefault(status, "empty")); -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1917.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1917.java -new file mode 100644 -index 0000000000000000000000000000000000000000..71538d858a681c91f7193003e0808cdb4fd1f847 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1917.java -@@ -0,0 +1,26 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1917 { -+ -+ protected static final int VERSION = MCVersions.V18W49A + 1; -+ -+ private V1917() {} -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:cat", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getInt("CatType") == 9) { -+ data.setInt("CatType", 10); -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1918.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1918.java -new file mode 100644 -index 0000000000000000000000000000000000000000..247182c053abd2de4382acfeddb52af5c32abb45 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1918.java -@@ -0,0 +1,65 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V1918 { -+ -+ protected static final int VERSION = MCVersions.V18W49A + 2; -+ -+ private V1918() {} -+ -+ private static String getProfessionString(final int professionId, final int careerId) { -+ if (professionId == 0) { -+ if (careerId == 2) { -+ return "minecraft:fisherman"; -+ } else if (careerId == 3) { -+ return "minecraft:shepherd"; -+ } else { -+ return careerId == 4 ? "minecraft:fletcher" : "minecraft:farmer"; -+ } -+ } else if (professionId == 1) { -+ return careerId == 2 ? "minecraft:cartographer" : "minecraft:librarian"; -+ } else if (professionId == 2) { -+ return "minecraft:cleric"; -+ } else if (professionId == 3) { -+ if (careerId == 2) { -+ return "minecraft:weaponsmith"; -+ } else { -+ return careerId == 3 ? "minecraft:toolsmith" : "minecraft:armorer"; -+ } -+ } else if (professionId == 4) { -+ return careerId == 2 ? "minecraft:leatherworker" : "minecraft:butcher"; -+ } else { -+ return professionId == 5 ? "minecraft:nitwit" : "minecraft:none"; -+ } -+ } -+ -+ public static void register() { -+ final DataConverter, MapType> converter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int profession = data.getInt("Profession"); -+ final int career = data.getInt("Career"); -+ final Number careerLevel = data.getNumber("CareerLevel"); -+ data.remove("Profession"); -+ data.remove("Career"); -+ data.remove("CareerLevel"); -+ -+ final MapType villagerData = Types.NBT.createEmptyMap(); -+ data.setMap("VillagerData", villagerData); -+ villagerData.setString("type", "minecraft:plains"); -+ villagerData.setString("profession", getProfessionString(profession, career)); -+ villagerData.setInt("level", careerLevel == null ? 1 : careerLevel.intValue()); -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", converter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombie_villager", converter); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1920.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1920.java -new file mode 100644 -index 0000000000000000000000000000000000000000..313f13968693d7acede8c6606973939d496d1baf ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1920.java -@@ -0,0 +1,70 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1920 { -+ -+ protected static final int VERSION = MCVersions.V18W50A + 1; -+ -+ private V1920() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ final MapType structures = level.getMap("Structures"); -+ if (structures == null) { -+ return null; -+ } -+ -+ final MapType starts = structures.getMap("Starts"); -+ if (starts != null) { -+ final MapType village = starts.getMap("New_Village"); -+ if (village != null) { -+ starts.remove("New_Village"); -+ starts.setMap("Village", village); -+ } else { -+ starts.remove("Village"); -+ } -+ } -+ -+ final MapType references = structures.getMap("References"); -+ if (references != null) { -+ final MapType newVillage = references.getMap("New_Village"); -+ if (newVillage == null) { -+ references.remove("Village"); -+ } else { -+ references.remove("New_Village"); -+ references.setMap("Village", newVillage); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String id = data.getString("id"); -+ -+ if ("minecraft:new_village".equals(id)) { -+ data.setString("id", "minecraft:village"); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:campfire", new DataWalkerItemLists("Items")); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1925.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1925.java -new file mode 100644 -index 0000000000000000000000000000000000000000..19dc3d9b18d95d5f0e898d4c52c77a527066adf1 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1925.java -@@ -0,0 +1,29 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V1925 { -+ -+ protected static final int VERSION = MCVersions.V19W03C + 1; -+ -+ public static void register() { -+ MCTypeRegistry.SAVED_DATA.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType root, final long sourceVersion, final long toVersion) { -+ final MapType data = root.getMap("data"); -+ if (data == null) { -+ final MapType ret = Types.NBT.createEmptyMap(); -+ ret.setMap("data", root); -+ -+ return ret; -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1928.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1928.java -new file mode 100644 -index 0000000000000000000000000000000000000000..86caefba615a917d3530112edcc083caaaea4bb9 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1928.java -@@ -0,0 +1,30 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.entity.ConverterAbstractEntityRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V1928 { -+ -+ protected static final int VERSION = MCVersions.V19W04B + 1; -+ -+ private V1928() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ ConverterAbstractEntityRename.register(VERSION, ImmutableMap.of( -+ "minecraft:illager_beast", "minecraft:ravager" -+ )::get); -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:illager_beast_spawn_egg", "minecraft:ravager_spawn_egg" -+ )::get); -+ -+ registerMob("minecraft:ravager"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1929.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1929.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d58c32aa89e416e40cfef7c5840b772dd4991173 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1929.java -@@ -0,0 +1,49 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V1929 { -+ -+ protected static final int VERSION = MCVersions.V19W04B + 2; -+ -+ private V1929() {} -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:wandering_trader", (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Inventory", fromVersion, toVersion); -+ -+ final MapType offers = data.getMap("Offers"); -+ if (offers != null) { -+ final ListType recipes = offers.getList("Recipes", ObjectType.MAP); -+ if (recipes != null) { -+ for (int i = 0, len = recipes.size(); i < len; ++i) { -+ final MapType recipe = recipes.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buy", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buyB", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "sell", fromVersion, toVersion); -+ } -+ } -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "ArmorItems", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "HandItems", fromVersion, toVersion); -+ -+ return null; -+ }); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:trader_llama", (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, data, "SaddleItem", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, data, "DecorItem", fromVersion, toVersion); -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Items", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "ArmorItems", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "HandItems", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1931.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1931.java -new file mode 100644 -index 0000000000000000000000000000000000000000..da845df91d42f1059490d749b235758850ce7254 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1931.java -@@ -0,0 +1,21 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V1931 { -+ -+ protected static final int VERSION = MCVersions.V19W06A; -+ -+ private V1931() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:fox"); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1936.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1936.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4e7b22874f17f531b583146db3aa4e57bdd5f27c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1936.java -@@ -0,0 +1,37 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1936 { -+ -+ protected static final int VERSION = MCVersions.V19W09A + 1; -+ -+ private V1936() {} -+ -+ public static void register() { -+ MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String chatOpacity = data.getString("chatOpacity"); -+ if (chatOpacity != null) { -+ // Vanilla uses createDouble here, but options is always string -> string. I presume they made -+ // a mistake with this converter. -+ data.setString("textBackgroundOpacity", Double.toString(calculateBackground(chatOpacity))); -+ } -+ return null; -+ } -+ }); -+ } -+ -+ private static double calculateBackground(final String opacity) { -+ try { -+ final double d = 0.9D * Double.parseDouble(opacity) + 0.1D; -+ return d / 2.0D; -+ } catch (final NumberFormatException ex) { -+ return 0.5D; -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1946.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1946.java -new file mode 100644 -index 0000000000000000000000000000000000000000..42bfb1877154327b0f266a17daafcc1756882ff7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1946.java -@@ -0,0 +1,42 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V1946 { -+ -+ protected static final int VERSION = MCVersions.V19W14B + 1; -+ -+ private V1946() {} -+ -+ public static void register() { -+ MCTypeRegistry.POI_CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType sections = Types.NBT.createEmptyMap(); -+ data.setMap("Sections", sections); -+ -+ for (int y = 0; y < 16; ++y) { -+ final String key = Integer.toString(y); -+ final MapType records = data.getMap(key); -+ -+ if (records == null) { -+ continue; -+ } -+ -+ data.remove(key); -+ -+ final MapType section = Types.NBT.createEmptyMap(); -+ section.setMap("Records", records); -+ sections.setMap(key, section); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1948.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1948.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6b4af1fe7c53e6122d7db952770d14a753f8cab3 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1948.java -@@ -0,0 +1,39 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1948 { -+ -+ protected static final int VERSION = MCVersions.V1_14_PRE2; -+ -+ private V1948() {} -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:white_banner", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final MapType display = tag.getMap("display"); -+ if (display == null) { -+ return null; -+ } -+ -+ final String name = display.getString("Name"); -+ if (name == null) { -+ return null; -+ } -+ -+ display.setString("Name", name.replace("\"translate\":\"block.minecraft.illager_banner\"", "\"translate\":\"block.minecraft.ominous_banner\"")); -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1953.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1953.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a73471e8f3df3b22349b2f842c3e98c2ff8bb5e1 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1953.java -@@ -0,0 +1,27 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1953 { -+ -+ protected static final int VERSION = MCVersions.V1_14 + 1; -+ -+ private V1953() {} -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:banner", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String name = data.getString("CustomName"); -+ if (name != null) { -+ data.setString("CustomName", name.replace("\"translate\":\"block.minecraft.illager_banner\"", "\"translate\":\"block.minecraft.ominous_banner\"")); -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1955.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1955.java -new file mode 100644 -index 0000000000000000000000000000000000000000..33bfe82709b507c4fd57199f5d8a44d131718d7f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1955.java -@@ -0,0 +1,94 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+import net.minecraft.util.Mth; -+ -+public final class V1955 { -+ -+ protected static final int VERSION = MCVersions.V1_14_1_PRE1; -+ -+ private static final int[] LEVEL_XP_THRESHOLDS = new int[] { -+ 0, -+ 10, -+ 50, -+ 100, -+ 150 -+ }; -+ -+ private V1955() {} -+ -+ static int getMinXpPerLevel(final int level) { -+ return LEVEL_XP_THRESHOLDS[Mth.clamp(level - 1, 0, LEVEL_XP_THRESHOLDS.length - 1)]; -+ } -+ -+ static void addLevel(final MapType data, final int level) { -+ MapType villagerData = data.getMap("VillagerData"); -+ if (villagerData == null) { -+ villagerData = Types.NBT.createEmptyMap(); -+ data.setMap("VillagerData", villagerData); -+ } -+ villagerData.setInt("level", level); -+ } -+ -+ static void addXpFromLevel(final MapType data, final int level) { -+ data.setInt("Xp", getMinXpPerLevel(level)); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType villagerData = data.getMap("VillagerData"); -+ int level = villagerData == null ? 0 : villagerData.getInt("level"); -+ if (level == 0 || level == 1) { -+ // count recipes -+ final MapType offers = data.getMap("Offers"); -+ final ListType recipes = offers == null ? null : offers.getList("Recipes", ObjectType.MAP); -+ final int recipeCount; -+ if (recipes != null) { -+ recipeCount = recipes.size(); -+ } else { -+ recipeCount = 0; -+ } -+ -+ level = Mth.clamp(recipeCount / 2, 1, 5); -+ if (level > 1) { -+ addLevel(data, level); -+ } -+ } -+ -+ if (!data.hasKey("Xp", ObjectType.NUMBER)) { -+ addXpFromLevel(data, level); -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombie_villager", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final Number xp = data.getNumber("Xp"); -+ if (xp == null) { -+ final int level; -+ final MapType villagerData = data.getMap("VillagerData"); -+ if (villagerData == null) { -+ level = 1; -+ } else { -+ level = villagerData.getInt("level", 1); -+ } -+ -+ data.setInt("Xp", getMinXpPerLevel(level)); -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1961.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1961.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8bc6a8734034942a81b282b8766b21fddbe2b304 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1961.java -@@ -0,0 +1,30 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V1961 { -+ -+ protected static final int VERSION = MCVersions.V1_14_2_PRE3 + 1; -+ -+ private V1961() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ level.remove("isLightOn"); -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1963.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1963.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5e4e7299cec1d3809d1b55ae460e64ec6d2bb477 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V1963.java -@@ -0,0 +1,40 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V1963 { -+ -+ protected static final int VERSION = MCVersions.V1_14_2; -+ -+ private V1963() {} -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType gossips = data.getList("Gossips", ObjectType.MAP); -+ if (gossips == null) { -+ return null; -+ } -+ -+ for (int i = 0; i < gossips.size();) { -+ final MapType gossip = gossips.getMap(i); -+ if ("golem".equals(gossip.getString("Type"))) { -+ gossips.remove(i); -+ continue; -+ } -+ -+ ++i; -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2100.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2100.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d905043c4f3071e8dc340ac2afe2b81aac345e1e ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2100.java -@@ -0,0 +1,46 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.advancements.ConverterAbstractAdvancementsRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.recipe.ConverterAbstractRecipeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V2100 { -+ -+ protected static final int VERSION = MCVersions.V1_14_4 + 124; -+ protected static final Map RECIPE_RENAMES = ImmutableMap.of( -+ "minecraft:sugar", "sugar_from_sugar_cane" -+ ); -+ -+ private V2100() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ ConverterAbstractRecipeRename.register(VERSION, RECIPE_RENAMES::get); -+ ConverterAbstractAdvancementsRename.register(VERSION, ImmutableMap.of( -+ "minecraft:recipes/misc/sugar", "minecraft:recipes/misc/sugar_from_sugar_cane" -+ )::get); -+ -+ registerMob("minecraft:bee"); -+ registerMob("minecraft:bee_stinger"); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:beehive", (data, fromVersion, toVersion) -> { -+ final ListType bees = data.getList("Bees", ObjectType.MAP); -+ if (bees != null) { -+ for (int i = 0, len = bees.size(); i < len; ++i) { -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, bees.getMap(i), "EntityData", fromVersion, toVersion); -+ } -+ } -+ -+ return null; -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2202.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2202.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b64183295fea0550ebd6e69e476155c8783f4120 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2202.java -@@ -0,0 +1,50 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V2202 { -+ -+ protected static final int VERSION = MCVersions.V19W35A + 1; -+ -+ private V2202() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ final int[] oldBiomes = level.getInts("Biomes"); -+ -+ if (oldBiomes == null) { -+ return null; -+ } -+ -+ final int[] newBiomes = new int[1024]; -+ level.setInts("Biomes", newBiomes); -+ -+ int n; -+ for(n = 0; n < 4; ++n) { -+ for(int j = 0; j < 4; ++j) { -+ int k = (j << 2) + 2; -+ int l = (n << 2) + 2; -+ int m = l << 4 | k; -+ newBiomes[n << 2 | j] = m < oldBiomes.length ? oldBiomes[m] : -1; -+ } -+ } -+ -+ for(n = 1; n < 64; ++n) { -+ System.arraycopy(newBiomes, 0, newBiomes, n * 16, 16); -+ } -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2209.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2209.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6054cd31cb2e140f05b92736405a7d073be5cf5c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2209.java -@@ -0,0 +1,26 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.poi.ConverterAbstractPOIRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V2209 { -+ -+ protected static final int VERSION = MCVersions.V19W40A + 1; -+ -+ private V2209() {} -+ -+ public static void register() { -+ final Map renamedIds = ImmutableMap.of( -+ "minecraft:bee_hive", "minecraft:beehive" -+ ); -+ -+ ConverterAbstractBlockRename.register(VERSION, renamedIds::get); -+ ConverterAbstractItemRename.register(VERSION, renamedIds::get); -+ ConverterAbstractPOIRename.register(VERSION, renamedIds::get); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2211.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2211.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6cff6d723616e0a38811872f7b5d28799240ddfe ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2211.java -@@ -0,0 +1,32 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V2211 { -+ -+ protected static final int VERSION = MCVersions.V19W41A + 1; -+ -+ private V2211() {} -+ -+ public static void register() { -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!data.hasKey("references", ObjectType.NUMBER)) { -+ return null; -+ } -+ -+ final int references = data.getInt("references"); -+ if (references <= 0) { -+ data.setInt("references", 1); -+ } -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2218.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2218.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e06a98a01086c9d6eb9fc80a151f0403247b0033 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2218.java -@@ -0,0 +1,33 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V2218 { -+ -+ protected static final int VERSION = MCVersions.V1_15_PRE1; -+ -+ private V2218() {} -+ -+ public static void register() { -+ MCTypeRegistry.POI_CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType sections = data.getMap("Sections"); -+ if (sections == null) { -+ return null; -+ } -+ -+ for (final String key : sections.keys()) { -+ final MapType section = sections.getMap(key); -+ -+ section.remove("Valid"); -+ } -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2501.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2501.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e54ef886dad69e36358cf146d7ed2f28c2182e66 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2501.java -@@ -0,0 +1,66 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V2501 { -+ -+ protected static final int VERSION = MCVersions.V1_15_2 + 271; -+ -+ private V2501() {} -+ -+ private static void registerFurnace(final String id) { -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, id, (data, fromVersion, toVersion) -> { -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Items", fromVersion, toVersion); -+ -+ WalkerUtils.convertKeys(MCTypeRegistry.RECIPE, data, "RecipesUsed", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ public static void register() { -+ final DataConverter, MapType> converter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int recipesUsedSize = data.getInt("RecipesUsedSize"); -+ data.remove("RecipesUsedSize"); -+ -+ if (recipesUsedSize <= 0) { -+ return null; -+ } -+ -+ final MapType newRecipes = Types.NBT.createEmptyMap(); -+ data.setMap("RecipesUsed", newRecipes); -+ -+ -+ for (int i = 0; i < recipesUsedSize; ++i) { -+ final String recipeKey = data.getString("RecipeLocation" + i); -+ data.remove("RecipeLocation" + i); -+ final int recipeAmount = data.getInt("RecipeAmount" + i); -+ data.remove("RecipeAmount" + i); -+ -+ if (i <= 0 || recipeKey == null) { -+ continue; -+ } -+ -+ newRecipes.setInt(recipeKey, recipeAmount); -+ } -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:furnace", converter); -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:blast_furnace", converter); -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:smoker", converter); -+ -+ registerFurnace("minecraft:furnace"); -+ registerFurnace("minecraft:smoker"); -+ registerFurnace("minecraft:blast_furnace"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2502.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2502.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7075f7beb8aacfdadd68f4353d2cf32edaa1905d ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2502.java -@@ -0,0 +1,20 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2502 { -+ -+ protected static final int VERSION = MCVersions.V1_15_2 + 272; -+ -+ private V2502() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:hoglin"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2503.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2503.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cd1bca807236b917244bbacd8df6f25fd3c42407 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2503.java -@@ -0,0 +1,67 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.advancements.ConverterAbstractAdvancementsRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.common.collect.ImmutableMap; -+import com.google.common.collect.ImmutableSet; -+import java.util.Set; -+ -+public final class V2503 { -+ -+ protected static final int VERSION = MCVersions.V1_15_2 + 273; -+ -+ private static final Set WALL_BLOCKS = ImmutableSet.of( -+ "minecraft:andesite_wall", -+ "minecraft:brick_wall", -+ "minecraft:cobblestone_wall", -+ "minecraft:diorite_wall", -+ "minecraft:end_stone_brick_wall", -+ "minecraft:granite_wall", -+ "minecraft:mossy_cobblestone_wall", -+ "minecraft:mossy_stone_brick_wall", -+ "minecraft:nether_brick_wall", -+ "minecraft:prismarine_wall", -+ "minecraft:red_nether_brick_wall", -+ "minecraft:red_sandstone_wall", -+ "minecraft:sandstone_wall", -+ "minecraft:stone_brick_wall" -+ ); -+ -+ private V2503() {} -+ -+ private static void changeWallProperty(final MapType properties, final String path) { -+ final String property = properties.getString(path); -+ if (property != null) { -+ properties.setString(path, "true".equals(property) ? "low" : "none"); -+ } -+ } -+ -+ public static void register() { -+ MCTypeRegistry.BLOCK_STATE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!WALL_BLOCKS.contains(data.getString("Name"))) { -+ return null; -+ } -+ -+ final MapType properties = data.getMap("Properties"); -+ if (properties == null) { -+ return null; -+ } -+ -+ changeWallProperty(properties, "east"); -+ changeWallProperty(properties, "west"); -+ changeWallProperty(properties, "north"); -+ changeWallProperty(properties, "south"); -+ -+ return null; -+ } -+ }); -+ ConverterAbstractAdvancementsRename.register(VERSION, ImmutableMap.of( -+ "minecraft:recipes/misc/composter", "minecraft:recipes/decorations/composter" -+ )::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2505.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2505.java -new file mode 100644 -index 0000000000000000000000000000000000000000..350f5cca06d2a864b5a3cc028753fd6489a28ad5 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2505.java -@@ -0,0 +1,49 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V2505 { -+ -+ protected static final int VERSION = MCVersions.V20W06A + 1; -+ -+ private V2505() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType brain = data.getMap("Brain"); -+ if (brain == null) { -+ return null; -+ } -+ -+ final MapType memories = brain.getMap("memories"); -+ if (memories == null) { -+ return null; -+ } -+ -+ for (final String key : memories.keys()) { -+ final Object value = memories.getGeneric(key); -+ -+ final MapType wrapped = Types.NBT.createEmptyMap(); -+ wrapped.setGeneric("value", value); -+ -+ memories.setMap(key, wrapped); -+ } -+ -+ return null; -+ } -+ }); -+ -+ registerMob("minecraft:piglin"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2508.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2508.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8cfd380e870ceea4892b8cd7bf855a6e5dc8cc6f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2508.java -@@ -0,0 +1,24 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V2508 { -+ -+ protected static final int VERSION = MCVersions.V20W08A + 1; -+ -+ private V2508() {} -+ -+ public static void register() { -+ final Map remap = ImmutableMap.of( -+ "minecraft:warped_fungi", "minecraft:warped_fungus", -+ "minecraft:crimson_fungi", "minecraft:crimson_fungus" -+ ); -+ -+ ConverterAbstractBlockRename.register(VERSION, remap::get); -+ ConverterAbstractItemRename.register(VERSION, remap::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2509.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2509.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1fa93dec8a81719a19c0f7db589778935ce44d56 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2509.java -@@ -0,0 +1,30 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.entity.ConverterAbstractEntityRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2509 { -+ -+ protected static final int VERSION = MCVersions.V20W08A + 2; -+ -+ private V2509() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:zombie_pigman_spawn_egg", "minecraft:zombified_piglin_spawn_egg" -+ )::get); -+ ConverterAbstractEntityRename.register(VERSION, ImmutableMap.of( -+ "minecraft:zombie_pigman", "minecraft:zombified_piglin" -+ )::get); -+ -+ registerMob("minecraft:zombified_piglin"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2511.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2511.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9fc7f133e03f8d1c6204e3e91d8ccf30e9cbcad7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2511.java -@@ -0,0 +1,97 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V2511 { -+ -+ protected static final int VERSION = MCVersions.V20W09A + 1; -+ -+ private V2511() {} -+ -+ private static int[] createUUIDArray(final long most, final long least) { -+ return new int[] { -+ (int)(most >>> 32), -+ (int)most, -+ (int)(least >>> 32), -+ (int)least -+ }; -+ } -+ -+ private static void setUUID(final MapType data, final long most, final long least) { -+ if (most != 0 && least != 0) { -+ data.setInts("OwnerUUID", createUUIDArray(most, least)); -+ } -+ } -+ -+ public static void register() { -+ final DataConverter, MapType> throwableConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType owner = data.getMap("owner"); -+ data.remove("owner"); -+ if (owner == null) { -+ return null; -+ } -+ -+ setUUID(data, owner.getLong("M"), owner.getLong("L")); -+ -+ return null; -+ } -+ }; -+ final DataConverter, MapType> potionConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType potion = data.getMap("Potion"); -+ data.remove("Potion"); -+ -+ data.setMap("Item", potion == null ? Types.NBT.createEmptyMap() : potion); -+ -+ return null; -+ } -+ }; -+ final DataConverter, MapType> llamaSpitConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType owner = data.getMap("Owner"); -+ data.remove("Owner"); -+ if (owner == null) { -+ return null; -+ } -+ -+ setUUID(data, owner.getLong("OwnerUUIDMost"), owner.getLong("OwnerUUIDLeast")); -+ -+ return null; -+ } -+ }; -+ final DataConverter, MapType> arrowConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ setUUID(data, data.getLong("OwnerUUIDMost"), data.getLong("OwnerUUIDLeast")); -+ -+ data.remove("OwnerUUIDMost"); -+ data.remove("OwnerUUIDLeast"); -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:egg", throwableConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:ender_pearl", throwableConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:experience_bottle", throwableConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:snowball", throwableConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:potion", throwableConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:potion", potionConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:llama_spit", llamaSpitConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:arrow", arrowConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:spectral_arrow", arrowConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:trident", arrowConverter); -+ -+ // Vanilla migrates the potion item but does not change the schema. -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:potion", new DataWalkerItems("Item")); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2514.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2514.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d494fac0900f61e60c01617e631a0431bbda9438 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2514.java -@@ -0,0 +1,590 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.google.common.collect.Sets; -+import java.util.Set; -+import java.util.UUID; -+ -+public final class V2514 { -+ -+ protected static final int VERSION = MCVersions.V20W11A + 1; -+ -+ private static final Set ABSTRACT_HORSES = Sets.newHashSet(); -+ private static final Set TAMEABLE_ANIMALS = Sets.newHashSet(); -+ private static final Set ANIMALS = Sets.newHashSet(); -+ private static final Set MOBS = Sets.newHashSet(); -+ private static final Set LIVING_ENTITIES = Sets.newHashSet(); -+ private static final Set PROJECTILES = Sets.newHashSet(); -+ static { -+ ABSTRACT_HORSES.add("minecraft:donkey"); -+ ABSTRACT_HORSES.add("minecraft:horse"); -+ ABSTRACT_HORSES.add("minecraft:llama"); -+ ABSTRACT_HORSES.add("minecraft:mule"); -+ ABSTRACT_HORSES.add("minecraft:skeleton_horse"); -+ ABSTRACT_HORSES.add("minecraft:trader_llama"); -+ ABSTRACT_HORSES.add("minecraft:zombie_horse"); -+ -+ TAMEABLE_ANIMALS.add("minecraft:cat"); -+ TAMEABLE_ANIMALS.add("minecraft:parrot"); -+ TAMEABLE_ANIMALS.add("minecraft:wolf"); -+ -+ ANIMALS.add("minecraft:bee"); -+ ANIMALS.add("minecraft:chicken"); -+ ANIMALS.add("minecraft:cow"); -+ ANIMALS.add("minecraft:fox"); -+ ANIMALS.add("minecraft:mooshroom"); -+ ANIMALS.add("minecraft:ocelot"); -+ ANIMALS.add("minecraft:panda"); -+ ANIMALS.add("minecraft:pig"); -+ ANIMALS.add("minecraft:polar_bear"); -+ ANIMALS.add("minecraft:rabbit"); -+ ANIMALS.add("minecraft:sheep"); -+ ANIMALS.add("minecraft:turtle"); -+ ANIMALS.add("minecraft:hoglin"); -+ -+ MOBS.add("minecraft:bat"); -+ MOBS.add("minecraft:blaze"); -+ MOBS.add("minecraft:cave_spider"); -+ MOBS.add("minecraft:cod"); -+ MOBS.add("minecraft:creeper"); -+ MOBS.add("minecraft:dolphin"); -+ MOBS.add("minecraft:drowned"); -+ MOBS.add("minecraft:elder_guardian"); -+ MOBS.add("minecraft:ender_dragon"); -+ MOBS.add("minecraft:enderman"); -+ MOBS.add("minecraft:endermite"); -+ MOBS.add("minecraft:evoker"); -+ MOBS.add("minecraft:ghast"); -+ MOBS.add("minecraft:giant"); -+ MOBS.add("minecraft:guardian"); -+ MOBS.add("minecraft:husk"); -+ MOBS.add("minecraft:illusioner"); -+ MOBS.add("minecraft:magma_cube"); -+ MOBS.add("minecraft:pufferfish"); -+ MOBS.add("minecraft:zombified_piglin"); -+ MOBS.add("minecraft:salmon"); -+ MOBS.add("minecraft:shulker"); -+ MOBS.add("minecraft:silverfish"); -+ MOBS.add("minecraft:skeleton"); -+ MOBS.add("minecraft:slime"); -+ MOBS.add("minecraft:snow_golem"); -+ MOBS.add("minecraft:spider"); -+ MOBS.add("minecraft:squid"); -+ MOBS.add("minecraft:stray"); -+ MOBS.add("minecraft:tropical_fish"); -+ MOBS.add("minecraft:vex"); -+ MOBS.add("minecraft:villager"); -+ MOBS.add("minecraft:iron_golem"); -+ MOBS.add("minecraft:vindicator"); -+ MOBS.add("minecraft:pillager"); -+ MOBS.add("minecraft:wandering_trader"); -+ MOBS.add("minecraft:witch"); -+ MOBS.add("minecraft:wither"); -+ MOBS.add("minecraft:wither_skeleton"); -+ MOBS.add("minecraft:zombie"); -+ MOBS.add("minecraft:zombie_villager"); -+ MOBS.add("minecraft:phantom"); -+ MOBS.add("minecraft:ravager"); -+ MOBS.add("minecraft:piglin"); -+ -+ LIVING_ENTITIES.add("minecraft:armor_stand"); -+ -+ PROJECTILES.add("minecraft:arrow"); -+ PROJECTILES.add("minecraft:dragon_fireball"); -+ PROJECTILES.add("minecraft:firework_rocket"); -+ PROJECTILES.add("minecraft:fireball"); -+ PROJECTILES.add("minecraft:llama_spit"); -+ PROJECTILES.add("minecraft:small_fireball"); -+ PROJECTILES.add("minecraft:snowball"); -+ PROJECTILES.add("minecraft:spectral_arrow"); -+ PROJECTILES.add("minecraft:egg"); -+ PROJECTILES.add("minecraft:ender_pearl"); -+ PROJECTILES.add("minecraft:experience_bottle"); -+ PROJECTILES.add("minecraft:potion"); -+ PROJECTILES.add("minecraft:trident"); -+ PROJECTILES.add("minecraft:wither_skull"); -+ } -+ -+ static int[] createUUIDArray(final long most, final long least) { -+ return new int[] { -+ (int)(most >>> 32), -+ (int)most, -+ (int)(least >>> 32), -+ (int)least -+ }; -+ } -+ -+ static int[] createUUIDFromString(final MapType data, final String path) { -+ if (data == null) { -+ return null; -+ } -+ -+ final String uuidString = data.getString(path); -+ if (uuidString == null) { -+ return null; -+ } -+ -+ try { -+ final UUID uuid = UUID.fromString(uuidString); -+ return createUUIDArray(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); -+ } catch (final IllegalArgumentException ignore) { -+ return null; -+ } -+ } -+ -+ static int[] createUUIDFromLongs(final MapType data, final String most, final String least) { -+ if (data == null) { -+ return null; -+ } -+ -+ final long mostBits = data.getLong(most); -+ final long leastBits = data.getLong(least); -+ -+ return (mostBits != 0 || leastBits != 0) ? createUUIDArray(mostBits, leastBits) : null; -+ } -+ -+ static void replaceUUIDString(final MapType data, final String oldPath, final String newPath) { -+ final int[] newUUID = createUUIDFromString(data, oldPath); -+ if (newUUID != null) { -+ data.remove(oldPath); -+ data.setInts(newPath, newUUID); -+ } -+ } -+ -+ static void replaceUUIDMLTag(final MapType data, final String oldPath, final String newPath) { -+ final int[] uuid = createUUIDFromLongs(data.getMap(oldPath), "M", "L"); -+ if (uuid != null) { -+ data.remove(oldPath); -+ data.setInts(newPath, uuid); -+ } -+ } -+ -+ static void replaceUUIDLeastMost(final MapType data, final String prefix, final String newPath) { -+ final String mostPath = prefix.concat("Most"); -+ final String leastPath = prefix.concat("Least"); -+ -+ final int[] uuid = createUUIDFromLongs(data, mostPath, leastPath); -+ if (uuid != null) { -+ data.remove(mostPath); -+ data.remove(leastPath); -+ data.setInts(newPath, uuid); -+ } -+ } -+ -+ private V2514() {} -+ -+ private static void updatePiglin(final MapType data) { -+ final MapType brain = data.getMap("Brain"); -+ if (brain == null) { -+ return; -+ } -+ -+ final MapType memories = brain.getMap("memories"); -+ if (memories == null) { -+ return; -+ } -+ -+ final MapType angryAt = memories.getMap("minecraft:angry_at"); -+ -+ replaceUUIDString(angryAt, "value", "value"); -+ } -+ -+ private static void updateEvokerFangs(final MapType data) { -+ replaceUUIDLeastMost(data, "OwnerUUID", "Owner"); -+ } -+ -+ private static void updateZombieVillager(final MapType data) { -+ replaceUUIDLeastMost(data, "ConversionPlayer", "ConversionPlayer"); -+ } -+ -+ private static void updateAreaEffectCloud(final MapType data) { -+ replaceUUIDLeastMost(data, "OwnerUUID", "Owner"); -+ } -+ -+ private static void updateShulkerBullet(final MapType data) { -+ replaceUUIDMLTag(data, "Owner", "Owner"); -+ replaceUUIDMLTag(data, "Target", "Target"); -+ } -+ -+ private static void updateItem(final MapType data) { -+ replaceUUIDMLTag(data, "Owner", "Owner"); -+ replaceUUIDMLTag(data, "Thrower", "Thrower"); -+ } -+ -+ private static void updateFox(final MapType data) { -+ final ListType trustedUUIDS = data.getList("TrustedUUIDs", ObjectType.MAP); -+ if (trustedUUIDS == null) { -+ return; -+ } -+ -+ final ListType newUUIDs = Types.NBT.createEmptyList(); -+ data.remove("TrustedUUIDs"); -+ data.setList("Trusted", newUUIDs); -+ -+ for (int i = 0, len = trustedUUIDS.size(); i < len; ++i) { -+ final MapType uuid = trustedUUIDS.getMap(i); -+ final int[] newUUID = createUUIDFromLongs(uuid, "M", "L"); -+ if (newUUID != null) { -+ newUUIDs.addIntArray(newUUID); -+ } -+ } -+ } -+ -+ private static void updateHurtBy(final MapType data) { -+ replaceUUIDString(data, "HurtBy", "HurtBy"); -+ } -+ -+ private static void updateAnimalOwner(final MapType data) { -+ updateAnimal(data); -+ -+ replaceUUIDString(data, "OwnerUUID", "Owner"); -+ } -+ -+ private static void updateAnimal(final MapType data) { -+ updateMob(data); -+ -+ replaceUUIDLeastMost(data, "LoveCause", "LoveCause"); -+ } -+ -+ private static void updateMob(final MapType data) { -+ updateLivingEntity(data); -+ -+ final MapType leash = data.getMap("Leash"); -+ if (leash == null) { -+ return; -+ } -+ -+ replaceUUIDLeastMost(leash, "UUID", "UUID"); -+ } -+ -+ private static void updateLivingEntity(final MapType data) { -+ final ListType attributes = data.getList("Attributes", ObjectType.MAP); -+ if (attributes == null) { -+ return; -+ } -+ -+ for (int i = 0, len = attributes.size(); i < len; ++i) { -+ final MapType attribute = attributes.getMap(i); -+ -+ final ListType modifiers = attribute.getList("Modifiers", ObjectType.MAP); -+ if (modifiers == null) { -+ continue; -+ } -+ -+ for (int k = 0; k < modifiers.size(); ++k) { -+ replaceUUIDLeastMost(modifiers.getMap(k), "UUID", "UUID"); -+ } -+ } -+ } -+ -+ private static void updateProjectile(final MapType data) { -+ final Object ownerUUID = data.getGeneric("OwnerUUID"); -+ if (ownerUUID != null) { -+ data.remove("OwnerUUID"); -+ data.setGeneric("Owner", ownerUUID); -+ } -+ } -+ -+ private static void updateEntityUUID(final MapType data) { -+ replaceUUIDLeastMost(data, "UUID", "UUID"); -+ } -+ -+ public static void register() { -+ // Entity UUID fixes -+ -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateEntityUUID(data); -+ return null; -+ } -+ }); -+ -+ final DataConverter, MapType> animalOwnerConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateAnimalOwner(data); -+ return null; -+ } -+ }; -+ final DataConverter, MapType> animalConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateAnimal(data); -+ return null; -+ } -+ }; -+ final DataConverter, MapType> mobConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateMob(data); -+ return null; -+ } -+ }; -+ final DataConverter, MapType> livingEntityConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateLivingEntity(data); -+ return null; -+ } -+ }; -+ final DataConverter, MapType> projectileConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateProjectile(data); -+ return null; -+ } -+ }; -+ for (final String id : ABSTRACT_HORSES) { -+ MCTypeRegistry.ENTITY.addConverterForId(id, animalOwnerConverter); -+ } -+ for (final String id : TAMEABLE_ANIMALS) { -+ MCTypeRegistry.ENTITY.addConverterForId(id, animalOwnerConverter); -+ } -+ for (final String id : ANIMALS) { -+ MCTypeRegistry.ENTITY.addConverterForId(id, animalConverter); -+ } -+ for (final String id : MOBS) { -+ MCTypeRegistry.ENTITY.addConverterForId(id, mobConverter); -+ } -+ for (final String id : LIVING_ENTITIES) { -+ MCTypeRegistry.ENTITY.addConverterForId(id, livingEntityConverter); -+ } -+ for (final String id : PROJECTILES) { -+ MCTypeRegistry.ENTITY.addConverterForId(id, projectileConverter); -+ } -+ -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:bee", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateHurtBy(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombified_piglin", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateHurtBy(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:fox", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateFox(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:item", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateItem(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:shulker_bullet", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateShulkerBullet(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:area_effect_cloud", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateAreaEffectCloud(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombie_villager", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateZombieVillager(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:evoker_fangs", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateEvokerFangs(data); -+ return null; -+ } -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:piglin", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updatePiglin(data); -+ return null; -+ } -+ }); -+ -+ -+ // Update TE -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:conduit", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ replaceUUIDMLTag(data, "target_uuid", "Target"); -+ return null; -+ } -+ }); -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:skull", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType owner = data.getMap("Owner"); -+ if (owner == null) { -+ return null; -+ } -+ -+ data.remove("Owner"); -+ -+ replaceUUIDString(owner, "Id", "Id"); -+ -+ data.setMap("SkullOwner", owner); -+ -+ return null; -+ } -+ }); -+ -+ // Player UUID -+ MCTypeRegistry.PLAYER.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ updateLivingEntity(data); -+ updateEntityUUID(data); -+ -+ final MapType rootVehicle = data.getMap("RootVehicle"); -+ if (rootVehicle == null) { -+ return null; -+ } -+ -+ replaceUUIDLeastMost(rootVehicle, "Attach", "Attach"); -+ -+ return null; -+ } -+ }); -+ -+ // Level.dat -+ MCTypeRegistry.LEVEL.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ replaceUUIDString(data, "WanderingTraderId", "WanderingTraderId"); -+ -+ final MapType dimensionData = data.getMap("DimensionData"); -+ if (dimensionData != null) { -+ for (final String key : dimensionData.keys()) { -+ final MapType dimension = dimensionData.getMap(key); -+ -+ final MapType dragonFight = dimension.getMap("DragonFight"); -+ if (dragonFight == null) { -+ continue; -+ } -+ -+ replaceUUIDLeastMost(dragonFight, "DragonUUID", "Dragon"); -+ } -+ } -+ -+ final MapType customBossEvents = data.getMap("CustomBossEvents"); -+ if (customBossEvents != null) { -+ for (final String key : customBossEvents.keys()) { -+ final MapType customBossEvent = customBossEvents.getMap(key); -+ -+ final ListType players = customBossEvent.getList("Players", ObjectType.MAP); -+ if (players == null) { -+ continue; -+ } -+ -+ final ListType newPlayers = Types.NBT.createEmptyList(); -+ customBossEvent.setList("Players", newPlayers); -+ -+ for (int i = 0, len = players.size(); i < len; ++i) { -+ final int[] newUUID = createUUIDFromLongs(players.getMap(i), "M", "L"); -+ if (newUUID != null) { -+ newPlayers.addIntArray(newUUID); -+ } -+ } -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.SAVED_DATA.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType root, final long sourceVersion, final long toVersion) { -+ final MapType data = root.getMap("data"); -+ if (data == null) { -+ return null; -+ } -+ -+ final ListType raids = data.getList("Raids", ObjectType.MAP); -+ if (raids == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = raids.size(); i < len; ++i) { -+ final MapType raid = raids.getMap(i); -+ -+ final ListType heros = raid.getList("HeroesOfTheVillage", ObjectType.MAP); -+ -+ if (heros == null) { -+ continue; -+ } -+ -+ final ListType newHeros = Types.NBT.createEmptyList(); -+ raid.setList("HeroesOfTheVillage", newHeros); -+ -+ for (int k = 0, klen = heros.size(); k < klen; ++k) { -+ final MapType uuidOld = heros.getMap(i); -+ final int[] uuidNew = createUUIDFromLongs(uuidOld, "UUIDMost", "UUIDLeast"); -+ if (uuidNew != null) { -+ newHeros.addIntArray(uuidNew); -+ } -+ } -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ updateAttributeModifiers(tag); -+ -+ if ("minecraft:player_head".equals(data.getString("id"))) { -+ updateSkullOwner(tag); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private static void updateAttributeModifiers(final MapType tag) { -+ final ListType attributes = tag.getList("AttributeModifiers", ObjectType.MAP); -+ if (attributes == null) { -+ return; -+ } -+ -+ for (int i = 0, len = attributes.size(); i < len; ++i) { -+ replaceUUIDLeastMost(attributes.getMap(i), "UUID", "UUID"); -+ } -+ } -+ -+ private static void updateSkullOwner(final MapType tag) { -+ replaceUUIDString(tag.getMap("SkullOwner"), "Id", "Id"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2516.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2516.java -new file mode 100644 -index 0000000000000000000000000000000000000000..40bf0a1788520bbf1d66da53b6532bdd8af246f4 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2516.java -@@ -0,0 +1,37 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V2516 { -+ -+ protected static final int VERSION = MCVersions.V20W12A + 1; -+ -+ private V2516() {} -+ -+ public static void register() { -+ final DataConverter, MapType> gossipUUIDConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType gossips = data.getList("Gossips", ObjectType.MAP); -+ -+ if (gossips == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = gossips.size(); i < len; ++i) { -+ V2514.replaceUUIDLeastMost(gossips.getMap(i), "Target", "Target"); -+ } -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", gossipUUIDConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombie_villager", gossipUUIDConverter); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2518.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2518.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e7a55eeb02fb99289e4c8bfe2d28fc4a0c716719 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2518.java -@@ -0,0 +1,63 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V2518 { -+ -+ protected static final int VERSION = MCVersions.V20W12A + 3; -+ -+ private static final Map FACING_RENAMES = ImmutableMap.builder() -+ .put("down", "down_south") -+ .put("up", "up_north") -+ .put("north", "north_up") -+ .put("south", "south_up") -+ .put("west", "west_up") -+ .put("east", "east_up") -+ .build(); -+ -+ -+ private V2518() {} -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:jigsaw", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String type = data.getString("attachement_type", "minecraft:empty"); -+ final String pool = data.getString("target_pool", "minecraft:empty"); -+ data.remove("attachement_type"); -+ data.remove("target_pool"); -+ -+ data.setString("name", type); -+ data.setString("target", type); -+ data.setString("pool", pool); -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.BLOCK_STATE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!"minecraft:jigsaw".equals(data.getString("Name"))) { -+ return null; -+ } -+ -+ final MapType properties = data.getMap("Properties"); -+ if (properties == null) { -+ return null; -+ } -+ -+ final String facing = properties.getString("facing", "north"); -+ properties.remove("facing"); -+ properties.setString("orientation", FACING_RENAMES.getOrDefault(facing, facing)); -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2519.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2519.java -new file mode 100644 -index 0000000000000000000000000000000000000000..47a8bb340e72e48fd237d4001b55c81b1182a72f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2519.java -@@ -0,0 +1,20 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2519 { -+ -+ protected static final int VERSION = MCVersions.V20W12A + 4; -+ -+ private V2519() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:strider"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2522.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2522.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3a91600427cb013cdfc03b084017b6f32d9e05fa ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2522.java -@@ -0,0 +1,20 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2522 { -+ -+ protected static final int VERSION = MCVersions.V20W13B + 1; -+ -+ private V2522() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:zoglin"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2523.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2523.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5d3726bb7670bc89feb8ebeed5c097a77e909f5a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2523.java -@@ -0,0 +1,92 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V2523 { -+ -+ protected static final int VERSION = MCVersions.V20W13B + 2; -+ -+ private static final Map RENAMES = ImmutableMap.builder() -+ .put("generic.maxHealth", "generic.max_health") -+ .put("Max Health", "generic.max_health") -+ .put("zombie.spawnReinforcements", "zombie.spawn_reinforcements") -+ .put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements") -+ .put("horse.jumpStrength", "horse.jump_strength") -+ .put("Jump Strength", "horse.jump_strength") -+ .put("generic.followRange", "generic.follow_range") -+ .put("Follow Range", "generic.follow_range") -+ .put("generic.knockbackResistance", "generic.knockback_resistance") -+ .put("Knockback Resistance", "generic.knockback_resistance") -+ .put("generic.movementSpeed", "generic.movement_speed") -+ .put("Movement Speed", "generic.movement_speed") -+ .put("generic.flyingSpeed", "generic.flying_speed") -+ .put("Flying Speed", "generic.flying_speed") -+ .put("generic.attackDamage", "generic.attack_damage") -+ .put("generic.attackKnockback", "generic.attack_knockback") -+ .put("generic.attackSpeed", "generic.attack_speed") -+ .put("generic.armorToughness", "generic.armor_toughness") -+ .build(); -+ -+ private V2523() {} -+ -+ private static void updateName(final MapType data, final String path) { -+ if (data == null) { -+ return; -+ } -+ -+ final String name = data.getString(path); -+ if (name != null) { -+ final String renamed = RENAMES.get(name); -+ if (renamed != null) { -+ data.setString(path, renamed); -+ } -+ } -+ } -+ -+ public static void register() { -+ final DataConverter, MapType> entityConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType attributes = data.getList("Attributes", ObjectType.MAP); -+ -+ if (attributes == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = attributes.size(); i < len; ++i) { -+ updateName(attributes.getMap(i), "Name"); -+ } -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.ENTITY.addStructureConverter(entityConverter); -+ MCTypeRegistry.PLAYER.addStructureConverter(entityConverter); -+ -+ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType attributes = data.getList("AttributeModifiers", ObjectType.MAP); -+ -+ if (attributes == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = attributes.size(); i < len; ++i) { -+ updateName(attributes.getMap(i), "AttributeName"); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2527.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2527.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5e951f91d03f95ed671bb7403592960690c65879 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2527.java -@@ -0,0 +1,123 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.mojang.datafixers.DataFixUtils; -+import net.minecraft.util.Mth; -+ -+public final class V2527 { -+ -+ protected static final int VERSION = MCVersions.V20W16A + 1; -+ -+ private V2527() {} -+ -+ public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType level = data.getMap("Level"); -+ -+ if (level == null) { -+ return null; -+ } -+ -+ final ListType sections = level.getList("Sections", ObjectType.MAP); -+ if (sections != null) { -+ for (int i = 0, len = sections.size(); i < len; ++i) { -+ final MapType section = sections.getMap(i); -+ -+ final ListType palette = section.getList("Palette", ObjectType.MAP); -+ -+ if (palette == null) { -+ continue; -+ } -+ -+ final int bits = Math.max(4, DataFixUtils.ceillog2(palette.size())); -+ -+ if (Mth.isPowerOfTwo(bits)) { -+ // fits perfectly -+ continue; -+ } -+ -+ final long[] states = section.getLongs("BlockStates"); -+ if (states == null) { -+ // wat -+ continue; -+ } -+ -+ section.setLongs("BlockStates", addPadding(4096, bits, states)); -+ } -+ } -+ -+ final MapType heightMaps = level.getMap("Heightmaps"); -+ if (heightMaps != null) { -+ for (final String key : heightMaps.keys()) { -+ final long[] old = heightMaps.getLongs(key); -+ heightMaps.setLongs(key, addPadding(256, 9, old)); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ public static long[] addPadding(final int indices, final int bits, final long[] old) { -+ int k = old.length; -+ if (k == 0) { -+ return old; -+ } else { -+ long l = (1L << bits) - 1L; -+ int m = 64 / bits; -+ int n = (indices + m - 1) / m; -+ long[] padded = new long[n]; -+ int o = 0; -+ int p = 0; -+ long q = 0L; -+ int r = 0; -+ long s = old[0]; -+ long t = k > 1 ? old[1] : 0L; -+ -+ for(int u = 0; u < indices; ++u) { -+ int v = u * bits; -+ int w = v >> 6; -+ int x = (u + 1) * bits - 1 >> 6; -+ int y = v ^ w << 6; -+ if (w != r) { -+ s = t; -+ t = w + 1 < k ? old[w + 1] : 0L; -+ r = w; -+ } -+ -+ long ab; -+ int ac; -+ if (w == x) { -+ ab = s >>> y & l; -+ } else { -+ ac = 64 - y; -+ ab = (s >>> y | t << ac) & l; -+ } -+ -+ ac = p + bits; -+ if (ac >= 64) { -+ padded[o++] = q; -+ q = ab; -+ p = bits; -+ } else { -+ q |= ab << p; -+ p = ac; -+ } -+ } -+ -+ if (q != 0L) { -+ padded[o] = q; -+ } -+ -+ return padded; -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2528.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2528.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f7f2e3f75a9f8a5533fe010bc23e8384878d7ce8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2528.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2528 { -+ -+ protected static final int VERSION = MCVersions.V20W16A + 2; -+ -+ private V2528() {} -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:soul_fire_torch", "minecraft:soul_torch", -+ "minecraft:soul_fire_lantern", "minecraft:soul_lantern" -+ )::get); -+ ConverterAbstractBlockRename.register(VERSION, ImmutableMap.of( -+ "minecraft:soul_fire_torch", "minecraft:soul_torch", -+ "minecraft:soul_fire_wall_torch", "minecraft:soul_wall_torch", -+ "minecraft:soul_fire_lantern", "minecraft:soul_lantern" -+ )::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2529.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2529.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f239dbf4beb87efd1fff4e5d8d6f041fa8687f01 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2529.java -@@ -0,0 +1,25 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V2529 { -+ -+ protected static final int VERSION = MCVersions.V20W17A; -+ -+ private V2529() {} -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:strider", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getBoolean("NoGravity")) { -+ data.setBoolean("NoGravity", false); -+ } -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2531.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2531.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7783d75578d29e09029b26c8c8c0b053c5526eb9 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2531.java -@@ -0,0 +1,63 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V2531 { -+ -+ protected static final int VERSION = MCVersions.V20W17A + 2; -+ -+ private V2531() {} -+ -+ private static boolean isConnected(final String facing) { -+ return !"none".equals(facing); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.BLOCK_STATE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!"minecraft:redstone_wire".equals(data.getString("Name"))) { -+ return null; -+ } -+ -+ final MapType properties = data.getMap("Properties"); -+ -+ if (properties == null) { -+ return null; -+ } -+ -+ -+ final String east = properties.getString("east", "none"); -+ final String west = properties.getString("west", "none"); -+ final String north = properties.getString("north", "none"); -+ final String south = properties.getString("south", "none"); -+ -+ final boolean connectedX = isConnected(east) || isConnected(west); -+ final boolean connectedZ = isConnected(north) || isConnected(south); -+ -+ final String newEast = !isConnected(east) && !connectedZ ? "side" : east; -+ final String newWest = !isConnected(west) && !connectedZ ? "side" : west; -+ final String newNorth = !isConnected(north) && !connectedX ? "side" : north; -+ final String newSouth = !isConnected(south) && !connectedX ? "side" : south; -+ -+ if (properties.hasKey("east")) { -+ properties.setString("east", newEast); -+ } -+ if (properties.hasKey("west")) { -+ properties.setString("west", newWest); -+ } -+ if (properties.hasKey("north")) { -+ properties.setString("north", newNorth); -+ } -+ if (properties.hasKey("south")) { -+ properties.setString("south", newSouth); -+ } -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2533.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2533.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ece1cd5afab80a8271b2ebac95dcc0a6239cd42c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2533.java -@@ -0,0 +1,43 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V2533 { -+ -+ protected static final int VERSION = MCVersions.V20W18A + 1; -+ -+ private V2533() {} -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:villager", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType attributes = data.getList("Attributes", ObjectType.MAP); -+ -+ if (attributes == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = attributes.size(); i < len; ++i) { -+ final MapType attribute = attributes.getMap(i); -+ -+ if (!"generic.follow_range".equals(attribute.getString("Name"))) { -+ continue; -+ } -+ -+ if (attribute.getDouble("Base") == 16.0) { -+ attribute.setDouble("Base", 48.0); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2535.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2535.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9648299bb96c20c783bb7c7010173a0f007584e0 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2535.java -@@ -0,0 +1,34 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V2535 { -+ -+ protected static final int VERSION = MCVersions.V20W19A + 1; -+ -+ private V2535() {} -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:shulker", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ // Mojang uses doubles for whatever reason... rotation is in FLOAT. by using double here -+ // the entity load will just ignore rotation and set it to 0... -+ final ListType rotation = data.getList("Rotation", ObjectType.FLOAT); -+ -+ if (rotation == null || rotation.size() == 0) { -+ return null; -+ } -+ -+ rotation.setFloat(0, rotation.getFloat(0) - 180.0F); -+ -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2550.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2550.java -new file mode 100644 -index 0000000000000000000000000000000000000000..19d900f5198982eb22a9fbc7639d333be9800fe2 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2550.java -@@ -0,0 +1,341 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.google.common.collect.ImmutableMap; -+import org.apache.commons.lang3.math.NumberUtils; -+import java.util.HashMap; -+import java.util.Locale; -+import java.util.Map; -+ -+public final class V2550 { -+ -+ protected static final int VERSION = MCVersions.V20W20B + 13; -+ -+ private static final ImmutableMap DEFAULTS = ImmutableMap.builder() -+ .put("minecraft:village", new StructureFeatureConfiguration(32, 8, 10387312)) -+ .put("minecraft:desert_pyramid", new StructureFeatureConfiguration(32, 8, 14357617)) -+ .put("minecraft:igloo", new StructureFeatureConfiguration(32, 8, 14357618)) -+ .put("minecraft:jungle_pyramid", new StructureFeatureConfiguration(32, 8, 14357619)) -+ .put("minecraft:swamp_hut", new StructureFeatureConfiguration(32, 8, 14357620)) -+ .put("minecraft:pillager_outpost", new StructureFeatureConfiguration(32, 8, 165745296)) -+ .put("minecraft:monument", new StructureFeatureConfiguration(32, 5, 10387313)) -+ .put("minecraft:endcity", new StructureFeatureConfiguration(20, 11, 10387313)) -+ .put("minecraft:mansion", new StructureFeatureConfiguration(80, 20, 10387319)) -+ .build(); -+ -+ record StructureFeatureConfiguration(int spacing, int separation, int salt) { -+ -+ public MapType serialize() { -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ ret.setInt("spacing", this.spacing); -+ ret.setInt("separation", this.separation); -+ ret.setInt("salt", this.salt); -+ -+ return ret; -+ } -+ } -+ -+ public static void register() { -+ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final long seed = data.getLong("RandomSeed"); -+ String generatorName = data.getString("generatorName"); -+ if (generatorName != null) { -+ generatorName = generatorName.toLowerCase(Locale.ROOT); -+ } -+ String legacyCustomOptions = data.getString("legacy_custom_options"); -+ if (legacyCustomOptions == null) { -+ legacyCustomOptions = "customized".equals(generatorName) ? data.getString("generatorOptions") : null; -+ } -+ -+ final MapType generator; -+ boolean caves = false; -+ -+ if ("customized".equals(generatorName) || generatorName == null) { -+ generator = defaultOverworld(seed); -+ } else { -+ switch (generatorName) { -+ case "flat": { -+ final MapType generatorOptions = data.getMap("generatorOptions"); -+ -+ final MapType structures = fixFlatStructures(generatorOptions); -+ final MapType settings = Types.NBT.createEmptyMap(); -+ generator = Types.NBT.createEmptyMap(); -+ generator.setString("type", "minecraft:flat"); -+ generator.setMap("settings", settings); -+ -+ settings.setMap("structures", structures); -+ -+ ListType layers = generatorOptions.getList("layers", ObjectType.MAP); -+ if (layers == null) { -+ layers = Types.NBT.createEmptyList(); -+ -+ final int[] heights = new int[] { 1, 2, 1 }; -+ final String[] blocks = new String[] { "minecraft:bedrock", "minecraft:dirt", "minecraft:grass_block" }; -+ for (int i = 0; i < 3; ++i) { -+ final MapType layer = Types.NBT.createEmptyMap(); -+ layer.setInt("height", heights[i]); -+ layer.setString("block", blocks[i]); -+ } -+ } -+ -+ settings.setList("layers", layers); -+ settings.setString("biome", generatorOptions.getString("biome", "minecraft:plains")); -+ -+ break; -+ } -+ -+ case "debug_all_block_states": { -+ generator = Types.NBT.createEmptyMap(); -+ generator.setString("type", "minecraft:debug"); -+ break; -+ } -+ -+ case "buffet": { -+ final MapType generatorOptions = data.getMap("generatorOptions"); -+ final MapType chunkGenerator = generatorOptions == null ? null : generatorOptions.getMap("chunk_generator"); -+ final String chunkGeneratorType = chunkGenerator == null ? null : chunkGenerator.getString("type"); -+ -+ final String newType; -+ if ("minecraft:caves".equals(chunkGeneratorType)) { -+ newType = "minecraft:caves"; -+ caves = true; -+ } else if ("minecraft:floating_islands".equals(chunkGeneratorType)) { -+ newType = "minecraft:floating_islands"; -+ } else { -+ newType = "minecraft:overworld"; -+ } -+ -+ MapType biomeSource = generatorOptions == null ? null : generatorOptions.getMap("biome_source"); -+ if (biomeSource == null) { -+ biomeSource = Types.NBT.createEmptyMap(); -+ biomeSource.setString("type", "minecraft:fixed"); -+ } -+ -+ if ("minecraft:fixed".equals(biomeSource.getString("type"))) { -+ final MapType options = biomeSource.getMap("options"); -+ final ListType biomes = options == null ? null : options.getList("biomes", ObjectType.STRING); -+ final String biome = biomes == null || biomes.size() == 0 ? "minecraft:ocean" : biomes.getString(0); -+ biomeSource.remove("options"); -+ biomeSource.setString("biome", biome); -+ } -+ -+ generator = noise(seed, newType, biomeSource); -+ break; -+ } -+ -+ default: { -+ boolean defaultGen = generatorName.equals("default"); -+ boolean default11Gen = generatorName.equals("default_1_1") || defaultGen && data.getInt("generatorVersion") == 0; -+ boolean amplified = generatorName.equals("amplified"); -+ boolean largeBiomes = generatorName.equals("largebiomes"); -+ -+ generator = noise(seed, amplified ? "minecraft:amplified" : "minecraft:overworld", -+ vanillaBiomeSource(seed, default11Gen, largeBiomes)); -+ break; -+ } -+ } -+ } -+ -+ final boolean mapFeatures = data.getBoolean("MapFeatures", true); -+ final boolean bonusChest = data.getBoolean("BonusChest", false); -+ -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ ret.setLong("seed", seed); -+ ret.setBoolean("generate_features", mapFeatures); -+ ret.setBoolean("bonus_chest", bonusChest); -+ ret.setMap("dimensions", vanillaLevels(seed, generator, caves)); -+ if (legacyCustomOptions != null) { -+ ret.setString("legacy_custom_options", legacyCustomOptions); -+ } -+ -+ return ret; -+ } -+ }); -+ } -+ -+ public static MapType noise(final long seed, final String worldType, final MapType biomeSource) { -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ ret.setString("type", "minecraft:noise"); -+ ret.setMap("biome_source", biomeSource); -+ ret.setLong("seed", seed); -+ ret.setString("settings", worldType); -+ -+ return ret; -+ } -+ -+ public static MapType vanillaBiomeSource(final long seed, final boolean default11Gen, final boolean largeBiomes) { -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ ret.setString("type", "minecraft:vanilla_layered"); -+ ret.setLong("seed", seed); -+ ret.setBoolean("large_biomes", largeBiomes); -+ if (default11Gen) { -+ ret.setBoolean("legacy_biome_init_layer", default11Gen); -+ } -+ -+ return ret; -+ } -+ -+ public static MapType fixFlatStructures(final MapType generatorOptions) { -+ int distance = 32; -+ int spread = 3; -+ int count = 128; -+ boolean stronghold = false; -+ final Map newStructures = new HashMap<>(); -+ -+ if (generatorOptions == null) { -+ stronghold = true; -+ newStructures.put("minecraft:village", DEFAULTS.get("minecraft:village")); -+ } -+ -+ final MapType oldStructures = generatorOptions == null ? null : generatorOptions.getMap("structures"); -+ if (oldStructures != null) { -+ for (final String structureName : oldStructures.keys()) { -+ final MapType structureValues = oldStructures.getMap(structureName); -+ if (structureValues == null) { -+ continue; -+ } -+ -+ for (final String structureValueKey : structureValues.keys()) { -+ final String structureValue = structureValues.getString(structureValueKey); -+ -+ if ("stronghold".equals(structureName)) { -+ stronghold = true; -+ switch (structureValueKey) { -+ case "distance": -+ distance = getInt(structureValue, distance, 1); -+ break; -+ case "spread": -+ spread = getInt(structureValue, spread, 1); -+ break; -+ case "count": -+ count = getInt(structureValue, count, 1); -+ break; -+ } -+ } else { -+ switch (structureValueKey) { -+ case "distance": -+ switch (structureName) { -+ case "village": -+ setSpacing(newStructures, "minecraft:village", structureValue, 9); -+ break; -+ case "biome_1": -+ setSpacing(newStructures, "minecraft:desert_pyramid", structureValue, 9); -+ setSpacing(newStructures, "minecraft:igloo", structureValue, 9); -+ setSpacing(newStructures, "minecraft:jungle_pyramid", structureValue, 9); -+ setSpacing(newStructures, "minecraft:swamp_hut", structureValue, 9); -+ setSpacing(newStructures, "minecraft:pillager_outpost", structureValue, 9); -+ break; -+ case "endcity": -+ setSpacing(newStructures, "minecraft:endcity", structureValue, 1); -+ break; -+ case "mansion": -+ setSpacing(newStructures, "minecraft:mansion", structureValue, 1); -+ break; -+ default: -+ break; -+ } -+ case "separation": -+ if ("oceanmonument".equals(structureName)) { -+ final StructureFeatureConfiguration structure = newStructures.getOrDefault("minecraft:monument", DEFAULTS.get("minecraft:monument")); -+ final int newSpacing = getInt(structureValue, structure.separation, 1); -+ newStructures.put("minecraft:monument", new StructureFeatureConfiguration(newSpacing, structure.separation, structure.salt)); -+ } -+ -+ break; -+ case "spacing": -+ if ("oceanmonument".equals(structureName)) { -+ setSpacing(newStructures, "minecraft:monument", structureValue, 1); -+ } -+ -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ final MapType ret = Types.NBT.createEmptyMap(); -+ final MapType structuresSerialized = Types.NBT.createEmptyMap(); -+ ret.setMap("structures", structuresSerialized); -+ for (final String key : newStructures.keySet()) { -+ structuresSerialized.setMap(key, newStructures.get(key).serialize()); -+ } -+ -+ if (stronghold) { -+ final MapType strongholdData = Types.NBT.createEmptyMap(); -+ ret.setMap("stronghold", strongholdData); -+ -+ strongholdData.setInt("distance", distance); -+ strongholdData.setInt("spread", spread); -+ strongholdData.setInt("count", count); -+ } -+ -+ return ret; -+ } -+ -+ public static MapType vanillaLevels(final long seed, final MapType generator, final boolean caves) { -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ final MapType overworld = Types.NBT.createEmptyMap(); -+ final MapType nether = Types.NBT.createEmptyMap(); -+ final MapType end = Types.NBT.createEmptyMap(); -+ -+ ret.setMap("minecraft:overworld", overworld); -+ ret.setMap("minecraft:the_nether", nether); -+ ret.setMap("minecraft:the_end", end); -+ -+ // overworld -+ overworld.setString("type", caves ? "minecraft:overworld_caves" : "minecraft:overworld"); -+ overworld.setMap("generator", generator); -+ -+ // nether -+ nether.setString("type", "minecraft:the_nether"); -+ final MapType netherBiomeSource = Types.NBT.createEmptyMap(); -+ netherBiomeSource.setString("type", "minecraft:multi_noise"); -+ netherBiomeSource.setLong("seed", seed); -+ netherBiomeSource.setString("preset", "minecraft:nether"); -+ -+ nether.setMap("generator", noise(seed, "minecraft:nether", netherBiomeSource)); -+ -+ // end -+ end.setString("type", "minecraft:the_end"); -+ final MapType endBiomeSource = Types.NBT.createEmptyMap(); -+ endBiomeSource.setString("type", "minecraft:the_end"); -+ endBiomeSource.setLong("seed", seed); -+ end.setMap("generator", noise(seed,"minecraft:end", endBiomeSource)); -+ -+ return ret; -+ } -+ -+ public static MapType defaultOverworld(final long seed) { -+ return noise(seed, "minecraft:overworld", vanillaBiomeSource(seed, false, false)); -+ } -+ -+ private static int getInt(final String value, final int dfl) { -+ return NumberUtils.toInt(value, dfl); -+ } -+ -+ private static int getInt(final String value, final int dfl, final int minVal) { -+ return Math.max(minVal, getInt(value, dfl)); -+ } -+ -+ private static void setSpacing(final Map structures, final String structureName, -+ final String value, final int minVal) { -+ final StructureFeatureConfiguration structure = structures.getOrDefault(structureName, DEFAULTS.get(structureName)); -+ final int newSpacing = getInt(value, structure.spacing, minVal); -+ -+ structures.put(structureName, new StructureFeatureConfiguration(newSpacing, structure.separation, structure.salt)); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2551.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2551.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ac0c4475556fe5202a6aa5724cb47b35c0cc9c00 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2551.java -@@ -0,0 +1,101 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+ -+public final class V2551 { -+ -+ protected static final int VERSION = MCVersions.V20W20B + 14; -+ -+ public static void register() { -+ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType dimensions = data.getMap("dimensions"); -+ -+ if (dimensions == null) { -+ return null; -+ } -+ -+ for (final String dimension : dimensions.keys()) { -+ final MapType dimensionData = dimensions.getMap(dimension); -+ if (dimensionData == null) { -+ continue; -+ } -+ -+ final MapType generator = dimensionData.getMap("generator"); -+ if (generator == null) { -+ continue; -+ } -+ -+ final String type = generator.getString("type"); -+ if (type == null) { -+ continue; -+ } -+ -+ switch (type) { -+ case "minecraft:flat": { -+ final MapType settings = generator.getMap("settings"); -+ if (settings == null) { -+ continue; -+ } -+ -+ WalkerUtils.convert(MCTypeRegistry.BIOME, settings, "biome", fromVersion, toVersion); -+ -+ final ListType layers = settings.getList("layers", ObjectType.MAP); -+ if (layers != null) { -+ for (int i = 0, len = layers.size(); i < len; ++i) { -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, layers.getMap(i), "block", fromVersion, toVersion); -+ } -+ } -+ -+ break; -+ } -+ case "minecraft:noise": { -+ final MapType settings = generator.getMap("settings"); -+ if (settings != null) { -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, settings, "default_block", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, settings, "default_fluid", fromVersion, toVersion); -+ } -+ -+ final MapType biomeSource = generator.getMap("biome_source"); -+ if (biomeSource != null) { -+ final String biomeSourceType = biomeSource.getString("type", ""); -+ switch (biomeSourceType) { -+ case "minecraft:fixed": { -+ WalkerUtils.convert(MCTypeRegistry.BIOME, biomeSource, "biome", fromVersion, toVersion); -+ break; -+ } -+ -+ case "minecraft:multi_noise": { -+ // Vanilla's schema is wrong. It should be DSL.fields("biomes", DSL.list(DSL.fields("biome"))) -+ // But it just contains the list part. That obviously can never be the case, because -+ // the root object is a compound, not a list. -+ -+ final ListType biomes = biomeSource.getList("biomes", ObjectType.MAP); -+ if (biomes != null) { -+ for (int i = 0, len = biomes.size(); i < len; ++i) { -+ WalkerUtils.convert(MCTypeRegistry.BIOME, biomes.getMap(i), "biome", fromVersion, toVersion); -+ } -+ } -+ break; -+ } -+ -+ case "minecraft:checkerboard": { -+ WalkerUtils.convertList(MCTypeRegistry.BIOME, biomeSource, "biomes", fromVersion, toVersion); -+ break; -+ } -+ } -+ } -+ -+ break; -+ } -+ } -+ } -+ -+ return null; -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2552.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2552.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c06aa2099494f82bad2c1f212b2db07405f8f6ff ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2552.java -@@ -0,0 +1,20 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2552 { -+ -+ protected static final int VERSION = MCVersions.V20W20B + 15; -+ -+ private V2552() {} -+ -+ public static void register() { -+ ConverterAbstractStringValueTypeRename.register(VERSION, MCTypeRegistry.BIOME, ImmutableMap.of( -+ "minecraft:nether", "minecraft:nether_wastes" -+ )::get); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2553.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2553.java -new file mode 100644 -index 0000000000000000000000000000000000000000..20c57f66e92922a8843887fb032f01c873c45679 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2553.java -@@ -0,0 +1,75 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import com.google.common.collect.ImmutableMap; -+import java.util.Map; -+ -+public final class V2553 { -+ -+ protected static final int VERSION = MCVersions.V20W20B + 16; -+ -+ public static final Map BIOME_RENAMES = ImmutableMap.builder() -+ .put("minecraft:extreme_hills", "minecraft:mountains") -+ .put("minecraft:swampland", "minecraft:swamp") -+ .put("minecraft:hell", "minecraft:nether_wastes") -+ .put("minecraft:sky", "minecraft:the_end") -+ .put("minecraft:ice_flats", "minecraft:snowy_tundra") -+ .put("minecraft:ice_mountains", "minecraft:snowy_mountains") -+ .put("minecraft:mushroom_island", "minecraft:mushroom_fields") -+ .put("minecraft:mushroom_island_shore", "minecraft:mushroom_field_shore") -+ .put("minecraft:beaches", "minecraft:beach") -+ .put("minecraft:forest_hills", "minecraft:wooded_hills") -+ .put("minecraft:smaller_extreme_hills", "minecraft:mountain_edge") -+ .put("minecraft:stone_beach", "minecraft:stone_shore") -+ .put("minecraft:cold_beach", "minecraft:snowy_beach") -+ .put("minecraft:roofed_forest", "minecraft:dark_forest") -+ .put("minecraft:taiga_cold", "minecraft:snowy_taiga") -+ .put("minecraft:taiga_cold_hills", "minecraft:snowy_taiga_hills") -+ .put("minecraft:redwood_taiga", "minecraft:giant_tree_taiga") -+ .put("minecraft:redwood_taiga_hills", "minecraft:giant_tree_taiga_hills") -+ .put("minecraft:extreme_hills_with_trees", "minecraft:wooded_mountains") -+ .put("minecraft:savanna_rock", "minecraft:savanna_plateau") -+ .put("minecraft:mesa", "minecraft:badlands") -+ .put("minecraft:mesa_rock", "minecraft:wooded_badlands_plateau") -+ .put("minecraft:mesa_clear_rock", "minecraft:badlands_plateau") -+ .put("minecraft:sky_island_low", "minecraft:small_end_islands") -+ .put("minecraft:sky_island_medium", "minecraft:end_midlands") -+ .put("minecraft:sky_island_high", "minecraft:end_highlands") -+ .put("minecraft:sky_island_barren", "minecraft:end_barrens") -+ .put("minecraft:void", "minecraft:the_void") -+ .put("minecraft:mutated_plains", "minecraft:sunflower_plains") -+ .put("minecraft:mutated_desert", "minecraft:desert_lakes") -+ .put("minecraft:mutated_extreme_hills", "minecraft:gravelly_mountains") -+ .put("minecraft:mutated_forest", "minecraft:flower_forest") -+ .put("minecraft:mutated_taiga", "minecraft:taiga_mountains") -+ .put("minecraft:mutated_swampland", "minecraft:swamp_hills") -+ .put("minecraft:mutated_ice_flats", "minecraft:ice_spikes") -+ .put("minecraft:mutated_jungle", "minecraft:modified_jungle") -+ .put("minecraft:mutated_jungle_edge", "minecraft:modified_jungle_edge") -+ .put("minecraft:mutated_birch_forest", "minecraft:tall_birch_forest") -+ .put("minecraft:mutated_birch_forest_hills", "minecraft:tall_birch_hills") -+ .put("minecraft:mutated_roofed_forest", "minecraft:dark_forest_hills") -+ .put("minecraft:mutated_taiga_cold", "minecraft:snowy_taiga_mountains") -+ .put("minecraft:mutated_redwood_taiga", "minecraft:giant_spruce_taiga") -+ .put("minecraft:mutated_redwood_taiga_hills", "minecraft:giant_spruce_taiga_hills") -+ .put("minecraft:mutated_extreme_hills_with_trees", "minecraft:modified_gravelly_mountains") -+ .put("minecraft:mutated_savanna", "minecraft:shattered_savanna") -+ .put("minecraft:mutated_savanna_rock", "minecraft:shattered_savanna_plateau") -+ .put("minecraft:mutated_mesa", "minecraft:eroded_badlands") -+ .put("minecraft:mutated_mesa_rock", "minecraft:modified_wooded_badlands_plateau") -+ .put("minecraft:mutated_mesa_clear_rock", "minecraft:modified_badlands_plateau") -+ .put("minecraft:warm_deep_ocean", "minecraft:deep_warm_ocean") -+ .put("minecraft:lukewarm_deep_ocean", "minecraft:deep_lukewarm_ocean") -+ .put("minecraft:cold_deep_ocean", "minecraft:deep_cold_ocean") -+ .put("minecraft:frozen_deep_ocean", "minecraft:deep_frozen_ocean") -+ .build(); -+ -+ -+ private V2553() {} -+ -+ public static void register() { -+ ConverterAbstractStringValueTypeRename.register(VERSION, MCTypeRegistry.BIOME, BIOME_RENAMES::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2558.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2558.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0e228fd642cbca13e8682950b5f0ec4e3e8a4da7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2558.java -@@ -0,0 +1,45 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.options.ConverterAbstractOptionsRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2558 { -+ -+ protected static final int VERSION = MCVersions.V1_16_PRE2 + 1; -+ -+ private V2558() {} -+ -+ public static void register() { -+ ConverterAbstractOptionsRename.register(VERSION, ImmutableMap.of( -+ "key_key.swapHands", "key_key.swapOffhand" -+ )::get); -+ -+ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ MapType dimensions = data.getMap("dimensions"); -+ if (dimensions == null) { -+ dimensions = Types.NBT.createEmptyMap(); -+ data.setMap("dimensions", dimensions); -+ } -+ -+ if (dimensions.isEmpty()) { -+ data.setMap("dimensions", recreateSettings(data)); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private static MapType recreateSettings(final MapType data) { -+ final long seed = data.getLong("seed"); -+ -+ return V2550.vanillaLevels(seed, V2550.defaultOverworld(seed), false); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2568.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2568.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5835159d7016fb4f05d137acba709fa7d8e8e752 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2568.java -@@ -0,0 +1,20 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2568 { -+ -+ protected static final int VERSION = MCVersions.V1_16_1 + 1; -+ -+ private V2568() {} -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:piglin_brute"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2671.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2671.java -new file mode 100644 -index 0000000000000000000000000000000000000000..374d24db80f3ed8cd241e18d776c39a8da72d8fd ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2671.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2671 { -+ -+ protected static final int VERSION = MCVersions.V1_16_5 + 85; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:goat"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2679.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2679.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6c788f51be0439797bf9fc8711d4cf8e382f5c11 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2679.java -@@ -0,0 +1,36 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V2679 { -+ -+ protected static final int VERSION = MCVersions.V1_16_5 + 93; -+ -+ public static void register() { -+ MCTypeRegistry.BLOCK_STATE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!"minecraft:cauldron".equals(data.getString("Name"))) { -+ return null; -+ } -+ -+ final MapType properties = data.getMap("Properties"); -+ -+ if (properties == null) { -+ return null; -+ } -+ -+ if (properties.getString("level", "0").equals("0")) { -+ data.remove("Properties"); -+ return null; -+ } else { -+ data.setString("Name", "minecraft:water_cauldron"); -+ return null; -+ } -+ } -+ }); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2680.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2680.java -new file mode 100644 -index 0000000000000000000000000000000000000000..232a28c07c6341a996253282d9872d76b3fce0e3 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2680.java -@@ -0,0 +1,21 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2680 { -+ -+ protected static final int VERSION = MCVersions.V1_16_5 + 94; -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:grass_path", "minecraft:dirt_path" -+ )::get); -+ ConverterAbstractBlockRename.registerAndFixJigsaw(VERSION, ImmutableMap.of( -+ "minecraft:grass_path", "minecraft:dirt_path" -+ )::get); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2686.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2686.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f6a6f33d4f701f4188828994c8e56dea21950366 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2686.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2686 { -+ -+ protected static final int VERSION = MCVersions.V20W49A + 1; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:axolotl"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2688.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2688.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2c6450ae2786d05a9eed8c2e8ae03acf5ff3dab4 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2688.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2688 { -+ -+ protected static final int VERSION = MCVersions.V20W51A + 1; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:glow_squid"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2690.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2690.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1638f04efd4063c23807b29bc226ad33eed27e7b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2690.java -@@ -0,0 +1,39 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2690 { -+ -+ protected static final int VERSION = MCVersions.V21W05A; -+ -+ protected static final ImmutableMap RENAMES = ImmutableMap.builder() -+ .put("minecraft:weathered_copper_block", "minecraft:oxidized_copper_block") -+ .put("minecraft:semi_weathered_copper_block", "minecraft:weathered_copper_block") -+ .put("minecraft:lightly_weathered_copper_block", "minecraft:exposed_copper_block") -+ .put("minecraft:weathered_cut_copper", "minecraft:oxidized_cut_copper") -+ .put("minecraft:semi_weathered_cut_copper", "minecraft:weathered_cut_copper") -+ .put("minecraft:lightly_weathered_cut_copper", "minecraft:exposed_cut_copper") -+ .put("minecraft:weathered_cut_copper_stairs", "minecraft:oxidized_cut_copper_stairs") -+ .put("minecraft:semi_weathered_cut_copper_stairs", "minecraft:weathered_cut_copper_stairs") -+ .put("minecraft:lightly_weathered_cut_copper_stairs", "minecraft:exposed_cut_copper_stairs") -+ .put("minecraft:weathered_cut_copper_slab", "minecraft:oxidized_cut_copper_slab") -+ .put("minecraft:semi_weathered_cut_copper_slab", "minecraft:weathered_cut_copper_slab") -+ .put("minecraft:lightly_weathered_cut_copper_slab", "minecraft:exposed_cut_copper_slab") -+ .put("minecraft:waxed_semi_weathered_copper", "minecraft:waxed_weathered_copper") -+ .put("minecraft:waxed_lightly_weathered_copper", "minecraft:waxed_exposed_copper") -+ .put("minecraft:waxed_semi_weathered_cut_copper", "minecraft:waxed_weathered_cut_copper") -+ .put("minecraft:waxed_lightly_weathered_cut_copper", "minecraft:waxed_exposed_cut_copper") -+ .put("minecraft:waxed_semi_weathered_cut_copper_stairs", "minecraft:waxed_weathered_cut_copper_stairs") -+ .put("minecraft:waxed_lightly_weathered_cut_copper_stairs", "minecraft:waxed_exposed_cut_copper_stairs") -+ .put("minecraft:waxed_semi_weathered_cut_copper_slab", "minecraft:waxed_weathered_cut_copper_slab") -+ .put("minecraft:waxed_lightly_weathered_cut_copper_slab", "minecraft:waxed_exposed_cut_copper_slab") -+ .build(); -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, RENAMES::get); -+ ConverterAbstractBlockRename.registerAndFixJigsaw(VERSION, RENAMES::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2691.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2691.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3841780d52c2e242609fc076efa5902c063b7b48 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2691.java -@@ -0,0 +1,23 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2691 { -+ -+ protected static final int VERSION = MCVersions.V21W05A + 1; -+ -+ protected static final ImmutableMap RENAMES = ImmutableMap.builder() -+ .put("minecraft:waxed_copper", "minecraft:waxed_copper_block") -+ .put("minecraft:oxidized_copper_block", "minecraft:oxidized_copper") -+ .put("minecraft:weathered_copper_block", "minecraft:weathered_copper") -+ .put("minecraft:exposed_copper_block", "minecraft:exposed_copper") -+ .build(); -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, RENAMES::get); -+ ConverterAbstractBlockRename.registerAndFixJigsaw(VERSION, RENAMES::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2696.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2696.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0094154c1da7cb95120e01bceeb836ca7ab68e25 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2696.java -@@ -0,0 +1,36 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2696 { -+ -+ protected static final int VERSION = MCVersions.V21W07A + 1; -+ -+ protected static final ImmutableMap RENAMES = ImmutableMap.builder() -+ .put("minecraft:grimstone", "minecraft:deepslate") -+ .put("minecraft:grimstone_slab", "minecraft:cobbled_deepslate_slab") -+ .put("minecraft:grimstone_stairs", "minecraft:cobbled_deepslate_stairs") -+ .put("minecraft:grimstone_wall", "minecraft:cobbled_deepslate_wall") -+ .put("minecraft:polished_grimstone", "minecraft:polished_deepslate") -+ .put("minecraft:polished_grimstone_slab", "minecraft:polished_deepslate_slab") -+ .put("minecraft:polished_grimstone_stairs", "minecraft:polished_deepslate_stairs") -+ .put("minecraft:polished_grimstone_wall", "minecraft:polished_deepslate_wall") -+ .put("minecraft:grimstone_tiles", "minecraft:deepslate_tiles") -+ .put("minecraft:grimstone_tile_slab", "minecraft:deepslate_tile_slab") -+ .put("minecraft:grimstone_tile_stairs", "minecraft:deepslate_tile_stairs") -+ .put("minecraft:grimstone_tile_wall", "minecraft:deepslate_tile_wall") -+ .put("minecraft:grimstone_bricks", "minecraft:deepslate_bricks") -+ .put("minecraft:grimstone_brick_slab", "minecraft:deepslate_brick_slab") -+ .put("minecraft:grimstone_brick_stairs", "minecraft:deepslate_brick_stairs") -+ .put("minecraft:grimstone_brick_wall", "minecraft:deepslate_brick_wall") -+ .put("minecraft:chiseled_grimstone", "minecraft:chiseled_deepslate") -+ .build(); -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, RENAMES::get); -+ ConverterAbstractBlockRename.registerAndFixJigsaw(VERSION, RENAMES::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2700.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2700.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c37142033061a3e4865686ee64d8f15f040d7d41 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2700.java -@@ -0,0 +1,17 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2700 { -+ -+ protected static final int VERSION = MCVersions.V21W10A + 1; -+ -+ public static void register() { -+ ConverterAbstractBlockRename.registerAndFixJigsaw(VERSION, ImmutableMap.of( -+ "minecraft:cave_vines_head", "minecraft:cave_vines", -+ "minecraft:cave_vines_body", "minecraft:cave_vines_plant" -+ )::get); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2701.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2701.java -new file mode 100644 -index 0000000000000000000000000000000000000000..47eb9e3b454af3ae5d88be5107c68bebc001a82b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2701.java -@@ -0,0 +1,209 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.common.collect.Sets; -+import java.util.Set; -+import java.util.regex.Matcher; -+import java.util.regex.Pattern; -+ -+public final class V2701 { -+ -+ protected static final int VERSION = MCVersions.V21W10A + 2; -+ -+ private static final Pattern INDEX_PATTERN = Pattern.compile("\\[(\\d+)\\]"); -+ -+ private static final Set PIECE_TYPE = Sets.newHashSet( -+ "minecraft:jigsaw", -+ "minecraft:nvi", -+ "minecraft:pcp", -+ "minecraft:bastionremnant", -+ "minecraft:runtime" -+ ); -+ private static final Set FEATURES = Sets.newHashSet( -+ "minecraft:tree", -+ "minecraft:flower", -+ "minecraft:block_pile", -+ "minecraft:random_patch" -+ ); -+ -+ public static void register() { -+ MCTypeRegistry.STRUCTURE_FEATURE.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final ListType children = data.getList("Children", ObjectType.MAP); -+ -+ if (children == null) { -+ return null; -+ } -+ -+ for (int i = 0, len = children.size(); i < len; ++i) { -+ final MapType child = children.getMap(i); -+ -+ if (!PIECE_TYPE.contains(child.getString("id"))) { -+ continue; -+ } -+ -+ final String poolElement = child.getString("pool_element"); -+ if (!"minecraft:feature_pool_element".equals(poolElement)) { -+ continue; -+ } -+ -+ final MapType feature = child.getMap("feature"); -+ if (feature == null) { -+ continue; -+ } -+ -+ final String featureName = feature.getString("name"); -+ -+ if (featureName == null) { -+ continue; -+ } -+ -+ final String replacement = convertToString(feature); -+ -+ if (replacement != null) { -+ child.setString("feature", replacement); -+ } -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private static String getNestedString(final MapType root, final String... paths) { -+ if (paths.length == 0) { -+ throw new IllegalArgumentException("Missing path"); -+ } -+ -+ Object current = root.getGeneric(paths[0]); -+ -+ for (int i = 1; i < paths.length; ++i) { -+ final String path = paths[i]; -+ -+ final Matcher indexMatcher = INDEX_PATTERN.matcher(path); -+ if (!indexMatcher.matches()) { -+ current = (current instanceof MapType) ? ((MapType)current).getGeneric(path) : null; -+ if (current == null) { -+ break; -+ } -+ continue; -+ } -+ -+ final int index = Integer.parseInt(indexMatcher.group(1)); -+ if (!(current instanceof ListType)) { -+ current = null; -+ break; -+ } else { -+ final ListType list = (ListType)current; -+ if (index >= 0 && index < list.size()) { -+ current = list.getGeneric(index); -+ } else { -+ current = null; -+ break; -+ } -+ } -+ } -+ -+ return current instanceof String ? (String)current : ""; -+ } -+ -+ protected static String convertToString(final MapType feature) { -+ return getReplacement( -+ getNestedString(feature, "type"), -+ getNestedString(feature, "name"), -+ getNestedString(feature, "config", "state_provider", "type"), -+ getNestedString(feature, "config", "state_provider", "state", "Name"), -+ getNestedString(feature, "config", "state_provider", "entries", "[0]", "data", "Name"), -+ getNestedString(feature, "config", "foliage_placer", "type"), -+ getNestedString(feature, "config", "leaves_provider", "state", "Name") -+ ); -+ } -+ -+ private static String getReplacement(final String type, final String name, final String stateType, final String stateName, -+ final String firstEntryName, final String foliageName, final String leavesName) { -+ final String actualType; -+ if (!type.isEmpty()) { -+ actualType = type; -+ } else { -+ if (name.isEmpty()) { -+ return null; -+ } -+ -+ if ("minecraft:normal_tree".equals(name)) { -+ actualType = "minecraft:tree"; -+ } else { -+ actualType = name; -+ } -+ } -+ -+ if (FEATURES.contains(actualType)) { -+ if ("minecraft:random_patch".equals(actualType)) { -+ if ("minecraft:simple_state_provider".equals(stateType)) { -+ if ("minecraft:sweet_berry_bush".equals(stateName)) { -+ return "minecraft:patch_berry_bush"; -+ } -+ -+ if ("minecraft:cactus".equals(stateName)) { -+ return "minecraft:patch_cactus"; -+ } -+ } else if ("minecraft:weighted_state_provider".equals(stateType) && ("minecraft:grass".equals(firstEntryName) || "minecraft:fern".equals(firstEntryName))) { -+ return "minecraft:patch_taiga_grass"; -+ } -+ } else if ("minecraft:block_pile".equals(actualType)) { -+ if (!"minecraft:simple_state_provider".equals(stateType) && !"minecraft:rotated_block_provider".equals(stateType)) { -+ if ("minecraft:weighted_state_provider".equals(stateType)) { -+ if ("minecraft:packed_ice".equals(firstEntryName) || "minecraft:blue_ice".equals(firstEntryName)) { -+ return "minecraft:pile_ice"; -+ } -+ -+ if ("minecraft:jack_o_lantern".equals(firstEntryName) || "minecraft:pumpkin".equals(firstEntryName)) { -+ return "minecraft:pile_pumpkin"; -+ } -+ } -+ } else { -+ if ("minecraft:hay_block".equals(stateName)) { -+ return "minecraft:pile_hay"; -+ } -+ -+ if ("minecraft:melon".equals(stateName)) { -+ return "minecraft:pile_melon"; -+ } -+ -+ if ("minecraft:snow".equals(stateName)) { -+ return "minecraft:pile_snow"; -+ } -+ } -+ } else { -+ if ("minecraft:flower".equals(actualType)) { -+ return "minecraft:flower_plain"; -+ } -+ -+ if ("minecraft:tree".equals(actualType)) { -+ if ("minecraft:acacia_foliage_placer".equals(foliageName)) { -+ return "minecraft:acacia"; -+ } -+ -+ if ("minecraft:blob_foliage_placer".equals(foliageName) && "minecraft:oak_leaves".equals(leavesName)) { -+ return "minecraft:oak"; -+ } -+ -+ if ("minecraft:pine_foliage_placer".equals(foliageName)) { -+ return "minecraft:pine"; -+ } -+ -+ if ("minecraft:spruce_foliage_placer".equals(foliageName)) { -+ return "minecraft:spruce"; -+ } -+ } -+ } -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2702.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2702.java -new file mode 100644 -index 0000000000000000000000000000000000000000..53e45b14c05dab35cd5725998458d47e28718075 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2702.java -@@ -0,0 +1,33 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V2702 { -+ -+ protected static final int VERSION = MCVersions.V21W10A + 3; -+ -+ public static void register() { -+ final DataConverter, MapType> arrowConverter = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.hasKey("pickup")) { -+ return null; -+ } -+ -+ final boolean player = data.getBoolean("player", true); -+ data.remove("player"); -+ -+ data.setByte("pickup", player ? (byte)1 : (byte)0); -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:arrow", arrowConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:spectral_arrow", arrowConverter); -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:trident", arrowConverter); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2707.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2707.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9acd9ed381063f93bfe74cf78db5cb8b87dfbcd5 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2707.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V2707 { -+ -+ protected static final int VERSION = MCVersions.V21W14A + 1; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("minecraft:marker"); // ????????????? -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2710.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2710.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0d31b10a4f93c0eb8bff66dd062ffb950b2182ec ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2710.java -@@ -0,0 +1,17 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.stats.ConverterAbstractStatsRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2710 { -+ -+ protected static final int VERSION = MCVersions.V21W15A + 1; -+ -+ public static void register() { -+ ConverterAbstractStatsRename.register(VERSION, ImmutableMap.of( -+ "minecraft:play_one_minute", "minecraft:play_time" -+ )::get); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2717.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2717.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8678ba95b5abe96b399a310623078f8827dfa0f0 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2717.java -@@ -0,0 +1,20 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.blockname.ConverterAbstractBlockRename; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V2717 { -+ -+ protected static final int VERSION = MCVersions.V1_17_PRE1 + 1; -+ -+ public static void register() { -+ final ImmutableMap rename = ImmutableMap.of( -+ "minecraft:azalea_leaves_flowers", "minecraft:flowering_azalea_leaves" -+ ); -+ ConverterAbstractItemRename.register(VERSION, rename::get); -+ ConverterAbstractBlockRename.register(VERSION, rename::get); -+ } -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V501.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V501.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6ab2bf99d72983fc2742a1f6f2f7fa671611526d ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V501.java -@@ -0,0 +1,21 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+ -+public final class V501 { -+ -+ protected static final int VERSION = MCVersions.V16W20A; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ registerMob("PolarBear"); -+ } -+ -+ private V501() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V502.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V502.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d2ecd656d6fb12763ec0cf972de813018da33271 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V502.java -@@ -0,0 +1,43 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.concurrent.ThreadLocalRandom; -+ -+public final class V502 { -+ -+ protected static final int VERSION = MCVersions.V16W20A + 1; -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, (final String name) -> { -+ return "minecraft:cooked_fished".equals(name) ? "minecraft:cooked_fish" : null; -+ }); -+ MCTypeRegistry.ENTITY.addConverterForId("Zombie", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!data.getBoolean("IsVillager") || data.getNumber("ZombieType") != null) { -+ return null; -+ } -+ -+ data.remove("IsVillager"); -+ -+ int type = data.getInt("VillagerProfession", -1); -+ // Vanilla doesn't remove the profession tag, so we don't! -+ if (type < 0 || type >= 6) { -+ type = ThreadLocalRandom.current().nextInt(6); -+ } -+ -+ data.setInt("ZombieType", type); -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V502() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V505.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V505.java -new file mode 100644 -index 0000000000000000000000000000000000000000..30769f902c7d694bce41ab319d0b9a87c6103f11 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V505.java -@@ -0,0 +1,24 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V505 { -+ -+ protected static final int VERSION = MCVersions.V16W21B + 1; -+ -+ public static void register() { -+ MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ data.setString("useVbo", "true"); -+ return null; -+ } -+ }); -+ } -+ -+ private V505() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V700.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V700.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1a6da0a9a886ea5192c4cc206ff0106c0640097c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V700.java -@@ -0,0 +1,35 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V700 { -+ -+ protected static final int VERSION = MCVersions.V1_10_2 + 188; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("Guardian", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (data.getBoolean("Elder")) { -+ data.setString("id", "ElderGuardian"); -+ } -+ data.remove("Elder"); -+ return null; -+ } -+ }); -+ -+ registerMob("ElderGuardian"); -+ } -+ -+ private V700() { -+ -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V701.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V701.java -new file mode 100644 -index 0000000000000000000000000000000000000000..42f173f426fb7d26e5ddb5a1c92c63b2e6a4930c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V701.java -@@ -0,0 +1,43 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V701 { -+ -+ protected static final int VERSION = MCVersions.V1_10_2 + 189; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("Skeleton", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int type = data.getInt("SkeletonType"); -+ data.remove("SkeletonType"); -+ -+ switch (type) { -+ case 1: -+ data.setString("id", "WitherSkeleton"); -+ break; -+ case 2: -+ data.setString("id", "Stray"); -+ break; -+ } -+ -+ return null; -+ } -+ }); -+ -+ registerMob("WitherSkeleton"); -+ registerMob("Stray"); -+ } -+ -+ private V701() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V702.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V702.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5cc91edde9c8160f75165bcef554023246e0a224 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V702.java -@@ -0,0 +1,53 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V702 { -+ -+ protected static final int VERSION = MCVersions.V1_10_2 + 190; -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("Zombie", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int zombieType = data.getInt("ZombieType"); -+ data.remove("ZombieType"); -+ -+ switch (zombieType) { -+ case 0: -+ default: -+ break; -+ -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ data.setString("id", "ZombieVillager"); -+ data.setInt("Profession", zombieType - 1); -+ break; -+ -+ case 6: -+ data.setString("id", "Husk"); -+ break; -+ } -+ -+ return null; -+ } -+ }); -+ -+ registerMob("ZombieVillager"); -+ registerMob( "Husk"); -+ } -+ -+ private V702() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V703.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V703.java -new file mode 100644 -index 0000000000000000000000000000000000000000..88d9c0fcd88ccfd6d6b46ae050914079c816fa3f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V703.java -@@ -0,0 +1,66 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V703 { -+ -+ protected static final int VERSION = MCVersions.V1_10_2 + 191; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("EntityHorse", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final int type = data.getInt("Type"); -+ data.remove("Type"); -+ -+ switch (type) { -+ case 0: -+ default: -+ data.setString("id", "Horse"); -+ break; -+ -+ case 1: -+ data.setString("id", "Donkey"); -+ break; -+ -+ case 2: -+ data.setString("id", "Mule"); -+ break; -+ -+ case 3: -+ data.setString("id", "ZombieHorse"); -+ break; -+ -+ case 4: -+ data.setString("id", "SkeletonHorse"); -+ break; -+ } -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Horse", new DataWalkerItems("ArmorItem", "SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Horse", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Donkey", new DataWalkerItems("SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Donkey", new DataWalkerItemLists("Items", "ArmorItems", "HandItems")); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Mule", new DataWalkerItems("SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Mule", new DataWalkerItemLists("Items", "ArmorItems", "HandItems")); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ZombieHorse", new DataWalkerItems("SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ZombieHorse", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "SkeletonHorse", new DataWalkerItems("SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "SkeletonHorse", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ private V703() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V704.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V704.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1d1df6d50f9e6acd8f416cb86e74e6974f4d3913 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V704.java -@@ -0,0 +1,328 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.item_name.DataWalkerItemNames; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import net.minecraft.core.Registry; -+import net.minecraft.world.item.BlockItem; -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.block.EntityBlock; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import java.util.HashMap; -+import java.util.Map; -+ -+public final class V704 { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final int VERSION = MCVersions.V1_10_2 + 192; -+ -+ public static final Map ITEM_ID_TO_TILE_ENTITY_ID = new HashMap() { -+ @Override -+ public String put(final String key, final String value) { -+ if (this.containsKey(key)) { -+ LOGGER.fatal("Duplicate item id to tile key: " + key); -+ throw new RuntimeException(); // only devs should see the consequence of this... at least start up the damn thing... -+ } -+ return super.put(key, value); -+ } -+ }; -+ static { -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:furnace", "minecraft:furnace"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:lit_furnace", "minecraft:furnace"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:chest", "minecraft:chest"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:trapped_chest", "minecraft:chest"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:ender_chest", "minecraft:ender_chest"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:jukebox", "minecraft:jukebox"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:dispenser", "minecraft:dispenser"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:dropper", "minecraft:dropper"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:mob_spawner", "minecraft:mob_spawner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:spawner", "minecraft:mob_spawner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:noteblock", "minecraft:noteblock"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:brewing_stand", "minecraft:brewing_stand"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:enhanting_table", "minecraft:enchanting_table"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:command_block", "minecraft:command_block"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:beacon", "minecraft:beacon"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:skull", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:daylight_detector", "minecraft:daylight_detector"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:hopper", "minecraft:hopper"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:flower_pot", "minecraft:flower_pot"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:repeating_command_block", "minecraft:command_block"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:chain_command_block", "minecraft:command_block"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:white_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:orange_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:magenta_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:light_blue_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:yellow_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:lime_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:pink_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:gray_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:silver_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:cyan_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:purple_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:blue_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:brown_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:green_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:red_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:black_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:light_gray_shulker_box", "minecraft:shulker_box"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:white_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:orange_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:magenta_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:light_blue_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:yellow_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:lime_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:pink_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:gray_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:silver_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:cyan_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:purple_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:blue_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:brown_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:green_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:red_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:black_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:standing_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:wall_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:piston_head", "minecraft:piston"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:daylight_detector_inverted", "minecraft:daylight_detector"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:unpowered_comparator", "minecraft:comparator"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:powered_comparator", "minecraft:comparator"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:wall_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:standing_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:structure_block", "minecraft:structure_block"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:end_portal", "minecraft:end_portal"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:end_gateway", "minecraft:end_gateway"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:shield", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:white_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:orange_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:magenta_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:light_blue_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:yellow_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:lime_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:pink_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:gray_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:silver_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:cyan_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:purple_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:blue_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:brown_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:green_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:red_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:black_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:oak_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:spruce_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:birch_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:jungle_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:acacia_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:dark_oak_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:crimson_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:warped_sign", "minecraft:sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:skeleton_skull", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:wither_skeleton_skull", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:zombie_head", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:player_head", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:creeper_head", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:dragon_head", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:barrel", "minecraft:barrel"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:conduit", "minecraft:conduit"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:smoker", "minecraft:smoker"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:blast_furnace", "minecraft:blast_furnace"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:lectern", "minecraft:lectern"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:bell", "minecraft:bell"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:jigsaw", "minecraft:jigsaw"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:campfire", "minecraft:campfire"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:bee_nest", "minecraft:beehive"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:beehive", "minecraft:beehive"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:sculk_sensor", "minecraft:sculk_sensor"); -+ -+ // These are missing from Vanilla (TODO check on update) -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:enchanting_table", "minecraft:enchanting_table"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:comparator", "minecraft:comparator"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:light_gray_bed", "minecraft:bed"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:light_gray_banner", "minecraft:banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:soul_campfire", "minecraft:campfire"); -+ } -+ -+ // This class is responsible for also integrity checking the item id to tile id map here, we just use the item registry to figure it out -+ -+ static { -+ for (final Item item : Registry.ITEM) { -+ if (!(item instanceof BlockItem)) { -+ continue; -+ } -+ -+ if (!(((BlockItem)item).getBlock() instanceof EntityBlock)) { -+ continue; -+ } -+ -+ final String itemName = Registry.ITEM.getKey(item).toString(); -+ if (!ITEM_ID_TO_TILE_ENTITY_ID.containsKey(itemName)) { -+ LOGGER.error("Item id " + itemName + " does not contain tile mapping! (V704)"); -+ } -+ } -+ } -+ -+ protected static final Map TILE_ID_UPDATE = new HashMap<>(); -+ static { -+ TILE_ID_UPDATE.put("Airportal", "minecraft:end_portal"); -+ TILE_ID_UPDATE.put("Banner", "minecraft:banner"); -+ TILE_ID_UPDATE.put("Beacon", "minecraft:beacon"); -+ TILE_ID_UPDATE.put("Cauldron", "minecraft:brewing_stand"); -+ TILE_ID_UPDATE.put("Chest", "minecraft:chest"); -+ TILE_ID_UPDATE.put("Comparator", "minecraft:comparator"); -+ TILE_ID_UPDATE.put("Control", "minecraft:command_block"); -+ TILE_ID_UPDATE.put("DLDetector", "minecraft:daylight_detector"); -+ TILE_ID_UPDATE.put("Dropper", "minecraft:dropper"); -+ TILE_ID_UPDATE.put("EnchantTable", "minecraft:enchanting_table"); -+ TILE_ID_UPDATE.put("EndGateway", "minecraft:end_gateway"); -+ TILE_ID_UPDATE.put("EnderChest", "minecraft:ender_chest"); -+ TILE_ID_UPDATE.put("FlowerPot", "minecraft:flower_pot"); -+ TILE_ID_UPDATE.put("Furnace", "minecraft:furnace"); -+ TILE_ID_UPDATE.put("Hopper", "minecraft:hopper"); -+ TILE_ID_UPDATE.put("MobSpawner", "minecraft:mob_spawner"); -+ TILE_ID_UPDATE.put("Music", "minecraft:noteblock"); -+ TILE_ID_UPDATE.put("Piston", "minecraft:piston"); -+ TILE_ID_UPDATE.put("RecordPlayer", "minecraft:jukebox"); -+ TILE_ID_UPDATE.put("Sign", "minecraft:sign"); -+ TILE_ID_UPDATE.put("Skull", "minecraft:skull"); -+ TILE_ID_UPDATE.put("Structure", "minecraft:structure_block"); -+ TILE_ID_UPDATE.put("Trap", "minecraft:dispenser"); -+ } -+ -+ protected static void registerInventory(final String id) { -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("Items")); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.TILE_ENTITY.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String id = data.getString("id"); -+ if (id == null) { -+ return null; -+ } -+ -+ data.setString("id", TILE_ID_UPDATE.getOrDefault(id, id)); -+ return null; -+ } -+ }); -+ -+ -+ -+ registerInventory( "minecraft:furnace"); -+ registerInventory( "minecraft:chest"); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:jukebox", new DataWalkerItems("RecordItem")); -+ registerInventory("minecraft:dispenser"); -+ registerInventory("minecraft:dropper"); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:mob_spawner", MCTypeRegistry.UNTAGGED_SPAWNER::convert); -+ registerInventory("minecraft:brewing_stand"); -+ registerInventory("minecraft:hopper"); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:flower_pot", new DataWalkerItemNames("Item")); -+ -+ MCTypeRegistry.ITEM_STACK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convert(MCTypeRegistry.ITEM_NAME, data, "id", fromVersion, toVersion); -+ -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ // only things here are in tag, if changed update if above -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, tag, "Items", fromVersion, toVersion); -+ -+ MapType entityTag = tag.getMap("EntityTag"); -+ if (entityTag != null) { -+ final String itemId = data.getString("id"); -+ final String entityId; -+ if ("minecraft:armor_stand".equals(itemId)) { -+ // The check for version id is changed here. For whatever reason, the legacy -+ // data converters used entity id "minecraft:armor_stand" when version was greater-than 514, -+ // but entity ids were not namespaced until V705! So somebody fucked up the legacy converters. -+ // DFU agrees with my analysis here, it will only set the entityId here to the namespaced variant -+ // with the V705 schema. -+ entityId = DataConverter.getVersion(fromVersion) < 705 ? "ArmorStand" : "minecraft:armor_stand"; -+ } else if (itemId != null && itemId.contains("_spawn_egg")) { -+ // V1451 changes spawn eggs to have the sub entity id be a part of the item id, but of course Mojang never -+ // bothered to write in logic to set the sub entity id, so we have to. -+ // format is ALWAYS :_spawn_egg post flattening -+ entityId = itemId.substring(0, itemId.indexOf("_spawn_egg")); -+ } else if ("minecraft:item_frame".equals(itemId)) { -+ // add missing item_frame entity id -+ // version check is same for armorstand, as both were namespaced at the same time -+ entityId = DataConverter.getVersion(fromVersion) < 705 ? "ItemFrame" : "minecraft:item_frame"; -+ } else { -+ entityId = entityTag.getString("id"); -+ } -+ -+ final boolean removeId; -+ if (entityId == null) { -+ if (!"minecraft:air".equals(itemId)) { -+ LOGGER.warn("Unable to resolve Entity for ItemStack (V704): " + itemId); -+ } -+ removeId = false; -+ } else { -+ removeId = !entityTag.hasKey("id", ObjectType.STRING); -+ if (removeId) { -+ entityTag.setString("id", entityId); -+ } -+ } -+ -+ final MapType replace = MCTypeRegistry.ENTITY.convert(entityTag, fromVersion, toVersion); -+ -+ if (replace != null) { -+ entityTag = replace; -+ tag.setMap("EntityTag", entityTag); -+ } -+ if (removeId) { -+ entityTag.remove("id"); -+ } -+ } -+ -+ MapType blockEntityTag = tag.getMap("BlockEntityTag"); -+ if (blockEntityTag != null) { -+ final String itemId = data.getString("id"); -+ final String entityId = ITEM_ID_TO_TILE_ENTITY_ID.get(itemId); -+ final boolean removeId; -+ if (entityId == null) { -+ if (!"minecraft:air".equals(itemId)) { -+ LOGGER.warn("Unable to resolve BlockEntity for ItemStack (V704): " + itemId); -+ } -+ removeId = false; -+ } else { -+ removeId = !blockEntityTag.hasKey("id", ObjectType.STRING); -+ if (removeId) { -+ blockEntityTag.setString("id", entityId); -+ } -+ } -+ final MapType replace = MCTypeRegistry.TILE_ENTITY.convert(blockEntityTag, fromVersion, toVersion); -+ if (replace != null) { -+ blockEntityTag = replace; -+ tag.setMap("BlockEntityTag", entityTag); -+ } -+ if (removeId) { -+ blockEntityTag.remove("id"); -+ } -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_NAME, tag, "CanDestroy", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_NAME, tag, "CanPlaceOn", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ private V704() {} -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V705.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V705.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5718a167e5b3cf8023cc2c831990b908bda17db6 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V705.java -@@ -0,0 +1,222 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.entity.ConverterAbstractEntityRename; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.block_name.DataWalkerBlockNames; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.minecraft.walkers.tile_entity.DataWalkerTileEntities; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import java.util.HashMap; -+import java.util.Map; -+ -+public final class V705 { -+ -+ private static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final int VERSION = MCVersions.V1_10_2 + 193; -+ -+ protected static final Map ENTITY_ID_UPDATE = new HashMap<>(); -+ static { -+ ENTITY_ID_UPDATE.put("AreaEffectCloud", "minecraft:area_effect_cloud"); -+ ENTITY_ID_UPDATE.put("ArmorStand", "minecraft:armor_stand"); -+ ENTITY_ID_UPDATE.put("Arrow", "minecraft:arrow"); -+ ENTITY_ID_UPDATE.put("Bat", "minecraft:bat"); -+ ENTITY_ID_UPDATE.put("Blaze", "minecraft:blaze"); -+ ENTITY_ID_UPDATE.put("Boat", "minecraft:boat"); -+ ENTITY_ID_UPDATE.put("CaveSpider", "minecraft:cave_spider"); -+ ENTITY_ID_UPDATE.put("Chicken", "minecraft:chicken"); -+ ENTITY_ID_UPDATE.put("Cow", "minecraft:cow"); -+ ENTITY_ID_UPDATE.put("Creeper", "minecraft:creeper"); -+ ENTITY_ID_UPDATE.put("Donkey", "minecraft:donkey"); -+ ENTITY_ID_UPDATE.put("DragonFireball", "minecraft:dragon_fireball"); -+ ENTITY_ID_UPDATE.put("ElderGuardian", "minecraft:elder_guardian"); -+ ENTITY_ID_UPDATE.put("EnderCrystal", "minecraft:ender_crystal"); -+ ENTITY_ID_UPDATE.put("EnderDragon", "minecraft:ender_dragon"); -+ ENTITY_ID_UPDATE.put("Enderman", "minecraft:enderman"); -+ ENTITY_ID_UPDATE.put("Endermite", "minecraft:endermite"); -+ ENTITY_ID_UPDATE.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); -+ ENTITY_ID_UPDATE.put("FallingSand", "minecraft:falling_block"); -+ ENTITY_ID_UPDATE.put("Fireball", "minecraft:fireball"); -+ ENTITY_ID_UPDATE.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); -+ ENTITY_ID_UPDATE.put("Ghast", "minecraft:ghast"); -+ ENTITY_ID_UPDATE.put("Giant", "minecraft:giant"); -+ ENTITY_ID_UPDATE.put("Guardian", "minecraft:guardian"); -+ ENTITY_ID_UPDATE.put("Horse", "minecraft:horse"); -+ ENTITY_ID_UPDATE.put("Husk", "minecraft:husk"); -+ ENTITY_ID_UPDATE.put("Item", "minecraft:item"); -+ ENTITY_ID_UPDATE.put("ItemFrame", "minecraft:item_frame"); -+ ENTITY_ID_UPDATE.put("LavaSlime", "minecraft:magma_cube"); -+ ENTITY_ID_UPDATE.put("LeashKnot", "minecraft:leash_knot"); -+ ENTITY_ID_UPDATE.put("MinecartChest", "minecraft:chest_minecart"); -+ ENTITY_ID_UPDATE.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); -+ ENTITY_ID_UPDATE.put("MinecartFurnace", "minecraft:furnace_minecart"); -+ ENTITY_ID_UPDATE.put("MinecartHopper", "minecraft:hopper_minecart"); -+ ENTITY_ID_UPDATE.put("MinecartRideable", "minecraft:minecart"); -+ ENTITY_ID_UPDATE.put("MinecartSpawner", "minecraft:spawner_minecart"); -+ ENTITY_ID_UPDATE.put("MinecartTNT", "minecraft:tnt_minecart"); -+ ENTITY_ID_UPDATE.put("Mule", "minecraft:mule"); -+ ENTITY_ID_UPDATE.put("MushroomCow", "minecraft:mooshroom"); -+ ENTITY_ID_UPDATE.put("Ozelot", "minecraft:ocelot"); -+ ENTITY_ID_UPDATE.put("Painting", "minecraft:painting"); -+ ENTITY_ID_UPDATE.put("Pig", "minecraft:pig"); -+ ENTITY_ID_UPDATE.put("PigZombie", "minecraft:zombie_pigman"); -+ ENTITY_ID_UPDATE.put("PolarBear", "minecraft:polar_bear"); -+ ENTITY_ID_UPDATE.put("PrimedTnt", "minecraft:tnt"); -+ ENTITY_ID_UPDATE.put("Rabbit", "minecraft:rabbit"); -+ ENTITY_ID_UPDATE.put("Sheep", "minecraft:sheep"); -+ ENTITY_ID_UPDATE.put("Shulker", "minecraft:shulker"); -+ ENTITY_ID_UPDATE.put("ShulkerBullet", "minecraft:shulker_bullet"); -+ ENTITY_ID_UPDATE.put("Silverfish", "minecraft:silverfish"); -+ ENTITY_ID_UPDATE.put("Skeleton", "minecraft:skeleton"); -+ ENTITY_ID_UPDATE.put("SkeletonHorse", "minecraft:skeleton_horse"); -+ ENTITY_ID_UPDATE.put("Slime", "minecraft:slime"); -+ ENTITY_ID_UPDATE.put("SmallFireball", "minecraft:small_fireball"); -+ ENTITY_ID_UPDATE.put("SnowMan", "minecraft:snowman"); -+ ENTITY_ID_UPDATE.put("Snowball", "minecraft:snowball"); -+ ENTITY_ID_UPDATE.put("SpectralArrow", "minecraft:spectral_arrow"); -+ ENTITY_ID_UPDATE.put("Spider", "minecraft:spider"); -+ ENTITY_ID_UPDATE.put("Squid", "minecraft:squid"); -+ ENTITY_ID_UPDATE.put("Stray", "minecraft:stray"); -+ ENTITY_ID_UPDATE.put("ThrownEgg", "minecraft:egg"); -+ ENTITY_ID_UPDATE.put("ThrownEnderpearl", "minecraft:ender_pearl"); -+ ENTITY_ID_UPDATE.put("ThrownExpBottle", "minecraft:xp_bottle"); -+ ENTITY_ID_UPDATE.put("ThrownPotion", "minecraft:potion"); -+ ENTITY_ID_UPDATE.put("Villager", "minecraft:villager"); -+ ENTITY_ID_UPDATE.put("VillagerGolem", "minecraft:villager_golem"); -+ ENTITY_ID_UPDATE.put("Witch", "minecraft:witch"); -+ ENTITY_ID_UPDATE.put("WitherBoss", "minecraft:wither"); -+ ENTITY_ID_UPDATE.put("WitherSkeleton", "minecraft:wither_skeleton"); -+ ENTITY_ID_UPDATE.put("WitherSkull", "minecraft:wither_skull"); -+ ENTITY_ID_UPDATE.put("Wolf", "minecraft:wolf"); -+ ENTITY_ID_UPDATE.put("XPOrb", "minecraft:xp_orb"); -+ ENTITY_ID_UPDATE.put("Zombie", "minecraft:zombie"); -+ ENTITY_ID_UPDATE.put("ZombieHorse", "minecraft:zombie_horse"); -+ ENTITY_ID_UPDATE.put("ZombieVillager", "minecraft:zombie_villager"); -+ } -+ -+ private static void registerMob(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("ArmorItems", "HandItems")); -+ } -+ -+ private static void registerThrowableProjectile(final String id) { -+ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerBlockNames("inTile")); -+ } -+ -+ public static void register() { -+ ConverterAbstractEntityRename.register(VERSION, ENTITY_ID_UPDATE::get); -+ -+ registerMob("minecraft:armor_stand"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:arrow", new DataWalkerBlockNames("inTile")); -+ registerMob("minecraft:bat"); -+ registerMob("minecraft:blaze"); -+ registerMob("minecraft:cave_spider"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:chest_minecart", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:chest_minecart", new DataWalkerItemLists("Items")); -+ registerMob("minecraft:chicken"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:commandblock_minecart", new DataWalkerBlockNames("DisplayTile")); -+ registerMob("minecraft:cow"); -+ registerMob("minecraft:creeper"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:donkey", new DataWalkerItemLists("Items", "ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:donkey", new DataWalkerItems("SaddleItem")); -+ registerThrowableProjectile("minecraft:egg"); -+ registerMob("minecraft:elder_guardian"); -+ registerMob("minecraft:ender_dragon"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:enderman", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:enderman", new DataWalkerBlockNames("carried")); -+ registerMob("minecraft:endermite"); -+ registerThrowableProjectile("minecraft:ender_pearl"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:falling_block", new DataWalkerBlockNames("Block")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:falling_block", new DataWalkerTileEntities("TileEntityData")); -+ registerThrowableProjectile("minecraft:fireball"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:fireworks_rocket", new DataWalkerItems("FireworksItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:furnace_minecart", new DataWalkerBlockNames("DisplayTile")); -+ registerMob("minecraft:ghast"); -+ registerMob("minecraft:giant"); -+ registerMob("minecraft:guardian"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:hopper_minecart", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:hopper_minecart", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:horse", new DataWalkerItems("ArmorItem", "SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:horse", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ registerMob("minecraft:husk"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:item", new DataWalkerItems("Item")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:item_frame", new DataWalkerItems("Item")); -+ registerMob("minecraft:magma_cube"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:minecart", new DataWalkerBlockNames("DisplayTile")); -+ registerMob("minecraft:mooshroom"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:mule", new DataWalkerItemLists("Items", "ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:mule", new DataWalkerItems("SaddleItem")); -+ registerMob("minecraft:ocelot"); -+ registerMob("minecraft:pig"); -+ registerMob("minecraft:polar_bear"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:potion", new DataWalkerItems("Potion")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:potion", new DataWalkerBlockNames("inTile")); -+ registerMob("minecraft:rabbit"); -+ registerMob("minecraft:sheep"); -+ registerMob("minecraft:shulker"); -+ registerMob("minecraft:silverfish"); -+ registerMob("minecraft:skeleton"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:skeleton_horse", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:skeleton_horse", new DataWalkerItems("SaddleItem")); -+ registerMob("minecraft:slime"); -+ registerThrowableProjectile("minecraft:small_fireball"); -+ registerThrowableProjectile("minecraft:snowball"); -+ registerMob("minecraft:snowman"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:spawner_minecart", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:spawner_minecart", MCTypeRegistry.UNTAGGED_SPAWNER::convert); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:spectral_arrow", new DataWalkerBlockNames("inTile")); -+ registerMob("minecraft:spider"); -+ registerMob("minecraft:squid"); -+ registerMob("minecraft:stray"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:tnt_minecart", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:villager", (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Inventory", fromVersion, toVersion); -+ -+ final MapType offers = data.getMap("Offers"); -+ if (offers != null) { -+ final ListType recipes = offers.getList("Recipes", ObjectType.MAP); -+ if (recipes != null) { -+ for (int i = 0, len = recipes.size(); i < len; ++i) { -+ final MapType recipe = recipes.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buy", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buyB", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "sell", fromVersion, toVersion); -+ } -+ } -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "ArmorItems", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "HandItems", fromVersion, toVersion); -+ -+ return null; -+ }); -+ registerMob("minecraft:villager_golem"); -+ registerMob("minecraft:witch"); -+ registerMob("minecraft:wither"); -+ registerMob("minecraft:wither_skeleton"); -+ registerThrowableProjectile("minecraft:wither_skull"); -+ registerMob("minecraft:wolf"); -+ registerThrowableProjectile("minecraft:xp_bottle"); -+ registerMob("minecraft:zombie"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:zombie_horse", new DataWalkerItems("SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:zombie_horse", new DataWalkerItemLists("ArmorItems", "HandItems")); -+ registerMob("minecraft:zombie_pigman"); -+ registerMob("minecraft:zombie_villager"); -+ registerMob("minecraft:evocation_illager"); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:llama", new DataWalkerItemLists("Items", "ArmorItems", "HandItems")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "minecraft:llama", new DataWalkerItems("SaddleItem", "DecorItem")); -+ registerMob("minecraft:vex"); -+ registerMob("minecraft:vindication_illager"); -+ // Don't need to re-register itemstack walker, the V704 will correctly choose the right id for armorstand based on -+ // the source version -+ } -+ -+ private V705() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V804.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V804.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0070a3d02a87b0f08cd5e74d4f106f3e97f6b4f8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V804.java -@@ -0,0 +1,60 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V804 { -+ -+ protected static final int VERSION = MCVersions.V16W35A + 1; -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:banner", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final MapType blockEntity = tag.getMap("BlockEntityTag"); -+ if (blockEntity == null) { -+ return null; -+ } -+ -+ if (!blockEntity.hasKey("Base", ObjectType.NUMBER)) { -+ return null; -+ } -+ -+ data.setShort("Damage", (short)(blockEntity.getShort("Base") & 15)); -+ -+ final MapType display = tag.getMap("display"); -+ if (display != null) { -+ final ListType lore = display.getList("Lore", ObjectType.STRING); -+ if (lore != null) { -+ if (lore.size() == 1 && "(+NBT)".equals(lore.getString(0))) { -+ return null; -+ } -+ } -+ } -+ -+ blockEntity.remove("Base"); -+ if (blockEntity.isEmpty()) { -+ tag.remove("BlockEntityTag"); -+ } -+ -+ if (tag.isEmpty()) { -+ data.remove("tag"); -+ } -+ -+ return null; -+ } -+ }); -+ } -+ -+ private V804() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V806.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V806.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a2717b9d936872ec07141b0f3ae2a6eec81f2dbf ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V806.java -@@ -0,0 +1,40 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+ -+public final class V806 { -+ -+ protected static final int VERSION = MCVersions.V16W36A + 1; -+ -+ public static void register() { -+ final DataConverter, MapType> potionWaterUpdater = new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ tag = Types.NBT.createEmptyMap(); -+ data.setMap("tag", tag); -+ } -+ -+ if (!tag.hasKey("Potion", ObjectType.STRING)) { -+ tag.setString("Potion", "minecraft:water"); -+ } -+ -+ return null; -+ } -+ }; -+ -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:potion", potionWaterUpdater); -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:splash_potion", potionWaterUpdater); -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:lingering_potion", potionWaterUpdater); -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:tipped_arrow", potionWaterUpdater); -+ } -+ -+ private V806() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V808.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V808.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8abdf7476f98b15efc588352eb0897474f229ef2 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V808.java -@@ -0,0 +1,30 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V808 { -+ -+ protected static final int VERSION = MCVersions.V16W38A + 1; -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addConverterForId("minecraft:shulker", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ if (!data.hasKey("Color", ObjectType.NUMBER)) { -+ data.setByte("Color", (byte)10); -+ } -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:shulker_box", new DataWalkerItemLists("Items")); -+ } -+ -+ private V808() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V813.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V813.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b6de7c32acd0adf78812edbbd184117661599c80 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V813.java -@@ -0,0 +1,64 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class V813 { -+ -+ protected static final int VERSION = MCVersions.V16W40A; -+ -+ public static final String[] SHULKER_ID_BY_COLOUR = new String[] { -+ "minecraft:white_shulker_box", -+ "minecraft:orange_shulker_box", -+ "minecraft:magenta_shulker_box", -+ "minecraft:light_blue_shulker_box", -+ "minecraft:yellow_shulker_box", -+ "minecraft:lime_shulker_box", -+ "minecraft:pink_shulker_box", -+ "minecraft:gray_shulker_box", -+ "minecraft:silver_shulker_box", -+ "minecraft:cyan_shulker_box", -+ "minecraft:purple_shulker_box", -+ "minecraft:blue_shulker_box", -+ "minecraft:brown_shulker_box", -+ "minecraft:green_shulker_box", -+ "minecraft:red_shulker_box", -+ "minecraft:black_shulker_box" -+ }; -+ -+ public static void register() { -+ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:shulker_box", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ final MapType blockEntity = tag.getMap("BlockEntityTag"); -+ if (blockEntity == null) { -+ return null; -+ } -+ -+ final int color = blockEntity.getInt("Color"); -+ blockEntity.remove("Color"); -+ -+ data.setString("id", SHULKER_ID_BY_COLOUR[color % SHULKER_ID_BY_COLOUR.length]); -+ -+ return null; -+ } -+ }); -+ -+ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:shulker_box", new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ data.remove("Color"); -+ return null; -+ } -+ }); -+ } -+ -+ private V813() {} -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V816.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V816.java -new file mode 100644 -index 0000000000000000000000000000000000000000..13d6435aaca10f04baebc43db7af5f2ecd019bad ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V816.java -@@ -0,0 +1,29 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.converters.DataConverter; -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.Locale; -+ -+public final class V816 { -+ -+ protected static final int VERSION = MCVersions.V16W43A; -+ -+ public static void register() { -+ MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(VERSION) { -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ final String lang = data.getString("lang"); -+ if (lang != null) { -+ data.setString("lang", lang.toLowerCase(Locale.ROOT)); -+ } -+ return null; -+ } -+ }); -+ } -+ -+ private V816() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V820.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V820.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9e2ef3cea4fd382a75a4d787fe2e2ff509eb49fc ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V820.java -@@ -0,0 +1,19 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; -+import com.google.common.collect.ImmutableMap; -+ -+public final class V820 { -+ -+ protected static final int VERSION = MCVersions.V1_11 + 1; -+ -+ public static void register() { -+ ConverterAbstractItemRename.register(VERSION, ImmutableMap.of( -+ "minecraft:totem", "minecraft:totem_of_undying" -+ )::get); -+ } -+ -+ private V820() {} -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V99.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V99.java -new file mode 100644 -index 0000000000000000000000000000000000000000..121430367b26dd89aad87a0f293ab3fcb129f377 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V99.java -@@ -0,0 +1,314 @@ -+package ca.spottedleaf.dataconverter.minecraft.versions; -+ -+import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.helpers.HelperItemNameV102; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.block_name.DataWalkerBlockNames; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; -+import ca.spottedleaf.dataconverter.minecraft.walkers.item_name.DataWalkerItemNames; -+import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItems; -+import ca.spottedleaf.dataconverter.minecraft.walkers.tile_entity.DataWalkerTileEntities; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import java.util.HashMap; -+import java.util.Map; -+ -+public final class V99 { -+ -+ // Structure for all data before data upgrading was added to minecraft (pre 15w32a) -+ -+ protected static final Logger LOGGER = LogManager.getLogger(); -+ -+ protected static final int VERSION = MCVersions.V15W32A - 1; -+ -+ protected static final Map ITEM_ID_TO_TILE_ENTITY_ID = new HashMap<>(); -+ -+ static { -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:furnace", "Furnace"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:lit_furnace", "Furnace"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:chest", "Chest"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:trapped_chest", "Chest"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:ender_chest", "EnderChest"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:jukebox", "RecordPlayer"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:dispenser", "Trap"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:dropper", "Dropper"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:sign", "Sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:mob_spawner", "MobSpawner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:noteblock", "Music"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:brewing_stand", "Cauldron"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:enhanting_table", "EnchantTable"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:command_block", "CommandBlock"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:beacon", "Beacon"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:skull", "Skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:daylight_detector", "DLDetector"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:hopper", "Hopper"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:banner", "Banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:flower_pot", "FlowerPot"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:repeating_command_block", "CommandBlock"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:chain_command_block", "CommandBlock"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:standing_sign", "Sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:wall_sign", "Sign"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:piston_head", "Piston"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:daylight_detector_inverted", "DLDetector"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:unpowered_comparator", "Comparator"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:powered_comparator", "Comparator"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:wall_banner", "Banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:standing_banner", "Banner"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:structure_block", "Structure"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:end_portal", "Airportal"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:end_gateway", "EndGateway"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:shield", "Banner"); -+ } -+ -+ public static void register() { -+ MCTypeRegistry.ENTITY.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convert(MCTypeRegistry.ENTITY, data, "Riding", fromVersion, toVersion); -+ -+ return null; -+ }); -+ // Thrown Projectile -> new DataWalkerBlockNames("inTile") -+ // Mob -> new DataWalkerItemLists("Equipment") -+ // Minecart -> new DataWalkerBlockNames("DisplayTile") -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Item", new DataWalkerItems("Item")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ThrownEgg", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Arrow", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "TippedArrow", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "SpectralArrow", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Snowball", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Fireball", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "SmallFireball", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ThrownEnderpearl", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ThrownPotion", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ThrownPotion", new DataWalkerItems("Potion")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ThrownExpBottle", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ItemFrame", new DataWalkerItems("Item")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "WitherSkull", new DataWalkerBlockNames("inTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "FallingSand", new DataWalkerBlockNames("Block")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "FallingSand", new DataWalkerTileEntities("TileEntityData")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "FireworksRocketEntity", new DataWalkerItems("FireworksItem")); -+ // Note: Minecart is the generic entity. It can be subtyped via an int to become one of the specific minecarts -+ // (i.e rideable, chest, furnace, tnt, etc) -+ // Because of this, we add all walkers to the generic type, even though they might not be needed. -+ // Vanilla does not make the generic minecart convert spawners, but we do. -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Minecart", new DataWalkerBlockNames("DisplayTile")); // for all minecart types -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Minecart", new DataWalkerItemLists("Items")); // for chest types -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Minecart", MCTypeRegistry.UNTAGGED_SPAWNER::convert); // for spawner type -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartRideable", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartChest", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartChest", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartFurnace", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartTNT", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartSpawner", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartSpawner", MCTypeRegistry.UNTAGGED_SPAWNER::convert); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartHopper", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartHopper", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MinecartCommandBlock", new DataWalkerBlockNames("DisplayTile")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "ArmorStand", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Creeper", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Skeleton", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Spider", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Giant", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Zombie", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Slime", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Ghast", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "PigZombie", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Enderman", new DataWalkerBlockNames("carried")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Enderman", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "CaveSpider", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Silverfish", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Blaze", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "LavaSlime", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "EnderDragon", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "WitherBoss", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Bat", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Witch", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Endermite", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Guardian", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Pig", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Sheep", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Cow", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Chicken", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Squid", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Wolf", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "MushroomCow", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "SnowMan", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Ozelot", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "VillagerGolem", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "EntityHorse", new DataWalkerItemLists("Items", "Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "EntityHorse", new DataWalkerItems("ArmorItem", "SaddleItem")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Rabbit", new DataWalkerItemLists("Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Villager", new DataWalkerItemLists("Inventory", "Equipment")); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Villager", (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType offers = data.getMap("Offers"); -+ if (offers != null) { -+ final ListType recipes = offers.getList("Recipes", ObjectType.MAP); -+ if (recipes != null) { -+ for (int i = 0; i < recipes.size(); ++i) { -+ final MapType recipe = recipes.getMap(i); -+ -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buy", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "buyB", fromVersion, toVersion); -+ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, recipe, "sell", fromVersion, toVersion); -+ } -+ } -+ } -+ -+ return null; -+ }); -+ MCTypeRegistry.ENTITY.addWalker(VERSION, "Shulker", new DataWalkerItemLists("Equipment")); -+ -+ // Inventory -> new DataWalkerItemLists("Items") -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "Furnace", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "Chest", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "RecordPlayer", new DataWalkerItems("RecordItem")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "Trap", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "Dropper", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "MobSpawner", MCTypeRegistry.UNTAGGED_SPAWNER::convert); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "Cauldron", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "Hopper", new DataWalkerItemLists("Items")); -+ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "FlowerPot", new DataWalkerItemNames("Item")); // Note: Vanilla does not properly handle this case, it will not convert int ids! -+ -+ MCTypeRegistry.ITEM_STACK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convert(MCTypeRegistry.ITEM_NAME, data, "id", fromVersion, toVersion); -+ -+ final MapType tag = data.getMap("tag"); -+ if (tag == null) { -+ return null; -+ } -+ -+ // only things here are in tag, if changed update if above -+ -+ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, tag, "Items", fromVersion, toVersion); -+ -+ MapType entityTag = tag.getMap("EntityTag"); -+ if (entityTag != null) { -+ String itemId = getStringId(data.getString("id")); -+ final String entityId; -+ if ("minecraft:armor_stand".equals(itemId)) { -+ // The check for version id is removed here. For whatever reason, the legacy -+ // data converters used entity id "minecraft:armor_stand" when version was greater-than 514, -+ // but entity ids were not namespaced until V705! So somebody fucked up the legacy converters. -+ // DFU agrees with my analysis here, it will only set the entityId here to the namespaced variant -+ // with the V705 schema. -+ entityId = "ArmorStand"; -+ } else if ("minecraft:item_frame".equals(itemId)) { -+ // add missing item_frame entity id -+ entityId = "ItemFrame"; -+ } else { -+ entityId = entityTag.getString("id"); -+ } -+ -+ final boolean removeId; -+ if (entityId == null) { -+ if (!"minecraft:air".equals(itemId)) { -+ LOGGER.warn("Unable to resolve Entity for ItemStack (V99): " + data.getGeneric("id")); -+ } -+ removeId = false; -+ } else { -+ removeId = !entityTag.hasKey("id", ObjectType.STRING); -+ if (removeId) { -+ entityTag.setString("id", entityId); -+ } -+ } -+ -+ final MapType replace = MCTypeRegistry.ENTITY.convert(entityTag, fromVersion, toVersion); -+ -+ if (replace != null) { -+ entityTag = replace; -+ tag.setMap("EntityTag", entityTag); -+ } -+ if (removeId) { -+ entityTag.remove("id"); -+ } -+ } -+ -+ MapType blockEntityTag = tag.getMap("BlockEntityTag"); -+ if (blockEntityTag != null) { -+ final String itemId = getStringId(data.getString("id")); -+ final String entityId = ITEM_ID_TO_TILE_ENTITY_ID.get(itemId); -+ final boolean removeId; -+ if (entityId == null) { -+ if (!"minecraft:air".equals(itemId)) { -+ LOGGER.warn("Unable to resolve BlockEntity for ItemStack (V99): " + data.getGeneric("id")); -+ } -+ removeId = false; -+ } else { -+ removeId = !blockEntityTag.hasKey("id", ObjectType.STRING); -+ blockEntityTag.setString("id", entityId); -+ } -+ final MapType replace = MCTypeRegistry.TILE_ENTITY.convert(blockEntityTag, fromVersion, toVersion); -+ if (replace != null) { -+ blockEntityTag = replace; -+ tag.setMap("BlockEntityTag", blockEntityTag); -+ } -+ if (removeId) { -+ blockEntityTag.remove("id"); -+ } -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_NAME, tag, "CanDestroy", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.BLOCK_NAME, tag, "CanPlaceOn", fromVersion, toVersion); -+ -+ return null; -+ }); -+ -+ MCTypeRegistry.PLAYER.addStructureWalker(VERSION, new DataWalkerItemLists("Inventory", "EnderItems")); -+ -+ MCTypeRegistry.CHUNK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ final MapType level = data.getMap("Level"); -+ if (level == null) { -+ return null; -+ } -+ -+ WalkerUtils.convertList(MCTypeRegistry.ENTITY, level, "Entities", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.TILE_ENTITY, level, "TileEntities", fromVersion, toVersion); -+ -+ final ListType tileTicks = level.getList("TileTicks", ObjectType.MAP); -+ if (tileTicks != null) { -+ for (int i = 0, len = tileTicks.size(); i < len; ++i) { -+ final MapType tileTick = tileTicks.getMap(i); -+ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, tileTick, "i", fromVersion, toVersion); -+ } -+ } -+ -+ return null; -+ }); -+ -+ MCTypeRegistry.ENTITY_CHUNK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { -+ WalkerUtils.convertList(MCTypeRegistry.ENTITY, data, "Entities", fromVersion, toVersion); -+ -+ return null; -+ }); -+ -+ MCTypeRegistry.SAVED_DATA.addStructureWalker(VERSION, (final MapType root, final long fromVersion, final long toVersion) -> { -+ final MapType data = root.getMap("data"); -+ if (data == null) { -+ return null; -+ } -+ -+ WalkerUtils.convertValues(MCTypeRegistry.STRUCTURE_FEATURE, data, "Features", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.OBJECTIVE, data, "Objectives", fromVersion, toVersion); -+ WalkerUtils.convertList(MCTypeRegistry.TEAM, data, "Teams", fromVersion, toVersion); -+ -+ return null; -+ }); -+ } -+ -+ protected static String getStringId(final Object id) { -+ if (id instanceof String) { -+ return (String)id; -+ } else if (id instanceof Number) { -+ return HelperItemNameV102.getNameFromId(((Number)id).intValue()); -+ } else { -+ return null; -+ } -+ } -+ -+ private V99() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/block_name/DataWalkerBlockNames.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/block_name/DataWalkerBlockNames.java -new file mode 100644 -index 0000000000000000000000000000000000000000..930e014858ef635ebe25f7f92dc81ba0eaac50a8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/block_name/DataWalkerBlockNames.java -@@ -0,0 +1,11 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.block_name; -+ -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerTypePaths; -+ -+public final class DataWalkerBlockNames extends DataWalkerTypePaths { -+ -+ public DataWalkerBlockNames(final String... paths) { -+ super(MCTypeRegistry.BLOCK_NAME, paths); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/DataWalkerListPaths.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/DataWalkerListPaths.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7c8f6a5034b48e1ec2c5925211f491115ca735aa ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/DataWalkerListPaths.java -@@ -0,0 +1,38 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.generic; -+ -+import ca.spottedleaf.dataconverter.converters.datatypes.DataType; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataWalker; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public class DataWalkerListPaths implements DataWalker { -+ -+ protected final DataType type; -+ protected final String[] paths; -+ -+ public DataWalkerListPaths(final DataType type, final String... paths) { -+ this.type = type; -+ this.paths = paths; -+ } -+ -+ @Override -+ public final MapType walk(final MapType data, final long fromVersion, final long toVersion) { -+ final DataType type = this.type; -+ for (final String path : this.paths) { -+ final ListType list = data.getListUnchecked(path); -+ if (list == null) { -+ continue; -+ } -+ -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ final Object current = list.getGeneric(i); -+ final Object converted = type.convert((T)current, fromVersion, toVersion); -+ if (converted != null) { -+ list.setGeneric(i, converted); -+ } -+ } -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/DataWalkerTypePaths.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/DataWalkerTypePaths.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e66b4e0f7cdb032b545ace7ba852ad7979f3c96a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/DataWalkerTypePaths.java -@@ -0,0 +1,34 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.generic; -+ -+import ca.spottedleaf.dataconverter.converters.datatypes.DataType; -+import ca.spottedleaf.dataconverter.converters.datatypes.DataWalker; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public class DataWalkerTypePaths implements DataWalker { -+ -+ protected final DataType type; -+ protected final String[] paths; -+ -+ public DataWalkerTypePaths(final DataType type, final String... paths) { -+ this.type = type; -+ this.paths = paths; -+ } -+ -+ @Override -+ public final MapType walk(final MapType data, final long fromVersion, final long toVersion) { -+ for (final String path : this.paths) { -+ final Object current = data.getGeneric(path); -+ if (current == null) { -+ continue; -+ } -+ -+ final Object converted = this.type.convert((T)current, fromVersion, toVersion); -+ -+ if (converted != null) { -+ data.setGeneric(path, converted); -+ } -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/WalkerUtils.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/WalkerUtils.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8ff0edce55feedf79c545f3dbc2045de9caaaf7a ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/WalkerUtils.java -@@ -0,0 +1,131 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.generic; -+ -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCDataType; -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCValueType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+import java.util.ArrayList; -+ -+public final class WalkerUtils { -+ -+ public static void convert(final MCDataType type, final MapType data, final String path, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ final MapType map = data.getMap(path); -+ if (map != null) { -+ final MapType replace = type.convert(map, fromVersion, toVersion); -+ if (replace != null) { -+ data.setMap(path, replace); -+ } -+ } -+ } -+ -+ public static void convertList(final MCDataType type, final MapType data, final String path, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ final ListType list = data.getList(path, ObjectType.MAP); -+ if (list != null) { -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ final MapType replace = type.convert(list.getMap(i), fromVersion, toVersion); -+ if (replace != null) { -+ list.setMap(i, replace); -+ } -+ } -+ } -+ } -+ -+ public static void convert(final MCValueType type, final MapType data, final String path, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ final Object value = data.getGeneric(path); -+ if (value != null) { -+ final Object converted = type.convert(value, fromVersion, toVersion); -+ if (converted != null) { -+ data.setGeneric(path, converted); -+ } -+ } -+ } -+ -+ public static void convert(final MCValueType type, final ListType data, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ for (int i = 0, len = data.size(); i < len; ++i) { -+ final Object value = data.getGeneric(i); -+ final Object converted = type.convert(value, fromVersion, toVersion); -+ if (converted != null) { -+ data.setGeneric(i, converted); -+ } -+ } -+ } -+ -+ public static void convertList(final MCValueType type, final MapType data, final String path, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ final ListType list = data.getListUnchecked(path); -+ if (list != null) { -+ convert(type, list, fromVersion, toVersion); -+ } -+ } -+ -+ public static void convertKeys(final MCValueType type, final MapType data, final String path, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ final MapType map = data.getMap(path); -+ if (map != null) { -+ convertKeys(type, map, fromVersion, toVersion); -+ } -+ } -+ -+ public static void convertKeys(final MCValueType type, final MapType data, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ for (final String key : new ArrayList<>(data.keys())) { -+ final String updated = (String)type.convert(key, fromVersion, toVersion); -+ if (updated != null) { -+ data.setGeneric(updated, data.getGeneric(key)); -+ data.remove(key); -+ } -+ } -+ } -+ -+ public static void convertValues(final MCDataType type, final MapType data, final String path, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ convertValues(type, data.getMap(path), fromVersion, toVersion); -+ } -+ -+ public static void convertValues(final MCDataType type, final MapType data, final long fromVersion, final long toVersion) { -+ if (data == null) { -+ return; -+ } -+ -+ for (final String key : data.keys()) { -+ final MapType value = data.getMap(key); -+ if (value != null) { -+ final MapType replace = type.convert(value, fromVersion, toVersion); -+ if (replace != null) { -+ // no CME, key is in map already -+ data.setMap(key, replace); -+ } -+ } -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/item_name/DataWalkerItemNames.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/item_name/DataWalkerItemNames.java -new file mode 100644 -index 0000000000000000000000000000000000000000..14e291efd864d97dcf83db01c09b9daaae1949bd ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/item_name/DataWalkerItemNames.java -@@ -0,0 +1,11 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.item_name; -+ -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerTypePaths; -+ -+public final class DataWalkerItemNames extends DataWalkerTypePaths { -+ -+ public DataWalkerItemNames(final String... paths) { -+ super(MCTypeRegistry.ITEM_NAME, paths); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/itemstack/DataWalkerItemLists.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/itemstack/DataWalkerItemLists.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5b4402c3cc4e68e9c591e8bbb4a2542d8e2214d4 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/itemstack/DataWalkerItemLists.java -@@ -0,0 +1,12 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.itemstack; -+ -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerListPaths; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public class DataWalkerItemLists extends DataWalkerListPaths, MapType> { -+ -+ public DataWalkerItemLists(final String... paths) { -+ super(MCTypeRegistry.ITEM_STACK, paths); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/itemstack/DataWalkerItems.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/itemstack/DataWalkerItems.java -new file mode 100644 -index 0000000000000000000000000000000000000000..04770e8378ac8784895cdfe400a47b0b601c2187 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/itemstack/DataWalkerItems.java -@@ -0,0 +1,12 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.itemstack; -+ -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerTypePaths; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public class DataWalkerItems extends DataWalkerTypePaths, MapType> { -+ -+ public DataWalkerItems(final String... paths) { -+ super(MCTypeRegistry.ITEM_STACK, paths); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/tile_entity/DataWalkerTileEntities.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/tile_entity/DataWalkerTileEntities.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d9cc21bf41cb4b377752b684f8e59818cd620103 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/tile_entity/DataWalkerTileEntities.java -@@ -0,0 +1,12 @@ -+package ca.spottedleaf.dataconverter.minecraft.walkers.tile_entity; -+ -+import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerTypePaths; -+import ca.spottedleaf.dataconverter.types.MapType; -+ -+public final class DataWalkerTileEntities extends DataWalkerTypePaths, MapType> { -+ -+ public DataWalkerTileEntities(final String... paths) { -+ super(MCTypeRegistry.TILE_ENTITY, paths); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/ListType.java b/src/main/java/ca/spottedleaf/dataconverter/types/ListType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a91834f7eb6d1aa49f42b0f25085ac84b93471bd ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/ListType.java -@@ -0,0 +1,270 @@ -+package ca.spottedleaf.dataconverter.types; -+ -+public interface ListType { -+ -+ @Override -+ public int hashCode(); -+ -+ @Override -+ public boolean equals(final Object other); -+ -+ // Provides a deep copy of this list -+ public ListType copy(); -+ -+ // returns NONE if no type has been assigned. if NONE, then this list is also empty. It is not true on the other hand that an empty list has no type. -+ public ObjectType getType(); -+ -+ public int size(); -+ -+ public void remove(final int index); -+ -+ public default Object getGeneric(final int index) { -+ switch (this.getType()) { -+ case NONE: -+ throw new IllegalStateException("List is empty and has no type"); -+ case BYTE: -+ return Byte.valueOf(this.getByte(index)); -+ case SHORT: -+ return Short.valueOf(this.getShort(index)); -+ case INT: -+ return Integer.valueOf(this.getInt(index)); -+ case LONG: -+ return Long.valueOf(this.getLong(index)); -+ case FLOAT: -+ return Float.valueOf(this.getFloat(index)); -+ case DOUBLE: -+ return Double.valueOf(this.getDouble(index)); -+ case NUMBER: -+ return this.getNumber(index); -+ case BYTE_ARRAY: -+ return this.getBytes(index); -+ case SHORT_ARRAY: -+ return this.getShorts(index); -+ case INT_ARRAY: -+ return this.getInts(index); -+ case LONG_ARRAY: -+ return this.getLongs(index); -+ case LIST: -+ return this.getList(index); -+ case MAP: -+ return this.getMap(index); -+ case STRING: -+ return this.getString(index); -+ default: -+ throw new UnsupportedOperationException(this.getType().name()); -+ } -+ } -+ -+ public default void setGeneric(final int index, final Object to) { -+ if (to instanceof Number) { -+ if (to instanceof Byte) { -+ this.setByte(index, ((Byte)to).byteValue()); -+ return; -+ } else if (to instanceof Short) { -+ this.setShort(index, ((Short)to).shortValue()); -+ return; -+ } else if (to instanceof Integer) { -+ this.setInt(index, ((Integer)to).intValue()); -+ return; -+ } else if (to instanceof Long) { -+ this.setLong(index, ((Long)to).longValue()); -+ return; -+ } else if (to instanceof Float) { -+ this.setFloat(index, ((Float)to).floatValue()); -+ return; -+ } else if (to instanceof Double) { -+ this.setDouble(index, ((Double)to).doubleValue()); -+ return; -+ } // else fall through to throw -+ } else if (to instanceof MapType) { -+ this.setMap(index, (MapType)to); -+ return; -+ } else if (to instanceof ListType) { -+ this.setList(index, (ListType)to); -+ return; -+ } else if (to instanceof String) { -+ this.setString(index, (String)to); -+ return; -+ } else if (to.getClass().isArray()) { -+ if (to instanceof byte[]) { -+ this.setBytes(index, (byte[])to); -+ return; -+ } else if (to instanceof short[]) { -+ this.setShorts(index, (short[])to); -+ return; -+ } else if (to instanceof int[]) { -+ this.setInts(index, (int[])to); -+ return; -+ } else if (to instanceof long[]) { -+ this.setLongs(index, (long[])to); -+ return; -+ } // else fall through to throw -+ } -+ -+ throw new IllegalArgumentException("Object " + to + " is not a valid type!"); -+ } -+ -+ // types here are strict. if the type on get does not match the underlying type, will throw. -+ -+ public Number getNumber(final int index); -+ -+ // if the value at index is a Number but not a byte, then returns the number casted to byte. If the value at the index is not a number, then throws -+ public byte getByte(final int index); -+ -+ public void setByte(final int index, final byte to); -+ -+ // if the value at index is a Number but not a short, then returns the number casted to short. If the value at the index is not a number, then throws -+ public short getShort(final int index); -+ -+ public void setShort(final int index, final short to); -+ -+ // if the value at index is a Number but not a int, then returns the number casted to int. If the value at the index is not a number, then throws -+ public int getInt(final int index); -+ -+ public void setInt(final int index, final int to); -+ -+ // if the value at index is a Number but not a long, then returns the number casted to long. If the value at the index is not a number, then throws -+ public long getLong(final int index); -+ -+ public void setLong(final int index, final long to); -+ -+ // if the value at index is a Number but not a float, then returns the number casted to float. If the value at the index is not a number, then throws -+ public float getFloat(final int index); -+ -+ public void setFloat(final int index, final float to); -+ -+ // if the value at index is a Number but not a double, then returns the number casted to double. If the value at the index is not a number, then throws -+ public double getDouble(final int index); -+ -+ public void setDouble(final int index, final double to); -+ -+ public byte[] getBytes(final int index); -+ -+ public void setBytes(final int index, final byte[] to); -+ -+ public short[] getShorts(final int index); -+ -+ public void setShorts(final int index, final short[] to); -+ -+ public int[] getInts(final int index); -+ -+ public void setInts(final int index, final int[] to); -+ -+ public long[] getLongs(final int index); -+ -+ public void setLongs(final int index, final long[] to); -+ -+ public ListType getList(final int index); -+ -+ public void setList(final int index, final ListType list); -+ -+ public MapType getMap(final int index); -+ -+ public void setMap(final int index, final MapType to); -+ -+ public String getString(final int index); -+ -+ public void setString(final int index, final String to); -+ -+ public default void addGeneric(final Object to) { -+ if (to instanceof Number) { -+ if (to instanceof Byte) { -+ this.addByte(((Byte)to).byteValue()); -+ return; -+ } else if (to instanceof Short) { -+ this.addShort(((Short)to).shortValue()); -+ return; -+ } else if (to instanceof Integer) { -+ this.addInt(((Integer)to).intValue()); -+ return; -+ } else if (to instanceof Long) { -+ this.addLong(((Long)to).longValue()); -+ return; -+ } else if (to instanceof Float) { -+ this.addFloat(((Float)to).floatValue()); -+ return; -+ } else if (to instanceof Double) { -+ this.addDouble(((Double)to).doubleValue()); -+ return; -+ } // else fall through to throw -+ } else if (to instanceof MapType) { -+ this.addMap((MapType)to); -+ return; -+ } else if (to instanceof ListType) { -+ this.addList((ListType)to); -+ return; -+ } else if (to instanceof String) { -+ this.addString((String)to); -+ return; -+ } else if (to.getClass().isArray()) { -+ if (to instanceof byte[]) { -+ this.addByteArray((byte[])to); -+ return; -+ } else if (to instanceof short[]) { -+ this.addShortArray((short[])to); -+ return; -+ } else if (to instanceof int[]) { -+ this.addIntArray((int[])to); -+ return; -+ } else if (to instanceof long[]) { -+ this.addLongArray((long[])to); -+ return; -+ } // else fall through to throw -+ } -+ -+ throw new IllegalArgumentException("Object " + to + " is not a valid type!"); -+ } -+ -+ public void addByte(final byte b); -+ -+ public void addByte(final int index, final byte b); -+ -+ public void addShort(final short s); -+ -+ public void addShort(final int index, final short s); -+ -+ public void addInt(final int i); -+ -+ public void addInt(final int index, final int i); -+ -+ public void addLong(final long l); -+ -+ public void addLong(final int index, final long l); -+ -+ public void addFloat(final float f); -+ -+ public void addFloat(final int index, final float f); -+ -+ public void addDouble(final double d); -+ -+ public void addDouble(final int index, final double d); -+ -+ public void addByteArray(final byte[] arr); -+ -+ public void addByteArray(final int index, final byte[] arr); -+ -+ public void addShortArray(final short[] arr); -+ -+ public void addShortArray(final int index, final short[] arr); -+ -+ public void addIntArray(final int[] arr); -+ -+ public void addIntArray(final int index, final int[] arr); -+ -+ public void addLongArray(final long[] arr); -+ -+ public void addLongArray(final int index, final long[] arr); -+ -+ public void addList(final ListType list); -+ -+ public void addList(final int index, final ListType list); -+ -+ public void addMap(final MapType map); -+ -+ public void addMap(final int index, final MapType map); -+ -+ public void addString(final String string); -+ -+ public void addString(final int index, final String string); -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/MapType.java b/src/main/java/ca/spottedleaf/dataconverter/types/MapType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d3ed052fea257ef2f8be54bf5e15f89a454d355f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/MapType.java -@@ -0,0 +1,199 @@ -+package ca.spottedleaf.dataconverter.types; -+ -+import java.util.Set; -+ -+public interface MapType { -+ -+ @Override -+ public int hashCode(); -+ -+ @Override -+ public boolean equals(final Object other); -+ -+ public int size(); -+ -+ public boolean isEmpty(); -+ -+ public void clear(); -+ -+ public Set keys(); -+ -+ // Provides a deep copy of this map -+ public MapType copy(); -+ -+ public boolean hasKey(final K key); -+ -+ public boolean hasKey(final K key, final ObjectType type); -+ -+ public void remove(final K key); -+ -+ public Object getGeneric(final K key); -+ -+ // types here are not strict. if the key maps to a different type, default is always returned -+ // if default is not a parameter, then default is always null -+ -+ public Number getNumber(final K key); -+ -+ public Number getNumber(final K key, final Number dfl); -+ -+ public boolean getBoolean(final K key); -+ -+ public boolean getBoolean(final K key, final boolean dfl); -+ -+ public void setBoolean(final K key, final boolean val); -+ -+ // if the mapped value is a Number but not a byte, then the number is casted to byte. If the mapped value does not exist or is not a number, returns 0 -+ public byte getByte(final K key); -+ -+ // if the mapped value is a Number but not a byte, then the number is casted to byte. If the mapped value does not exist or is not a number, returns dfl -+ public byte getByte(final K key, final byte dfl); -+ -+ public void setByte(final K key, final byte val); -+ -+ // if the mapped value is a Number but not a short, then the number is casted to short. If the mapped value does not exist or is not a number, returns 0 -+ public short getShort(final K key); -+ -+ // if the mapped value is a Number but not a short, then the number is casted to short. If the mapped value does not exist or is not a number, returns dfl -+ public short getShort(final K key, final short dfl); -+ -+ public void setShort(final K key, final short val); -+ -+ // if the mapped value is a Number but not a int, then the number is casted to int. If the mapped value does not exist or is not a number, returns 0 -+ public int getInt(final K key); -+ -+ // if the mapped value is a Number but not a int, then the number is casted to int. If the mapped value does not exist or is not a number, returns dfl -+ public int getInt(final K key, final int dfl); -+ -+ public void setInt(final K key, final int val); -+ -+ // if the mapped value is a Number but not a long, then the number is casted to long. If the mapped value does not exist or is not a number, returns 0 -+ public long getLong(final K key); -+ -+ // if the mapped value is a Number but not a long, then the number is casted to long. If the mapped value does not exist or is not a number, returns dfl -+ public long getLong(final K key, final long dfl); -+ -+ public void setLong(final K key, final long val); -+ -+ // if the mapped value is a Number but not a float, then the number is casted to float. If the mapped value does not exist or is not a number, returns 0 -+ public float getFloat(final K key); -+ -+ // if the mapped value is a Number but not a float, then the number is casted to float. If the mapped value does not exist or is not a number, returns dfl -+ public float getFloat(final K key, final float dfl); -+ -+ public void setFloat(final K key, final float val); -+ -+ // if the mapped value is a Number but not a double, then the number is casted to double. If the mapped value does not exist or is not a number, returns 0 -+ public double getDouble(final K key); -+ -+ // if the mapped value is a Number but not a double, then the number is casted to double. If the mapped value does not exist or is not a number, returns dfl -+ public double getDouble(final K key, final double dfl); -+ -+ public void setDouble(final K key, final double val); -+ -+ public byte[] getBytes(final K key); -+ -+ public byte[] getBytes(final K key, final byte[] dfl); -+ -+ public void setBytes(final K key, final byte[] val); -+ -+ public short[] getShorts(final K key); -+ -+ public short[] getShorts(final K key, final short[] dfl); -+ -+ public void setShorts(final K key, final short[] val); -+ -+ public int[] getInts(final K key); -+ -+ public int[] getInts(final K key, final int[] dfl); -+ -+ public void setInts(final K key, final int[] val); -+ -+ public long[] getLongs(final K key); -+ -+ public long[] getLongs(final K key, final long[] dfl); -+ -+ public void setLongs(final K key, final long[] val); -+ -+ public ListType getListUnchecked(final K key); -+ -+ public ListType getListUnchecked(final K key, final ListType dfl); -+ -+ public default ListType getList(final K key, final ObjectType type) { -+ return this.getList(key, type, null); -+ } -+ -+ public default ListType getList(final K key, final ObjectType type, final ListType dfl) { -+ final ListType ret = this.getListUnchecked(key, null); -+ final ObjectType retType; -+ if (ret != null && ((retType = ret.getType()) == type || retType == ObjectType.UNDEFINED)) { -+ return ret; -+ } else { -+ return dfl; -+ } -+ } -+ -+ public void setList(final K key, final ListType val); -+ -+ public MapType getMap(final K key); -+ -+ public MapType getMap(final K key, final MapType dfl); -+ -+ public void setMap(final K key, final MapType val); -+ -+ public String getString(final K key); -+ -+ public String getString(final K key, final String dfl); -+ -+ public void setString(final K key, final String val); -+ -+ public default void setGeneric(final K key, final Object value) { -+ if (value instanceof Boolean) { -+ this.setBoolean(key, ((Boolean)value).booleanValue()); -+ } else if (value instanceof Number) { -+ if (value instanceof Byte) { -+ this.setByte(key, ((Byte)value).byteValue()); -+ return; -+ } else if (value instanceof Short) { -+ this.setShort(key, ((Short)value).shortValue()); -+ return; -+ } else if (value instanceof Integer) { -+ this.setInt(key, ((Integer)value).intValue()); -+ return; -+ } else if (value instanceof Long) { -+ this.setLong(key, ((Long)value).longValue()); -+ return; -+ } else if (value instanceof Float) { -+ this.setFloat(key, ((Float)value).floatValue()); -+ return; -+ } else if (value instanceof Double) { -+ this.setDouble(key, ((Double)value).doubleValue()); -+ return; -+ } // else fall through to throw -+ } else if (value instanceof MapType) { -+ this.setMap(key, (MapType)value); -+ return; -+ } else if (value instanceof ListType) { -+ this.setList(key, (ListType)value); -+ return; -+ } else if (value instanceof String) { -+ this.setString(key, (String)value); -+ return; -+ } else if (value.getClass().isArray()) { -+ if (value instanceof byte[]) { -+ this.setBytes(key, (byte[])value); -+ return; -+ } else if (value instanceof short[]) { -+ this.setShorts(key, (short[])value); -+ return; -+ } else if (value instanceof int[]) { -+ this.setInts(key, (int[])value); -+ return; -+ } else if (value instanceof long[]) { -+ this.setLongs(key, (long[])value); -+ return; -+ } // else fall through to throw -+ } -+ -+ throw new IllegalArgumentException("Object " + value + " is not a valid type!"); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/ObjectType.java b/src/main/java/ca/spottedleaf/dataconverter/types/ObjectType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1aab91233ddb98c3af5d424bac120891f1ee16c7 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/ObjectType.java -@@ -0,0 +1,72 @@ -+package ca.spottedleaf.dataconverter.types; -+ -+public enum ObjectType { -+ NONE(null), -+ BYTE(Byte.class), -+ SHORT(Short.class), -+ INT(Integer.class), -+ LONG(Long.class), -+ FLOAT(Float.class), -+ DOUBLE(Double.class), -+ NUMBER(Number.class), -+ BYTE_ARRAY(byte[].class), -+ SHORT_ARRAY(short[].class), -+ INT_ARRAY(int[].class), -+ LONG_ARRAY(long[].class), -+ LIST(ListType.class), -+ MAP(MapType.class), -+ STRING(String.class), -+ UNDEFINED(null); -+ -+ private final Class clazz; -+ private final boolean isNumber; -+ -+ private ObjectType(final Class clazz) { -+ this.clazz = clazz; -+ this.isNumber = clazz != null && Number.class.isAssignableFrom(clazz); -+ } -+ -+ public boolean isNumber() { -+ return this.isNumber; -+ } -+ -+ public Class getObjectClass() { -+ return this.clazz; -+ } -+ -+ public static ObjectType getType(final Object object) { -+ if (object instanceof Number) { -+ if (object instanceof Byte) { -+ return BYTE; -+ } else if (object instanceof Short) { -+ return SHORT; -+ } else if (object instanceof Integer) { -+ return INT; -+ } else if (object instanceof Long) { -+ return LONG; -+ } else if (object instanceof Float) { -+ return FLOAT; -+ } else if (object instanceof Double) { -+ return DOUBLE; -+ } // else return null -+ } else if (object instanceof MapType) { -+ return MAP; -+ } else if (object instanceof ListType) { -+ return LIST; -+ } else if (object instanceof String) { -+ return STRING; -+ } else if (object.getClass().isArray()) { -+ if (object instanceof byte[]) { -+ return BYTE_ARRAY; -+ } else if (object instanceof short[]) { -+ return SHORT_ARRAY; -+ } else if (object instanceof int[]) { -+ return INT_ARRAY; -+ } else if (object instanceof long[]) { -+ return LONG_ARRAY; -+ } // else return null -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/TypeUtil.java b/src/main/java/ca/spottedleaf/dataconverter/types/TypeUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..156a2ea46f8f88a02e88b50d7bb7be82ecd41919 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/TypeUtil.java -@@ -0,0 +1,9 @@ -+package ca.spottedleaf.dataconverter.types; -+ -+public interface TypeUtil { -+ -+ public ListType createEmptyList(); -+ -+ public MapType createEmptyMap(); -+ -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/Types.java b/src/main/java/ca/spottedleaf/dataconverter/types/Types.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2ab9e3b579f20c9a189518496c522155630a36c4 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/Types.java -@@ -0,0 +1,15 @@ -+package ca.spottedleaf.dataconverter.types; -+ -+import ca.spottedleaf.dataconverter.types.json.JsonTypeCompressedUtil; -+import ca.spottedleaf.dataconverter.types.json.JsonTypeUtil; -+import ca.spottedleaf.dataconverter.types.nbt.NBTTypeUtil; -+ -+public interface Types { -+ -+ public static final TypeUtil NBT = new NBTTypeUtil(); -+ -+ public static final TypeUtil JSON = new JsonTypeUtil(); -+ -+ // why does this exist -+ public static final TypeUtil JSON_COMPRESSED = new JsonTypeCompressedUtil(); -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonListType.java b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonListType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4c56144f0cba37f3d7788e5c08e41f6874ae92fc ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonListType.java -@@ -0,0 +1,408 @@ -+package ca.spottedleaf.dataconverter.types.json; -+ -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonElement; -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+ -+public final class JsonListType implements ListType { -+ -+ protected final JsonArray array; -+ protected final boolean compressed; -+ -+ public JsonListType(final boolean compressed) { -+ this.array = new JsonArray(); -+ this.compressed = compressed; -+ } -+ -+ public JsonListType(final JsonArray array, final boolean compressed) { -+ this.array = array; -+ this.compressed = compressed; -+ } -+ -+ @Override -+ public boolean equals(final Object obj) { -+ if (this == obj) { -+ return true; -+ } -+ -+ if (obj == null || obj.getClass() != JsonListType.class) { -+ return false; -+ } -+ -+ return this.array.equals(((JsonListType)obj).array); -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.array.hashCode(); -+ } -+ -+ @Override -+ public String toString() { -+ return "JsonListType{" + -+ "array=" + this.array + -+ ", compressed=" + this.compressed + -+ '}'; -+ } -+ -+ public JsonArray getJson() { -+ return this.array; -+ } -+ -+ @Override -+ public ListType copy() { -+ return new JsonListType(JsonTypeUtil.copyJson(this.array), this.compressed); -+ } -+ -+ @Override -+ public ObjectType getType() { -+ return ObjectType.UNDEFINED; -+ } -+ -+ @Override -+ public int size() { -+ return this.array.size(); -+ } -+ -+ @Override -+ public void remove(final int index) { -+ this.array.remove(index); -+ } -+ -+ @Override -+ public Number getNumber(final int index) { -+ final JsonElement element = this.array.get(index); -+ if (element instanceof JsonPrimitive) { -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isNumber()) { -+ return primitive.getAsNumber(); -+ } else if (primitive.isBoolean()) { -+ return primitive.getAsBoolean() ? Byte.valueOf((byte)1) : Byte.valueOf((byte)0); -+ } else if (this.compressed && primitive.isString()) { -+ try { -+ return Integer.valueOf(Integer.parseInt(primitive.getAsString())); -+ } catch (final NumberFormatException ex) { -+ return null; -+ } -+ } -+ } -+ -+ return null; -+ } -+ -+ @Override -+ public byte getByte(final int index) { -+ final Number number = this.getNumber(index); -+ -+ return number == null ? 0 : number.byteValue(); -+ } -+ -+ @Override -+ public void setByte(final int index, final byte to) { -+ this.array.set(index, new JsonPrimitive(Byte.valueOf(to))); -+ } -+ -+ @Override -+ public short getShort(final int index) { -+ final Number number = this.getNumber(index); -+ -+ return number == null ? 0 : number.shortValue(); -+ } -+ -+ @Override -+ public void setShort(final int index, final short to) { -+ this.array.set(index, new JsonPrimitive(Short.valueOf(to))); -+ } -+ -+ @Override -+ public int getInt(final int index) { -+ final Number number = this.getNumber(index); -+ -+ return number == null ? 0 : number.intValue(); -+ } -+ -+ @Override -+ public void setInt(final int index, final int to) { -+ this.array.set(index, new JsonPrimitive(Integer.valueOf(to))); -+ } -+ -+ @Override -+ public long getLong(final int index) { -+ final Number number = this.getNumber(index); -+ -+ return number == null ? 0 : number.longValue(); -+ } -+ -+ @Override -+ public void setLong(final int index, final long to) { -+ this.array.set(index, new JsonPrimitive(Long.valueOf(to))); -+ } -+ -+ @Override -+ public float getFloat(final int index) { -+ final Number number = this.getNumber(index); -+ -+ return number == null ? 0 : number.floatValue(); -+ } -+ -+ @Override -+ public void setFloat(final int index, final float to) { -+ this.array.set(index, new JsonPrimitive(Float.valueOf(to))); -+ } -+ -+ @Override -+ public double getDouble(final int index) { -+ final Number number = this.getNumber(index); -+ -+ return number == null ? 0 : number.doubleValue(); -+ } -+ -+ @Override -+ public void setDouble(final int index, final double to) { -+ this.array.set(index, new JsonPrimitive(Double.valueOf(to))); -+ } -+ -+ @Override -+ public byte[] getBytes(final int index) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void setBytes(final int index, final byte[] to) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public short[] getShorts(final int index) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void setShorts(final int index, final short[] to) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public int[] getInts(final int index) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void setInts(final int index, final int[] to) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public long[] getLongs(final int index) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void setLongs(final int index, final long[] to) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public ListType getList(final int index) { -+ final JsonElement element = this.array.get(index); -+ if (element instanceof JsonArray) { -+ return new JsonListType((JsonArray)element, this.compressed); -+ } -+ return null; -+ } -+ -+ @Override -+ public void setList(final int index, final ListType list) { -+ this.array.set(index, ((JsonListType)list).array); -+ } -+ -+ @Override -+ public MapType getMap(final int index) { -+ final JsonElement element = this.array.get(index); -+ if (element instanceof JsonObject) { -+ return new JsonMapType((JsonObject)element, this.compressed); -+ } -+ return null; -+ } -+ -+ @Override -+ public void setMap(final int index, final MapType to) { -+ this.array.set(index, ((JsonMapType)to).map); -+ } -+ -+ @Override -+ public String getString(final int index) { -+ final JsonElement element = this.array.get(index); -+ if (element instanceof JsonPrimitive) { -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isString() || (this.compressed && primitive.isNumber())) { -+ return primitive.getAsString(); -+ } -+ } -+ -+ return null; -+ } -+ -+ @Override -+ public void setString(final int index, final String to) { -+ this.array.set(index, new JsonPrimitive(to)); -+ } -+ -+ @Override -+ public void addByte(final byte b) { -+ this.array.add(Byte.valueOf(b)); -+ } -+ -+ @Override -+ public void addByte(final int index, final byte b) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addShort(final short s) { -+ this.array.add(Short.valueOf(s)); -+ } -+ -+ @Override -+ public void addShort(final int index, final short s) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addInt(final int i) { -+ this.array.add(Integer.valueOf(i)); -+ } -+ -+ @Override -+ public void addInt(final int index, final int i) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addLong(final long l) { -+ this.array.add(Long.valueOf(l)); -+ } -+ -+ @Override -+ public void addLong(final int index, final long l) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addFloat(final float f) { -+ this.array.add(Float.valueOf(f)); -+ } -+ -+ @Override -+ public void addFloat(final int index, final float f) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addDouble(final double d) { -+ this.array.add(Double.valueOf(d)); -+ } -+ -+ @Override -+ public void addDouble(final int index, final double d) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addByteArray(final byte[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addByteArray(final int index, final byte[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addShortArray(final short[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addShortArray(final int index, final short[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addIntArray(final int[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addIntArray(final int index, final int[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addLongArray(final long[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addLongArray(final int index, final long[] arr) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addList(final ListType list) { -+ this.array.add(((JsonListType)list).array); -+ } -+ -+ @Override -+ public void addList(final int index, final ListType list) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addMap(final MapType map) { -+ this.array.add(((JsonMapType)map).map); -+ } -+ -+ @Override -+ public void addMap(final int index, final MapType map) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addString(final String string) { -+ this.array.add(string); -+ } -+ -+ @Override -+ public void addString(final int index, final String string) { -+ // doesn't implement any methods for adding at index... yee haw... -+ throw new UnsupportedOperationException(); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonMapType.java b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonMapType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f495c4d65519b3bba6ac371415b7338a726195d8 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonMapType.java -@@ -0,0 +1,443 @@ -+package ca.spottedleaf.dataconverter.types.json; -+ -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonElement; -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+import java.util.LinkedHashSet; -+import java.util.Map; -+import java.util.Set; -+ -+public final class JsonMapType implements MapType { -+ -+ protected final JsonObject map; -+ protected final boolean compressed; -+ -+ public JsonMapType(final boolean compressed) { -+ this.map = new JsonObject(); -+ this.compressed = compressed; -+ } -+ -+ public JsonMapType(final JsonObject map, final boolean compressed) { -+ this.map = map; -+ this.compressed = compressed; -+ } -+ -+ @Override -+ public boolean equals(final Object obj) { -+ if (this == obj) { -+ return true; -+ } -+ -+ if (obj == null || obj.getClass() != JsonMapType.class) { -+ return false; -+ } -+ -+ return this.map.equals(((JsonMapType)obj).map); -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.map.hashCode(); -+ } -+ -+ @Override -+ public String toString() { -+ return "JsonMapType{" + -+ "map=" + this.map + -+ ", compressed=" + this.compressed + -+ '}'; -+ } -+ -+ public JsonObject getJson() { -+ return this.map; -+ } -+ -+ @Override -+ public int size() { -+ return this.map.entrySet().size(); -+ } -+ -+ @Override -+ public boolean isEmpty() { -+ return this.map.entrySet().isEmpty(); -+ } -+ -+ @Override -+ public void clear() { -+ this.map.entrySet().clear(); -+ } -+ -+ @Override -+ public Set keys() { -+ // ah shit. no keyset method -+ final Set keys = new LinkedHashSet<>(); -+ -+ for (final Map.Entry entry : this.map.entrySet()) { -+ keys.add(entry.getKey()); -+ } -+ -+ return keys; -+ } -+ -+ @Override -+ public MapType copy() { -+ return new JsonMapType(JsonTypeUtil.copyJson(this.map), this.compressed); -+ } -+ -+ @Override -+ public boolean hasKey(final String key) { -+ return this.map.has(key); -+ } -+ -+ @Override -+ public boolean hasKey(final String key, final ObjectType type) { -+ final JsonElement element = this.map.get(key); -+ if (element == null) { -+ return false; -+ } -+ -+ if (type == ObjectType.UNDEFINED) { -+ return true; -+ } -+ -+ if (element.isJsonArray()) { -+ return type == ObjectType.LIST; -+ } else if (element.isJsonObject()) { -+ return type == ObjectType.MAP; -+ } else if (element.isJsonNull()) { -+ return false; -+ } -+ -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isString()) { -+ return type == ObjectType.STRING || (this.compressed && type == ObjectType.NUMBER); -+ } else if (primitive.isBoolean()) { -+ return type.isNumber(); -+ } else { -+ // is number -+ final Number number = primitive.getAsNumber(); -+ if (number instanceof Byte) { -+ return type == ObjectType.BYTE || (this.compressed && type == ObjectType.STRING); -+ } else if (number instanceof Short) { -+ return type == ObjectType.SHORT || (this.compressed && type == ObjectType.STRING); -+ } else if (number instanceof Integer) { -+ return type == ObjectType.INT || (this.compressed && type == ObjectType.STRING); -+ } else if (number instanceof Long) { -+ return type == ObjectType.LONG || (this.compressed && type == ObjectType.STRING); -+ } else if (number instanceof Float) { -+ return type == ObjectType.FLOAT || (this.compressed && type == ObjectType.STRING); -+ } else { -+ return type == ObjectType.DOUBLE || (this.compressed && type == ObjectType.STRING); -+ } -+ } -+ } -+ -+ @Override -+ public void remove(final String key) { -+ this.map.remove(key); -+ } -+ -+ @Override -+ public Object getGeneric(final String key) { -+ final JsonElement element = this.map.get(key); -+ if (element == null || element.isJsonNull()) { -+ return null; -+ } else if (element.isJsonObject()) { -+ return new JsonMapType((JsonObject)element, this.compressed); -+ } else if (element.isJsonArray()) { -+ return new JsonListType((JsonArray)element, this.compressed); -+ } else { -+ // primitive -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isNumber()) { -+ return primitive.getAsNumber(); -+ } else if (primitive.isString()) { -+ return primitive.getAsString(); -+ } else if (primitive.isBoolean()) { -+ return Boolean.valueOf(primitive.getAsBoolean()); -+ } else { -+ throw new IllegalStateException("Unknown json object " + element); -+ } -+ } -+ } -+ -+ @Override -+ public Number getNumber(final String key) { -+ return this.getNumber(key, null); -+ } -+ -+ @Override -+ public Number getNumber(final String key, final Number dfl) { -+ final JsonElement element = this.map.get(key); -+ if (element instanceof JsonPrimitive) { -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isNumber()) { -+ return primitive.getAsNumber(); -+ } else if (primitive.isBoolean()) { -+ return primitive.getAsBoolean() ? Byte.valueOf((byte)1) : Byte.valueOf((byte)0); -+ } else if (this.compressed && primitive.isString()) { -+ try { -+ return Integer.valueOf(Integer.parseInt(primitive.getAsString())); -+ } catch (final NumberFormatException ex) { -+ return null; -+ } -+ } -+ } -+ -+ return dfl; -+ } -+ -+ @Override -+ public boolean getBoolean(final String key) { -+ return this.getBoolean(key, false); -+ } -+ -+ @Override -+ public boolean getBoolean(final String key, final boolean dfl) { -+ final JsonElement element = this.map.get(key); -+ if (element instanceof JsonPrimitive) { -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isNumber()) { -+ return primitive.getAsNumber().byteValue() != 0; -+ } else if (primitive.isBoolean()) { -+ return primitive.getAsBoolean(); -+ } -+ } -+ -+ return dfl; -+ } -+ -+ @Override -+ public void setBoolean(final String key, final boolean val) { -+ this.map.addProperty(key, Boolean.valueOf(val)); -+ } -+ -+ @Override -+ public byte getByte(final String key) { -+ return this.getByte(key, (byte)0); -+ } -+ -+ @Override -+ public byte getByte(final String key, final byte dfl) { -+ final Number ret = this.getNumber(key, null); -+ return ret == null ? dfl : ret.byteValue(); -+ } -+ -+ @Override -+ public void setByte(final String key, final byte val) { -+ this.map.addProperty(key, Byte.valueOf(val)); -+ } -+ -+ @Override -+ public short getShort(final String key) { -+ return this.getShort(key, (short)0); -+ } -+ -+ @Override -+ public short getShort(final String key, final short dfl) { -+ final Number ret = this.getNumber(key, null); -+ return ret == null ? dfl : ret.shortValue(); -+ } -+ -+ @Override -+ public void setShort(final String key, final short val) { -+ this.map.addProperty(key, Short.valueOf(val)); -+ } -+ -+ @Override -+ public int getInt(final String key) { -+ return this.getInt(key, 0); -+ } -+ -+ @Override -+ public int getInt(final String key, final int dfl) { -+ final Number ret = this.getNumber(key, null); -+ return ret == null ? dfl : ret.intValue(); -+ } -+ -+ @Override -+ public void setInt(final String key, final int val) { -+ this.map.addProperty(key, Integer.valueOf(val)); -+ } -+ -+ @Override -+ public long getLong(final String key) { -+ return this.getLong(key, 0L); -+ } -+ -+ @Override -+ public long getLong(final String key, final long dfl) { -+ final Number ret = this.getNumber(key, null); -+ return ret == null ? dfl : ret.longValue(); -+ } -+ -+ @Override -+ public void setLong(final String key, final long val) { -+ this.map.addProperty(key, Long.valueOf(val)); -+ } -+ -+ @Override -+ public float getFloat(final String key) { -+ return this.getFloat(key, 0.0F); -+ } -+ -+ @Override -+ public float getFloat(final String key, final float dfl) { -+ final Number ret = this.getNumber(key, null); -+ return ret == null ? dfl : ret.floatValue(); -+ } -+ -+ @Override -+ public void setFloat(final String key, final float val) { -+ this.map.addProperty(key, Float.valueOf(val)); -+ } -+ -+ @Override -+ public double getDouble(final String key) { -+ return this.getDouble(key, 0.0D); -+ } -+ -+ @Override -+ public double getDouble(final String key, final double dfl) { -+ final Number ret = this.getNumber(key, null); -+ return ret == null ? dfl : ret.doubleValue(); -+ } -+ -+ @Override -+ public void setDouble(final String key, final double val) { -+ this.map.addProperty(key, Double.valueOf(val)); -+ } -+ -+ @Override -+ public byte[] getBytes(final String key) { -+ return this.getBytes(key, null); -+ } -+ -+ @Override -+ public byte[] getBytes(final String key, final byte[] dfl) { -+ return dfl; -+ } -+ -+ @Override -+ public void setBytes(final String key, final byte[] val) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public short[] getShorts(final String key) { -+ return this.getShorts(key, null); -+ } -+ -+ @Override -+ public short[] getShorts(final String key, final short[] dfl) { -+ return dfl; -+ } -+ -+ @Override -+ public void setShorts(final String key, final short[] val) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public int[] getInts(final String key) { -+ return this.getInts(key, null); -+ } -+ -+ @Override -+ public int[] getInts(final String key, final int[] dfl) { -+ return dfl; -+ } -+ -+ @Override -+ public void setInts(final String key, final int[] val) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public long[] getLongs(final String key) { -+ return this.getLongs(key, null); -+ } -+ -+ @Override -+ public long[] getLongs(final String key, final long[] dfl) { -+ return dfl; -+ } -+ -+ @Override -+ public void setLongs(final String key, final long[] val) { -+ // JSON does not support raw primitive arrays -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public ListType getListUnchecked(final String key) { -+ return this.getListUnchecked(key, null); -+ } -+ -+ @Override -+ public ListType getListUnchecked(final String key, final ListType dfl) { -+ final JsonElement element = this.map.get(key); -+ if (element instanceof JsonArray) { -+ return new JsonListType((JsonArray)element, this.compressed); -+ } -+ -+ return dfl; -+ } -+ -+ @Override -+ public void setList(final String key, final ListType val) { -+ this.map.add(key, ((JsonListType)val).getJson()); -+ } -+ -+ @Override -+ public MapType getMap(final String key) { -+ return this.getMap(key, null); -+ } -+ -+ @Override -+ public MapType getMap(final String key, final MapType dfl) { -+ final JsonElement element = this.map.get(key); -+ if (element instanceof JsonObject) { -+ return new JsonMapType((JsonObject)element, this.compressed); -+ } -+ -+ return dfl; -+ } -+ -+ @Override -+ public void setMap(final String key, final MapType val) { -+ this.map.add(key, ((JsonMapType)val).map); -+ } -+ -+ @Override -+ public String getString(final String key) { -+ return this.getString(key, null); -+ } -+ -+ @Override -+ public String getString(final String key, final String dfl) { -+ final JsonElement element = this.map.get(key); -+ if (element instanceof JsonPrimitive) { -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isString()) { -+ return primitive.getAsString(); -+ } else if (this.compressed && primitive.isNumber()) { -+ return primitive.getAsString(); -+ } -+ } -+ -+ return dfl; -+ } -+ -+ @Override -+ public void setString(final String key, final String val) { -+ this.map.addProperty(key, val); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonTypeCompressedUtil.java b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonTypeCompressedUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9c3093b66b847b5248bde923243fce78842bf67f ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonTypeCompressedUtil.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.types.json; -+ -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.TypeUtil; -+ -+public final class JsonTypeCompressedUtil implements TypeUtil { -+ -+ @Override -+ public ListType createEmptyList() { -+ return new JsonListType(true); -+ } -+ -+ @Override -+ public MapType createEmptyMap() { -+ return new JsonMapType(true); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonTypeUtil.java b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonTypeUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9410ae68395a09c7710bdbb2ccc6acf6633cad23 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/json/JsonTypeUtil.java -@@ -0,0 +1,81 @@ -+package ca.spottedleaf.dataconverter.types.json; -+ -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.TypeUtil; -+import ca.spottedleaf.dataconverter.types.nbt.NBTListType; -+import ca.spottedleaf.dataconverter.types.nbt.NBTMapType; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonElement; -+import com.google.gson.JsonNull; -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+import com.google.gson.internal.Streams; -+import com.google.gson.stream.JsonReader; -+import java.io.StringReader; -+import java.util.Map; -+ -+public final class JsonTypeUtil implements TypeUtil { -+ -+ @Override -+ public ListType createEmptyList() { -+ return new JsonListType(false); -+ } -+ -+ @Override -+ public MapType createEmptyMap() { -+ return new JsonMapType(false); -+ } -+ -+ public static T copyJson(final T from) { -+ // This is stupidly inefficient. However, deepCopy() is not exposed in this gson version. -+ final String out = from.toString(); -+ -+ return (T)Streams.parse(new JsonReader(new StringReader(out))); -+ } -+ -+ private static Object convertToGenericNBT(final JsonElement element, final boolean compressed) { -+ if (element instanceof JsonObject) { -+ return convertJsonToNBT(new JsonMapType((JsonObject)element, compressed)); -+ } else if (element instanceof JsonArray) { -+ return convertJsonToNBT(new JsonListType((JsonArray)element, compressed)); -+ } else if (element instanceof JsonNull) { -+ return null; -+ } else { -+ final JsonPrimitive primitive = (JsonPrimitive)element; -+ if (primitive.isBoolean()) { -+ return primitive.getAsBoolean() ? Byte.valueOf((byte)1) : Byte.valueOf((byte)0); -+ } else if (primitive.isNumber()) { -+ return primitive.getAsNumber(); -+ } else if (primitive.isString()) { -+ return primitive.getAsString(); -+ } -+ } -+ -+ throw new IllegalStateException("Unrecognized type " + element); -+ } -+ -+ public static NBTMapType convertJsonToNBT(final JsonMapType json) { -+ final NBTMapType ret = new NBTMapType(); -+ for (final Map.Entry entry : json.map.entrySet()) { -+ final Object obj = convertToGenericNBT(entry.getValue(), json.compressed); -+ if (obj == null) { -+ continue; -+ } -+ -+ ret.setGeneric(entry.getKey(), obj); -+ } -+ -+ return ret; -+ } -+ -+ public static NBTListType convertJsonToNBT(final JsonListType json) { -+ final NBTListType ret = new NBTListType(); -+ -+ for (int i = 0, len = json.size(); i < len; ++i) { -+ ret.addGeneric(convertToGenericNBT(json.array.get(i), json.compressed)); -+ } -+ -+ return ret; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTListType.java b/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTListType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3a0187de2c7b455cd15419da08026d5d9f72d35b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTListType.java -@@ -0,0 +1,433 @@ -+package ca.spottedleaf.dataconverter.types.nbt; -+ -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import net.minecraft.nbt.ByteArrayTag; -+import net.minecraft.nbt.ByteTag; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.DoubleTag; -+import net.minecraft.nbt.FloatTag; -+import net.minecraft.nbt.IntArrayTag; -+import net.minecraft.nbt.IntTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.LongArrayTag; -+import net.minecraft.nbt.LongTag; -+import net.minecraft.nbt.NumericTag; -+import net.minecraft.nbt.ShortTag; -+import net.minecraft.nbt.StringTag; -+import net.minecraft.nbt.Tag; -+ -+public final class NBTListType implements ListType { -+ -+ private final ListTag list; -+ -+ public NBTListType() { -+ this.list = new ListTag(); -+ } -+ -+ public NBTListType(final ListTag tag) { -+ this.list = tag; -+ } -+ -+ @Override -+ public boolean equals(final Object obj) { -+ if (this == obj) { -+ return true; -+ } -+ if (obj == null || obj.getClass() != NBTListType.class) { -+ return false; -+ } -+ -+ return this.list.equals(((NBTListType)obj).list); -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.list.hashCode(); -+ } -+ -+ @Override -+ public String toString() { -+ return "NBTListType{" + -+ "list=" + this.list + -+ '}'; -+ } -+ -+ public ListTag getTag() { -+ return this.list; -+ } -+ -+ @Override -+ public ListType copy() { -+ return new NBTListType(this.list.copy()); -+ } -+ -+ protected static ObjectType getType(final byte id) { -+ switch (id) { -+ case 0: // END -+ return ObjectType.NONE; -+ case 1: // BYTE -+ return ObjectType.BYTE; -+ case 2: // SHORT -+ return ObjectType.SHORT; -+ case 3: // INT -+ return ObjectType.INT; -+ case 4: // LONG -+ return ObjectType.LONG; -+ case 5: // FLOAT -+ return ObjectType.FLOAT; -+ case 6: // DOUBLE -+ return ObjectType.DOUBLE; -+ case 7: // BYTE_ARRAY -+ return ObjectType.BYTE_ARRAY; -+ case 8: // STRING -+ return ObjectType.STRING; -+ case 9: // LIST -+ return ObjectType.LIST; -+ case 10: // COMPOUND -+ return ObjectType.MAP; -+ case 11: // INT_ARRAY -+ return ObjectType.INT_ARRAY; -+ case 12: // LONG_ARRAY -+ return ObjectType.LONG_ARRAY; -+ default: -+ throw new IllegalStateException("Unknown type: " + id); -+ } -+ } -+ -+ @Override -+ public ObjectType getType() { -+ return getType(this.list.getElementType()); -+ } -+ -+ @Override -+ public int size() { -+ return this.list.size(); -+ } -+ -+ @Override -+ public void remove(final int index) { -+ this.list.remove(index); -+ } -+ -+ @Override -+ public Number getNumber(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsNumber(); -+ } -+ -+ @Override -+ public byte getByte(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsByte(); -+ } -+ -+ @Override -+ public void setByte(final int index, final byte to) { -+ this.list.set(index, ByteTag.valueOf(to)); -+ } -+ -+ @Override -+ public short getShort(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsShort(); -+ } -+ -+ @Override -+ public void setShort(final int index, final short to) { -+ this.list.set(index, ShortTag.valueOf(to)); -+ } -+ -+ @Override -+ public int getInt(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsInt(); -+ } -+ -+ @Override -+ public void setInt(final int index, final int to) { -+ this.list.set(index, IntTag.valueOf(to)); -+ } -+ -+ @Override -+ public long getLong(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsLong(); -+ } -+ -+ @Override -+ public void setLong(final int index, final long to) { -+ this.list.set(index, LongTag.valueOf(to)); -+ } -+ -+ @Override -+ public float getFloat(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsFloat(); -+ } -+ -+ @Override -+ public void setFloat(final int index, final float to) { -+ this.list.set(index, FloatTag.valueOf(to)); -+ } -+ -+ @Override -+ public double getDouble(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof NumericTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((NumericTag)tag).getAsDouble(); -+ } -+ -+ @Override -+ public void setDouble(final int index, final double to) { -+ this.list.set(index, DoubleTag.valueOf(to)); -+ } -+ -+ @Override -+ public byte[] getBytes(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof ByteArrayTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((ByteArrayTag)tag).getAsByteArray(); -+ } -+ -+ @Override -+ public void setBytes(final int index, final byte[] to) { -+ this.list.set(index, new ByteArrayTag(to)); -+ } -+ -+ @Override -+ public short[] getShorts(final int index) { -+ // NBT does not support shorts -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void setShorts(final int index, final short[] to) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public int[] getInts(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof IntArrayTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((IntArrayTag)tag).getAsIntArray(); -+ } -+ -+ @Override -+ public void setInts(final int index, final int[] to) { -+ this.list.set(index, new IntArrayTag(to)); -+ } -+ -+ @Override -+ public long[] getLongs(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof LongArrayTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((LongArrayTag)tag).getAsLongArray(); -+ } -+ -+ @Override -+ public void setLongs(final int index, final long[] to) { -+ this.list.set(index, new LongArrayTag(to)); -+ } -+ -+ @Override -+ public ListType getList(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof ListTag)) { -+ throw new IllegalStateException(); -+ } -+ return new NBTListType((ListTag)tag); -+ } -+ -+ @Override -+ public void setList(final int index, final ListType list) { -+ this.list.set(index, ((NBTListType)list).getTag()); -+ } -+ -+ @Override -+ public MapType getMap(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof CompoundTag)) { -+ throw new IllegalStateException(); -+ } -+ return new NBTMapType((CompoundTag)tag); -+ } -+ -+ @Override -+ public void setMap(final int index, final MapType to) { -+ this.list.set(index, ((NBTMapType)to).getTag()); -+ } -+ -+ @Override -+ public String getString(final int index) { -+ final Tag tag = this.list.get(index); // does bound checking for us -+ if (!(tag instanceof StringTag)) { -+ throw new IllegalStateException(); -+ } -+ return ((StringTag)tag).getAsString(); -+ } -+ -+ @Override -+ public void setString(final int index, final String to) { -+ this.list.set(index, StringTag.valueOf(to)); -+ } -+ -+ @Override -+ public void addByte(final byte b) { -+ this.list.add(ByteTag.valueOf(b)); -+ } -+ -+ @Override -+ public void addByte(final int index, final byte b) { -+ this.list.add(index, ByteTag.valueOf(b)); -+ } -+ -+ @Override -+ public void addShort(final short s) { -+ this.list.add(ShortTag.valueOf(s)); -+ } -+ -+ @Override -+ public void addShort(final int index, final short s) { -+ this.list.add(index, ShortTag.valueOf(s)); -+ } -+ -+ @Override -+ public void addInt(final int i) { -+ this.list.add(IntTag.valueOf(i)); -+ } -+ -+ @Override -+ public void addInt(final int index, final int i) { -+ this.list.add(index, IntTag.valueOf(i)); -+ } -+ -+ @Override -+ public void addLong(final long l) { -+ this.list.add(LongTag.valueOf(l)); -+ } -+ -+ @Override -+ public void addLong(final int index, final long l) { -+ this.list.add(index, LongTag.valueOf(l)); -+ } -+ -+ @Override -+ public void addFloat(final float f) { -+ this.list.add(FloatTag.valueOf(f)); -+ } -+ -+ @Override -+ public void addFloat(final int index, final float f) { -+ this.list.add(index, FloatTag.valueOf(f)); -+ } -+ -+ @Override -+ public void addDouble(final double d) { -+ this.list.add(DoubleTag.valueOf(d)); -+ } -+ -+ @Override -+ public void addDouble(final int index, final double d) { -+ this.list.add(index, DoubleTag.valueOf(d)); -+ } -+ -+ @Override -+ public void addByteArray(final byte[] arr) { -+ this.list.add(new ByteArrayTag(arr)); -+ } -+ -+ @Override -+ public void addByteArray(final int index, final byte[] arr) { -+ this.list.add(index, new ByteArrayTag(arr)); -+ } -+ -+ @Override -+ public void addShortArray(final short[] arr) { -+ // NBT does not support short[] -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addShortArray(final int index, final short[] arr) { -+ // NBT does not support short[] -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void addIntArray(final int[] arr) { -+ this.list.add(new IntArrayTag(arr)); -+ } -+ -+ @Override -+ public void addIntArray(final int index, final int[] arr) { -+ this.list.add(index, new IntArrayTag(arr)); -+ } -+ -+ @Override -+ public void addLongArray(final long[] arr) { -+ this.list.add(new LongArrayTag(arr)); -+ } -+ -+ @Override -+ public void addLongArray(final int index, final long[] arr) { -+ this.list.add(index, new LongArrayTag(arr)); -+ } -+ -+ @Override -+ public void addList(final ListType list) { -+ this.list.add(((NBTListType)list).getTag()); -+ } -+ -+ @Override -+ public void addList(final int index, final ListType list) { -+ this.list.add(index, ((NBTListType)list).getTag()); -+ } -+ -+ @Override -+ public void addMap(final MapType map) { -+ this.list.add(((NBTMapType)map).getTag()); -+ } -+ -+ @Override -+ public void addMap(final int index, final MapType map) { -+ this.list.add(index, ((NBTMapType)map).getTag()); -+ } -+ -+ @Override -+ public void addString(final String string) { -+ this.list.add(StringTag.valueOf(string)); -+ } -+ -+ @Override -+ public void addString(final int index, final String string) { -+ this.list.add(index, StringTag.valueOf(string)); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTMapType.java b/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTMapType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d31d33ea82bdf86da69c0b7114d0033210567289 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTMapType.java -@@ -0,0 +1,433 @@ -+package ca.spottedleaf.dataconverter.types.nbt; -+ -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.ObjectType; -+import net.minecraft.nbt.ByteArrayTag; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.IntArrayTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.LongArrayTag; -+import net.minecraft.nbt.NumericTag; -+import net.minecraft.nbt.StringTag; -+import net.minecraft.nbt.Tag; -+ -+import java.util.Set; -+ -+public final class NBTMapType implements MapType { -+ -+ private final CompoundTag map; -+ -+ public NBTMapType() { -+ this.map = new CompoundTag(); -+ } -+ -+ public NBTMapType(final CompoundTag tag) { -+ this.map = tag; -+ } -+ -+ @Override -+ public boolean equals(final Object obj) { -+ if (this == obj) { -+ return true; -+ } -+ if (obj == null || obj.getClass() != NBTMapType.class) { -+ return false; -+ } -+ -+ return this.map.equals(((NBTMapType)obj).map); -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.map.hashCode(); -+ } -+ -+ @Override -+ public String toString() { -+ return "NBTMapType{" + -+ "map=" + this.map + -+ '}'; -+ } -+ -+ @Override -+ public int size() { -+ return this.map.size(); -+ } -+ -+ @Override -+ public boolean isEmpty() { -+ return this.map.isEmpty(); -+ } -+ -+ @Override -+ public void clear() { -+ this.map.getAllKeys().clear(); -+ } -+ -+ @Override -+ public Set keys() { -+ return this.map.getAllKeys(); -+ } -+ -+ public CompoundTag getTag() { -+ return this.map; -+ } -+ -+ @Override -+ public MapType copy() { -+ return new NBTMapType(this.map.copy()); -+ } -+ -+ @Override -+ public boolean hasKey(final String key) { -+ return this.map.get(key) != null; -+ } -+ -+ @Override -+ public boolean hasKey(final String key, final ObjectType type) { -+ final Tag tag = this.map.get(key); -+ if (tag == null) { -+ return false; -+ } -+ -+ final ObjectType valueType = NBTListType.getType(tag.getId()); -+ -+ return valueType == type || (type == ObjectType.NUMBER && valueType.isNumber()); -+ } -+ -+ @Override -+ public void remove(final String key) { -+ this.map.remove(key); -+ } -+ -+ @Override -+ public Object getGeneric(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag == null) { -+ return null; -+ } -+ -+ switch (NBTListType.getType(tag.getId())) { -+ case BYTE: -+ case SHORT: -+ case INT: -+ case LONG: -+ case FLOAT: -+ case DOUBLE: -+ return ((NumericTag)tag).getAsNumber(); -+ case MAP: -+ return new NBTMapType((CompoundTag)tag); -+ case LIST: -+ return new NBTListType((ListTag)tag); -+ case STRING: -+ return ((StringTag)tag).getAsString(); -+ case BYTE_ARRAY: -+ return ((ByteArrayTag)tag).getAsByteArray(); -+ // Note: No short array tag! -+ case INT_ARRAY: -+ return ((IntArrayTag)tag).getAsIntArray(); -+ case LONG_ARRAY: -+ return ((LongArrayTag)tag).getAsLongArray(); -+ } -+ -+ throw new IllegalStateException("Unrecognized type " + tag); -+ } -+ -+ @Override -+ public Number getNumber(final String key) { -+ return this.getNumber(key, null); -+ } -+ -+ @Override -+ public Number getNumber(final String key, final Number dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsNumber(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public boolean getBoolean(final String key) { -+ return this.getByte(key) != 0; -+ } -+ -+ @Override -+ public boolean getBoolean(final String key, final boolean dfl) { -+ return this.getByte(key, dfl ? (byte)1 : (byte)0) != 0; -+ } -+ -+ @Override -+ public void setBoolean(final String key, final boolean val) { -+ this.setByte(key, val ? (byte)1 : (byte)0); -+ } -+ -+ @Override -+ public byte getByte(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsByte(); -+ } -+ return 0; -+ } -+ -+ @Override -+ public byte getByte(final String key, final byte dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsByte(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setByte(final String key, final byte val) { -+ this.map.putByte(key, val); -+ } -+ -+ @Override -+ public short getShort(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsShort(); -+ } -+ return 0; -+ } -+ -+ @Override -+ public short getShort(final String key, final short dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsShort(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setShort(final String key, final short val) { -+ this.map.putShort(key, val); -+ } -+ -+ @Override -+ public int getInt(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsInt(); -+ } -+ return 0; -+ } -+ -+ @Override -+ public int getInt(final String key, final int dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsInt(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setInt(final String key, final int val) { -+ this.map.putInt(key, val); -+ } -+ -+ @Override -+ public long getLong(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsLong(); -+ } -+ return 0; -+ } -+ -+ @Override -+ public long getLong(final String key, final long dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsLong(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setLong(final String key, final long val) { -+ this.map.putLong(key, val); -+ } -+ -+ @Override -+ public float getFloat(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsFloat(); -+ } -+ return 0; -+ } -+ -+ @Override -+ public float getFloat(final String key, final float dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsFloat(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setFloat(final String key, final float val) { -+ this.map.putFloat(key, val); -+ } -+ -+ @Override -+ public double getDouble(final String key) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsDouble(); -+ } -+ return 0; -+ } -+ -+ @Override -+ public double getDouble(final String key, final double dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof NumericTag) { -+ return ((NumericTag)tag).getAsDouble(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setDouble(final String key, final double val) { -+ this.map.putDouble(key, val); -+ } -+ -+ @Override -+ public byte[] getBytes(final String key) { -+ return this.getBytes(key, null); -+ } -+ -+ @Override -+ public byte[] getBytes(final String key, final byte[] dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof ByteArrayTag) { -+ return ((ByteArrayTag)tag).getAsByteArray(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setBytes(final String key, final byte[] val) { -+ this.map.putByteArray(key, val); -+ } -+ -+ @Override -+ public short[] getShorts(final String key) { -+ return this.getShorts(key, null); -+ } -+ -+ @Override -+ public short[] getShorts(final String key, final short[] dfl) { -+ // NBT does not support short array -+ return dfl; -+ } -+ -+ @Override -+ public void setShorts(final String key, final short[] val) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public int[] getInts(final String key) { -+ return this.getInts(key, null); -+ } -+ -+ @Override -+ public int[] getInts(final String key, final int[] dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof IntArrayTag) { -+ return ((IntArrayTag)tag).getAsIntArray(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setInts(final String key, final int[] val) { -+ this.map.putIntArray(key, val); -+ } -+ -+ @Override -+ public long[] getLongs(final String key) { -+ return this.getLongs(key, null); -+ } -+ -+ @Override -+ public long[] getLongs(final String key, final long[] dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof LongArrayTag) { -+ return ((LongArrayTag)tag).getAsLongArray(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setLongs(final String key, final long[] val) { -+ this.map.putLongArray(key, val); -+ } -+ -+ @Override -+ public ListType getListUnchecked(final String key) { -+ return this.getListUnchecked(key, null); -+ } -+ -+ @Override -+ public ListType getListUnchecked(final String key, final ListType dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof ListTag) { -+ return new NBTListType((ListTag)tag); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setList(final String key, final ListType val) { -+ this.map.put(key, ((NBTListType)val).getTag()); -+ } -+ -+ @Override -+ public MapType getMap(final String key) { -+ return this.getMap(key, null); -+ } -+ -+ @Override -+ public MapType getMap(final String key, final MapType dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof CompoundTag) { -+ return new NBTMapType((CompoundTag)tag); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setMap(final String key, final MapType val) { -+ this.map.put(key, ((NBTMapType)val).getTag()); -+ } -+ -+ @Override -+ public String getString(final String key) { -+ return this.getString(key, null); -+ } -+ -+ @Override -+ public String getString(final String key, final String dfl) { -+ final Tag tag = this.map.get(key); -+ if (tag instanceof StringTag) { -+ return ((StringTag)tag).getAsString(); -+ } -+ return dfl; -+ } -+ -+ @Override -+ public void setString(final String key, final String val) { -+ this.map.putString(key, val); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTTypeUtil.java b/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTTypeUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..62c0f4073aff301bf5b3187e0d4446fd8d0ac475 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/types/nbt/NBTTypeUtil.java -@@ -0,0 +1,18 @@ -+package ca.spottedleaf.dataconverter.types.nbt; -+ -+import ca.spottedleaf.dataconverter.types.ListType; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.TypeUtil; -+ -+public final class NBTTypeUtil implements TypeUtil { -+ -+ @Override -+ public ListType createEmptyList() { -+ return new NBTListType(); -+ } -+ -+ @Override -+ public MapType createEmptyMap() { -+ return new NBTMapType(); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/util/Int2IntArraySortedMap.java b/src/main/java/ca/spottedleaf/dataconverter/util/Int2IntArraySortedMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6596de3d9ebae583c252aa061f0cfdf8778ea1a5 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/util/Int2IntArraySortedMap.java -@@ -0,0 +1,77 @@ -+package ca.spottedleaf.dataconverter.util; -+ -+import it.unimi.dsi.fastutil.ints.Int2IntFunction; -+ -+import java.util.Arrays; -+ -+public class Int2IntArraySortedMap { -+ -+ protected int[] key; -+ protected int[] val; -+ protected int size; -+ -+ public Int2IntArraySortedMap() { -+ this.key = new int[8]; -+ this.val = new int[8]; -+ } -+ -+ public int put(final int key, final int value) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ final int current = this.val[index]; -+ this.val[index] = value; -+ return current; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ ++this.size; -+ -+ this.key[insert] = key; -+ this.val[insert] = value; -+ -+ return 0; -+ } -+ -+ public int computeIfAbsent(final int key, final Int2IntFunction producer) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ return this.val[index]; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ ++this.size; -+ -+ this.key[insert] = key; -+ -+ return this.val[insert] = producer.apply(key); -+ } -+ -+ public int get(final int key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ return 0; -+ } -+ return this.val[index]; -+ } -+ -+ public int getFloor(final int key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ final int insert = -(index + 1) - 1; -+ return insert < 0 ? 0 : this.val[insert]; -+ } -+ return this.val[index]; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/util/Int2ObjectArraySortedMap.java b/src/main/java/ca/spottedleaf/dataconverter/util/Int2ObjectArraySortedMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..de9d632489609136c712a9adaee941fd38fad440 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/util/Int2ObjectArraySortedMap.java -@@ -0,0 +1,74 @@ -+package ca.spottedleaf.dataconverter.util; -+ -+import java.util.Arrays; -+import java.util.function.IntFunction; -+ -+public class Int2ObjectArraySortedMap { -+ -+ protected int[] key; -+ protected V[] val; -+ protected int size; -+ -+ public Int2ObjectArraySortedMap() { -+ this.key = new int[8]; -+ this.val = (V[])new Object[8]; -+ } -+ -+ public V put(final int key, final V value) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ final V current = this.val[index]; -+ this.val[index] = value; -+ return current; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ -+ this.key[insert] = key; -+ this.val[insert] = value; -+ -+ return null; -+ } -+ -+ public V computeIfAbsent(final int key, final IntFunction producer) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ return this.val[index]; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ -+ this.key[insert] = key; -+ -+ return this.val[insert] = producer.apply(key); -+ } -+ -+ public V get(final int key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ return null; -+ } -+ return this.val[index]; -+ } -+ -+ public V getFloor(final int key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ final int insert = -(index + 1); -+ return this.val[insert]; -+ } -+ return this.val[index]; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/util/Long2IntArraySortedMap.java b/src/main/java/ca/spottedleaf/dataconverter/util/Long2IntArraySortedMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..94705bb141b550589faa9a0408402d8636c61907 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/util/Long2IntArraySortedMap.java -@@ -0,0 +1,76 @@ -+package ca.spottedleaf.dataconverter.util; -+ -+import it.unimi.dsi.fastutil.longs.Long2IntFunction; -+import java.util.Arrays; -+ -+public class Long2IntArraySortedMap { -+ -+ protected long[] key; -+ protected int[] val; -+ protected int size; -+ -+ public Long2IntArraySortedMap() { -+ this.key = new long[8]; -+ this.val = new int[8]; -+ } -+ -+ public int put(final long key, final int value) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ final int current = this.val[index]; -+ this.val[index] = value; -+ return current; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ ++this.size; -+ -+ this.key[insert] = key; -+ this.val[insert] = value; -+ -+ return 0; -+ } -+ -+ public int computeIfAbsent(final long key, final Long2IntFunction producer) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ return this.val[index]; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ ++this.size; -+ -+ this.key[insert] = key; -+ -+ return this.val[insert] = producer.apply(key); -+ } -+ -+ public int get(final long key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ return 0; -+ } -+ return this.val[index]; -+ } -+ -+ public int getFloor(final long key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ final int insert = -(index + 1) - 1; -+ return insert < 0 ? 0 : this.val[insert]; -+ } -+ return this.val[index]; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/dataconverter/util/Long2ObjectArraySortedMap.java b/src/main/java/ca/spottedleaf/dataconverter/util/Long2ObjectArraySortedMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6f634c8825589a23f46ad7b54354475c9a95bd1b ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/dataconverter/util/Long2ObjectArraySortedMap.java -@@ -0,0 +1,76 @@ -+package ca.spottedleaf.dataconverter.util; -+ -+import java.util.Arrays; -+import java.util.function.LongFunction; -+ -+public class Long2ObjectArraySortedMap { -+ -+ protected long[] key; -+ protected V[] val; -+ protected int size; -+ -+ public Long2ObjectArraySortedMap() { -+ this.key = new long[8]; -+ this.val = (V[])new Object[8]; -+ } -+ -+ public V put(final long key, final V value) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ final V current = this.val[index]; -+ this.val[index] = value; -+ return current; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ ++this.size; -+ -+ this.key[insert] = key; -+ this.val[insert] = value; -+ -+ return null; -+ } -+ -+ public V computeIfAbsent(final long key, final LongFunction producer) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index >= 0) { -+ return this.val[index]; -+ } -+ final int insert = -(index + 1); -+ // shift entries down -+ if (this.size >= this.val.length) { -+ this.key = Arrays.copyOf(this.key, this.key.length * 2); -+ this.val = Arrays.copyOf(this.val, this.val.length * 2); -+ } -+ System.arraycopy(this.key, insert, this.key, insert + 1, this.size - insert); -+ System.arraycopy(this.val, insert, this.val, insert + 1, this.size - insert); -+ ++this.size; -+ -+ this.key[insert] = key; -+ -+ return this.val[insert] = producer.apply(key); -+ } -+ -+ public V get(final long key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ return null; -+ } -+ return this.val[index]; -+ } -+ -+ public V getFloor(final long key) { -+ final int index = Arrays.binarySearch(this.key, 0, this.size, key); -+ if (index < 0) { -+ final int insert = -(index + 1) - 1; -+ return insert < 0 ? null : this.val[insert]; -+ } -+ return this.val[index]; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/starlight/light/BlockStarLightEngine.java b/src/main/java/ca/spottedleaf/starlight/light/BlockStarLightEngine.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9efbdba758aebcad3454a9a52c8a7eae4b7fc7eb ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/starlight/light/BlockStarLightEngine.java -@@ -0,0 +1,283 @@ -+package ca.spottedleaf.starlight.light; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.chunk.*; -+import net.minecraft.world.phys.shapes.Shapes; -+import net.minecraft.world.phys.shapes.VoxelShape; -+ -+import java.util.ArrayList; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Set; -+import java.util.stream.Collectors; -+ -+public final class BlockStarLightEngine extends StarLightEngine { -+ -+ public BlockStarLightEngine(final Level world) { -+ super(false, world); -+ } -+ -+ @Override -+ protected boolean[] getEmptinessMap(final ChunkAccess chunk) { -+ return chunk.getBlockEmptinessMap(); -+ } -+ -+ @Override -+ protected void setEmptinessMap(final ChunkAccess chunk, final boolean[] to) { -+ chunk.setBlockEmptinessMap(to); -+ } -+ -+ @Override -+ protected SWMRNibbleArray[] getNibblesOnChunk(final ChunkAccess chunk) { -+ return chunk.getBlockNibbles(); -+ } -+ -+ @Override -+ protected void setNibbles(final ChunkAccess chunk, final SWMRNibbleArray[] to) { -+ chunk.setBlockNibbles(to); -+ } -+ -+ @Override -+ protected boolean canUseChunk(final ChunkAccess chunk) { -+ return chunk.getStatus().isOrAfter(ChunkStatus.LIGHT) && (this.isClientSide || chunk.isLightCorrect()); -+ } -+ -+ @Override -+ protected void setNibbleNull(final int chunkX, final int chunkY, final int chunkZ) { -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ if (nibble != null) { -+ // de-initialisation is not as straightforward as with sky data, since deinit of block light is typically -+ // because a block was removed - which can decrease light. with sky data, block breaking can only result -+ // in increases, and thus the existing sky block check will actually correctly propagate light through -+ // a null section. so in order to propagate decreases correctly, we can do a couple of things: not remove -+ // the data section, or do edge checks on ALL axis (x, y, z). however I do not want edge checks running -+ // for clients at all, as they are expensive. so we don't remove the section, but to maintain the appearence -+ // of vanilla data management we "hide" them. -+ nibble.setHidden(); -+ } -+ } -+ -+ @Override -+ protected void initNibble(final int chunkX, final int chunkY, final int chunkZ, final boolean extrude, final boolean initRemovedNibbles) { -+ if (chunkY < this.minLightSection || chunkY > this.maxLightSection || this.getChunkInCache(chunkX, chunkZ) == null) { -+ return; -+ } -+ -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ if (nibble == null) { -+ if (!initRemovedNibbles) { -+ throw new IllegalStateException(); -+ } else { -+ this.setNibbleInCache(chunkX, chunkY, chunkZ, new SWMRNibbleArray()); -+ } -+ } else { -+ nibble.setNonNull(); -+ } -+ } -+ -+ @Override -+ protected final void checkBlock(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ) { -+ // blocks can change opacity -+ // blocks can change emitted light -+ // blocks can change direction of propagation -+ -+ final int encodeOffset = this.coordinateOffset; -+ final int emittedMask = this.emittedLightMask; -+ -+ final int currentLevel = this.getLightLevel(worldX, worldY, worldZ); -+ final BlockState blockState = this.getBlockState(worldX, worldY, worldZ); -+ final int emittedLevel = blockState.getLightEmission() & emittedMask; -+ -+ this.setLightLevel(worldX, worldY, worldZ, emittedLevel); -+ // this accounts for change in emitted light that would cause an increase -+ if (emittedLevel != 0) { -+ this.appendToIncreaseQueue( -+ ((worldX + (worldZ << 6) + (worldY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (emittedLevel & 0xFL) << (6 + 6 + 16) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | (blockState.isConditionallyFullOpaque() ? FLAG_HAS_SIDED_TRANSPARENT_BLOCKS : 0) -+ ); -+ } -+ // this also accounts for a change in emitted light that would cause a decrease -+ // this also accounts for the change of direction of propagation (i.e old block was full transparent, new block is full opaque or vice versa) -+ // as it checks all neighbours (even if current level is 0) -+ this.appendToDecreaseQueue( -+ ((worldX + (worldZ << 6) + (worldY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (currentLevel & 0xFL) << (6 + 6 + 16) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ // always keep sided transparent false here, new block might be conditionally transparent which would -+ // prevent us from decreasing sources in the directions where the new block is opaque -+ // if it turns out we were wrong to de-propagate the source, the re-propagate logic WILL always -+ // catch that and fix it. -+ ); -+ // re-propagating neighbours (done by the decrease queue) will also account for opacity changes in this block -+ } -+ -+ protected final BlockPos.MutableBlockPos recalcCenterPos = new BlockPos.MutableBlockPos(); -+ protected final BlockPos.MutableBlockPos recalcNeighbourPos = new BlockPos.MutableBlockPos(); -+ -+ @Override -+ protected int calculateLightValue(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ, -+ final int expect) { -+ final BlockState centerState = this.getBlockState(worldX, worldY, worldZ); -+ int level = centerState.getLightEmission() & 0xF; -+ -+ if (level >= (15 - 1) || level > expect) { -+ return level; -+ } -+ -+ final int sectionOffset = this.chunkSectionIndexOffset; -+ final BlockState conditionallyOpaqueState; -+ int opacity = centerState.getOpacityIfCached(); -+ -+ if (opacity == -1) { -+ this.recalcCenterPos.set(worldX, worldY, worldZ); -+ opacity = centerState.getLightBlock(lightAccess.getLevel(), this.recalcCenterPos); -+ if (centerState.isConditionallyFullOpaque()) { -+ conditionallyOpaqueState = centerState; -+ } else { -+ conditionallyOpaqueState = null; -+ } -+ } else if (opacity >= 15) { -+ return level; -+ } else { -+ conditionallyOpaqueState = null; -+ } -+ opacity = Math.max(1, opacity); -+ -+ for (final AxisDirection direction : AXIS_DIRECTIONS) { -+ final int offX = worldX + direction.x; -+ final int offY = worldY + direction.y; -+ final int offZ = worldZ + direction.z; -+ -+ final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; -+ -+ final int neighbourLevel = this.getLightLevel(sectionIndex, (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8)); -+ -+ if ((neighbourLevel - 1) <= level) { -+ // don't need to test transparency, we know it wont affect the result. -+ continue; -+ } -+ -+ final BlockState neighbourState = this.getBlockState(offX, offY, offZ); -+ if (neighbourState.isConditionallyFullOpaque()) { -+ // here the block can be conditionally opaque (i.e light cannot propagate from it), so we need to test that -+ // we don't read the blockstate because most of the time this is false, so using the faster -+ // known transparency lookup results in a net win -+ this.recalcNeighbourPos.set(offX, offY, offZ); -+ final VoxelShape neighbourFace = neighbourState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcNeighbourPos, direction.opposite.nms); -+ final VoxelShape thisFace = conditionallyOpaqueState == null ? Shapes.empty() : conditionallyOpaqueState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcCenterPos, direction.nms); -+ if (Shapes.faceShapeOccludes(thisFace, neighbourFace)) { -+ // not allowed to propagate -+ continue; -+ } -+ } -+ -+ // passed transparency, -+ -+ final int calculated = neighbourLevel - opacity; -+ level = Math.max(calculated, level); -+ if (level > expect) { -+ return level; -+ } -+ } -+ -+ return level; -+ } -+ -+ @Override -+ protected void propagateBlockChanges(final LightChunkGetter lightAccess, final ChunkAccess atChunk, final Set positions) { -+ for (final BlockPos pos : positions) { -+ this.checkBlock(lightAccess, pos.getX(), pos.getY(), pos.getZ()); -+ } -+ -+ this.performLightDecrease(lightAccess); -+ } -+ -+ protected Iterator getSources(final LightChunkGetter lightAccess, final ChunkAccess chunk) { -+ if (chunk instanceof ImposterProtoChunk || chunk instanceof LevelChunk) { -+ // implementation on Chunk is pretty awful, so write our own here. The big optimisation is -+ // skipping empty sections, and the far more optimised reading of types. -+ List sources = new ArrayList<>(); -+ -+ int offX = chunk.getPos().x << 4; -+ int offZ = chunk.getPos().z << 4; -+ -+ final LevelChunkSection[] sections = chunk.getSections(); -+ for (int sectionY = this.minSection; sectionY <= this.maxSection; ++sectionY) { -+ final LevelChunkSection section = sections[sectionY - this.minSection]; -+ if (section == null || section.isEmpty()) { -+ // no sources in empty sections -+ continue; -+ } -+ final PalettedContainer states = section.states; -+ final int offY = sectionY << 4; -+ -+ for (int index = 0; index < (16 * 16 * 16); ++index) { -+ final BlockState state = states.get(index); -+ if (state.getLightEmission() <= 0) { -+ continue; -+ } -+ -+ // index = x | (z << 4) | (y << 8) -+ sources.add(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15))); -+ } -+ } -+ -+ return sources.iterator(); -+ } else { -+ // world gen and lighting run in parallel, and if lighting keeps up it can be lighting chunks that are -+ // being generated. In the nether, lava will add a lot of sources. This resulted in quite a few CME crashes. -+ // So all we do spinloop until we can collect a list of sources, and even if it is out of date we will pick up -+ // the missing sources from checkBlock. -+ for (;;) { -+ try { -+ return chunk.getLights().collect(Collectors.toList()).iterator(); -+ } catch (final Exception cme) { -+ continue; -+ } -+ } -+ } -+ } -+ -+ @Override -+ public void lightChunk(final LightChunkGetter lightAccess, final ChunkAccess chunk, final boolean needsEdgeChecks) { -+ // setup sources -+ final int emittedMask = this.emittedLightMask; -+ for (final Iterator positions = this.getSources(lightAccess, chunk); positions.hasNext();) { -+ final BlockPos pos = positions.next(); -+ final BlockState blockState = this.getBlockState(pos.getX(), pos.getY(), pos.getZ()); -+ final int emittedLight = blockState.getLightEmission() & emittedMask; -+ -+ if (emittedLight <= this.getLightLevel(pos.getX(), pos.getY(), pos.getZ())) { -+ // some other source is brighter -+ continue; -+ } -+ -+ this.appendToIncreaseQueue( -+ ((pos.getX() + (pos.getZ() << 6) + (pos.getY() << (6 + 6)) + this.coordinateOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (emittedLight & 0xFL) << (6 + 6 + 16) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | (blockState.isConditionallyFullOpaque() ? FLAG_HAS_SIDED_TRANSPARENT_BLOCKS : 0) -+ ); -+ -+ -+ // propagation wont set this for us -+ this.setLightLevel(pos.getX(), pos.getY(), pos.getZ(), emittedLight); -+ } -+ -+ if (needsEdgeChecks) { -+ // not required to propagate here, but this will reduce the hit of the edge checks -+ this.performLightIncrease(lightAccess); -+ -+ // verify neighbour edges -+ this.checkChunkEdges(lightAccess, chunk, this.minLightSection, this.maxLightSection); -+ } else { -+ this.propagateNeighbourLevels(lightAccess, chunk, this.minLightSection, this.maxLightSection); -+ -+ this.performLightIncrease(lightAccess); -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/starlight/light/SWMRNibbleArray.java b/src/main/java/ca/spottedleaf/starlight/light/SWMRNibbleArray.java -new file mode 100644 -index 0000000000000000000000000000000000000000..174dc7ffa66258da0b867fba5c54880e81daa6ce ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/starlight/light/SWMRNibbleArray.java -@@ -0,0 +1,439 @@ -+package ca.spottedleaf.starlight.light; -+ -+import net.minecraft.world.level.chunk.DataLayer; -+ -+import java.util.ArrayDeque; -+import java.util.Arrays; -+ -+// SWMR -> Single Writer Multi Reader Nibble Array -+public final class SWMRNibbleArray { -+ -+ /* -+ * Null nibble - nibble does not exist, and should not be written to. Just like vanilla - null -+ * nibbles are always 0 - and they are never written to directly. Only initialised/uninitialised -+ * nibbles can be written to. -+ * -+ * Uninitialised nibble - They are all 0, but the backing array isn't initialised. -+ * -+ * Initialised nibble - Has light data. -+ */ -+ -+ protected static final int INIT_STATE_NULL = 0; // null -+ protected static final int INIT_STATE_UNINIT = 1; // uninitialised -+ protected static final int INIT_STATE_INIT = 2; // initialised -+ protected static final int INIT_STATE_HIDDEN = 3; // initialised, but conversion to Vanilla data should be treated as if NULL -+ -+ public static final int ARRAY_SIZE = 16 * 16 * 16 / (8/4); // blocks / bytes per block -+ // this allows us to maintain only 1 byte array when we're not updating -+ static final ThreadLocal> WORKING_BYTES_POOL = ThreadLocal.withInitial(ArrayDeque::new); -+ -+ private static byte[] allocateBytes() { -+ final byte[] inPool = WORKING_BYTES_POOL.get().pollFirst(); -+ if (inPool != null) { -+ return inPool; -+ } -+ -+ return new byte[ARRAY_SIZE]; -+ } -+ -+ private static void freeBytes(final byte[] bytes) { -+ WORKING_BYTES_POOL.get().addFirst(bytes); -+ } -+ -+ public static SWMRNibbleArray fromVanilla(final DataLayer nibble) { -+ if (nibble == null) { -+ return new SWMRNibbleArray(null, true); -+ } else if (nibble.isEmpty()) { -+ return new SWMRNibbleArray(); -+ } else { -+ return new SWMRNibbleArray(nibble.getData().clone()); // make sure we don't write to the parameter later -+ } -+ } -+ -+ protected int stateUpdating; -+ protected volatile int stateVisible; -+ -+ protected byte[] storageUpdating; -+ protected boolean updatingDirty; // only returns whether storageUpdating is dirty -+ protected byte[] storageVisible; -+ -+ public SWMRNibbleArray() { -+ this(null, false); // lazy init -+ } -+ -+ public SWMRNibbleArray(final byte[] bytes) { -+ this(bytes, false); -+ } -+ -+ public SWMRNibbleArray(final byte[] bytes, final boolean isNullNibble) { -+ if (bytes != null && bytes.length != ARRAY_SIZE) { -+ throw new IllegalArgumentException("Data of wrong length: " + bytes.length); -+ } -+ this.stateVisible = this.stateUpdating = bytes == null ? (isNullNibble ? INIT_STATE_NULL : INIT_STATE_UNINIT) : INIT_STATE_INIT; -+ this.storageUpdating = this.storageVisible = bytes; -+ } -+ -+ public SWMRNibbleArray(final byte[] bytes, final int state) { -+ if (bytes != null && bytes.length != ARRAY_SIZE) { -+ throw new IllegalArgumentException("Data of wrong length: " + bytes.length); -+ } -+ if (bytes == null && (state == INIT_STATE_INIT || state == INIT_STATE_HIDDEN)) { -+ throw new IllegalArgumentException("Data cannot be null and have state be initialised"); -+ } -+ this.stateUpdating = this.stateVisible = state; -+ this.storageUpdating = this.storageVisible = bytes; -+ } -+ -+ @Override -+ public String toString() { -+ StringBuilder stringBuilder = new StringBuilder(); -+ stringBuilder.append("State: "); -+ switch (this.stateVisible) { -+ case INIT_STATE_NULL: -+ stringBuilder.append("null"); -+ break; -+ case INIT_STATE_UNINIT: -+ stringBuilder.append("uninitialised"); -+ break; -+ case INIT_STATE_INIT: -+ stringBuilder.append("initialised"); -+ break; -+ case INIT_STATE_HIDDEN: -+ stringBuilder.append("hidden"); -+ break; -+ default: -+ stringBuilder.append("unknown"); -+ break; -+ } -+ stringBuilder.append("\nData:\n"); -+ -+ final byte[] data = this.storageVisible; -+ if (data != null) { -+ for (int i = 0; i < 4096; ++i) { -+ // Copied from NibbleArray#toString -+ final int level = ((data[i >>> 1] >>> ((i & 1) << 2)) & 0xF); -+ -+ stringBuilder.append(Integer.toHexString(level)); -+ if ((i & 15) == 15) { -+ stringBuilder.append("\n"); -+ } -+ -+ if ((i & 255) == 255) { -+ stringBuilder.append("\n"); -+ } -+ } -+ } else { -+ stringBuilder.append("null"); -+ } -+ -+ return stringBuilder.toString(); -+ } -+ -+ public SaveState getSaveState() { -+ synchronized (this) { -+ final int state = this.stateVisible; -+ final byte[] data = this.storageVisible; -+ if (state == INIT_STATE_NULL) { -+ return null; -+ } -+ if (state == INIT_STATE_UNINIT) { -+ return new SaveState(null, state); -+ } -+ final boolean zero = isAllZero(data); -+ if (zero) { -+ return state == INIT_STATE_INIT ? new SaveState(null, INIT_STATE_UNINIT) : null; -+ } else { -+ return new SaveState(data.clone(), state); -+ } -+ } -+ } -+ -+ protected static boolean isAllZero(final byte[] data) { -+ for (int i = 0; i < (ARRAY_SIZE >>> 4); ++i) { -+ byte whole = data[i << 4]; -+ -+ for (int k = 1; k < (1 << 4); ++k) { -+ whole |= data[(i << 4) | k]; -+ } -+ -+ if (whole != 0) { -+ return false; -+ } -+ } -+ -+ return true; -+ } -+ -+ // operation type: updating on src, updating on other -+ public void extrudeLower(final SWMRNibbleArray other) { -+ if (other.stateUpdating == INIT_STATE_NULL) { -+ throw new IllegalArgumentException(); -+ } -+ -+ if (other.storageUpdating == null) { -+ this.setUninitialised(); -+ return; -+ } -+ -+ final byte[] src = other.storageUpdating; -+ final byte[] into; -+ -+ if (this.storageUpdating != null) { -+ into = this.storageUpdating; -+ } else { -+ this.storageUpdating = into = allocateBytes(); -+ this.stateUpdating = INIT_STATE_INIT; -+ } -+ this.updatingDirty = true; -+ -+ final int start = 0; -+ final int end = (15 | (15 << 4)) >>> 1; -+ -+ /* x | (z << 4) | (y << 8) */ -+ for (int y = 0; y <= 15; ++y) { -+ System.arraycopy(src, start, into, y << (8 - 1), end - start + 1); -+ } -+ } -+ -+ // operation type: updating -+ public void setFull() { -+ if (this.stateUpdating != INIT_STATE_HIDDEN) { -+ this.stateUpdating = INIT_STATE_INIT; -+ } -+ Arrays.fill(this.storageUpdating == null || !this.updatingDirty ? this.storageUpdating = allocateBytes() : this.storageUpdating, (byte)-1); -+ this.updatingDirty = true; -+ } -+ -+ // operation type: updating -+ public void setZero() { -+ if (this.stateUpdating != INIT_STATE_HIDDEN) { -+ this.stateUpdating = INIT_STATE_INIT; -+ } -+ Arrays.fill(this.storageUpdating == null || !this.updatingDirty ? this.storageUpdating = allocateBytes() : this.storageUpdating, (byte)0); -+ this.updatingDirty = true; -+ } -+ -+ // operation type: updating -+ public void setNonNull() { -+ if (this.stateUpdating == INIT_STATE_HIDDEN) { -+ this.stateUpdating = INIT_STATE_INIT; -+ return; -+ } -+ if (this.stateUpdating != INIT_STATE_NULL) { -+ return; -+ } -+ this.stateUpdating = INIT_STATE_UNINIT; -+ } -+ -+ // operation type: updating -+ public void setNull() { -+ this.stateUpdating = INIT_STATE_NULL; -+ if (this.updatingDirty && this.storageUpdating != null) { -+ freeBytes(this.storageUpdating); -+ } -+ this.storageUpdating = null; -+ this.updatingDirty = false; -+ } -+ -+ // operation type: updating -+ public void setUninitialised() { -+ this.stateUpdating = INIT_STATE_UNINIT; -+ if (this.storageUpdating != null && this.updatingDirty) { -+ freeBytes(this.storageUpdating); -+ } -+ this.storageUpdating = null; -+ this.updatingDirty = false; -+ } -+ -+ // operation type: updating -+ public void setHidden() { -+ if (this.stateUpdating == INIT_STATE_HIDDEN) { -+ return; -+ } -+ if (this.stateUpdating != INIT_STATE_INIT) { -+ this.setNull(); -+ } else { -+ this.stateUpdating = INIT_STATE_HIDDEN; -+ } -+ } -+ -+ // operation type: updating -+ public boolean isDirty() { -+ return this.stateUpdating != this.stateVisible || this.updatingDirty; -+ } -+ -+ // operation type: updating -+ public boolean isNullNibbleUpdating() { -+ return this.stateUpdating == INIT_STATE_NULL; -+ } -+ -+ // operation type: visible -+ public boolean isNullNibbleVisible() { -+ return this.stateVisible == INIT_STATE_NULL; -+ } -+ -+ // opeartion type: updating -+ public boolean isUninitialisedUpdating() { -+ return this.stateUpdating == INIT_STATE_UNINIT; -+ } -+ -+ // operation type: visible -+ public boolean isUninitialisedVisible() { -+ return this.stateVisible == INIT_STATE_UNINIT; -+ } -+ -+ // operation type: updating -+ public boolean isInitialisedUpdating() { -+ return this.stateUpdating == INIT_STATE_INIT; -+ } -+ -+ // operation type: visible -+ public boolean isInitialisedVisible() { -+ return this.stateVisible == INIT_STATE_INIT; -+ } -+ -+ // operation type: updating -+ public boolean isHiddenUpdating() { -+ return this.stateUpdating == INIT_STATE_HIDDEN; -+ } -+ -+ // operation type: updating -+ public boolean isHiddenVisible() { -+ return this.stateVisible == INIT_STATE_HIDDEN; -+ } -+ -+ // operation type: updating -+ protected void swapUpdatingAndMarkDirty() { -+ if (this.updatingDirty) { -+ return; -+ } -+ -+ if (this.storageUpdating == null) { -+ this.storageUpdating = allocateBytes(); -+ Arrays.fill(this.storageUpdating, (byte)0); -+ } else { -+ System.arraycopy(this.storageUpdating, 0, this.storageUpdating = allocateBytes(), 0, ARRAY_SIZE); -+ } -+ -+ if (this.stateUpdating != INIT_STATE_HIDDEN) { -+ this.stateUpdating = INIT_STATE_INIT; -+ } -+ this.updatingDirty = true; -+ } -+ -+ // operation type: updating -+ public boolean updateVisible() { -+ if (!this.isDirty()) { -+ return false; -+ } -+ -+ synchronized (this) { -+ if (this.stateUpdating == INIT_STATE_NULL || this.stateUpdating == INIT_STATE_UNINIT) { -+ this.storageVisible = null; -+ } else { -+ if (this.storageVisible == null) { -+ this.storageVisible = this.storageUpdating.clone(); -+ } else { -+ if (this.storageUpdating != this.storageVisible) { -+ System.arraycopy(this.storageUpdating, 0, this.storageVisible, 0, ARRAY_SIZE); -+ } -+ } -+ -+ if (this.storageUpdating != this.storageVisible) { -+ freeBytes(this.storageUpdating); -+ } -+ this.storageUpdating = this.storageVisible; -+ } -+ this.updatingDirty = false; -+ this.stateVisible = this.stateUpdating; -+ } -+ -+ return true; -+ } -+ -+ // operation type: visible -+ public DataLayer toVanillaNibble() { -+ synchronized (this) { -+ switch (this.stateVisible) { -+ case INIT_STATE_HIDDEN: -+ case INIT_STATE_NULL: -+ return null; -+ case INIT_STATE_UNINIT: -+ return new DataLayer(); -+ case INIT_STATE_INIT: -+ return new DataLayer(this.storageVisible.clone()); -+ default: -+ throw new IllegalStateException(); -+ } -+ } -+ } -+ -+ /* x | (z << 4) | (y << 8) */ -+ -+ // operation type: updating -+ public int getUpdating(final int x, final int y, final int z) { -+ return this.getUpdating((x & 15) | ((z & 15) << 4) | ((y & 15) << 8)); -+ } -+ -+ // operation type: updating -+ public int getUpdating(final int index) { -+ // indices range from 0 -> 4096 -+ final byte[] bytes = this.storageUpdating; -+ if (bytes == null) { -+ return 0; -+ } -+ final byte value = bytes[index >>> 1]; -+ -+ // if we are an even index, we want lower 4 bits -+ // if we are an odd index, we want upper 4 bits -+ return ((value >>> ((index & 1) << 2)) & 0xF); -+ } -+ -+ // operation type: visible -+ public int getVisible(final int x, final int y, final int z) { -+ return this.getVisible((x & 15) | ((z & 15) << 4) | ((y & 15) << 8)); -+ } -+ -+ // operation type: visible -+ public int getVisible(final int index) { -+ synchronized (this) { -+ // indices range from 0 -> 4096 -+ final byte[] visibleBytes = this.storageVisible; -+ if (visibleBytes == null) { -+ return 0; -+ } -+ final byte value = visibleBytes[index >>> 1]; -+ -+ // if we are an even index, we want lower 4 bits -+ // if we are an odd index, we want upper 4 bits -+ return ((value >>> ((index & 1) << 2)) & 0xF); -+ } -+ } -+ -+ // operation type: updating -+ public void set(final int x, final int y, final int z, final int value) { -+ this.set((x & 15) | ((z & 15) << 4) | ((y & 15) << 8), value); -+ } -+ -+ // operation type: updating -+ public void set(final int index, final int value) { -+ if (!this.updatingDirty) { -+ this.swapUpdatingAndMarkDirty(); -+ } -+ final int shift = (index & 1) << 2; -+ final int i = index >>> 1; -+ -+ this.storageUpdating[i] = (byte)((this.storageUpdating[i] & (0xF0 >>> shift)) | (value << shift)); -+ } -+ -+ public static final class SaveState { -+ -+ public final byte[] data; -+ public final int state; -+ -+ public SaveState(final byte[] data, final int state) { -+ this.data = data; -+ this.state = state; -+ } -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/starlight/light/SkyStarLightEngine.java b/src/main/java/ca/spottedleaf/starlight/light/SkyStarLightEngine.java -new file mode 100644 -index 0000000000000000000000000000000000000000..143810dc53782a9a6d870089d7bd5c3006a565b3 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/starlight/light/SkyStarLightEngine.java -@@ -0,0 +1,715 @@ -+package ca.spottedleaf.starlight.light; -+ -+import com.tuinity.tuinity.util.WorldUtil; -+import it.unimi.dsi.fastutil.shorts.ShortCollection; -+import it.unimi.dsi.fastutil.shorts.ShortIterator; -+import net.minecraft.core.BlockPos; -+import net.minecraft.world.level.BlockGetter; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; -+import net.minecraft.world.level.chunk.LevelChunkSection; -+import net.minecraft.world.level.chunk.LightChunkGetter; -+import net.minecraft.world.phys.shapes.Shapes; -+import net.minecraft.world.phys.shapes.VoxelShape; -+import java.util.Arrays; -+import java.util.Set; -+ -+public final class SkyStarLightEngine extends StarLightEngine { -+ -+ /* -+ Specification for managing the initialisation and de-initialisation of skylight nibble arrays: -+ -+ Skylight nibble initialisation requires that non-empty chunk sections have 1 radius nibbles non-null. -+ -+ This presents some problems, as vanilla is only guaranteed to have 0 radius neighbours loaded when editing blocks. -+ However starlight fixes this so that it has 1 radius loaded. Still, we don't actually have guarantees -+ that we have the necessary chunks loaded to de-initialise neighbour sections (but we do have enough to de-initialise -+ our own) - we need a radius of 2 to de-initialise neighbour nibbles. -+ How do we solve this? -+ -+ Each chunk will store the last known "emptiness" of sections for each of their 1 radius neighbour chunk sections. -+ If the chunk does not have full data, then its nibbles are NOT de-initialised. This is because obviously the -+ chunk did not go through the light stage yet - or its neighbours are not lit. In either case, once the last -+ known "emptiness" of neighbouring sections is filled with data, the chunk will run a full check of the data -+ to see if any of its nibbles need to be de-initialised. -+ -+ The emptiness map allows us to de-initialise neighbour nibbles if the neighbour has it filled with data, -+ and if it doesn't have data then we know it will correctly de-initialise once it fills up. -+ -+ Unlike vanilla, we store whether nibbles are uninitialised on disk - so we don't need any dumb hacking -+ around those. -+ */ -+ -+ protected final int[] heightMapBlockChange = new int[16 * 16]; -+ { -+ Arrays.fill(this.heightMapBlockChange, Integer.MIN_VALUE); // clear heightmap -+ } -+ -+ protected final boolean[] nullPropagationCheckCache; -+ -+ public SkyStarLightEngine(final Level world) { -+ super(true, world); -+ this.nullPropagationCheckCache = new boolean[WorldUtil.getTotalLightSections(world)]; -+ } -+ -+ @Override -+ protected void initNibble(final int chunkX, final int chunkY, final int chunkZ, final boolean extrude, final boolean initRemovedNibbles) { -+ if (chunkY < this.minLightSection || chunkY > this.maxLightSection || this.getChunkInCache(chunkX, chunkZ) == null) { -+ return; -+ } -+ SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ if (nibble == null) { -+ if (!initRemovedNibbles) { -+ throw new IllegalStateException(); -+ } else { -+ this.setNibbleInCache(chunkX, chunkY, chunkZ, nibble = new SWMRNibbleArray(null, true)); -+ } -+ } -+ this.initNibble(nibble, chunkX, chunkY, chunkZ, extrude); -+ } -+ -+ @Override -+ protected void setNibbleNull(final int chunkX, final int chunkY, final int chunkZ) { -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ if (nibble != null) { -+ nibble.setNull(); -+ } -+ } -+ -+ protected final void initNibble(final SWMRNibbleArray currNibble, final int chunkX, final int chunkY, final int chunkZ, final boolean extrude) { -+ if (!currNibble.isNullNibbleUpdating()) { -+ // already initialised -+ return; -+ } -+ -+ final boolean[] emptinessMap = this.getEmptinessMap(chunkX, chunkZ); -+ -+ // are we above this chunk's lowest empty section? -+ int lowestY = this.minLightSection - 1; -+ for (int currY = this.maxSection; currY >= this.minSection; --currY) { -+ if (emptinessMap == null) { -+ // cannot delay nibble init for lit chunks, as we need to init to propagate into them. -+ final LevelChunkSection current = this.getChunkSection(chunkX, currY, chunkZ); -+ if (current == null || current == EMPTY_CHUNK_SECTION) { -+ continue; -+ } -+ } else { -+ if (emptinessMap[currY - this.minSection]) { -+ continue; -+ } -+ } -+ -+ // should always be full lit here -+ lowestY = currY; -+ break; -+ } -+ -+ if (chunkY > lowestY) { -+ // we need to set this one to full -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ nibble.setNonNull(); -+ nibble.setFull(); -+ return; -+ } -+ -+ if (extrude) { -+ // this nibble is going to depend solely on the skylight data above it -+ // find first non-null data above (there does exist one, as we just found it above) -+ for (int currY = chunkY + 1; currY <= this.maxLightSection; ++currY) { -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, currY, chunkZ); -+ if (nibble != null && !nibble.isNullNibbleUpdating()) { -+ currNibble.setNonNull(); -+ currNibble.extrudeLower(nibble); -+ break; -+ } -+ } -+ } else { -+ currNibble.setNonNull(); -+ } -+ } -+ -+ protected final void rewriteNibbleCacheForSkylight(final ChunkAccess chunk) { -+ for (int index = 0, max = this.nibbleCache.length; index < max; ++index) { -+ final SWMRNibbleArray nibble = this.nibbleCache[index]; -+ if (nibble != null && nibble.isNullNibbleUpdating()) { -+ // stop propagation in these areas -+ this.nibbleCache[index] = null; -+ nibble.updateVisible(); -+ } -+ } -+ } -+ -+ // rets whether neighbours were init'd -+ -+ protected final boolean checkNullSection(final int chunkX, final int chunkY, final int chunkZ, -+ final boolean extrudeInitialised) { -+ // null chunk sections may have nibble neighbours in the horizontal 1 radius that are -+ // non-null. Propagation to these neighbours is necessary. -+ // What makes this easy is we know none of these neighbours are non-empty (otherwise -+ // this nibble would be initialised). So, we don't have to initialise -+ // the neighbours in the full 1 radius, because there's no worry that any "paths" -+ // to the neighbours on this horizontal plane are blocked. -+ if (chunkY < this.minLightSection || chunkY > this.maxLightSection || this.nullPropagationCheckCache[chunkY - this.minLightSection]) { -+ return false; -+ } -+ this.nullPropagationCheckCache[chunkY - this.minLightSection] = true; -+ -+ // check horizontal neighbours -+ boolean needInitNeighbours = false; -+ neighbour_search: -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(dx + chunkX, chunkY, dz + chunkZ); -+ if (nibble != null && !nibble.isNullNibbleUpdating()) { -+ needInitNeighbours = true; -+ break neighbour_search; -+ } -+ } -+ } -+ -+ if (needInitNeighbours) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ this.initNibble(dx + chunkX, chunkY, dz + chunkZ, (dx | dz) == 0 ? extrudeInitialised : true, true); -+ } -+ } -+ } -+ -+ return needInitNeighbours; -+ } -+ -+ protected final int getLightLevelExtruded(final int worldX, final int worldY, final int worldZ) { -+ final int chunkX = worldX >> 4; -+ int chunkY = worldY >> 4; -+ final int chunkZ = worldZ >> 4; -+ -+ SWMRNibbleArray nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ if (nibble != null) { -+ return nibble.getUpdating(worldX, worldY, worldZ); -+ } -+ -+ for (;;) { -+ if (++chunkY > this.maxLightSection) { -+ return 15; -+ } -+ -+ nibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ -+ if (nibble != null) { -+ return nibble.getUpdating(worldX, 0, worldZ); -+ } -+ } -+ } -+ -+ @Override -+ protected boolean[] getEmptinessMap(final ChunkAccess chunk) { -+ return chunk.getSkyEmptinessMap(); -+ } -+ -+ @Override -+ protected void setEmptinessMap(final ChunkAccess chunk, final boolean[] to) { -+ chunk.setSkyEmptinessMap(to); -+ } -+ -+ @Override -+ protected SWMRNibbleArray[] getNibblesOnChunk(final ChunkAccess chunk) { -+ return chunk.getSkyNibbles(); -+ } -+ -+ @Override -+ protected void setNibbles(final ChunkAccess chunk, final SWMRNibbleArray[] to) { -+ chunk.setSkyNibbles(to); -+ } -+ -+ @Override -+ protected boolean canUseChunk(final ChunkAccess chunk) { -+ // can only use chunks for sky stuff if their sections have been init'd -+ return chunk.getStatus().isOrAfter(ChunkStatus.LIGHT) && (this.isClientSide || chunk.isLightCorrect()); -+ } -+ -+ @Override -+ protected void checkChunkEdges(final LightChunkGetter lightAccess, final ChunkAccess chunk, final int fromSection, -+ final int toSection) { -+ Arrays.fill(this.nullPropagationCheckCache, false); -+ this.rewriteNibbleCacheForSkylight(chunk); -+ final int chunkX = chunk.getPos().x; -+ final int chunkZ = chunk.getPos().z; -+ for (int y = toSection; y >= fromSection; --y) { -+ this.checkNullSection(chunkX, y, chunkZ, true); -+ } -+ -+ super.checkChunkEdges(lightAccess, chunk, fromSection, toSection); -+ } -+ -+ @Override -+ protected void checkChunkEdges(final LightChunkGetter lightAccess, final ChunkAccess chunk, final ShortCollection sections) { -+ Arrays.fill(this.nullPropagationCheckCache, false); -+ this.rewriteNibbleCacheForSkylight(chunk); -+ final int chunkX = chunk.getPos().x; -+ final int chunkZ = chunk.getPos().z; -+ for (final ShortIterator iterator = sections.iterator(); iterator.hasNext();) { -+ final int y = (int)iterator.nextShort(); -+ this.checkNullSection(chunkX, y, chunkZ, true); -+ } -+ -+ super.checkChunkEdges(lightAccess, chunk, sections); -+ } -+ -+ @Override -+ protected void checkBlock(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ) { -+ // blocks can change opacity -+ // blocks can change direction of propagation -+ -+ // same logic applies from BlockStarLightEngine#checkBlock -+ -+ final int encodeOffset = this.coordinateOffset; -+ -+ final int currentLevel = this.getLightLevel(worldX, worldY, worldZ); -+ -+ if (currentLevel == 15) { -+ // must re-propagate clobbered source -+ this.appendToIncreaseQueue( -+ ((worldX + (worldZ << 6) + (worldY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (currentLevel & 0xFL) << (6 + 6 + 16) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | FLAG_HAS_SIDED_TRANSPARENT_BLOCKS // don't know if the block is conditionally transparent -+ ); -+ } else { -+ this.setLightLevel(worldX, worldY, worldZ, 0); -+ } -+ -+ this.appendToDecreaseQueue( -+ ((worldX + (worldZ << 6) + (worldY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (currentLevel & 0xFL) << (6 + 6 + 16) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ ); -+ } -+ -+ protected final BlockPos.MutableBlockPos recalcCenterPos = new BlockPos.MutableBlockPos(); -+ protected final BlockPos.MutableBlockPos recalcNeighbourPos = new BlockPos.MutableBlockPos(); -+ -+ @Override -+ protected int calculateLightValue(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ, -+ final int expect) { -+ if (expect == 15) { -+ return expect; -+ } -+ -+ final int sectionOffset = this.chunkSectionIndexOffset; -+ final BlockState centerState = this.getBlockState(worldX, worldY, worldZ); -+ int opacity = centerState.getOpacityIfCached(); -+ -+ BlockState conditionallyOpaqueState; -+ if (opacity < 0) { -+ this.recalcCenterPos.set(worldX, worldY, worldZ); -+ opacity = Math.max(1, centerState.getLightBlock(lightAccess.getLevel(), this.recalcCenterPos)); -+ if (centerState.isConditionallyFullOpaque()) { -+ conditionallyOpaqueState = centerState; -+ } else { -+ conditionallyOpaqueState = null; -+ } -+ } else { -+ conditionallyOpaqueState = null; -+ opacity = Math.max(1, opacity); -+ } -+ -+ int level = 0; -+ -+ for (final AxisDirection direction : AXIS_DIRECTIONS) { -+ final int offX = worldX + direction.x; -+ final int offY = worldY + direction.y; -+ final int offZ = worldZ + direction.z; -+ -+ final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; -+ -+ final int neighbourLevel = this.getLightLevel(sectionIndex, (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8)); -+ -+ if ((neighbourLevel - 1) <= level) { -+ // don't need to test transparency, we know it wont affect the result. -+ continue; -+ } -+ -+ final BlockState neighbourState = this.getBlockState(offX, offY, offZ); -+ -+ if (neighbourState.isConditionallyFullOpaque()) { -+ // here the block can be conditionally opaque (i.e light cannot propagate from it), so we need to test that -+ // we don't read the blockstate because most of the time this is false, so using the faster -+ // known transparency lookup results in a net win -+ this.recalcNeighbourPos.set(offX, offY, offZ); -+ final VoxelShape neighbourFace = neighbourState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcNeighbourPos, direction.opposite.nms); -+ final VoxelShape thisFace = conditionallyOpaqueState == null ? Shapes.empty() : conditionallyOpaqueState.getFaceOcclusionShape(lightAccess.getLevel(), this.recalcCenterPos, direction.nms); -+ if (Shapes.faceShapeOccludes(thisFace, neighbourFace)) { -+ // not allowed to propagate -+ continue; -+ } -+ } -+ -+ final int calculated = neighbourLevel - opacity; -+ level = Math.max(calculated, level); -+ if (level > expect) { -+ return level; -+ } -+ } -+ -+ return level; -+ } -+ -+ @Override -+ protected void propagateBlockChanges(final LightChunkGetter lightAccess, final ChunkAccess atChunk, final Set positions) { -+ this.rewriteNibbleCacheForSkylight(atChunk); -+ Arrays.fill(this.nullPropagationCheckCache, false); -+ -+ final BlockGetter world = lightAccess.getLevel(); -+ final int chunkX = atChunk.getPos().x; -+ final int chunkZ = atChunk.getPos().z; -+ final int heightMapOffset = chunkX * -16 + (chunkZ * (-16 * 16)); -+ -+ // setup heightmap for changes -+ for (final BlockPos pos : positions) { -+ final int index = pos.getX() + (pos.getZ() << 4) + heightMapOffset; -+ final int curr = this.heightMapBlockChange[index]; -+ if (pos.getY() > curr) { -+ this.heightMapBlockChange[index] = pos.getY(); -+ } -+ } -+ -+ // note: light sets are delayed while processing skylight source changes due to how -+ // nibbles are initialised, as we want to avoid clobbering nibble values so what when -+ // below nibbles are initialised they aren't reading from partially modified nibbles -+ -+ // now we can recalculate the sources for the changed columns -+ for (int index = 0; index < (16 * 16); ++index) { -+ final int maxY = this.heightMapBlockChange[index]; -+ if (maxY == Integer.MIN_VALUE) { -+ // not changed -+ continue; -+ } -+ this.heightMapBlockChange[index] = Integer.MIN_VALUE; // restore default for next caller -+ -+ final int columnX = (index & 15) | (chunkX << 4); -+ final int columnZ = (index >>> 4) | (chunkZ << 4); -+ -+ // try and propagate from the above y -+ // delay light set until after processing all sources to setup -+ final int maxPropagationY = this.tryPropagateSkylight(world, columnX, maxY, columnZ, true, true); -+ -+ // maxPropagationY is now the highest block that could not be propagated to -+ -+ // remove all sources below that are 15 -+ final long propagateDirection = AxisDirection.POSITIVE_Y.everythingButThisDirection; -+ final int encodeOffset = this.coordinateOffset; -+ -+ if (this.getLightLevelExtruded(columnX, maxPropagationY, columnZ) == 15) { -+ // ensure section is checked -+ this.checkNullSection(columnX >> 4, maxPropagationY >> 4, columnZ >> 4, true); -+ -+ for (int currY = maxPropagationY; currY >= (this.minLightSection << 4); --currY) { -+ if ((currY & 15) == 15) { -+ // ensure section is checked -+ this.checkNullSection(columnX >> 4, (currY >> 4), columnZ >> 4, true); -+ } -+ -+ // ensure section below is always checked -+ final SWMRNibbleArray nibble = this.getNibbleFromCache(columnX >> 4, currY >> 4, columnZ >> 4); -+ if (nibble == null) { -+ // advance currY to the the top of the section below -+ currY = (currY) & (~15); -+ // note: this value ^ is actually 1 above the top, but the loop decrements by 1 so we actually -+ // end up there -+ continue; -+ } -+ -+ if (nibble.getUpdating(columnX, currY, columnZ) != 15) { -+ break; -+ } -+ -+ // delay light set until after processing all sources to setup -+ this.appendToDecreaseQueue( -+ ((columnX + (columnZ << 6) + (currY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (15L << (6 + 6 + 16)) -+ | (propagateDirection << (6 + 6 + 16 + 4)) -+ // do not set transparent blocks for the same reason we don't in the checkBlock method -+ ); -+ } -+ } -+ } -+ -+ // delayed light sets are processed here, and must be processed before checkBlock as checkBlock reads -+ // immediate light value -+ this.processDelayedIncreases(); -+ this.processDelayedDecreases(); -+ -+ for (final BlockPos pos : positions) { -+ this.checkBlock(lightAccess, pos.getX(), pos.getY(), pos.getZ()); -+ } -+ -+ this.performLightDecrease(lightAccess); -+ } -+ -+ protected final int[] heightMapGen = new int[32 * 32]; -+ -+ @Override -+ protected void lightChunk(final LightChunkGetter lightAccess, final ChunkAccess chunk, final boolean needsEdgeChecks) { -+ this.rewriteNibbleCacheForSkylight(chunk); -+ Arrays.fill(this.nullPropagationCheckCache, false); -+ -+ final BlockGetter world = lightAccess.getLevel(); -+ final ChunkPos chunkPos = chunk.getPos(); -+ final int chunkX = chunkPos.x; -+ final int chunkZ = chunkPos.z; -+ -+ final LevelChunkSection[] sections = chunk.getSections(); -+ -+ int highestNonEmptySection = this.maxSection; -+ while (highestNonEmptySection == (this.minSection - 1) || -+ sections[highestNonEmptySection - this.minSection] == null || sections[highestNonEmptySection - this.minSection].isEmpty()) { -+ this.checkNullSection(chunkX, highestNonEmptySection, chunkZ, false); -+ // try propagate FULL to neighbours -+ -+ // check neighbours to see if we need to propagate into them -+ for (final AxisDirection direction : ONLY_HORIZONTAL_DIRECTIONS) { -+ final int neighbourX = chunkX + direction.x; -+ final int neighbourZ = chunkZ + direction.z; -+ final SWMRNibbleArray neighbourNibble = this.getNibbleFromCache(neighbourX, highestNonEmptySection, neighbourZ); -+ if (neighbourNibble == null) { -+ // unloaded neighbour -+ // most of the time we fall here -+ continue; -+ } -+ -+ // it looks like we need to propagate into the neighbour -+ -+ final int incX; -+ final int incZ; -+ final int startX; -+ final int startZ; -+ -+ if (direction.x != 0) { -+ // x direction -+ incX = 0; -+ incZ = 1; -+ -+ if (direction.x < 0) { -+ // negative -+ startX = chunkX << 4; -+ } else { -+ startX = chunkX << 4 | 15; -+ } -+ startZ = chunkZ << 4; -+ } else { -+ // z direction -+ incX = 1; -+ incZ = 0; -+ -+ if (direction.z < 0) { -+ // negative -+ startZ = chunkZ << 4; -+ } else { -+ startZ = chunkZ << 4 | 15; -+ } -+ startX = chunkX << 4; -+ } -+ -+ final int encodeOffset = this.coordinateOffset; -+ final long propagateDirection = 1L << direction.ordinal(); // we only want to check in this direction -+ -+ for (int currY = highestNonEmptySection << 4, maxY = currY | 15; currY <= maxY; ++currY) { -+ for (int i = 0, currX = startX, currZ = startZ; i < 16; ++i, currX += incX, currZ += incZ) { -+ this.appendToIncreaseQueue( -+ ((currX + (currZ << 6) + (currY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (15L << (6 + 6 + 16)) // we know we're at full lit here -+ | (propagateDirection << (6 + 6 + 16 + 4)) -+ // no transparent flag, we know for a fact there are no blocks here that could be directionally transparent (as the section is EMPTY) -+ ); -+ } -+ } -+ } -+ -+ if (highestNonEmptySection-- == (this.minSection - 1)) { -+ break; -+ } -+ } -+ -+ if (highestNonEmptySection >= this.minSection) { -+ // fill out our other sources -+ final int minX = chunkPos.x << 4; -+ final int maxX = chunkPos.x << 4 | 15; -+ final int minZ = chunkPos.z << 4; -+ final int maxZ = chunkPos.z << 4 | 15; -+ final int startY = highestNonEmptySection << 4 | 15; -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ this.tryPropagateSkylight(world, currX, startY + 1, currZ, false, false); -+ } -+ } -+ } // else: apparently the chunk is empty -+ -+ if (needsEdgeChecks) { -+ // not required to propagate here, but this will reduce the hit of the edge checks -+ this.performLightIncrease(lightAccess); -+ -+ for (int y = highestNonEmptySection; y >= this.minLightSection; --y) { -+ this.checkNullSection(chunkX, y, chunkZ, false); -+ } -+ // no need to rewrite the nibble cache again -+ super.checkChunkEdges(lightAccess, chunk, this.minLightSection, highestNonEmptySection); -+ } else { -+ for (int y = highestNonEmptySection; y >= this.minLightSection; --y) { -+ this.checkNullSection(chunkX, y, chunkZ, false); -+ } -+ this.propagateNeighbourLevels(lightAccess, chunk, this.minLightSection, highestNonEmptySection); -+ -+ this.performLightIncrease(lightAccess); -+ } -+ } -+ -+ protected final void processDelayedIncreases() { -+ // copied from performLightIncrease -+ final long[] queue = this.increaseQueue; -+ final int decodeOffsetX = -this.encodeOffsetX; -+ final int decodeOffsetY = -this.encodeOffsetY; -+ final int decodeOffsetZ = -this.encodeOffsetZ; -+ -+ for (int i = 0, len = this.increaseQueueInitialLength; i < len; ++i) { -+ final long queueValue = queue[i]; -+ -+ final int posX = ((int)queueValue & 63) + decodeOffsetX; -+ final int posZ = (((int)queueValue >>> 6) & 63) + decodeOffsetZ; -+ final int posY = (((int)queueValue >>> 12) & ((1 << 16) - 1)) + decodeOffsetY; -+ final int propagatedLightLevel = (int)((queueValue >>> (6 + 6 + 16)) & 0xF); -+ -+ this.setLightLevel(posX, posY, posZ, propagatedLightLevel); -+ } -+ } -+ -+ protected final void processDelayedDecreases() { -+ // copied from performLightDecrease -+ final long[] queue = this.decreaseQueue; -+ final int decodeOffsetX = -this.encodeOffsetX; -+ final int decodeOffsetY = -this.encodeOffsetY; -+ final int decodeOffsetZ = -this.encodeOffsetZ; -+ -+ for (int i = 0, len = this.decreaseQueueInitialLength; i < len; ++i) { -+ final long queueValue = queue[i]; -+ -+ final int posX = ((int)queueValue & 63) + decodeOffsetX; -+ final int posZ = (((int)queueValue >>> 6) & 63) + decodeOffsetZ; -+ final int posY = (((int)queueValue >>> 12) & ((1 << 16) - 1)) + decodeOffsetY; -+ -+ this.setLightLevel(posX, posY, posZ, 0); -+ } -+ } -+ -+ // delaying the light set is useful for block changes since they need to worry about initialising nibblearrays -+ // while also queueing light at the same time (initialising nibblearrays might depend on nibbles above, so -+ // clobbering the light values will result in broken propagation) -+ protected final int tryPropagateSkylight(final BlockGetter world, final int worldX, int startY, final int worldZ, -+ final boolean extrudeInitialised, final boolean delayLightSet) { -+ final BlockPos.MutableBlockPos mutablePos = this.mutablePos3; -+ final int encodeOffset = this.coordinateOffset; -+ final long propagateDirection = AxisDirection.POSITIVE_Y.everythingButThisDirection; // just don't check upwards. -+ -+ if (this.getLightLevelExtruded(worldX, startY + 1, worldZ) != 15) { -+ return startY; -+ } -+ -+ // ensure this section is always checked -+ this.checkNullSection(worldX >> 4, startY >> 4, worldZ >> 4, extrudeInitialised); -+ -+ BlockState above = this.getBlockState(worldX, startY + 1, worldZ); -+ if (above == null) { -+ above = AIR_BLOCK_STATE; -+ } -+ -+ for (;startY >= (this.minLightSection << 4); --startY) { -+ if ((startY & 15) == 15) { -+ // ensure this section is always checked -+ this.checkNullSection(worldX >> 4, startY >> 4, worldZ >> 4, extrudeInitialised); -+ } -+ BlockState current = this.getBlockState(worldX, startY, worldZ); -+ if (current == null) { -+ current = AIR_BLOCK_STATE; -+ } -+ -+ final VoxelShape fromShape; -+ if (above.isConditionallyFullOpaque()) { -+ this.mutablePos2.set(worldX, startY + 1, worldZ); -+ fromShape = above.getFaceOcclusionShape(world, this.mutablePos2, AxisDirection.NEGATIVE_Y.nms); -+ if (Shapes.faceShapeOccludes(Shapes.empty(), fromShape)) { -+ // above wont let us propagate -+ break; -+ } -+ } else { -+ fromShape = Shapes.empty(); -+ } -+ -+ final int opacityIfCached = current.getOpacityIfCached(); -+ // does light propagate from the top down? -+ if (opacityIfCached != -1) { -+ if (opacityIfCached != 0) { -+ // we cannot propagate 15 through this -+ break; -+ } -+ // most of the time it falls here. -+ // add to propagate -+ // light set delayed until we determine if this nibble section is null -+ this.appendToIncreaseQueue( -+ ((worldX + (worldZ << 6) + (startY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (15L << (6 + 6 + 16)) // we know we're at full lit here -+ | (propagateDirection << (6 + 6 + 16 + 4)) -+ ); -+ } else { -+ mutablePos.set(worldX, startY, worldZ); -+ long flags = 0L; -+ if (current.isConditionallyFullOpaque()) { -+ final VoxelShape cullingFace = current.getFaceOcclusionShape(world, mutablePos, AxisDirection.POSITIVE_Y.nms); -+ -+ if (Shapes.faceShapeOccludes(fromShape, cullingFace)) { -+ // can't propagate here, we're done on this column. -+ break; -+ } -+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS; -+ } -+ -+ final int opacity = current.getLightBlock(world, mutablePos); -+ if (opacity > 0) { -+ // let the queued value (if any) handle it from here. -+ break; -+ } -+ -+ // light set delayed until we determine if this nibble section is null -+ this.appendToIncreaseQueue( -+ ((worldX + (worldZ << 6) + (startY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | (15L << (6 + 6 + 16)) // we know we're at full lit here -+ | (propagateDirection << (6 + 6 + 16 + 4)) -+ | flags -+ ); -+ } -+ -+ above = current; -+ -+ if (this.getNibbleFromCache(worldX >> 4, startY >> 4, worldZ >> 4) == null) { -+ // we skip empty sections here, as this is just an easy way of making sure the above block -+ // can propagate through air. -+ -+ // nothing can propagate in null sections, remove the queue entry for it -+ --this.increaseQueueInitialLength; -+ -+ // advance currY to the the top of the section below -+ startY = (startY) & (~15); -+ // note: this value ^ is actually 1 above the top, but the loop decrements by 1 so we actually -+ // end up there -+ -+ // make sure this is marked as AIR -+ above = AIR_BLOCK_STATE; -+ } else if (!delayLightSet) { -+ this.setLightLevel(worldX, startY, worldZ, 15); -+ } -+ } -+ -+ return startY; -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/starlight/light/StarLightEngine.java b/src/main/java/ca/spottedleaf/starlight/light/StarLightEngine.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ef930395407533a2c669499c02989bbbe0ac6101 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/starlight/light/StarLightEngine.java -@@ -0,0 +1,1573 @@ -+package ca.spottedleaf.starlight.light; -+ -+import com.tuinity.tuinity.util.CoordinateUtils; -+import com.tuinity.tuinity.util.IntegerUtil; -+import com.tuinity.tuinity.util.WorldUtil; -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import it.unimi.dsi.fastutil.shorts.ShortCollection; -+import it.unimi.dsi.fastutil.shorts.ShortIterator; -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.Direction; -+import net.minecraft.core.SectionPos; -+import net.minecraft.world.level.*; -+import net.minecraft.world.level.block.Blocks; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.LevelChunkSection; -+import net.minecraft.world.level.chunk.LightChunkGetter; -+import net.minecraft.world.phys.shapes.Shapes; -+import net.minecraft.world.phys.shapes.VoxelShape; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.List; -+import java.util.Set; -+import java.util.function.Consumer; -+import java.util.function.IntConsumer; -+ -+public abstract class StarLightEngine { -+ -+ protected static final BlockState AIR_BLOCK_STATE = Blocks.AIR.defaultBlockState(); -+ -+ protected static final LevelChunkSection EMPTY_CHUNK_SECTION = new LevelChunkSection(0); -+ -+ protected static final AxisDirection[] DIRECTIONS = AxisDirection.values(); -+ protected static final AxisDirection[] AXIS_DIRECTIONS = DIRECTIONS; -+ protected static final AxisDirection[] ONLY_HORIZONTAL_DIRECTIONS = new AxisDirection[] { -+ AxisDirection.POSITIVE_X, AxisDirection.NEGATIVE_X, -+ AxisDirection.POSITIVE_Z, AxisDirection.NEGATIVE_Z -+ }; -+ -+ protected static enum AxisDirection { -+ -+ // Declaration order is important and relied upon. Do not change without modifying propagation code. -+ POSITIVE_X(1, 0, 0), NEGATIVE_X(-1, 0, 0), -+ POSITIVE_Z(0, 0, 1), NEGATIVE_Z(0, 0, -1), -+ POSITIVE_Y(0, 1, 0), NEGATIVE_Y(0, -1, 0); -+ -+ static { -+ POSITIVE_X.opposite = NEGATIVE_X; NEGATIVE_X.opposite = POSITIVE_X; -+ POSITIVE_Z.opposite = NEGATIVE_Z; NEGATIVE_Z.opposite = POSITIVE_Z; -+ POSITIVE_Y.opposite = NEGATIVE_Y; NEGATIVE_Y.opposite = POSITIVE_Y; -+ } -+ -+ protected AxisDirection opposite; -+ -+ public final int x; -+ public final int y; -+ public final int z; -+ public final Direction nms; -+ public final long everythingButThisDirection; -+ public final long everythingButTheOppositeDirection; -+ -+ AxisDirection(final int x, final int y, final int z) { -+ this.x = x; -+ this.y = y; -+ this.z = z; -+ this.nms = Direction.fromNormal(x, y, z); -+ this.everythingButThisDirection = (long)(ALL_DIRECTIONS_BITSET ^ (1 << this.ordinal())); -+ // positive is always even, negative is always odd. Flip the 1 bit to get the negative direction. -+ this.everythingButTheOppositeDirection = (long)(ALL_DIRECTIONS_BITSET ^ (1 << (this.ordinal() ^ 1))); -+ } -+ -+ public AxisDirection getOpposite() { -+ return this.opposite; -+ } -+ } -+ -+ // I'd like to thank https://www.seedofandromeda.com/blogs/29-fast-flood-fill-lighting-in-a-blocky-voxel-game-pt-1 -+ // for explaining how light propagates via breadth-first search -+ -+ // While the above is a good start to understanding the general idea of what the general principles are, it's not -+ // exactly how the vanilla light engine should behave for minecraft. -+ -+ // similar to the above, except the chunk section indices vary from [-1, 1], or [0, 2] -+ // for the y chunk section it's from [minLightSection, maxLightSection] or [0, maxLightSection - minLightSection] -+ // index = x + (z * 5) + (y * 25) -+ // null index indicates the chunk section doesn't exist (empty or out of bounds) -+ protected final LevelChunkSection[] sectionCache; -+ -+ // the exact same as above, except for storing fast access to SWMRNibbleArray -+ // for the y chunk section it's from [minLightSection, maxLightSection] or [0, maxLightSection - minLightSection] -+ // index = x + (z * 5) + (y * 25) -+ protected final SWMRNibbleArray[] nibbleCache; -+ -+ // the exact same as above, except for storing fast access to nibbles to call change callbacks for -+ // for the y chunk section it's from [minLightSection, maxLightSection] or [0, maxLightSection - minLightSection] -+ // index = x + (z * 5) + (y * 25) -+ protected final boolean[] notifyUpdateCache; -+ -+ // always initialsed during start of lighting. -+ // index = x + (z * 5) -+ protected final ChunkAccess[] chunkCache = new ChunkAccess[5 * 5]; -+ -+ // index = x + (z * 5) -+ protected final boolean[][] emptinessMapCache = new boolean[5 * 5][]; -+ -+ protected final BlockPos.MutableBlockPos mutablePos1 = new BlockPos.MutableBlockPos(); -+ protected final BlockPos.MutableBlockPos mutablePos2 = new BlockPos.MutableBlockPos(); -+ protected final BlockPos.MutableBlockPos mutablePos3 = new BlockPos.MutableBlockPos(); -+ -+ protected int encodeOffsetX; -+ protected int encodeOffsetY; -+ protected int encodeOffsetZ; -+ -+ protected int coordinateOffset; -+ -+ protected int chunkOffsetX; -+ protected int chunkOffsetY; -+ protected int chunkOffsetZ; -+ -+ protected int chunkIndexOffset; -+ protected int chunkSectionIndexOffset; -+ -+ protected final boolean skylightPropagator; -+ protected final int emittedLightMask; -+ protected final boolean isClientSide; -+ -+ protected final Level world; -+ protected final int minLightSection; -+ protected final int maxLightSection; -+ protected final int minSection; -+ protected final int maxSection; -+ -+ protected StarLightEngine(final boolean skylightPropagator, final Level world) { -+ this.skylightPropagator = skylightPropagator; -+ this.emittedLightMask = skylightPropagator ? 0 : 0xF; -+ this.isClientSide = world.isClientSide; -+ this.world = world; -+ this.minLightSection = WorldUtil.getMinLightSection(world); -+ this.maxLightSection = WorldUtil.getMaxLightSection(world); -+ this.minSection = WorldUtil.getMinSection(world); -+ this.maxSection = WorldUtil.getMaxSection(world); -+ -+ this.sectionCache = new LevelChunkSection[5 * 5 * ((this.maxLightSection - this.minLightSection + 1) + 2)]; // add two extra sections for buffer -+ this.nibbleCache = new SWMRNibbleArray[5 * 5 * ((this.maxLightSection - this.minLightSection + 1) + 2)]; // add two extra sections for buffer -+ this.notifyUpdateCache = new boolean[5 * 5 * ((this.maxLightSection - this.minLightSection + 1) + 2)]; // add two extra sections for buffer -+ } -+ -+ protected final void setupEncodeOffset(final int centerX, final int centerY, final int centerZ) { -+ // 31 = center + encodeOffset -+ this.encodeOffsetX = 31 - centerX; -+ this.encodeOffsetY = (-(this.minLightSection - 1) << 4); // we want 0 to be the smallest encoded value -+ this.encodeOffsetZ = 31 - centerZ; -+ -+ // coordinateIndex = x | (z << 6) | (y << 12) -+ this.coordinateOffset = this.encodeOffsetX + (this.encodeOffsetZ << 6) + (this.encodeOffsetY << 12); -+ -+ // 2 = (centerX >> 4) + chunkOffset -+ this.chunkOffsetX = 2 - (centerX >> 4); -+ this.chunkOffsetY = -(this.minLightSection - 1); // lowest should be 0 -+ this.chunkOffsetZ = 2 - (centerZ >> 4); -+ -+ // chunk index = x + (5 * z) -+ this.chunkIndexOffset = this.chunkOffsetX + (5 * this.chunkOffsetZ); -+ -+ // chunk section index = x + (5 * z) + ((5*5) * y) -+ this.chunkSectionIndexOffset = this.chunkIndexOffset + ((5 * 5) * this.chunkOffsetY); -+ } -+ -+ protected final void setupCaches(final LightChunkGetter chunkProvider, final int centerX, final int centerY, final int centerZ, -+ final boolean relaxed, final boolean tryToLoadChunksFor2Radius) { -+ final int centerChunkX = centerX >> 4; -+ final int centerChunkY = centerY >> 4; -+ final int centerChunkZ = centerZ >> 4; -+ -+ this.setupEncodeOffset(centerChunkX * 16 + 7, centerChunkY * 16 + 7, centerChunkZ * 16 + 7); -+ -+ final int radius = tryToLoadChunksFor2Radius ? 2 : 1; -+ -+ for (int dz = -radius; dz <= radius; ++dz) { -+ for (int dx = -radius; dx <= radius; ++dx) { -+ final int cx = centerChunkX + dx; -+ final int cz = centerChunkZ + dz; -+ final boolean isTwoRadius = Math.max(IntegerUtil.branchlessAbs(dx), IntegerUtil.branchlessAbs(dz)) == 2; -+ final ChunkAccess chunk = (ChunkAccess)chunkProvider.getChunkForLighting(cx, cz); -+ -+ if (chunk == null) { -+ if (relaxed | isTwoRadius) { -+ continue; -+ } -+ throw new IllegalArgumentException("Trying to propagate light update before 1 radius neighbours ready"); -+ } -+ -+ if (!this.canUseChunk(chunk)) { -+ continue; -+ } -+ -+ this.setChunkInCache(cx, cz, chunk); -+ this.setEmptinessMapCache(cx, cz, this.getEmptinessMap(chunk)); -+ if (!isTwoRadius) { -+ this.setBlocksForChunkInCache(cx, cz, chunk.getSections()); -+ this.setNibblesForChunkInCache(cx, cz, this.getNibblesOnChunk(chunk)); -+ } -+ } -+ } -+ } -+ -+ protected final ChunkAccess getChunkInCache(final int chunkX, final int chunkZ) { -+ return this.chunkCache[chunkX + 5*chunkZ + this.chunkIndexOffset]; -+ } -+ -+ protected final void setChunkInCache(final int chunkX, final int chunkZ, final ChunkAccess chunk) { -+ this.chunkCache[chunkX + 5*chunkZ + this.chunkIndexOffset] = chunk; -+ } -+ -+ protected final LevelChunkSection getChunkSection(final int chunkX, final int chunkY, final int chunkZ) { -+ return this.sectionCache[chunkX + 5*chunkZ + (5 * 5) * chunkY + this.chunkSectionIndexOffset]; -+ } -+ -+ protected final void setChunkSectionInCache(final int chunkX, final int chunkY, final int chunkZ, final LevelChunkSection section) { -+ this.sectionCache[chunkX + 5*chunkZ + 5*5*chunkY + this.chunkSectionIndexOffset] = section; -+ } -+ -+ protected final void setBlocksForChunkInCache(final int chunkX, final int chunkZ, final LevelChunkSection[] sections) { -+ for (int cy = this.minLightSection; cy <= this.maxLightSection; ++cy) { -+ this.setChunkSectionInCache(chunkX, cy, chunkZ, -+ sections == null ? null : (cy >= this.minSection && cy <= this.maxSection ? (sections[cy - this.minSection] == null || sections[cy - this.minSection].isEmpty() ? EMPTY_CHUNK_SECTION : sections[cy - this.minSection]) : EMPTY_CHUNK_SECTION)); -+ } -+ } -+ -+ protected final SWMRNibbleArray getNibbleFromCache(final int chunkX, final int chunkY, final int chunkZ) { -+ return this.nibbleCache[chunkX + 5*chunkZ + (5 * 5) * chunkY + this.chunkSectionIndexOffset]; -+ } -+ -+ protected final SWMRNibbleArray[] getNibblesForChunkFromCache(final int chunkX, final int chunkZ) { -+ final SWMRNibbleArray[] ret = new SWMRNibbleArray[this.maxLightSection - this.minLightSection + 1]; -+ -+ for (int cy = this.minLightSection; cy <= this.maxLightSection; ++cy) { -+ ret[cy - this.minLightSection] = this.nibbleCache[chunkX + 5*chunkZ + (cy * (5 * 5)) + this.chunkSectionIndexOffset]; -+ } -+ -+ return ret; -+ } -+ -+ protected final void setNibbleInCache(final int chunkX, final int chunkY, final int chunkZ, final SWMRNibbleArray nibble) { -+ this.nibbleCache[chunkX + 5*chunkZ + (5 * 5) * chunkY + this.chunkSectionIndexOffset] = nibble; -+ } -+ -+ protected final void setNibblesForChunkInCache(final int chunkX, final int chunkZ, final SWMRNibbleArray[] nibbles) { -+ for (int cy = this.minLightSection; cy <= this.maxLightSection; ++cy) { -+ this.setNibbleInCache(chunkX, cy, chunkZ, nibbles == null ? null : nibbles[cy - this.minLightSection]); -+ } -+ } -+ -+ protected final void updateVisible(final LightChunkGetter lightAccess) { -+ for (int index = 0, max = this.nibbleCache.length; index < max; ++index) { -+ final SWMRNibbleArray nibble = this.nibbleCache[index]; -+ if (!this.notifyUpdateCache[index] && (nibble == null || !nibble.isDirty())) { -+ continue; -+ } -+ -+ final int chunkX = (index % 5) - this.chunkOffsetX; -+ final int chunkZ = ((index / 5) % 5) - this.chunkOffsetZ; -+ final int chunkY = ((index / (5*5)) % (16 + 2 + 2)) - this.chunkOffsetY; -+ if ((nibble != null && nibble.updateVisible()) || this.notifyUpdateCache[index]) { -+ lightAccess.onLightUpdate(this.skylightPropagator ? LightLayer.SKY : LightLayer.BLOCK, SectionPos.of(chunkX, chunkY, chunkZ)); -+ } -+ } -+ } -+ -+ protected final void destroyCaches() { -+ Arrays.fill(this.sectionCache, null); -+ Arrays.fill(this.nibbleCache, null); -+ Arrays.fill(this.chunkCache, null); -+ Arrays.fill(this.emptinessMapCache, null); -+ if (this.isClientSide) { -+ Arrays.fill(this.notifyUpdateCache, false); -+ } -+ } -+ -+ protected final BlockState getBlockState(final int worldX, final int worldY, final int worldZ) { -+ final LevelChunkSection section = this.sectionCache[(worldX >> 4) + 5 * (worldZ >> 4) + (5 * 5) * (worldY >> 4) + this.chunkSectionIndexOffset]; -+ -+ if (section != null) { -+ return section == EMPTY_CHUNK_SECTION ? AIR_BLOCK_STATE : section.getBlockState(worldX & 15, worldY & 15, worldZ & 15); -+ } -+ -+ return null; -+ } -+ -+ protected final BlockState getBlockState(final int sectionIndex, final int localIndex) { -+ final LevelChunkSection section = this.sectionCache[sectionIndex]; -+ -+ if (section != null) { -+ return section == EMPTY_CHUNK_SECTION ? AIR_BLOCK_STATE : section.states.get(localIndex); -+ } -+ -+ return null; -+ } -+ -+ protected final int getLightLevel(final int worldX, final int worldY, final int worldZ) { -+ final SWMRNibbleArray nibble = this.nibbleCache[(worldX >> 4) + 5 * (worldZ >> 4) + (5 * 5) * (worldY >> 4) + this.chunkSectionIndexOffset]; -+ -+ return nibble == null ? 0 : nibble.getUpdating((worldX & 15) | ((worldZ & 15) << 4) | ((worldY & 15) << 8)); -+ } -+ -+ protected final int getLightLevel(final int sectionIndex, final int localIndex) { -+ final SWMRNibbleArray nibble = this.nibbleCache[sectionIndex]; -+ -+ return nibble == null ? 0 : nibble.getUpdating(localIndex); -+ } -+ -+ protected final void setLightLevel(final int worldX, final int worldY, final int worldZ, final int level) { -+ final int sectionIndex = (worldX >> 4) + 5 * (worldZ >> 4) + (5 * 5) * (worldY >> 4) + this.chunkSectionIndexOffset; -+ final SWMRNibbleArray nibble = this.nibbleCache[sectionIndex]; -+ -+ if (nibble != null) { -+ nibble.set((worldX & 15) | ((worldZ & 15) << 4) | ((worldY & 15) << 8), level); -+ if (this.isClientSide) { -+ int cx1 = (worldX - 1) >> 4; -+ int cx2 = (worldX + 1) >> 4; -+ int cy1 = (worldY - 1) >> 4; -+ int cy2 = (worldY + 1) >> 4; -+ int cz1 = (worldZ - 1) >> 4; -+ int cz2 = (worldZ + 1) >> 4; -+ for (int x = cx1; x <= cx2; ++x) { -+ for (int y = cy1; y <= cy2; ++y) { -+ for (int z = cz1; z <= cz2; ++z) { -+ this.notifyUpdateCache[x + 5 * z + (5 * 5) * y + this.chunkSectionIndexOffset] = true; -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ protected final void postLightUpdate(final int worldX, final int worldY, final int worldZ) { -+ if (this.isClientSide) { -+ int cx1 = (worldX - 1) >> 4; -+ int cx2 = (worldX + 1) >> 4; -+ int cy1 = (worldY - 1) >> 4; -+ int cy2 = (worldY + 1) >> 4; -+ int cz1 = (worldZ - 1) >> 4; -+ int cz2 = (worldZ + 1) >> 4; -+ for (int x = cx1; x <= cx2; ++x) { -+ for (int y = cy1; y <= cy2; ++y) { -+ for (int z = cz1; z <= cz2; ++z) { -+ this.notifyUpdateCache[x + (5 * z) + (5 * 5 * y) + this.chunkSectionIndexOffset] = true; -+ } -+ } -+ } -+ } -+ } -+ -+ protected final void setLightLevel(final int sectionIndex, final int localIndex, final int worldX, final int worldY, final int worldZ, final int level) { -+ final SWMRNibbleArray nibble = this.nibbleCache[sectionIndex]; -+ -+ if (nibble != null) { -+ nibble.set(localIndex, level); -+ if (this.isClientSide) { -+ int cx1 = (worldX - 1) >> 4; -+ int cx2 = (worldX + 1) >> 4; -+ int cy1 = (worldY - 1) >> 4; -+ int cy2 = (worldY + 1) >> 4; -+ int cz1 = (worldZ - 1) >> 4; -+ int cz2 = (worldZ + 1) >> 4; -+ for (int x = cx1; x <= cx2; ++x) { -+ for (int y = cy1; y <= cy2; ++y) { -+ for (int z = cz1; z <= cz2; ++z) { -+ this.notifyUpdateCache[x + (5 * z) + (5 * 5 * y) + this.chunkSectionIndexOffset] = true; -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ protected final boolean[] getEmptinessMap(final int chunkX, final int chunkZ) { -+ return this.emptinessMapCache[chunkX + 5*chunkZ + this.chunkIndexOffset]; -+ } -+ -+ protected final void setEmptinessMapCache(final int chunkX, final int chunkZ, final boolean[] emptinessMap) { -+ this.emptinessMapCache[chunkX + 5*chunkZ + this.chunkIndexOffset] = emptinessMap; -+ } -+ -+ protected final long getKnownTransparency(final int worldX, final int worldY, final int worldZ) { -+ throw new UnsupportedOperationException(); // :( -+ } -+ -+ // warn: localIndex = y | (x << 4) | (z << 8) -+ protected final long getKnownTransparency(final int sectionIndex, final int localIndex) { -+ throw new UnsupportedOperationException(); // :( -+ } -+ -+ public static SWMRNibbleArray[] getFilledEmptyLight(final LevelHeightAccessor world) { -+ return getFilledEmptyLight(WorldUtil.getTotalLightSections(world)); -+ } -+ -+ private static SWMRNibbleArray[] getFilledEmptyLight(final int totalLightSections) { -+ final SWMRNibbleArray[] ret = new SWMRNibbleArray[totalLightSections]; -+ -+ for (int i = 0, len = ret.length; i < len; ++i) { -+ ret[i] = new SWMRNibbleArray(null, true); -+ } -+ -+ return ret; -+ } -+ -+ protected abstract boolean[] getEmptinessMap(final ChunkAccess chunk); -+ -+ protected abstract void setEmptinessMap(final ChunkAccess chunk, final boolean[] to); -+ -+ protected abstract SWMRNibbleArray[] getNibblesOnChunk(final ChunkAccess chunk); -+ -+ protected abstract void setNibbles(final ChunkAccess chunk, final SWMRNibbleArray[] to); -+ -+ protected abstract boolean canUseChunk(final ChunkAccess chunk); -+ -+ public final void blocksChangedInChunk(final LightChunkGetter lightAccess, final int chunkX, final int chunkZ, -+ final Set positions, final Boolean[] changedSections) { -+ this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true, true); -+ try { -+ final ChunkAccess chunk = this.getChunkInCache(chunkX, chunkZ); -+ if (chunk == null) { -+ return; -+ } -+ if (changedSections != null) { -+ final boolean[] ret = this.handleEmptySectionChanges(lightAccess, chunk, changedSections, false); -+ if (ret != null) { -+ this.setEmptinessMap(chunk, ret); -+ } -+ } -+ if (!positions.isEmpty()) { -+ this.propagateBlockChanges(lightAccess, chunk, positions); -+ } -+ this.updateVisible(lightAccess); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ // subclasses should not initialise caches, as this will always be done by the super call -+ // subclasses should not invoke updateVisible, as this will always be done by the super call -+ protected abstract void propagateBlockChanges(final LightChunkGetter lightAccess, final ChunkAccess atChunk, final Set positions); -+ -+ protected abstract void checkBlock(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ); -+ -+ // if ret > expect, then the real value is at least ret (early returns if ret > expect, rather than calculating actual) -+ // if ret == expect, then expect is the correct light value for pos -+ // if ret < expect, then ret is the real light value -+ protected abstract int calculateLightValue(final LightChunkGetter lightAccess, final int worldX, final int worldY, final int worldZ, -+ final int expect); -+ -+ protected final int[] chunkCheckDelayedUpdatesCenter = new int[16 * 16]; -+ protected final int[] chunkCheckDelayedUpdatesNeighbour = new int[16 * 16]; -+ -+ protected void checkChunkEdge(final LightChunkGetter lightAccess, final ChunkAccess chunk, -+ final int chunkX, final int chunkY, final int chunkZ) { -+ final SWMRNibbleArray currNibble = this.getNibbleFromCache(chunkX, chunkY, chunkZ); -+ if (currNibble == null) { -+ return; -+ } -+ -+ for (final AxisDirection direction : ONLY_HORIZONTAL_DIRECTIONS) { -+ final int neighbourOffX = direction.x; -+ final int neighbourOffZ = direction.z; -+ -+ final SWMRNibbleArray neighbourNibble = this.getNibbleFromCache(chunkX + neighbourOffX, -+ chunkY, chunkZ + neighbourOffZ); -+ -+ if (neighbourNibble == null) { -+ continue; -+ } -+ -+ if (!currNibble.isInitialisedUpdating() && !neighbourNibble.isInitialisedUpdating()) { -+ // both are zero, nothing to check. -+ continue; -+ } -+ -+ // this chunk -+ final int incX; -+ final int incZ; -+ final int startX; -+ final int startZ; -+ -+ if (neighbourOffX != 0) { -+ // x direction -+ incX = 0; -+ incZ = 1; -+ -+ if (direction.x < 0) { -+ // negative -+ startX = chunkX << 4; -+ } else { -+ startX = chunkX << 4 | 15; -+ } -+ startZ = chunkZ << 4; -+ } else { -+ // z direction -+ incX = 1; -+ incZ = 0; -+ -+ if (neighbourOffZ < 0) { -+ // negative -+ startZ = chunkZ << 4; -+ } else { -+ startZ = chunkZ << 4 | 15; -+ } -+ startX = chunkX << 4; -+ } -+ -+ int centerDelayedChecks = 0; -+ int neighbourDelayedChecks = 0; -+ for (int currY = chunkY << 4, maxY = currY | 15; currY <= maxY; ++currY) { -+ for (int i = 0, currX = startX, currZ = startZ; i < 16; ++i, currX += incX, currZ += incZ) { -+ final int neighbourX = currX + neighbourOffX; -+ final int neighbourZ = currZ + neighbourOffZ; -+ -+ final int currentIndex = (currX & 15) | -+ ((currZ & 15)) << 4 | -+ ((currY & 15) << 8); -+ final int currentLevel = currNibble.getUpdating(currentIndex); -+ -+ final int neighbourIndex = -+ (neighbourX & 15) | -+ ((neighbourZ & 15)) << 4 | -+ ((currY & 15) << 8); -+ final int neighbourLevel = neighbourNibble.getUpdating(neighbourIndex); -+ -+ // the checks are delayed because the checkBlock method clobbers light values - which then -+ // affect later calculate light value operations. While they don't affect it in a behaviourly significant -+ // way, they do have a negative performance impact due to simply queueing more values -+ -+ if (this.calculateLightValue(lightAccess, currX, currY, currZ, currentLevel) != currentLevel) { -+ this.chunkCheckDelayedUpdatesCenter[centerDelayedChecks++] = currentIndex; -+ } -+ -+ if (this.calculateLightValue(lightAccess, neighbourX, currY, neighbourZ, neighbourLevel) != neighbourLevel) { -+ this.chunkCheckDelayedUpdatesNeighbour[neighbourDelayedChecks++] = neighbourIndex; -+ } -+ } -+ } -+ -+ final int currentChunkOffX = chunkX << 4; -+ final int currentChunkOffZ = chunkZ << 4; -+ final int neighbourChunkOffX = (chunkX + direction.x) << 4; -+ final int neighbourChunkOffZ = (chunkZ + direction.z) << 4; -+ final int chunkOffY = chunkY << 4; -+ for (int i = 0, len = Math.max(centerDelayedChecks, neighbourDelayedChecks); i < len; ++i) { -+ // try to queue neighbouring data together -+ // index = x | (z << 4) | (y << 8) -+ if (i < centerDelayedChecks) { -+ final int value = this.chunkCheckDelayedUpdatesCenter[i]; -+ this.checkBlock(lightAccess, currentChunkOffX | (value & 15), -+ chunkOffY | (value >>> 8), -+ currentChunkOffZ | ((value >>> 4) & 0xF)); -+ } -+ if (i < neighbourDelayedChecks) { -+ final int value = this.chunkCheckDelayedUpdatesNeighbour[i]; -+ this.checkBlock(lightAccess, neighbourChunkOffX | (value & 15), -+ chunkOffY | (value >>> 8), -+ neighbourChunkOffZ | ((value >>> 4) & 0xF)); -+ } -+ } -+ } -+ } -+ -+ protected void checkChunkEdges(final LightChunkGetter lightAccess, final ChunkAccess chunk, final ShortCollection sections) { -+ final ChunkPos chunkPos = chunk.getPos(); -+ final int chunkX = chunkPos.x; -+ final int chunkZ = chunkPos.z; -+ -+ for (final ShortIterator iterator = sections.iterator(); iterator.hasNext();) { -+ this.checkChunkEdge(lightAccess, chunk, chunkX, iterator.nextShort(), chunkZ); -+ } -+ -+ this.performLightDecrease(lightAccess); -+ } -+ -+ // subclasses should not initialise caches, as this will always be done by the super call -+ // subclasses should not invoke updateVisible, as this will always be done by the super call -+ // verifies that light levels on this chunks edges are consistent with this chunk's neighbours -+ // edges. if they are not, they are decreased (effectively performing the logic in checkBlock). -+ // This does not resolve skylight source problems. -+ protected void checkChunkEdges(final LightChunkGetter lightAccess, final ChunkAccess chunk, final int fromSection, final int toSection) { -+ final ChunkPos chunkPos = chunk.getPos(); -+ final int chunkX = chunkPos.x; -+ final int chunkZ = chunkPos.z; -+ -+ for (int currSectionY = toSection; currSectionY >= fromSection; --currSectionY) { -+ this.checkChunkEdge(lightAccess, chunk, chunkX, currSectionY, chunkZ); -+ } -+ -+ this.performLightDecrease(lightAccess); -+ } -+ -+ // pulls light from neighbours, and adds them into the increase queue. does not actually propagate. -+ protected final void propagateNeighbourLevels(final LightChunkGetter lightAccess, final ChunkAccess chunk, final int fromSection, final int toSection) { -+ final ChunkPos chunkPos = chunk.getPos(); -+ final int chunkX = chunkPos.x; -+ final int chunkZ = chunkPos.z; -+ -+ for (int currSectionY = toSection; currSectionY >= fromSection; --currSectionY) { -+ final SWMRNibbleArray currNibble = this.getNibbleFromCache(chunkX, currSectionY, chunkZ); -+ if (currNibble == null) { -+ continue; -+ } -+ for (final AxisDirection direction : ONLY_HORIZONTAL_DIRECTIONS) { -+ final int neighbourOffX = direction.x; -+ final int neighbourOffZ = direction.z; -+ -+ final SWMRNibbleArray neighbourNibble = this.getNibbleFromCache(chunkX + neighbourOffX, -+ currSectionY, chunkZ + neighbourOffZ); -+ -+ if (neighbourNibble == null || !neighbourNibble.isInitialisedUpdating()) { -+ // can't pull from 0 -+ continue; -+ } -+ -+ // neighbour chunk -+ final int incX; -+ final int incZ; -+ final int startX; -+ final int startZ; -+ -+ if (neighbourOffX != 0) { -+ // x direction -+ incX = 0; -+ incZ = 1; -+ -+ if (direction.x < 0) { -+ // negative -+ startX = (chunkX << 4) - 1; -+ } else { -+ startX = (chunkX << 4) + 16; -+ } -+ startZ = chunkZ << 4; -+ } else { -+ // z direction -+ incX = 1; -+ incZ = 0; -+ -+ if (neighbourOffZ < 0) { -+ // negative -+ startZ = (chunkZ << 4) - 1; -+ } else { -+ startZ = (chunkZ << 4) + 16; -+ } -+ startX = chunkX << 4; -+ } -+ -+ final long propagateDirection = 1L << direction.getOpposite().ordinal(); // we only want to check in this direction towards this chunk -+ final int encodeOffset = this.coordinateOffset; -+ -+ for (int currY = currSectionY << 4, maxY = currY | 15; currY <= maxY; ++currY) { -+ for (int i = 0, currX = startX, currZ = startZ; i < 16; ++i, currX += incX, currZ += incZ) { -+ final int level = neighbourNibble.getUpdating( -+ (currX & 15) -+ | ((currZ & 15) << 4) -+ | ((currY & 15) << 8) -+ ); -+ -+ if (level <= 1) { -+ // nothing to propagate -+ continue; -+ } -+ -+ this.appendToIncreaseQueue( -+ ((currX + (currZ << 6) + (currY << (6 + 6)) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((level & 0xFL) << (6 + 6 + 16)) -+ | (propagateDirection << (6 + 6 + 16 + 4)) -+ | FLAG_HAS_SIDED_TRANSPARENT_BLOCKS // don't know if the current block is transparent, must check. -+ ); -+ } -+ } -+ } -+ } -+ } -+ -+ public static Boolean[] getEmptySectionsForChunk(final ChunkAccess chunk) { -+ final LevelChunkSection[] sections = chunk.getSections(); -+ final Boolean[] ret = new Boolean[sections.length]; -+ -+ for (int i = 0; i < sections.length; ++i) { -+ if (sections[i] == null || sections[i].isEmpty()) { -+ ret[i] = Boolean.TRUE; -+ } else { -+ ret[i] = Boolean.FALSE; -+ } -+ } -+ -+ return ret; -+ } -+ -+ public final void forceHandleEmptySectionChanges(final LightChunkGetter lightAccess, final ChunkAccess chunk, final Boolean[] emptinessChanges) { -+ final int chunkX = chunk.getPos().x; -+ final int chunkZ = chunk.getPos().z; -+ this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true, true); -+ try { -+ // force current chunk into cache -+ this.setChunkInCache(chunkX, chunkZ, chunk); -+ this.setBlocksForChunkInCache(chunkX, chunkZ, chunk.getSections()); -+ this.setNibblesForChunkInCache(chunkX, chunkZ, this.getNibblesOnChunk(chunk)); -+ this.setEmptinessMapCache(chunkX, chunkZ, this.getEmptinessMap(chunk)); -+ -+ final boolean[] ret = this.handleEmptySectionChanges(lightAccess, chunk, emptinessChanges, false); -+ if (ret != null) { -+ this.setEmptinessMap(chunk, ret); -+ } -+ this.updateVisible(lightAccess); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ public final void handleEmptySectionChanges(final LightChunkGetter lightAccess, final int chunkX, final int chunkZ, -+ final Boolean[] emptinessChanges) { -+ this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true, true); -+ try { -+ final ChunkAccess chunk = this.getChunkInCache(chunkX, chunkZ); -+ if (chunk == null) { -+ return; -+ } -+ final boolean[] ret = this.handleEmptySectionChanges(lightAccess, chunk, emptinessChanges, false); -+ if (ret != null) { -+ this.setEmptinessMap(chunk, ret); -+ } -+ this.updateVisible(lightAccess); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ protected abstract void initNibble(final int chunkX, final int chunkY, final int chunkZ, final boolean extrude, final boolean initRemovedNibbles); -+ -+ protected abstract void setNibbleNull(final int chunkX, final int chunkY, final int chunkZ); -+ -+ // subclasses should not initialise caches, as this will always be done by the super call -+ // subclasses should not invoke updateVisible, as this will always be done by the super call -+ // subclasses are guaranteed that this is always called before a changed block set -+ // newChunk specifies whether the changes describe a "first load" of a chunk or changes to existing, already loaded chunks -+ // rets non-null when the emptiness map changed and needs to be updated -+ protected final boolean[] handleEmptySectionChanges(final LightChunkGetter lightAccess, final ChunkAccess chunk, -+ final Boolean[] emptinessChanges, final boolean unlit) { -+ final Level world = (Level)lightAccess.getLevel(); -+ final int chunkX = chunk.getPos().x; -+ final int chunkZ = chunk.getPos().z; -+ -+ boolean[] chunkEmptinessMap = this.getEmptinessMap(chunkX, chunkZ); -+ boolean[] ret = null; -+ final boolean needsInit = unlit || chunkEmptinessMap == null; -+ if (needsInit) { -+ this.setEmptinessMapCache(chunkX, chunkZ, ret = chunkEmptinessMap = new boolean[WorldUtil.getTotalSections(world)]); -+ } -+ -+ // update emptiness map -+ for (int sectionIndex = (emptinessChanges.length - 1); sectionIndex >= 0; --sectionIndex) { -+ final Boolean valueBoxed = emptinessChanges[sectionIndex]; -+ if (valueBoxed == null) { -+ if (needsInit) { -+ throw new IllegalStateException("Current chunk has not initialised emptiness map yet supplied emptiness map isn't filled?"); -+ } -+ continue; -+ } -+ chunkEmptinessMap[sectionIndex] = valueBoxed.booleanValue(); -+ } -+ -+ // now init neighbour nibbles -+ for (int sectionIndex = (emptinessChanges.length - 1); sectionIndex >= 0; --sectionIndex) { -+ final Boolean valueBoxed = emptinessChanges[sectionIndex]; -+ final int sectionY = sectionIndex + this.minSection; -+ if (valueBoxed == null) { -+ continue; -+ } -+ -+ final boolean empty = valueBoxed.booleanValue(); -+ -+ if (empty) { -+ continue; -+ } -+ -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ // if we're not empty, we also need to initialise nibbles -+ // note: if we're unlit, we absolutely do not want to extrude, as light data isn't set up -+ final boolean extrude = (dx | dz) != 0 || !unlit; -+ for (int dy = 1; dy >= -1; --dy) { -+ this.initNibble(dx + chunkX, dy + sectionY, dz + chunkZ, extrude, false); -+ } -+ } -+ } -+ } -+ -+ // check for de-init and lazy-init -+ // lazy init is when chunks are being lit, so at the time they weren't loaded when their neighbours were running -+ // init checks. -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ // does this neighbour have 1 radius loaded? -+ boolean neighboursLoaded = true; -+ neighbour_loaded_search: -+ for (int dz2 = -1; dz2 <= 1; ++dz2) { -+ for (int dx2 = -1; dx2 <= 1; ++dx2) { -+ if (this.getEmptinessMap(dx + dx2 + chunkX, dz + dz2 + chunkZ) == null) { -+ neighboursLoaded = false; -+ break neighbour_loaded_search; -+ } -+ } -+ } -+ -+ for (int sectionY = this.maxLightSection; sectionY >= this.minLightSection; --sectionY) { -+ // check neighbours to see if we need to de-init this one -+ boolean allEmpty = true; -+ neighbour_search: -+ for (int dy2 = -1; dy2 <= 1; ++dy2) { -+ for (int dz2 = -1; dz2 <= 1; ++dz2) { -+ for (int dx2 = -1; dx2 <= 1; ++dx2) { -+ final int y = sectionY + dy2; -+ if (y < this.minSection || y > this.maxSection) { -+ // empty -+ continue; -+ } -+ final boolean[] emptinessMap = this.getEmptinessMap(dx + dx2 + chunkX, dz + dz2 + chunkZ); -+ if (emptinessMap != null) { -+ if (!emptinessMap[y - this.minSection]) { -+ allEmpty = false; -+ break neighbour_search; -+ } -+ } else { -+ final LevelChunkSection section = this.getChunkSection(dx + dx2 + chunkX, y, dz + dz2 + chunkZ); -+ if (section != null && section != EMPTY_CHUNK_SECTION) { -+ allEmpty = false; -+ break neighbour_search; -+ } -+ } -+ } -+ } -+ } -+ -+ if (allEmpty & neighboursLoaded) { -+ // can only de-init when neighbours are loaded -+ // de-init is fine to delay, as de-init is just an optimisation - it's not required for lighting -+ // to be correct -+ -+ // all were empty, so de-init -+ this.setNibbleNull(dx + chunkX, sectionY, dz + chunkZ); -+ } else if (!allEmpty) { -+ // must init -+ final boolean extrude = (dx | dz) != 0 || !unlit; -+ this.initNibble(dx + chunkX, sectionY, dz + chunkZ, extrude, false); -+ } -+ } -+ } -+ } -+ -+ return ret; -+ } -+ -+ public final void checkChunkEdges(final LightChunkGetter lightAccess, final int chunkX, final int chunkZ) { -+ this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true, false); -+ try { -+ final ChunkAccess chunk = this.getChunkInCache(chunkX, chunkZ); -+ if (chunk == null) { -+ return; -+ } -+ this.checkChunkEdges(lightAccess, chunk, this.minLightSection, this.maxLightSection); -+ this.updateVisible(lightAccess); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ public final void checkChunkEdges(final LightChunkGetter lightAccess, final int chunkX, final int chunkZ, final ShortCollection sections) { -+ this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true, false); -+ try { -+ final ChunkAccess chunk = this.getChunkInCache(chunkX, chunkZ); -+ if (chunk == null) { -+ return; -+ } -+ this.checkChunkEdges(lightAccess, chunk, sections); -+ this.updateVisible(lightAccess); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ // subclasses should not initialise caches, as this will always be done by the super call -+ // subclasses should not invoke updateVisible, as this will always be done by the super call -+ // needsEdgeChecks applies when possibly loading vanilla data, which means we need to validate the current -+ // chunks light values with respect to neighbours -+ // subclasses should note that the emptiness changes are propagated BEFORE this is called, so this function -+ // does not need to detect empty chunks itself (and it should do no handling for them either!) -+ protected abstract void lightChunk(final LightChunkGetter lightAccess, final ChunkAccess chunk, final boolean needsEdgeChecks); -+ -+ public final void light(final LightChunkGetter lightAccess, final ChunkAccess chunk, final Boolean[] emptySections) { -+ final int chunkX = chunk.getPos().x; -+ final int chunkZ = chunk.getPos().z; -+ this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true, true); -+ -+ try { -+ final SWMRNibbleArray[] nibbles = getFilledEmptyLight(this.maxLightSection - this.minLightSection + 1); -+ // force current chunk into cache -+ this.setChunkInCache(chunkX, chunkZ, chunk); -+ this.setBlocksForChunkInCache(chunkX, chunkZ, chunk.getSections()); -+ this.setNibblesForChunkInCache(chunkX, chunkZ, nibbles); -+ this.setEmptinessMapCache(chunkX, chunkZ, this.getEmptinessMap(chunk)); -+ -+ final boolean[] ret = this.handleEmptySectionChanges(lightAccess, chunk, emptySections, true); -+ if (ret != null) { -+ this.setEmptinessMap(chunk, ret); -+ } -+ this.lightChunk(lightAccess, chunk, true); -+ this.setNibbles(chunk, nibbles); -+ this.updateVisible(lightAccess); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ public final void relightChunks(final LightChunkGetter lightAccess, final Set chunks, -+ final Consumer chunkLightCallback, final IntConsumer onComplete) { -+ // it's recommended for maximum performance that the set is ordered according to a BFS from the center of -+ // the region of chunks to relight -+ // it's required that tickets are added for each chunk to keep them loaded -+ final Long2ObjectOpenHashMap nibblesByChunk = new Long2ObjectOpenHashMap<>(); -+ final Long2ObjectOpenHashMap emptinessMapByChunk = new Long2ObjectOpenHashMap<>(); -+ -+ final int[] neighbourLightOrder = new int[] { -+ // d = 0 -+ 0, 0, -+ // d = 1 -+ -1, 0, -+ 0, -1, -+ 1, 0, -+ 0, 1, -+ // d = 2 -+ -1, 1, -+ 1, 1, -+ -1, -1, -+ 1, -1, -+ }; -+ -+ int lightCalls = 0; -+ -+ for (final ChunkPos chunkPos : chunks) { -+ final int chunkX = chunkPos.x; -+ final int chunkZ = chunkPos.z; -+ final ChunkAccess chunk = (ChunkAccess)lightAccess.getChunkForLighting(chunkX, chunkZ); -+ if (chunk == null || !this.canUseChunk(chunk)) { -+ throw new IllegalStateException(); -+ } -+ -+ for (int i = 0, len = neighbourLightOrder.length; i < len; i += 2) { -+ final int dx = neighbourLightOrder[i]; -+ final int dz = neighbourLightOrder[i + 1]; -+ final int neighbourX = dx + chunkX; -+ final int neighbourZ = dz + chunkZ; -+ -+ final ChunkAccess neighbour = (ChunkAccess)lightAccess.getChunkForLighting(neighbourX, neighbourZ); -+ if (neighbour == null || !this.canUseChunk(neighbour)) { -+ continue; -+ } -+ -+ if (nibblesByChunk.get(CoordinateUtils.getChunkKey(neighbourX, neighbourZ)) != null) { -+ // lit already called for neighbour, no need to light it now -+ continue; -+ } -+ -+ // light neighbour chunk -+ this.setupEncodeOffset(neighbourX * 16 + 7, 128, neighbourZ * 16 + 7); -+ try { -+ // insert all neighbouring chunks for this neighbour that we have data for -+ for (int dz2 = -1; dz2 <= 1; ++dz2) { -+ for (int dx2 = -1; dx2 <= 1; ++dx2) { -+ final int neighbourX2 = neighbourX + dx2; -+ final int neighbourZ2 = neighbourZ + dz2; -+ final long key = CoordinateUtils.getChunkKey(neighbourX2, neighbourZ2); -+ final ChunkAccess neighbour2 = (ChunkAccess)lightAccess.getChunkForLighting(neighbourX2, neighbourZ2); -+ if (neighbour2 == null || !this.canUseChunk(neighbour2)) { -+ continue; -+ } -+ -+ final SWMRNibbleArray[] nibbles = nibblesByChunk.get(key); -+ if (nibbles == null) { -+ // we haven't lit this chunk -+ continue; -+ } -+ -+ this.setChunkInCache(neighbourX2, neighbourZ2, neighbour2); -+ this.setBlocksForChunkInCache(neighbourX2, neighbourZ2, neighbour2.getSections()); -+ this.setNibblesForChunkInCache(neighbourX2, neighbourZ2, nibbles); -+ this.setEmptinessMapCache(neighbourX2, neighbourZ2, emptinessMapByChunk.get(key)); -+ } -+ } -+ -+ final long key = CoordinateUtils.getChunkKey(neighbourX, neighbourZ); -+ -+ // now insert the neighbour chunk and light it -+ final SWMRNibbleArray[] nibbles = getFilledEmptyLight(this.world); -+ nibblesByChunk.put(key, nibbles); -+ -+ this.setChunkInCache(neighbourX, neighbourZ, neighbour); -+ this.setBlocksForChunkInCache(neighbourX, neighbourZ, neighbour.getSections()); -+ this.setNibblesForChunkInCache(neighbourX, neighbourZ, nibbles); -+ -+ final boolean[] neighbourEmptiness = this.handleEmptySectionChanges(lightAccess, neighbour, getEmptySectionsForChunk(neighbour), true); -+ emptinessMapByChunk.put(key, neighbourEmptiness); -+ if (chunks.contains(new ChunkPos(neighbourX, neighbourZ))) { -+ this.setEmptinessMap(neighbour, neighbourEmptiness); -+ } -+ -+ this.lightChunk(lightAccess, neighbour, false); -+ } finally { -+ this.destroyCaches(); -+ } -+ } -+ -+ // done lighting all neighbours, so the chunk is now fully lit -+ -+ // make sure nibbles are fully updated before calling back -+ final SWMRNibbleArray[] nibbles = nibblesByChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ for (final SWMRNibbleArray nibble : nibbles) { -+ nibble.updateVisible(); -+ } -+ -+ this.setNibbles(chunk, nibbles); -+ -+ for (int y = this.minLightSection; y <= this.maxLightSection; ++y) { -+ lightAccess.onLightUpdate(this.skylightPropagator ? LightLayer.SKY : LightLayer.BLOCK, SectionPos.of(chunkX, y, chunkX)); -+ } -+ -+ // now do callback -+ if (chunkLightCallback != null) { -+ chunkLightCallback.accept(chunkPos); -+ } -+ ++lightCalls; -+ } -+ -+ if (onComplete != null) { -+ onComplete.accept(lightCalls); -+ } -+ } -+ -+ // old algorithm for propagating -+ // this is also the basic algorithm, the optimised algorithm is always going to be tested against this one -+ // and this one is always tested against vanilla -+ // contains: -+ // lower (6 + 6 + 16) = 28 bits: encoded coordinate position (x | (z << 6) | (y << (6 + 6)))) -+ // next 4 bits: propagated light level (0, 15] -+ // next 6 bits: propagation direction bitset -+ // next 24 bits: unused -+ // last 4 bits: state flags -+ // state flags: -+ // whether the propagation must set the current position's light value (0 if decrease, propagated light level if increase) -+ // whether the propagation needs to check if its current level is equal to the expected level -+ // used only in increase propagation -+ protected static final long FLAG_RECHECK_LEVEL = Long.MIN_VALUE >>> 1; -+ // whether the propagation needs to consider if its block is conditionally transparent -+ protected static final long FLAG_HAS_SIDED_TRANSPARENT_BLOCKS = Long.MIN_VALUE; -+ -+ protected long[] increaseQueue = new long[16 * 16 * 16]; -+ protected int increaseQueueInitialLength; -+ protected long[] decreaseQueue = new long[16 * 16 * 16]; -+ protected int decreaseQueueInitialLength; -+ -+ protected final long[] resizeIncreaseQueue() { -+ return this.increaseQueue = Arrays.copyOf(this.increaseQueue, this.increaseQueue.length * 2); -+ } -+ -+ protected final long[] resizeDecreaseQueue() { -+ return this.decreaseQueue = Arrays.copyOf(this.decreaseQueue, this.decreaseQueue.length * 2); -+ } -+ -+ protected final void appendToIncreaseQueue(final long value) { -+ final int idx = this.increaseQueueInitialLength++; -+ long[] queue = this.increaseQueue; -+ if (idx >= queue.length) { -+ queue = this.resizeIncreaseQueue(); -+ queue[idx] = value; -+ } else { -+ queue[idx] = value; -+ } -+ } -+ -+ protected final void appendToDecreaseQueue(final long value) { -+ final int idx = this.decreaseQueueInitialLength++; -+ long[] queue = this.decreaseQueue; -+ if (idx >= queue.length) { -+ queue = this.resizeDecreaseQueue(); -+ queue[idx] = value; -+ } else { -+ queue[idx] = value; -+ } -+ } -+ -+ protected static final AxisDirection[][] OLD_CHECK_DIRECTIONS = new AxisDirection[1 << 6][]; -+ protected static final int ALL_DIRECTIONS_BITSET = (1 << 6) - 1; -+ static { -+ for (int i = 0; i < OLD_CHECK_DIRECTIONS.length; ++i) { -+ final List directions = new ArrayList<>(); -+ for (int bitset = i, len = Integer.bitCount(i), index = 0; index < len; ++index, bitset ^= IntegerUtil.getTrailingBit(bitset)) { -+ directions.add(AXIS_DIRECTIONS[IntegerUtil.trailingZeros(bitset)]); -+ } -+ OLD_CHECK_DIRECTIONS[i] = directions.toArray(new AxisDirection[0]); -+ } -+ } -+ -+ protected final void performLightIncrease(final LightChunkGetter lightAccess) { -+ final BlockGetter world = lightAccess.getLevel(); -+ long[] queue = this.increaseQueue; -+ int queueReadIndex = 0; -+ int queueLength = this.increaseQueueInitialLength; -+ this.increaseQueueInitialLength = 0; -+ final int decodeOffsetX = -this.encodeOffsetX; -+ final int decodeOffsetY = -this.encodeOffsetY; -+ final int decodeOffsetZ = -this.encodeOffsetZ; -+ final int encodeOffset = this.coordinateOffset; -+ final int sectionOffset = this.chunkSectionIndexOffset; -+ -+ while (queueReadIndex < queueLength) { -+ final long queueValue = queue[queueReadIndex++]; -+ -+ final int posX = ((int)queueValue & 63) + decodeOffsetX; -+ final int posZ = (((int)queueValue >>> 6) & 63) + decodeOffsetZ; -+ final int posY = (((int)queueValue >>> 12) & ((1 << 16) - 1)) + decodeOffsetY; -+ final int propagatedLightLevel = (int)((queueValue >>> (6 + 6 + 16)) & 0xFL); -+ final AxisDirection[] checkDirections = OLD_CHECK_DIRECTIONS[(int)((queueValue >>> (6 + 6 + 16 + 4)) & 63L)]; -+ -+ if ((queueValue & FLAG_RECHECK_LEVEL) != 0L) { -+ if (this.getLightLevel(posX, posY, posZ) != propagatedLightLevel) { -+ // not at the level we expect, so something changed. -+ continue; -+ } -+ } -+ -+ if ((queueValue & FLAG_HAS_SIDED_TRANSPARENT_BLOCKS) == 0L) { -+ // we don't need to worry about our state here. -+ for (final AxisDirection propagate : checkDirections) { -+ final int offX = posX + propagate.x; -+ final int offY = posY + propagate.y; -+ final int offZ = posZ + propagate.z; -+ -+ final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; -+ final int localIndex = (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8); -+ -+ final SWMRNibbleArray currentNibble = this.nibbleCache[sectionIndex]; -+ final int currentLevel; -+ if (currentNibble == null || (currentLevel = currentNibble.getUpdating(localIndex)) >= (propagatedLightLevel - 1)) { -+ continue; // already at the level we want or unloaded -+ } -+ -+ final BlockState blockState = this.getBlockState(sectionIndex, localIndex); -+ if (blockState == null) { -+ continue; -+ } -+ final int opacityCached = blockState.getOpacityIfCached(); -+ if (opacityCached != -1) { -+ final int targetLevel = propagatedLightLevel - Math.max(1, opacityCached); -+ if (targetLevel > currentLevel) { -+ -+ currentNibble.set(localIndex, targetLevel); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 1) { -+ if (queueLength >= queue.length) { -+ queue = this.resizeIncreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4)); -+ continue; -+ } -+ } -+ continue; -+ } else { -+ this.mutablePos1.set(offX, offY, offZ); -+ long flags = 0; -+ if (blockState.isConditionallyFullOpaque()) { -+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms); -+ -+ if (Shapes.faceShapeOccludes(Shapes.empty(), cullingFace)) { -+ continue; -+ } -+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS; -+ } -+ -+ final int opacity = blockState.getLightBlock(world, this.mutablePos1); -+ final int targetLevel = propagatedLightLevel - Math.max(1, opacity); -+ if (targetLevel <= currentLevel) { -+ continue; -+ } -+ -+ currentNibble.set(localIndex, targetLevel); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 1) { -+ if (queueLength >= queue.length) { -+ queue = this.resizeIncreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4)) -+ | (flags); -+ } -+ continue; -+ } -+ } -+ } else { -+ // we actually need to worry about our state here -+ final BlockState fromBlock = this.getBlockState(posX, posY, posZ); -+ this.mutablePos2.set(posX, posY, posZ); -+ for (final AxisDirection propagate : checkDirections) { -+ final int offX = posX + propagate.x; -+ final int offY = posY + propagate.y; -+ final int offZ = posZ + propagate.z; -+ -+ final VoxelShape fromShape = fromBlock.isConditionallyFullOpaque() ? fromBlock.getFaceOcclusionShape(world, this.mutablePos2, propagate.nms) : Shapes.empty(); -+ -+ if (fromShape != Shapes.empty() && Shapes.faceShapeOccludes(Shapes.empty(), fromShape)) { -+ continue; -+ } -+ -+ final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; -+ final int localIndex = (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8); -+ -+ final SWMRNibbleArray currentNibble = this.nibbleCache[sectionIndex]; -+ final int currentLevel; -+ -+ if (currentNibble == null || (currentLevel = currentNibble.getUpdating(localIndex)) >= (propagatedLightLevel - 1)) { -+ continue; // already at the level we want -+ } -+ -+ final BlockState blockState = this.getBlockState(sectionIndex, localIndex); -+ if (blockState == null) { -+ continue; -+ } -+ final int opacityCached = blockState.getOpacityIfCached(); -+ if (opacityCached != -1) { -+ final int targetLevel = propagatedLightLevel - Math.max(1, opacityCached); -+ if (targetLevel > currentLevel) { -+ -+ currentNibble.set(localIndex, targetLevel); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 1) { -+ if (queueLength >= queue.length) { -+ queue = this.resizeIncreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4)); -+ continue; -+ } -+ } -+ continue; -+ } else { -+ this.mutablePos1.set(offX, offY, offZ); -+ long flags = 0; -+ if (blockState.isConditionallyFullOpaque()) { -+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms); -+ -+ if (Shapes.faceShapeOccludes(fromShape, cullingFace)) { -+ continue; -+ } -+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS; -+ } -+ -+ final int opacity = blockState.getLightBlock(world, this.mutablePos1); -+ final int targetLevel = propagatedLightLevel - Math.max(1, opacity); -+ if (targetLevel <= currentLevel) { -+ continue; -+ } -+ -+ currentNibble.set(localIndex, targetLevel); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 1) { -+ if (queueLength >= queue.length) { -+ queue = this.resizeIncreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | (propagate.everythingButTheOppositeDirection << (6 + 6 + 16 + 4)) -+ | (flags); -+ } -+ continue; -+ } -+ } -+ } -+ } -+ } -+ -+ protected final void performLightDecrease(final LightChunkGetter lightAccess) { -+ final BlockGetter world = lightAccess.getLevel(); -+ long[] queue = this.decreaseQueue; -+ long[] increaseQueue = this.increaseQueue; -+ int queueReadIndex = 0; -+ int queueLength = this.decreaseQueueInitialLength; -+ this.decreaseQueueInitialLength = 0; -+ int increaseQueueLength = this.increaseQueueInitialLength; -+ final int decodeOffsetX = -this.encodeOffsetX; -+ final int decodeOffsetY = -this.encodeOffsetY; -+ final int decodeOffsetZ = -this.encodeOffsetZ; -+ final int encodeOffset = this.coordinateOffset; -+ final int sectionOffset = this.chunkSectionIndexOffset; -+ final int emittedMask = this.emittedLightMask; -+ -+ while (queueReadIndex < queueLength) { -+ final long queueValue = queue[queueReadIndex++]; -+ -+ final int posX = ((int)queueValue & 63) + decodeOffsetX; -+ final int posZ = (((int)queueValue >>> 6) & 63) + decodeOffsetZ; -+ final int posY = (((int)queueValue >>> 12) & ((1 << 16) - 1)) + decodeOffsetY; -+ final int propagatedLightLevel = (int)((queueValue >>> (6 + 6 + 16)) & 0xF); -+ final AxisDirection[] checkDirections = OLD_CHECK_DIRECTIONS[(int)((queueValue >>> (6 + 6 + 16 + 4)) & 63)]; -+ -+ if ((queueValue & FLAG_HAS_SIDED_TRANSPARENT_BLOCKS) == 0L) { -+ // we don't need to worry about our state here. -+ for (final AxisDirection propagate : checkDirections) { -+ final int offX = posX + propagate.x; -+ final int offY = posY + propagate.y; -+ final int offZ = posZ + propagate.z; -+ -+ final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; -+ final int localIndex = (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8); -+ -+ final SWMRNibbleArray currentNibble = this.nibbleCache[sectionIndex]; -+ final int lightLevel; -+ -+ if (currentNibble == null || (lightLevel = currentNibble.getUpdating(localIndex)) == 0) { -+ // already at lowest (or unloaded), nothing we can do -+ continue; -+ } -+ -+ final BlockState blockState = this.getBlockState(sectionIndex, localIndex); -+ if (blockState == null) { -+ continue; -+ } -+ final int opacityCached = blockState.getOpacityIfCached(); -+ if (opacityCached != -1) { -+ final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacityCached)); -+ if (lightLevel > targetLevel) { -+ // it looks like another source propagated here, so re-propagate it -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((lightLevel & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | FLAG_RECHECK_LEVEL; -+ continue; -+ } -+ final int emittedLight = blockState.getLightEmission() & emittedMask; -+ if (emittedLight != 0) { -+ // re-propagate source -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((emittedLight & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | (blockState.isConditionallyFullOpaque() ? FLAG_HAS_SIDED_TRANSPARENT_BLOCKS : 0L); -+ } -+ -+ currentNibble.set(localIndex, emittedLight); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour... -+ if (queueLength >= queue.length) { -+ queue = this.resizeDecreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4)); -+ continue; -+ } -+ continue; -+ } else { -+ this.mutablePos1.set(offX, offY, offZ); -+ long flags = 0; -+ if (blockState.isConditionallyFullOpaque()) { -+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms); -+ -+ if (Shapes.faceShapeOccludes(Shapes.empty(), cullingFace)) { -+ continue; -+ } -+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS; -+ } -+ -+ final int opacity = blockState.getLightBlock(world, this.mutablePos1); -+ final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacity)); -+ if (lightLevel > targetLevel) { -+ // it looks like another source propagated here, so re-propagate it -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((lightLevel & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | (FLAG_RECHECK_LEVEL | flags); -+ continue; -+ } -+ final int emittedLight = blockState.getLightEmission() & emittedMask; -+ if (emittedLight != 0) { -+ // re-propagate source -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((emittedLight & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | flags; -+ } -+ -+ currentNibble.set(localIndex, emittedLight); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 0) { -+ if (queueLength >= queue.length) { -+ queue = this.resizeDecreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4)) -+ | flags; -+ } -+ continue; -+ } -+ } -+ } else { -+ // we actually need to worry about our state here -+ final BlockState fromBlock = this.getBlockState(posX, posY, posZ); -+ this.mutablePos2.set(posX, posY, posZ); -+ for (final AxisDirection propagate : checkDirections) { -+ final int offX = posX + propagate.x; -+ final int offY = posY + propagate.y; -+ final int offZ = posZ + propagate.z; -+ -+ final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; -+ final int localIndex = (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8); -+ -+ final VoxelShape fromShape = fromBlock.isConditionallyFullOpaque() ? fromBlock.getFaceOcclusionShape(world, this.mutablePos2, propagate.nms) : Shapes.empty(); -+ -+ if (fromShape != Shapes.empty() && Shapes.faceShapeOccludes(Shapes.empty(), fromShape)) { -+ continue; -+ } -+ -+ final SWMRNibbleArray currentNibble = this.nibbleCache[sectionIndex]; -+ final int lightLevel; -+ -+ if (currentNibble == null || (lightLevel = currentNibble.getUpdating(localIndex)) == 0) { -+ // already at lowest (or unloaded), nothing we can do -+ continue; -+ } -+ -+ final BlockState blockState = this.getBlockState(sectionIndex, localIndex); -+ if (blockState == null) { -+ continue; -+ } -+ final int opacityCached = blockState.getOpacityIfCached(); -+ if (opacityCached != -1) { -+ final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacityCached)); -+ if (lightLevel > targetLevel) { -+ // it looks like another source propagated here, so re-propagate it -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((lightLevel & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | FLAG_RECHECK_LEVEL; -+ continue; -+ } -+ final int emittedLight = blockState.getLightEmission() & emittedMask; -+ if (emittedLight != 0) { -+ // re-propagate source -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((emittedLight & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | (blockState.isConditionallyFullOpaque() ? FLAG_HAS_SIDED_TRANSPARENT_BLOCKS : 0L); -+ } -+ -+ currentNibble.set(localIndex, emittedLight); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour... -+ if (queueLength >= queue.length) { -+ queue = this.resizeDecreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4)); -+ continue; -+ } -+ continue; -+ } else { -+ this.mutablePos1.set(offX, offY, offZ); -+ long flags = 0; -+ if (blockState.isConditionallyFullOpaque()) { -+ final VoxelShape cullingFace = blockState.getFaceOcclusionShape(world, this.mutablePos1, propagate.getOpposite().nms); -+ -+ if (Shapes.faceShapeOccludes(fromShape, cullingFace)) { -+ continue; -+ } -+ flags |= FLAG_HAS_SIDED_TRANSPARENT_BLOCKS; -+ } -+ -+ final int opacity = blockState.getLightBlock(world, this.mutablePos1); -+ final int targetLevel = Math.max(0, propagatedLightLevel - Math.max(1, opacity)); -+ if (lightLevel > targetLevel) { -+ // it looks like another source propagated here, so re-propagate it -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((lightLevel & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | (FLAG_RECHECK_LEVEL | flags); -+ continue; -+ } -+ final int emittedLight = blockState.getLightEmission() & emittedMask; -+ if (emittedLight != 0) { -+ // re-propagate source -+ if (increaseQueueLength >= increaseQueue.length) { -+ increaseQueue = this.resizeIncreaseQueue(); -+ } -+ increaseQueue[increaseQueueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((emittedLight & 0xFL) << (6 + 6 + 16)) -+ | (((long)ALL_DIRECTIONS_BITSET) << (6 + 6 + 16 + 4)) -+ | flags; -+ } -+ -+ currentNibble.set(localIndex, emittedLight); -+ this.postLightUpdate(offX, offY, offZ); -+ -+ if (targetLevel > 0) { // we actually need to propagate 0 just in case we find a neighbour... -+ if (queueLength >= queue.length) { -+ queue = this.resizeDecreaseQueue(); -+ } -+ queue[queueLength++] = -+ ((offX + (offZ << 6) + (offY << 12) + encodeOffset) & ((1L << (6 + 6 + 16)) - 1)) -+ | ((targetLevel & 0xFL) << (6 + 6 + 16)) -+ | ((propagate.everythingButTheOppositeDirection) << (6 + 6 + 16 + 4)) -+ | flags; -+ } -+ continue; -+ } -+ } -+ } -+ } -+ -+ // propagate sources we clobbered -+ this.increaseQueueInitialLength = increaseQueueLength; -+ this.performLightIncrease(lightAccess); -+ } -+} -diff --git a/src/main/java/ca/spottedleaf/starlight/light/StarLightInterface.java b/src/main/java/ca/spottedleaf/starlight/light/StarLightInterface.java -new file mode 100644 -index 0000000000000000000000000000000000000000..300364f693583be802a71d94cda5d96c77c7b67c ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/starlight/light/StarLightInterface.java -@@ -0,0 +1,635 @@ -+package ca.spottedleaf.starlight.light; -+ -+import com.tuinity.tuinity.util.CoordinateUtils; -+import com.tuinity.tuinity.util.WorldUtil; -+import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -+import it.unimi.dsi.fastutil.shorts.ShortCollection; -+import it.unimi.dsi.fastutil.shorts.ShortOpenHashSet; -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.SectionPos; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.TicketType; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; -+import net.minecraft.world.level.chunk.DataLayer; -+import net.minecraft.world.level.chunk.LightChunkGetter; -+import net.minecraft.world.level.lighting.LayerLightEventListener; -+import net.minecraft.world.level.lighting.LevelLightEngine; -+import java.util.*; -+import java.util.concurrent.CompletableFuture; -+import java.util.function.Consumer; -+import java.util.function.IntConsumer; -+ -+public final class StarLightInterface { -+ -+ public static final TicketType CHUNK_WORK_TICKET = TicketType.create("starlight_chunk_work_ticket", (p1, p2) -> Long.compare(p1.toLong(), p2.toLong())); -+ -+ /** -+ * Can be {@code null}, indicating the light is all empty. -+ */ -+ protected final Level world; -+ protected final LightChunkGetter lightAccess; -+ -+ protected final ArrayDeque cachedSkyPropagators; -+ protected final ArrayDeque cachedBlockPropagators; -+ -+ protected final LightQueue lightQueue = new LightQueue(this); -+ -+ protected final LayerLightEventListener skyReader; -+ protected final LayerLightEventListener blockReader; -+ protected final boolean isClientSide; -+ -+ protected final int minSection; -+ protected final int maxSection; -+ protected final int minLightSection; -+ protected final int maxLightSection; -+ -+ public final LevelLightEngine lightEngine; -+ -+ public StarLightInterface(final LightChunkGetter lightAccess, final boolean hasSkyLight, final boolean hasBlockLight, final LevelLightEngine lightEngine) { -+ this.lightAccess = lightAccess; -+ this.world = lightAccess == null ? null : (Level)lightAccess.getLevel(); -+ this.cachedSkyPropagators = hasSkyLight && lightAccess != null ? new ArrayDeque<>() : null; -+ this.cachedBlockPropagators = hasBlockLight && lightAccess != null ? new ArrayDeque<>() : null; -+ this.isClientSide = !(this.world instanceof ServerLevel); -+ if (this.world == null) { -+ this.minSection = 0; -+ this.maxSection = 15; -+ this.minLightSection = -1; -+ this.maxLightSection = 16; -+ } else { -+ this.minSection = WorldUtil.getMinSection(this.world); -+ this.maxSection = WorldUtil.getMaxSection(this.world); -+ this.minLightSection = WorldUtil.getMinLightSection(this.world); -+ this.maxLightSection = WorldUtil.getMaxLightSection(this.world); -+ } -+ this.lightEngine = lightEngine; -+ this.skyReader = !hasSkyLight ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : new LayerLightEventListener() { -+ @Override -+ public void checkBlock(final BlockPos blockPos) { -+ StarLightInterface.this.lightEngine.checkBlock(blockPos.immutable()); -+ } -+ -+ @Override -+ public void onBlockEmissionIncrease(final BlockPos blockPos, final int i) { -+ // skylight doesn't care -+ } -+ -+ @Override -+ public boolean hasLightWork() { -+ // not really correct... -+ return StarLightInterface.this.hasUpdates(); -+ } -+ -+ @Override -+ public int runUpdates(final int i, final boolean bl, final boolean bl2) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void enableLightSources(final ChunkPos chunkPos, final boolean bl) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public DataLayer getDataLayerData(final SectionPos pos) { -+ final ChunkAccess chunk = StarLightInterface.this.getAnyChunkNow(pos.getX(), pos.getZ()); -+ if (chunk == null || (!StarLightInterface.this.isClientSide && !chunk.isLightCorrect()) || !chunk.getStatus().isOrAfter(ChunkStatus.LIGHT)) { -+ return null; -+ } -+ -+ final int sectionY = pos.getY(); -+ -+ if (sectionY > StarLightInterface.this.maxLightSection || sectionY < StarLightInterface.this.minLightSection) { -+ return null; -+ } -+ -+ if (chunk.getSkyEmptinessMap() == null) { -+ return null; -+ } -+ -+ return chunk.getSkyNibbles()[sectionY - StarLightInterface.this.minLightSection].toVanillaNibble(); -+ } -+ -+ @Override -+ public int getLightValue(final BlockPos blockPos) { -+ final int x = blockPos.getX(); -+ int y = blockPos.getY(); -+ final int z = blockPos.getZ(); -+ -+ final ChunkAccess chunk = StarLightInterface.this.getAnyChunkNow(x >> 4, z >> 4); -+ if (chunk == null || (!StarLightInterface.this.isClientSide && !chunk.isLightCorrect()) || !chunk.getStatus().isOrAfter(ChunkStatus.LIGHT)) { -+ return 15; -+ } -+ -+ int sectionY = y >> 4; -+ -+ if (sectionY > StarLightInterface.this.maxLightSection) { -+ return 15; -+ } -+ -+ if (sectionY < StarLightInterface.this.minLightSection) { -+ sectionY = StarLightInterface.this.minLightSection; -+ y = sectionY << 4; -+ } -+ -+ final SWMRNibbleArray[] nibbles = chunk.getSkyNibbles(); -+ final SWMRNibbleArray immediate = nibbles[sectionY - StarLightInterface.this.minLightSection]; -+ -+ if (StarLightInterface.this.isClientSide) { -+ if (!immediate.isNullNibbleUpdating()) { -+ return immediate.getUpdating(x, y, z); -+ } -+ } else { -+ if (!immediate.isNullNibbleVisible()) { -+ return immediate.getVisible(x, y, z); -+ } -+ } -+ -+ final boolean[] emptinessMap = chunk.getSkyEmptinessMap(); -+ -+ if (emptinessMap == null) { -+ return 15; -+ } -+ -+ // are we above this chunk's lowest empty section? -+ int lowestY = StarLightInterface.this.minLightSection - 1; -+ for (int currY = StarLightInterface.this.maxSection; currY >= StarLightInterface.this.minSection; --currY) { -+ if (emptinessMap[currY - StarLightInterface.this.minSection]) { -+ continue; -+ } -+ -+ // should always be full lit here -+ lowestY = currY; -+ break; -+ } -+ -+ if (sectionY > lowestY) { -+ return 15; -+ } -+ -+ // this nibble is going to depend solely on the skylight data above it -+ // find first non-null data above (there does exist one, as we just found it above) -+ for (int currY = sectionY + 1; currY <= StarLightInterface.this.maxLightSection; ++currY) { -+ final SWMRNibbleArray nibble = nibbles[currY - StarLightInterface.this.minLightSection]; -+ if (StarLightInterface.this.isClientSide) { -+ if (!nibble.isNullNibbleUpdating()) { -+ return nibble.getUpdating(x, 0, z); -+ } -+ } else { -+ if (!nibble.isNullNibbleVisible()) { -+ return nibble.getVisible(x, 0, z); -+ } -+ } -+ } -+ -+ // should never reach here -+ return 15; -+ } -+ -+ @Override -+ public void updateSectionStatus(final SectionPos pos, final boolean notReady) { -+ StarLightInterface.this.sectionChange(pos, notReady); -+ } -+ }; -+ this.blockReader = !hasBlockLight ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : new LayerLightEventListener() { -+ @Override -+ public void checkBlock(final BlockPos blockPos) { -+ StarLightInterface.this.lightEngine.checkBlock(blockPos.immutable()); -+ } -+ -+ @Override -+ public void onBlockEmissionIncrease(final BlockPos blockPos, final int i) { -+ this.checkBlock(blockPos); -+ } -+ -+ @Override -+ public boolean hasLightWork() { -+ // not really correct... -+ return StarLightInterface.this.hasUpdates(); -+ } -+ -+ @Override -+ public int runUpdates(final int i, final boolean bl, final boolean bl2) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public void enableLightSources(final ChunkPos chunkPos, final boolean bl) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public DataLayer getDataLayerData(final SectionPos pos) { -+ final ChunkAccess chunk = StarLightInterface.this.getAnyChunkNow(pos.getX(), pos.getZ()); -+ -+ if (chunk == null || pos.getY() < StarLightInterface.this.minLightSection || pos.getY() > StarLightInterface.this.maxLightSection) { -+ return null; -+ } -+ -+ return chunk.getBlockNibbles()[pos.getY() - StarLightInterface.this.minLightSection].toVanillaNibble(); -+ } -+ -+ @Override -+ public int getLightValue(final BlockPos blockPos) { -+ final int cx = blockPos.getX() >> 4; -+ final int cy = blockPos.getY() >> 4; -+ final int cz = blockPos.getZ() >> 4; -+ -+ if (cy < StarLightInterface.this.minLightSection || cy > StarLightInterface.this.maxLightSection) { -+ return 0; -+ } -+ -+ final ChunkAccess chunk = StarLightInterface.this.getAnyChunkNow(cx, cz); -+ -+ if (chunk == null) { -+ return 0; -+ } -+ -+ final SWMRNibbleArray nibble = chunk.getBlockNibbles()[cy - StarLightInterface.this.minLightSection]; -+ if (StarLightInterface.this.isClientSide) { -+ return nibble.getUpdating(blockPos.getX(), blockPos.getY(), blockPos.getZ()); -+ } else { -+ return nibble.getVisible(blockPos.getX(), blockPos.getY(), blockPos.getZ()); -+ } -+ } -+ -+ @Override -+ public void updateSectionStatus(final SectionPos pos, final boolean notReady) { -+ StarLightInterface.this.sectionChange(pos, notReady); -+ } -+ }; -+ } -+ -+ public LayerLightEventListener getSkyReader() { -+ return this.skyReader; -+ } -+ -+ public LayerLightEventListener getBlockReader() { -+ return this.blockReader; -+ } -+ -+ public boolean isClientSide() { -+ return this.isClientSide; -+ } -+ -+ public ChunkAccess getAnyChunkNow(final int chunkX, final int chunkZ) { -+ if (this.world == null) { -+ // empty world -+ return null; -+ } -+ return ((ServerLevel)this.world).getChunkSource().getChunkAtImmediately(chunkX, chunkZ); -+ } -+ -+ public boolean hasUpdates() { -+ return !this.lightQueue.isEmpty(); -+ } -+ -+ public Level getWorld() { -+ return this.world; -+ } -+ -+ public LightChunkGetter getLightAccess() { -+ return this.lightAccess; -+ } -+ -+ protected final SkyStarLightEngine getSkyLightEngine() { -+ if (this.cachedSkyPropagators == null) { -+ return null; -+ } -+ final SkyStarLightEngine ret; -+ synchronized (this.cachedSkyPropagators) { -+ ret = this.cachedSkyPropagators.pollFirst(); -+ } -+ -+ if (ret == null) { -+ return new SkyStarLightEngine(this.world); -+ } -+ return ret; -+ } -+ -+ protected final void releaseSkyLightEngine(final SkyStarLightEngine engine) { -+ if (this.cachedSkyPropagators == null) { -+ return; -+ } -+ synchronized (this.cachedSkyPropagators) { -+ this.cachedSkyPropagators.addFirst(engine); -+ } -+ } -+ -+ protected final BlockStarLightEngine getBlockLightEngine() { -+ if (this.cachedBlockPropagators == null) { -+ return null; -+ } -+ final BlockStarLightEngine ret; -+ synchronized (this.cachedBlockPropagators) { -+ ret = this.cachedBlockPropagators.pollFirst(); -+ } -+ -+ if (ret == null) { -+ return new BlockStarLightEngine(this.world); -+ } -+ return ret; -+ } -+ -+ protected final void releaseBlockLightEngine(final BlockStarLightEngine engine) { -+ if (this.cachedBlockPropagators == null) { -+ return; -+ } -+ synchronized (this.cachedBlockPropagators) { -+ this.cachedBlockPropagators.addFirst(engine); -+ } -+ } -+ -+ public CompletableFuture blockChange(final BlockPos pos) { -+ if (this.world == null || pos.getY() < WorldUtil.getMinBlockY(this.world) || pos.getY() > WorldUtil.getMaxBlockY(this.world)) { // empty world -+ return null; -+ } -+ -+ return this.lightQueue.queueBlockChange(pos); -+ } -+ -+ public CompletableFuture sectionChange(final SectionPos pos, final boolean newEmptyValue) { -+ if (this.world == null) { // empty world -+ return null; -+ } -+ -+ return this.lightQueue.queueSectionChange(pos, newEmptyValue); -+ } -+ -+ public void forceLoadInChunk(final ChunkAccess chunk, final Boolean[] emptySections) { -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ -+ try { -+ if (skyEngine != null) { -+ skyEngine.forceHandleEmptySectionChanges(this.lightAccess, chunk, emptySections); -+ } -+ if (blockEngine != null) { -+ blockEngine.forceHandleEmptySectionChanges(this.lightAccess, chunk, emptySections); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ public void loadInChunk(final int chunkX, final int chunkZ, final Boolean[] emptySections) { -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ -+ try { -+ if (skyEngine != null) { -+ skyEngine.handleEmptySectionChanges(this.lightAccess, chunkX, chunkZ, emptySections); -+ } -+ if (blockEngine != null) { -+ blockEngine.handleEmptySectionChanges(this.lightAccess, chunkX, chunkZ, emptySections); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ public void lightChunk(final ChunkAccess chunk, final Boolean[] emptySections) { -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ -+ try { -+ if (skyEngine != null) { -+ skyEngine.light(this.lightAccess, chunk, emptySections); -+ } -+ if (blockEngine != null) { -+ blockEngine.light(this.lightAccess, chunk, emptySections); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ public void relightChunks(final Set chunks, final Consumer chunkLightCallback, -+ final IntConsumer onComplete) { -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ -+ try { -+ if (skyEngine != null) { -+ skyEngine.relightChunks(this.lightAccess, chunks, blockEngine == null ? chunkLightCallback : null, -+ blockEngine == null ? onComplete : null); -+ } -+ if (blockEngine != null) { -+ blockEngine.relightChunks(this.lightAccess, chunks, chunkLightCallback, onComplete); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ public void checkChunkEdges(final int chunkX, final int chunkZ) { -+ this.checkSkyEdges(chunkX, chunkZ); -+ this.checkBlockEdges(chunkX, chunkZ); -+ } -+ -+ public void checkSkyEdges(final int chunkX, final int chunkZ) { -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ -+ try { -+ if (skyEngine != null) { -+ skyEngine.checkChunkEdges(this.lightAccess, chunkX, chunkZ); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ } -+ } -+ -+ public void checkBlockEdges(final int chunkX, final int chunkZ) { -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ try { -+ if (blockEngine != null) { -+ blockEngine.checkChunkEdges(this.lightAccess, chunkX, chunkZ); -+ } -+ } finally { -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ public void checkSkyEdges(final int chunkX, final int chunkZ, final ShortCollection sections) { -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ -+ try { -+ if (skyEngine != null) { -+ skyEngine.checkChunkEdges(this.lightAccess, chunkX, chunkZ, sections); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ } -+ } -+ -+ public void checkBlockEdges(final int chunkX, final int chunkZ, final ShortCollection sections) { -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ try { -+ if (blockEngine != null) { -+ blockEngine.checkChunkEdges(this.lightAccess, chunkX, chunkZ, sections); -+ } -+ } finally { -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ public void scheduleChunkLight(final ChunkPos pos, final Runnable run) { -+ this.lightQueue.queueChunkLighting(pos, run); -+ } -+ -+ public void removeChunkTasks(final ChunkPos pos) { -+ this.lightQueue.removeChunk(pos); -+ } -+ -+ public void propagateChanges() { -+ if (this.lightQueue.isEmpty()) { -+ return; -+ } -+ -+ final SkyStarLightEngine skyEngine = this.getSkyLightEngine(); -+ final BlockStarLightEngine blockEngine = this.getBlockLightEngine(); -+ -+ try { -+ LightQueue.ChunkTasks task; -+ while ((task = this.lightQueue.removeFirstTask()) != null) { -+ if (task.lightTasks != null) { -+ for (final Runnable run : task.lightTasks) { -+ run.run(); -+ } -+ } -+ -+ final long coordinate = task.chunkCoordinate; -+ final int chunkX = CoordinateUtils.getChunkX(coordinate); -+ final int chunkZ = CoordinateUtils.getChunkZ(coordinate); -+ -+ final Set positions = task.changedPositions; -+ final Boolean[] sectionChanges = task.changedSectionSet; -+ -+ if (skyEngine != null && (!positions.isEmpty() || sectionChanges != null)) { -+ skyEngine.blocksChangedInChunk(this.lightAccess, chunkX, chunkZ, positions, sectionChanges); -+ } -+ if (blockEngine != null && (!positions.isEmpty() || sectionChanges != null)) { -+ blockEngine.blocksChangedInChunk(this.lightAccess, chunkX, chunkZ, positions, sectionChanges); -+ } -+ -+ if (skyEngine != null && task.queuedEdgeChecksSky != null) { -+ skyEngine.checkChunkEdges(this.lightAccess, chunkX, chunkZ, task.queuedEdgeChecksSky); -+ } -+ if (blockEngine != null && task.queuedEdgeChecksBlock != null) { -+ blockEngine.checkChunkEdges(this.lightAccess, chunkX, chunkZ, task.queuedEdgeChecksBlock); -+ } -+ -+ task.onComplete.complete(null); -+ } -+ } finally { -+ this.releaseSkyLightEngine(skyEngine); -+ this.releaseBlockLightEngine(blockEngine); -+ } -+ } -+ -+ protected static final class LightQueue { -+ -+ protected final Long2ObjectLinkedOpenHashMap chunkTasks = new Long2ObjectLinkedOpenHashMap<>(); -+ protected final StarLightInterface manager; -+ -+ public LightQueue(final StarLightInterface manager) { -+ this.manager = manager; -+ } -+ -+ public synchronized boolean isEmpty() { -+ return this.chunkTasks.isEmpty(); -+ } -+ -+ public synchronized CompletableFuture queueBlockChange(final BlockPos pos) { -+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new); -+ tasks.changedPositions.add(pos.immutable()); -+ return tasks.onComplete; -+ } -+ -+ public synchronized CompletableFuture queueSectionChange(final SectionPos pos, final boolean newEmptyValue) { -+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new); -+ -+ if (tasks.changedSectionSet == null) { -+ tasks.changedSectionSet = new Boolean[this.manager.maxSection - this.manager.minSection + 1]; -+ } -+ tasks.changedSectionSet[pos.getY() - this.manager.minSection] = Boolean.valueOf(newEmptyValue); -+ -+ return tasks.onComplete; -+ } -+ -+ public synchronized CompletableFuture queueChunkLighting(final ChunkPos pos, final Runnable lightTask) { -+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new); -+ if (tasks.lightTasks == null) { -+ tasks.lightTasks = new ArrayList<>(); -+ } -+ tasks.lightTasks.add(lightTask); -+ -+ return tasks.onComplete; -+ } -+ -+ public synchronized CompletableFuture queueChunkSkylightEdgeCheck(final SectionPos pos, final ShortCollection sections) { -+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new); -+ -+ ShortOpenHashSet queuedEdges = tasks.queuedEdgeChecksSky; -+ if (queuedEdges == null) { -+ queuedEdges = tasks.queuedEdgeChecksSky = new ShortOpenHashSet(); -+ } -+ queuedEdges.addAll(sections); -+ -+ return tasks.onComplete; -+ } -+ -+ public synchronized CompletableFuture queueChunkBlocklightEdgeCheck(final SectionPos pos, final ShortCollection sections) { -+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new); -+ -+ ShortOpenHashSet queuedEdges = tasks.queuedEdgeChecksBlock; -+ if (queuedEdges == null) { -+ queuedEdges = tasks.queuedEdgeChecksBlock = new ShortOpenHashSet(); -+ } -+ queuedEdges.addAll(sections); -+ -+ return tasks.onComplete; -+ } -+ -+ public void removeChunk(final ChunkPos pos) { -+ final ChunkTasks tasks; -+ synchronized (this) { -+ tasks = this.chunkTasks.remove(CoordinateUtils.getChunkKey(pos)); -+ } -+ if (tasks != null) { -+ tasks.onComplete.complete(null); -+ } -+ } -+ -+ public synchronized ChunkTasks removeFirstTask() { -+ if (this.chunkTasks.isEmpty()) { -+ return null; -+ } -+ return this.chunkTasks.removeFirst(); -+ } -+ -+ protected static final class ChunkTasks { -+ -+ public final Set changedPositions = new HashSet<>(); -+ public Boolean[] changedSectionSet; -+ public ShortOpenHashSet queuedEdgeChecksSky; -+ public ShortOpenHashSet queuedEdgeChecksBlock; -+ public List lightTasks; -+ -+ public final CompletableFuture onComplete = new CompletableFuture<>(); -+ -+ public final long chunkCoordinate; -+ -+ public ChunkTasks(final long chunkCoordinate) { -+ this.chunkCoordinate = chunkCoordinate; -+ } -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java -index 8c883d2f88acc731734a121ebb76821e66658cc9..c2e8380590d83ce20ee02c90d825b0ad5e883ba9 100644 ---- a/src/main/java/co/aikar/timings/MinecraftTimings.java -+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java -@@ -45,6 +45,8 @@ public final class MinecraftTimings { - - public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update"); - public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate"); -+ public static final Timing distanceManagerTick = Timings.ofSafe("Distance Manager Tick"); // Tuinity - add timings for distance manager -+ public static final Timing scoreboardScoreSearch = Timings.ofSafe("Scoreboard score search"); // Tuinity - add timings for scoreboard search - - private static final Map, String> taskNameCache = new MapMaker().weakKeys().makeMap(); - -diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index cfe293881f68c8db337c3a48948362bb7b3e3522..b5728243f01aa6ea75cb42af453fd9348a5f438b 100644 ---- a/src/main/java/co/aikar/timings/TimingsExport.java -+++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -153,7 +153,7 @@ public class TimingsExport extends Thread { - return pair(rule, world.getWorld().getGameRuleValue(rule)); - })), - pair("ticking-distance", world.getChunkSource().chunkMap.getEffectiveViewDistance()), -- pair("notick-viewdistance", world.getChunkSource().chunkMap.getEffectiveNoTickViewDistance()) -+ pair("notick-viewdistance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()) // Tuinity - replace old player chunk management - )); - })); - -@@ -228,7 +228,8 @@ public class TimingsExport extends Thread { - parent.put("config", createObject( - pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), - pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), -- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) -+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Tuinity - add config to timings report -+ pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)) // Tuinity - add config to timings report - )); - - new TimingsExport(listeners, parent, history).start(); -diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 218f5bafeed8551b55b91c7fccaf6935c8b631ca..3918b24c98faa5232c7ffd733ba8000562132785 100644 ---- a/src/main/java/com/destroystokyo/paper/Metrics.java -+++ b/src/main/java/com/destroystokyo/paper/Metrics.java -@@ -593,7 +593,7 @@ public class Metrics { - boolean logFailedRequests = config.getBoolean("logFailedRequests", false); - // Only start Metrics, if it's enabled in the config - if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); -+ Metrics metrics = new Metrics("Tuinity", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page - - metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { - String minecraftVersion = Bukkit.getVersion(); -@@ -603,7 +603,7 @@ public class Metrics { - - metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); - metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline")); -- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); -+ metrics.addCustomChart(new Metrics.SimplePie("tuinity_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page - - metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { - Map> map = new HashMap<>(); -diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java -index ba8395435482fc4d6e02fc86794cdb0d35d4399c..af66c6d863a57b2c34006b06852e9811a74d7dfa 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperCommand.java -+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java -@@ -272,7 +272,7 @@ public class PaperCommand extends Command { - int ticking = 0; - int entityTicking = 0; - -- for (ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunkMap.values()) { -+ for (ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunks.getUpdatingMap().values()) { // Tuinity - change updating chunks map - if (chunk.getFullChunkUnchecked() == null) { - continue; - } -@@ -496,6 +496,46 @@ public class PaperCommand extends Command { - } - } - -+ // Tuinity start - rewrite light engine -+ private void starlightFixLight(ServerPlayer sender, ServerLevel world, ThreadedLevelLightEngine lightengine, int radius) { -+ long start = System.nanoTime(); -+ java.util.LinkedHashSet chunks = new java.util.LinkedHashSet<>(MCUtil.getSpiralOutChunks(sender.blockPosition(), radius)); // getChunkCoordinates is actually just bad mappings, this function rets position as blockpos -+ -+ int[] pending = new int[1]; -+ for (java.util.Iterator iterator = chunks.iterator(); iterator.hasNext();) { -+ final ChunkPos chunkPos = iterator.next(); -+ -+ final net.minecraft.world.level.chunk.ChunkAccess chunk = world.getChunkSource().getChunkAtImmediately(chunkPos.x, chunkPos.z); -+ if (chunk == null || !chunk.isLightCorrect() || !chunk.getStatus().isOrAfter(net.minecraft.world.level.chunk.ChunkStatus.LIGHT)) { -+ // cannot relight this chunk -+ iterator.remove(); -+ continue; -+ } -+ -+ ++pending[0]; -+ } -+ -+ int[] relitChunks = new int[1]; -+ lightengine.relight(chunks, -+ (ChunkPos chunkPos) -> { -+ ++relitChunks[0]; -+ sender.getBukkitEntity().sendMessage( -+ ChatColor.BLUE + "Relit chunk " + ChatColor.DARK_AQUA + chunkPos + ChatColor.BLUE + -+ ", progress: " + ChatColor.DARK_AQUA + (int)(Math.round(100.0 * (double)(relitChunks[0])/(double)pending[0])) + "%" -+ ); -+ }, -+ (int totalRelit) -> { -+ final long end = System.nanoTime(); -+ final long diff = Math.round(1.0e-6*(end - start)); -+ sender.getBukkitEntity().sendMessage( -+ ChatColor.BLUE + "Relit " + ChatColor.DARK_AQUA + totalRelit + ChatColor.BLUE + " chunks. Took " + -+ ChatColor.DARK_AQUA + diff + "ms" -+ ); -+ }); -+ sender.getBukkitEntity().sendMessage(ChatColor.BLUE + "Relighting " + ChatColor.DARK_AQUA + pending[0] + ChatColor.BLUE + " chunks"); -+ } -+ // Tuinity end - rewrite light engine -+ - private void doFixLight(CommandSender sender, String[] args) { - if (!(sender instanceof Player)) { - sender.sendMessage("Only players can use this command"); -@@ -504,7 +544,7 @@ public class PaperCommand extends Command { - int radius = 2; - if (args.length > 1) { - try { -- radius = Math.min(5, Integer.parseInt(args[1])); -+ radius = Math.min(32, Integer.parseInt(args[1])); // Tuinity - MOOOOOORE - } catch (Exception e) { - sender.sendMessage("Not a number"); - return; -@@ -517,6 +557,13 @@ public class PaperCommand extends Command { - ServerLevel world = (ServerLevel) handle.level; - ThreadedLevelLightEngine lightengine = world.getChunkSource().getLightEngine(); - -+ // Tuinity start - rewrite light engine -+ if (true) { -+ this.starlightFixLight(handle, world, lightengine, radius); -+ return; -+ } -+ // Tuinity end - rewrite light engine -+ - net.minecraft.core.BlockPos center = MCUtil.toBlockPosition(player.getLocation()); - Deque queue = new ArrayDeque<>(MCUtil.getSpiralOutChunks(center, radius)); - updateLight(sender, world, lightengine, queue); -diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -index 580bae0d414d371a07a6bfeefc41fdd989dc0083..d50b61876f15d95b836b3dd81d9c3492c91a8448 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -@@ -29,8 +29,8 @@ public class PaperVersionFetcher implements VersionFetcher { - @Nonnull - @Override - public Component getVersionMessage(@Nonnull String serverVersion) { -- String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]"); -- final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]); -+ String[] parts = serverVersion.substring("git-Tuinity-".length()).split("[-\\s]"); // Tuinity -+ final Component updateMessage = getUpdateStatusMessage("Spottedleaf/Tuinity", GITHUB_BRANCH_NAME, parts[0]); // Tuinity - final Component history = getHistory(); - - return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage; -@@ -54,13 +54,10 @@ public class PaperVersionFetcher implements VersionFetcher { - - private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) { - int distance; -- try { -- int jenkinsBuild = Integer.parseInt(versionInfo); -- distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion()); -- } catch (NumberFormatException ignored) { -+ // Tuinity - we don't have jenkins setup - versionInfo = versionInfo.replace("\"", ""); - distance = fetchDistanceFromGitHub(repo, branch, versionInfo); -- } -+ // Tuinity - we don't have jenkins setup - - switch (distance) { - case -1: -diff --git a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java -index 5fdaefc128956581be4bb9b34199fd6410563991..8203524862c309bd52fd3a8a47b219aca570f0b1 100644 ---- a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java -+++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java -@@ -312,6 +312,7 @@ public final class PaperTickList extends ServerTickList { // extend to avo - toTick.tickState = STATE_SCHEDULED; - this.addToNotTickingReady(toTick); - } -+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - exec chunk tasks during world tick - } catch (final Throwable thr) { - // start copy from TickListServer // TODO check on update - CrashReport crashreport = CrashReport.forThrowable(thr, "Exception while ticking"); -diff --git a/src/main/java/com/tuinity/tuinity/chunk/PlayerChunkLoader.java b/src/main/java/com/tuinity/tuinity/chunk/PlayerChunkLoader.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d9bfe05d4f86229ed743113bfb0bbd983adb7e68 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/chunk/PlayerChunkLoader.java -@@ -0,0 +1,965 @@ -+package com.tuinity.tuinity.chunk; -+ -+import com.destroystokyo.paper.util.misc.PlayerAreaMap; -+import com.destroystokyo.paper.util.misc.PooledLinkedHashSets; -+import com.tuinity.tuinity.config.TuinityConfig; -+import com.tuinity.tuinity.util.CoordinateUtils; -+import com.tuinity.tuinity.util.TickThread; -+import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; -+import it.unimi.dsi.fastutil.objects.Reference2ObjectLinkedOpenHashMap; -+import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -+import net.minecraft.network.protocol.Packet; -+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; -+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; -+import net.minecraft.server.MCUtil; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.TicketType; -+import net.minecraft.util.Mth; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.chunk.LevelChunk; -+import java.util.ArrayDeque; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.TreeSet; -+import java.util.concurrent.atomic.AtomicInteger; -+ -+public final class PlayerChunkLoader { -+ -+ public static final int MIN_VIEW_DISTANCE = 2; -+ public static final int MAX_VIEW_DISTANCE = 32; -+ -+ public static final int TICK_TICKET_LEVEL = 31; -+ public static final int LOADED_TICKET_LEVEL = 33; -+ -+ protected final ChunkMap chunkMap; -+ protected final Reference2ObjectLinkedOpenHashMap playerMap = new Reference2ObjectLinkedOpenHashMap<>(512, 0.7f); -+ protected final ReferenceLinkedOpenHashSet chunkSendQueue = new ReferenceLinkedOpenHashSet<>(512, 0.7f); -+ -+ protected final TreeSet chunkLoadQueue = new TreeSet<>((final PlayerLoaderData p1, final PlayerLoaderData p2) -> { -+ if (p1 == p2) { -+ return 0; -+ } -+ -+ final ChunkPriorityHolder holder1 = p1.loadQueue.peekFirst(); -+ final ChunkPriorityHolder holder2 = p2.loadQueue.peekFirst(); -+ -+ final int priorityCompare = Double.compare(holder1 == null ? Double.MAX_VALUE : holder1.priority, holder2 == null ? Double.MAX_VALUE : holder2.priority); -+ -+ if (priorityCompare != 0) { -+ return priorityCompare; -+ } -+ -+ final int idCompare = Integer.compare(p1.player.getId(), p2.player.getId()); -+ -+ if (idCompare != 0) { -+ return idCompare; -+ } -+ -+ // last resort -+ return Integer.compare(System.identityHashCode(p1), System.identityHashCode(p2)); -+ }); -+ -+ protected final TreeSet chunkSendWaitQueue = new TreeSet<>((final PlayerLoaderData p1, final PlayerLoaderData p2) -> { -+ if (p1 == p2) { -+ return 0; -+ } -+ -+ final int timeCompare = Long.compare(p1.nextChunkSendTarget, p2.nextChunkSendTarget); -+ if (timeCompare != 0) { -+ return timeCompare; -+ } -+ -+ final int idCompare = Integer.compare(p1.player.getId(), p2.player.getId()); -+ -+ if (idCompare != 0) { -+ return idCompare; -+ } -+ -+ // last resort -+ return Integer.compare(System.identityHashCode(p1), System.identityHashCode(p2)); -+ }); -+ -+ -+ // no throttling is applied below this VD for loading -+ -+ /** -+ * The chunks to be sent to players, provided they're send-ready. Send-ready means the chunk and its 1 radius neighbours are loaded. -+ */ -+ public final PlayerAreaMap broadcastMap; -+ -+ /** -+ * The chunks to be brought up to send-ready status. Send-ready means the chunk and its 1 radius neighbours are loaded. -+ */ -+ public final PlayerAreaMap loadMap; -+ -+ /** -+ * Areamap used only to remove tickets for send-ready chunks. View distance is always + 1 of load view distance. Thus, -+ * this map is always representing the chunks we are actually going to load. -+ */ -+ public final PlayerAreaMap loadTicketCleanup; -+ -+ /** -+ * The chunks to brought to ticking level. Each chunk must have 2 radius neighbours loaded before this can happen. -+ */ -+ public final PlayerAreaMap tickMap; -+ -+ /** -+ * -1 if defaulting to [load distance], else always in [2, load distance] -+ */ -+ protected int rawSendDistance = -1; -+ -+ /** -+ * -1 if defaulting to [tick view distance + 1], else always in [tick view distance + 1, 32 + 1] -+ */ -+ protected int rawLoadDistance = -1; -+ -+ /** -+ * Never -1, always in [2, 32] -+ */ -+ protected int rawTickDistance = -1; -+ -+ // methods to bridge for API -+ -+ public int getTargetViewDistance() { -+ return this.getTickDistance(); -+ } -+ -+ public void setTargetViewDistance(final int distance) { -+ this.setTickDistance(distance); -+ } -+ -+ public int getTargetNoTickViewDistance() { -+ return this.getLoadDistance() - 1; -+ } -+ -+ public void setTargetNoTickViewDistance(final int distance) { -+ this.setLoadDistance(distance == -1 ? -1 : distance + 1); -+ } -+ -+ public int getTargetSendDistance() { -+ return this.rawSendDistance == -1 ? this.getLoadDistance() : this.rawSendDistance; -+ } -+ -+ public void setTargetSendDistance(final int distance) { -+ this.setSendDistance(distance); -+ } -+ -+ // internal methods -+ -+ public int getSendDistance() { -+ final int loadDistance = this.getLoadDistance(); -+ return this.rawSendDistance == -1 ? loadDistance : Math.min(this.rawSendDistance, loadDistance); -+ } -+ -+ public void setSendDistance(final int distance) { -+ if (distance != -1 && (distance < MIN_VIEW_DISTANCE || distance > MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ this.rawSendDistance = distance; -+ } -+ -+ public int getLoadDistance() { -+ final int tickDistance = this.getTickDistance(); -+ return this.rawLoadDistance == -1 ? tickDistance + 1 : Math.max(tickDistance + 1, this.rawLoadDistance); -+ } -+ -+ public void setLoadDistance(final int distance) { -+ if (distance != -1 && (distance < MIN_VIEW_DISTANCE || distance > MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ this.rawLoadDistance = distance; -+ } -+ -+ public int getTickDistance() { -+ return this.rawTickDistance; -+ } -+ -+ public void setTickDistance(final int distance) { -+ if (distance < MIN_VIEW_DISTANCE || distance > MAX_VIEW_DISTANCE) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ this.rawTickDistance = distance; -+ } -+ -+ /* -+ Players have 3 different types of view distance: -+ 1. Sending view distance -+ 2. Loading view distance -+ 3. Ticking view distance -+ -+ But for configuration purposes (and API) there are: -+ 1. No-tick view distance -+ 2. Tick view distance -+ 3. Broadcast view distance -+ -+ These aren't always the same as the types we represent internally. -+ -+ Loading view distance is always max(no-tick + 1, tick + 1) -+ - no-tick has 1 added because clients need an extra radius to render chunks -+ - tick has 1 added because it needs an extra radius of chunks to load before they can be marked ticking -+ -+ Loading view distance is defined as the radius of chunks that will be brought to send-ready status, which means -+ it loads chunks in radius load-view-distance + 1. -+ -+ The maximum value for send view distance is the load view distance. API can set it lower. -+ */ -+ -+ public PlayerChunkLoader(final ChunkMap chunkMap, final PooledLinkedHashSets pooledHashSets) { -+ this.chunkMap = chunkMap; -+ this.broadcastMap = new PlayerAreaMap(pooledHashSets, -+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -+ if (player.needsChunkCenterUpdate) { -+ player.needsChunkCenterUpdate = false; -+ player.connection.send(new ClientboundSetChunkCacheCenterPacket(currPosX, currPosZ)); -+ } -+ PlayerChunkLoader.this.onChunkEnter(player, rangeX, rangeZ); -+ }, -+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -+ PlayerChunkLoader.this.onChunkLeave(player, rangeX, rangeZ); -+ }); -+ this.loadMap = new PlayerAreaMap(pooledHashSets, -+ null, -+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -+ if (newState != null) { -+ return; -+ } -+ PlayerChunkLoader.this.isTargetedForPlayerLoad.remove(CoordinateUtils.getChunkKey(rangeX, rangeZ)); -+ }); -+ this.loadTicketCleanup = new PlayerAreaMap(pooledHashSets, -+ null, -+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -+ if (newState != null) { -+ return; -+ } -+ ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ); -+ PlayerChunkLoader.this.chunkMap.level.getChunkSource().removeTicketAtLevel(TicketType.PLAYER, chunkPos, LOADED_TICKET_LEVEL, chunkPos); -+ if (PlayerChunkLoader.this.chunkTicketTracker.remove(chunkPos.toLong())) { -+ --PlayerChunkLoader.this.concurrentChunkLoads; -+ } -+ }); -+ this.tickMap = new PlayerAreaMap(pooledHashSets, -+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -+ if (newState.size() != 1) { -+ return; -+ } -+ LevelChunk chunk = PlayerChunkLoader.this.chunkMap.level.getChunkSource().getChunkAtIfLoadedMainThreadNoCache(rangeX, rangeZ); -+ if (chunk == null || !chunk.areNeighboursLoaded(2)) { -+ return; -+ } -+ -+ ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ); -+ PlayerChunkLoader.this.chunkMap.level.getChunkSource().addTicketAtLevel(TicketType.PLAYER, chunkPos, TICK_TICKET_LEVEL, chunkPos); -+ }, -+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -+ if (newState != null) { -+ return; -+ } -+ ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ); -+ PlayerChunkLoader.this.chunkMap.level.getChunkSource().removeTicketAtLevel(TicketType.PLAYER, chunkPos, TICK_TICKET_LEVEL, chunkPos); -+ }); -+ } -+ -+ protected final LongOpenHashSet isTargetedForPlayerLoad = new LongOpenHashSet(); -+ protected final LongOpenHashSet chunkTicketTracker = new LongOpenHashSet(); -+ -+ // rets whether the chunk is at a loaded stage that is ready to be sent to players -+ public boolean isChunkPlayerLoaded(final int chunkX, final int chunkZ) { -+ final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ final ChunkHolder chunk = this.chunkMap.getVisibleChunkIfPresent(key); -+ -+ if (chunk == null) { -+ return false; -+ } -+ -+ return chunk.getSendingChunk() != null && this.isTargetedForPlayerLoad.contains(key); -+ } -+ -+ public boolean isChunkSent(final ServerPlayer player, final int chunkX, final int chunkZ) { -+ final PlayerLoaderData data = this.playerMap.get(player); -+ if (data == null) { -+ return false; -+ } -+ -+ return data.hasSentChunk(chunkX, chunkZ); -+ } -+ -+ protected int getMaxConcurrentChunkSends() { -+ double config = TuinityConfig.playerMaxConcurrentChunkSends; -+ return Math.max(1, config <= 0 ? (int)Math.ceil(-config * this.chunkMap.level.players().size()) : (int)config); -+ } -+ -+ protected int getMaxChunkLoads() { -+ double config = TuinityConfig.playerMaxConcurrentChunkLoads; -+ return Math.max(1, (config <= 0 ? (int)Math.ceil(-config * MinecraftServer.getServer().getPlayerCount()) : (int)config) * 9); -+ } -+ -+ protected double getTargetSendRatePerPlayer() { -+ double config = TuinityConfig.playerTargetChunkSendRate; -+ return config <= 0 ? -config : config / MinecraftServer.getServer().getPlayerCount(); -+ } -+ -+ public void onChunkPlayerTickReady(final int chunkX, final int chunkZ) { -+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ this.chunkMap.level.getChunkSource().addTicketAtLevel(TicketType.PLAYER, chunkPos, TICK_TICKET_LEVEL, chunkPos); -+ } -+ -+ public void onChunkSendReady(final int chunkX, final int chunkZ) { -+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ -+ final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersInSendRange = this.broadcastMap.getObjectsInRange(chunkX, chunkZ); -+ -+ if (playersInSendRange == null) { -+ return; -+ } -+ -+ final Object[] rawData = playersInSendRange.getBackingSet(); -+ for (int i = 0, len = rawData.length; i < len; ++i) { -+ final Object raw = rawData[i]; -+ -+ if (!(raw instanceof ServerPlayer)) { -+ continue; -+ } -+ this.onChunkEnter((ServerPlayer)raw, chunkX, chunkZ); -+ } -+ -+ // now let's try and queue mid tick logic again -+ } -+ -+ public void onChunkEnter(final ServerPlayer player, final int chunkX, final int chunkZ) { -+ final PlayerLoaderData data = this.playerMap.get(player); -+ -+ if (data == null) { -+ return; -+ } -+ -+ if (data.hasSentChunk(chunkX, chunkZ) || !this.isChunkPlayerLoaded(chunkX, chunkZ)) { -+ // if we don't have player tickets, then the load logic will pick this up and queue to send -+ return; -+ } -+ -+ final long playerPos = this.broadcastMap.getLastCoordinate(player); -+ final int playerChunkX = CoordinateUtils.getChunkX(playerPos); -+ final int playerChunkZ = CoordinateUtils.getChunkZ(playerPos); -+ final int manhattanDistance = Math.abs(playerChunkX - chunkX) + Math.abs(playerChunkZ - chunkZ); -+ -+ final ChunkPriorityHolder holder = new ChunkPriorityHolder(chunkX, chunkZ, manhattanDistance, 0.0); -+ data.sendQueue.add(holder); -+ } -+ -+ public void onChunkLoad(final int chunkX, final int chunkZ) { -+ if (this.chunkTicketTracker.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ --this.concurrentChunkLoads; -+ } -+ } -+ -+ public void onChunkLeave(final ServerPlayer player, final int chunkX, final int chunkZ) { -+ final PlayerLoaderData data = this.playerMap.get(player); -+ -+ if (data == null) { -+ return; -+ } -+ -+ data.unloadChunk(chunkX, chunkZ); -+ } -+ -+ public void addPlayer(final ServerPlayer player) { -+ TickThread.ensureTickThread("Cannot add player async"); -+ if (!player.isRealPlayer) { -+ return; -+ } -+ final PlayerLoaderData data = new PlayerLoaderData(player, this); -+ if (this.playerMap.putIfAbsent(player, data) == null) { -+ data.update(); -+ } -+ } -+ -+ public void removePlayer(final ServerPlayer player) { -+ TickThread.ensureTickThread("Cannot remove player async"); -+ if (!player.isRealPlayer) { -+ return; -+ } -+ -+ final PlayerLoaderData loaderData = this.playerMap.remove(player); -+ if (loaderData == null) { -+ return; -+ } -+ loaderData.remove(); -+ this.chunkLoadQueue.remove(loaderData); -+ this.chunkSendQueue.remove(loaderData); -+ this.chunkSendWaitQueue.remove(loaderData); -+ synchronized (this.sendingChunkCounts) { -+ final int count = this.sendingChunkCounts.removeInt(loaderData); -+ if (count != 0) { -+ concurrentChunkSends.getAndAdd(-count); -+ } -+ } -+ } -+ -+ public void updatePlayer(final ServerPlayer player) { -+ TickThread.ensureTickThread("Cannot update player async"); -+ if (!player.isRealPlayer) { -+ return; -+ } -+ final PlayerLoaderData loaderData = this.playerMap.get(player); -+ if (loaderData != null) { -+ loaderData.update(); -+ } -+ } -+ -+ public PlayerLoaderData getData(final ServerPlayer player) { -+ return this.playerMap.get(player); -+ } -+ -+ public void tick() { -+ TickThread.ensureTickThread("Cannot tick async"); -+ for (final PlayerLoaderData data : this.playerMap.values()) { -+ data.update(); -+ } -+ this.tickMidTick(); -+ } -+ -+ protected static final AtomicInteger concurrentChunkSends = new AtomicInteger(); -+ protected final Reference2IntOpenHashMap sendingChunkCounts = new Reference2IntOpenHashMap<>(); -+ private void trySendChunks() { -+ final long time = System.nanoTime(); -+ // drain entries from wait queue -+ while (!this.chunkSendWaitQueue.isEmpty()) { -+ final PlayerLoaderData data = this.chunkSendWaitQueue.first(); -+ -+ if (data.nextChunkSendTarget > time) { -+ break; -+ } -+ -+ this.chunkSendWaitQueue.pollFirst(); -+ -+ this.chunkSendQueue.add(data); -+ } -+ -+ if (this.chunkSendQueue.isEmpty()) { -+ return; -+ } -+ -+ final int maxSends = this.getMaxConcurrentChunkSends(); -+ final double sendRate = this.getTargetSendRatePerPlayer(); -+ final long nextDeadline = (long)((1 / sendRate) * 1.0e9) + time; -+ for (;;) { -+ if (this.chunkSendQueue.isEmpty()) { -+ break; -+ } -+ final int currSends = concurrentChunkSends.get(); -+ if (currSends >= maxSends) { -+ break; -+ } -+ -+ if (!concurrentChunkSends.compareAndSet(currSends, currSends + 1)) { -+ continue; -+ } -+ -+ // send chunk -+ -+ final PlayerLoaderData data = this.chunkSendQueue.removeFirst(); -+ -+ final ChunkPriorityHolder queuedSend = data.sendQueue.pollFirst(); -+ if (queuedSend == null) { -+ concurrentChunkSends.getAndDecrement(); // we never sent, so decrease -+ // stop iterating over players who have nothing to send -+ if (this.chunkSendQueue.isEmpty()) { -+ // nothing left -+ break; -+ } -+ continue; -+ } -+ -+ if (!this.isChunkPlayerLoaded(queuedSend.chunkX, queuedSend.chunkZ)) { -+ throw new IllegalStateException(); -+ } -+ -+ data.nextChunkSendTarget = nextDeadline; -+ this.chunkSendWaitQueue.add(data); -+ -+ synchronized (this.sendingChunkCounts) { -+ this.sendingChunkCounts.addTo(data, 1); -+ } -+ -+ data.sendChunk(queuedSend.chunkX, queuedSend.chunkZ, () -> { -+ synchronized (this.sendingChunkCounts) { -+ final int count = this.sendingChunkCounts.getInt(data); -+ if (count == 0) { -+ // disconnected, so we don't need to decrement: it will be decremented for us -+ return; -+ } -+ if (count == 1) { -+ this.sendingChunkCounts.removeInt(data); -+ } else { -+ this.sendingChunkCounts.put(data, count - 1); -+ } -+ } -+ -+ concurrentChunkSends.getAndDecrement(); -+ }); -+ } -+ } -+ -+ protected int concurrentChunkLoads; -+ private void tryLoadChunks() { -+ if (this.chunkLoadQueue.isEmpty()) { -+ return; -+ } -+ -+ final int maxLoads = this.getMaxChunkLoads(); -+ for (;;) { -+ final PlayerLoaderData data = this.chunkLoadQueue.pollFirst(); -+ -+ final ChunkPriorityHolder queuedLoad = data.loadQueue.peekFirst(); -+ if (queuedLoad == null) { -+ if (this.chunkLoadQueue.isEmpty()) { -+ break; -+ } -+ continue; -+ } -+ -+ if (this.isChunkPlayerLoaded(queuedLoad.chunkX, queuedLoad.chunkZ)) { -+ // already loaded! -+ data.loadQueue.pollFirst(); // already loaded so we just skip -+ this.chunkLoadQueue.add(data); -+ -+ // ensure the chunk is queued to send -+ this.onChunkSendReady(queuedLoad.chunkX, queuedLoad.chunkZ); -+ continue; -+ } -+ -+ final long chunkKey = CoordinateUtils.getChunkKey(queuedLoad.chunkX, queuedLoad.chunkZ); -+ -+ final double priority = queuedLoad.priority; -+ // while we do need to rate limit chunk loads, the logic for sending chunks requires that tickets are present. -+ // when chunks are loaded (i.e spawn) but do not have this player's tickets, they have to wait behind the -+ // load queue. To avoid this problem, we check early here if tickets are required to load the chunk - if they -+ // aren't required, it bypasses the limiter system. -+ boolean unloadedTargetChunk = false; -+ unloaded_check: -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ final int offX = queuedLoad.chunkX + dx; -+ final int offZ = queuedLoad.chunkZ + dz; -+ if (this.chunkMap.level.getChunkSource().getChunkAtIfLoadedMainThreadNoCache(offX, offZ) == null) { -+ unloadedTargetChunk = true; -+ break unloaded_check; -+ } -+ } -+ } -+ if (unloadedTargetChunk && priority > 0.0) { -+ // priority > 0.0 implies rate limited chunks -+ -+ final int currentChunkLoads = this.concurrentChunkLoads; -+ if (currentChunkLoads >= maxLoads) { -+ // don't poll, we didn't load it -+ this.chunkLoadQueue.add(data); -+ break; -+ } -+ } -+ -+ // can only poll after we decide to load -+ data.loadQueue.pollFirst(); -+ -+ // now that we've polled we can re-add to load queue -+ this.chunkLoadQueue.add(data); -+ -+ // add necessary tickets to load chunk up to send-ready -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ final int offX = queuedLoad.chunkX + dx; -+ final int offZ = queuedLoad.chunkZ + dz; -+ final ChunkPos chunkPos = new ChunkPos(offX, offZ); -+ -+ this.chunkMap.level.getChunkSource().addTicketAtLevel(TicketType.PLAYER, chunkPos, LOADED_TICKET_LEVEL, chunkPos); -+ if (this.chunkMap.level.getChunkSource().getChunkAtIfLoadedMainThreadNoCache(offX, offZ) != null) { -+ continue; -+ } -+ -+ if (priority > 0.0 && this.chunkTicketTracker.add(CoordinateUtils.getChunkKey(offX, offZ))) { -+ // wont reach here if unloadedTargetChunk is false -+ ++this.concurrentChunkLoads; -+ } -+ } -+ } -+ -+ // mark that we've added tickets here -+ this.isTargetedForPlayerLoad.add(chunkKey); -+ -+ // it's possible all we needed was the player tickets to queue up the send. -+ if (this.isChunkPlayerLoaded(queuedLoad.chunkX, queuedLoad.chunkZ)) { -+ // yup, all we needed. -+ this.onChunkSendReady(queuedLoad.chunkX, queuedLoad.chunkZ); -+ } -+ } -+ } -+ -+ public void tickMidTick() { -+ // try to send more chunks -+ this.trySendChunks(); -+ -+ // try to queue more chunks to load -+ this.tryLoadChunks(); -+ } -+ -+ static final class ChunkPriorityHolder { -+ public final int chunkX; -+ public final int chunkZ; -+ public final int manhattanDistanceToPlayer; -+ public final double priority; -+ -+ public ChunkPriorityHolder(final int chunkX, final int chunkZ, final int manhattanDistanceToPlayer, final double priority) { -+ this.chunkX = chunkX; -+ this.chunkZ = chunkZ; -+ this.manhattanDistanceToPlayer = manhattanDistanceToPlayer; -+ this.priority = priority; -+ } -+ } -+ -+ public static final class PlayerLoaderData { -+ -+ protected static final float FOV = 110.0f; -+ protected static final double PRIORITISED_DISTANCE = 12.0 * 16.0; -+ -+ // Player max sprint speed is approximately 8m/s -+ protected static final double LOOK_PRIORITY_SPEED_THRESHOLD = (10.0/20.0) * (10.0/20.0); -+ protected static final double LOOK_PRIORITY_YAW_DELTA_RECALC_THRESHOLD = 3.0f; -+ -+ protected double lastLocX = Double.NEGATIVE_INFINITY; -+ protected double lastLocZ = Double.NEGATIVE_INFINITY; -+ -+ protected int lastChunkX; -+ protected int lastChunkZ; -+ -+ // this is corrected so that 0 is along the positive x-axis -+ protected float lastYaw = Float.NEGATIVE_INFINITY; -+ -+ protected int lastSendDistance = Integer.MIN_VALUE; -+ protected int lastLoadDistance = Integer.MIN_VALUE; -+ protected int lastTickDistance = Integer.MIN_VALUE; -+ protected boolean usingLookingPriority; -+ -+ protected final ServerPlayer player; -+ protected final PlayerChunkLoader loader; -+ -+ // warning: modifications of this field must be aware that the loadQueue inside PlayerChunkLoader uses this field -+ // in a comparator! -+ protected final ArrayDeque loadQueue = new ArrayDeque<>(); -+ protected final LongOpenHashSet sentChunks = new LongOpenHashSet(); -+ -+ protected final TreeSet sendQueue = new TreeSet<>((final ChunkPriorityHolder p1, final ChunkPriorityHolder p2) -> { -+ final int distanceCompare = Integer.compare(p1.manhattanDistanceToPlayer, p2.manhattanDistanceToPlayer); -+ if (distanceCompare != 0) { -+ return distanceCompare; -+ } -+ -+ final int coordinateXCompare = Integer.compare(p1.chunkX, p2.chunkX); -+ if (coordinateXCompare != 0) { -+ return coordinateXCompare; -+ } -+ -+ return Integer.compare(p1.chunkZ, p2.chunkZ); -+ }); -+ -+ protected int sendViewDistance = -1; -+ protected int loadViewDistance = -1; -+ protected int tickViewDistance = -1; -+ -+ protected long nextChunkSendTarget; -+ -+ public PlayerLoaderData(final ServerPlayer player, final PlayerChunkLoader loader) { -+ this.player = player; -+ this.loader = loader; -+ } -+ -+ // these view distance methods are for api -+ public int getTargetSendViewDistance() { -+ final int tickViewDistance = this.tickViewDistance == -1 ? this.loader.getTickDistance() : this.tickViewDistance; -+ final int loadViewDistance = Math.max(tickViewDistance + 1, this.loadViewDistance == -1 ? this.loader.getLoadDistance() : this.loadViewDistance); -+ final int clientViewDistance = this.getClientViewDistance(); -+ final int sendViewDistance = Math.min(loadViewDistance, this.sendViewDistance == -1 ? (!TuinityConfig.playerAutoConfigureSendViewDistance || clientViewDistance == -1 ? this.loader.getSendDistance() : clientViewDistance + 1) : this.sendViewDistance); -+ return sendViewDistance; -+ } -+ -+ public void setTargetSendViewDistance(final int distance) { -+ if (distance != -1 && (distance < MIN_VIEW_DISTANCE || distance > MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ this.sendViewDistance = distance; -+ } -+ -+ public int getTargetNoTickViewDistance() { -+ return (this.loadViewDistance == -1 ? this.getLoadDistance() : this.loadViewDistance) - 1; -+ } -+ -+ public void setTargetNoTickViewDistance(final int distance) { -+ if (distance != -1 && (distance < MIN_VIEW_DISTANCE || distance > MAX_VIEW_DISTANCE)) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ this.loadViewDistance = distance == -1 ? -1 : distance + 1; -+ } -+ -+ public int getTargetTickViewDistance() { -+ return this.tickViewDistance == -1 ? this.loader.getTickDistance() : this.tickViewDistance; -+ } -+ -+ public void setTargetTickViewDistance(final int distance) { -+ if (distance < MIN_VIEW_DISTANCE || distance > MAX_VIEW_DISTANCE) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ this.tickViewDistance = distance; -+ } -+ -+ protected int getLoadDistance() { -+ final int tickViewDistance = this.tickViewDistance == -1 ? this.loader.getTickDistance() : this.tickViewDistance; -+ -+ return Math.max(tickViewDistance + 1, this.loadViewDistance == -1 ? this.loader.getLoadDistance() : this.loadViewDistance); -+ } -+ -+ public boolean hasSentChunk(final int chunkX, final int chunkZ) { -+ return this.sentChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ } -+ -+ public void sendChunk(final int chunkX, final int chunkZ, final Runnable onChunkSend) { -+ if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ this.player.getLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, -+ new ChunkPos(chunkX, chunkZ), new Packet[2], false, true); // unloaded, loaded -+ this.player.connection.connection.execute(onChunkSend); -+ } else { -+ throw new IllegalStateException(); -+ } -+ } -+ -+ public void unloadChunk(final int chunkX, final int chunkZ) { -+ if (this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ this.player.getLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, -+ new ChunkPos(chunkX, chunkZ), null, true, false); // unloaded, loaded -+ } -+ } -+ -+ protected static boolean triangleIntersects(final double p1x, final double p1z, // triangle point -+ final double p2x, final double p2z, // triangle point -+ final double p3x, final double p3z, // triangle point -+ -+ final double targetX, final double targetZ) { // point -+ // from barycentric coordinates: -+ // targetX = a*p1x + b*p2x + c*p3x -+ // targetZ = a*p1z + b*p2z + c*p3z -+ // 1.0 = a*1.0 + b*1.0 + c*1.0 -+ // where a, b, c >= 0.0 -+ // so, if any of a, b, c are less-than zero then there is no intersection. -+ -+ // d = ((p2z - p3z)(p1x - p3x) + (p3x - p2x)(p1z - p3z)) -+ // a = ((p2z - p3z)(targetX - p3x) + (p3x - p2x)(targetZ - p3z)) / d -+ // b = ((p3z - p1z)(targetX - p3x) + (p1x - p3x)(targetZ - p3z)) / d -+ // c = 1.0 - a - b -+ -+ final double d = (p2z - p3z)*(p1x - p3x) + (p3x - p2x)*(p1z - p3z); -+ final double a = ((p2z - p3z)*(targetX - p3x) + (p3x - p2x)*(targetZ - p3z)) / d; -+ -+ if (a < 0.0 || a > 1.0) { -+ return false; -+ } -+ -+ final double b = ((p3z - p1z)*(targetX - p3x) + (p1x - p3x)*(targetZ - p3z)) / d; -+ if (b < 0.0 || b > 1.0) { -+ return false; -+ } -+ -+ final double c = 1.0 - a - b; -+ -+ return c >= 0.0 && c <= 1.0; -+ } -+ -+ public void remove() { -+ this.loader.broadcastMap.remove(this.player); -+ this.loader.loadMap.remove(this.player); -+ this.loader.loadTicketCleanup.remove(this.player); -+ this.loader.tickMap.remove(this.player); -+ } -+ -+ protected int getClientViewDistance() { -+ return this.player.clientViewDistance == null ? -1 : this.player.clientViewDistance.intValue(); -+ } -+ -+ public void update() { -+ final int tickViewDistance = this.tickViewDistance == -1 ? this.loader.getTickDistance() : this.tickViewDistance; -+ // load view cannot be less-than tick view + 1 -+ final int loadViewDistance = Math.max(tickViewDistance + 1, this.loadViewDistance == -1 ? this.loader.getLoadDistance() : this.loadViewDistance); -+ // send view cannot be greater-than load view -+ final int clientViewDistance = this.getClientViewDistance(); -+ final int sendViewDistance = Math.min(loadViewDistance, this.sendViewDistance == -1 ? (!TuinityConfig.playerAutoConfigureSendViewDistance || clientViewDistance == -1 ? this.loader.getSendDistance() : clientViewDistance + 1) : this.sendViewDistance); -+ -+ final double posX = this.player.getX(); -+ final double posZ = this.player.getZ(); -+ final float yaw = MCUtil.normalizeYaw(this.player.yRot + 90.0f); // mc yaw 0 is along the positive z axis, but obviously this is really dumb - offset so we are at positive x-axis -+ -+ // in general, we really only want to prioritise chunks in front if we know we're moving pretty fast into them. -+ final boolean useLookPriority = TuinityConfig.playerFrustumPrioritisation && (this.player.getDeltaMovement().horizontalDistanceSqr() > LOOK_PRIORITY_SPEED_THRESHOLD || -+ this.player.getAbilities().flying); -+ -+ // make sure we're in the send queue -+ this.loader.chunkSendWaitQueue.add(this); -+ -+ if ( -+ // has view distance stayed the same? -+ sendViewDistance == this.lastSendDistance -+ && loadViewDistance == this.lastLoadDistance -+ && tickViewDistance == this.lastTickDistance -+ -+ && (this.usingLookingPriority ? ( -+ // has our block stayed the same (this also accounts for chunk change)? -+ Mth.floor(this.lastLocX) == Mth.floor(posX) -+ && Mth.floor(this.lastLocZ) == Mth.floor(posZ) -+ ) : ( -+ // has our chunk stayed the same -+ (Mth.floor(this.lastLocX) >> 4) == (Mth.floor(posX) >> 4) -+ && (Mth.floor(this.lastLocZ) >> 4) == (Mth.floor(posZ) >> 4) -+ )) -+ -+ // has our decision about look priority changed? -+ && this.usingLookingPriority == useLookPriority -+ -+ // if we are currently using look priority, has our yaw stayed within recalc threshold? -+ && (!this.usingLookingPriority || Math.abs(yaw - this.lastYaw) <= LOOK_PRIORITY_YAW_DELTA_RECALC_THRESHOLD) -+ ) { -+ // nothing we care about changed, so we're not re-calculating -+ return; -+ } -+ -+ final int centerChunkX = Mth.floor(posX) >> 4; -+ final int centerChunkZ = Mth.floor(posZ) >> 4; -+ -+ this.player.needsChunkCenterUpdate = true; -+ this.loader.broadcastMap.addOrUpdate(this.player, centerChunkX, centerChunkZ, sendViewDistance); -+ this.player.needsChunkCenterUpdate = false; -+ this.loader.loadMap.addOrUpdate(this.player, centerChunkX, centerChunkZ, loadViewDistance); -+ this.loader.loadTicketCleanup.addOrUpdate(this.player, centerChunkX, centerChunkZ, loadViewDistance + 1); -+ this.loader.tickMap.addOrUpdate(this.player, centerChunkX, centerChunkZ, tickViewDistance); -+ -+ if (sendViewDistance != this.lastSendDistance) { -+ // update the view radius for client -+ // note that this should be after the map calls because the client wont expect unload calls not in its VD -+ // and it's possible we decreased VD here -+ this.player.connection.send(new ClientboundSetChunkCacheRadiusPacket(sendViewDistance - 1)); // client already expects the 1 radius neighbours, so subtract 1. -+ } -+ -+ this.lastLocX = posX; -+ this.lastLocZ = posZ; -+ this.lastYaw = yaw; -+ this.lastSendDistance = sendViewDistance; -+ this.lastLoadDistance = loadViewDistance; -+ this.lastTickDistance = tickViewDistance; -+ this.usingLookingPriority = useLookPriority; -+ -+ this.lastChunkX = centerChunkX; -+ this.lastChunkZ = centerChunkZ; -+ -+ // points for player "view" triangle: -+ -+ // obviously, the player pos is a vertex -+ final double p1x = posX; -+ final double p1z = posZ; -+ -+ // to the left of the looking direction -+ final double p2x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw + (double)(FOV / 2.0))) // calculate rotated vector -+ + p1x; // offset vector -+ final double p2z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw + (double)(FOV / 2.0))) // calculate rotated vector -+ + p1z; // offset vector -+ -+ // to the right of the looking direction -+ final double p3x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw - (double)(FOV / 2.0))) // calculate rotated vector -+ + p1x; // offset vector -+ final double p3z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw - (double)(FOV / 2.0))) // calculate rotated vector -+ + p1z; // offset vector -+ -+ // now that we have all of our points, we can recalculate the load queue -+ -+ final List loadQueue = new ArrayList<>(); -+ -+ // clear send queue, we are re-sorting -+ this.sendQueue.clear(); -+ -+ final int searchViewDistance = Math.max(loadViewDistance, sendViewDistance); -+ -+ for (int dx = -searchViewDistance; dx <= searchViewDistance; ++dx) { -+ for (int dz = -searchViewDistance; dz <= searchViewDistance; ++dz) { -+ final int chunkX = dx + centerChunkX; -+ final int chunkZ = dz + centerChunkZ; -+ final int squareDistance = Math.max(Math.abs(dx), Math.abs(dz)); -+ -+ if (this.hasSentChunk(chunkX, chunkZ)) { -+ // already sent (which means it is also loaded) -+ continue; -+ } -+ -+ final boolean loadChunk = squareDistance <= loadViewDistance; -+ final boolean sendChunk = squareDistance <= sendViewDistance; -+ -+ final boolean prioritised = useLookPriority && triangleIntersects( -+ // prioritisation triangle -+ p1x, p1z, p2x, p2z, p3x, p3z, -+ -+ // center of chunk -+ (double)((chunkX << 4) | 8), (double)((chunkZ << 4) | 8) -+ ); -+ -+ -+ final int manhattanDistance = (Math.abs(dx) + Math.abs(dz)); -+ -+ final double priority; -+ -+ if (squareDistance <= TuinityConfig.playerMinChunkLoadRadius) { -+ // priority should be negative, and we also want to order it from center outwards -+ // so we want (0,0) to be the smallest, and (minLoadedRadius,minLoadedRadius) to be the greatest -+ priority = -((2 * TuinityConfig.playerMinChunkLoadRadius + 1) - (dx + dz)); -+ } else { -+ if (prioritised) { -+ // we don't prioritise these chunks above others because we also want to make sure some chunks -+ // will be loaded if the player changes direction -+ priority = (double)manhattanDistance / 6.0; -+ } else { -+ priority = (double)manhattanDistance; -+ } -+ } -+ -+ final ChunkPriorityHolder holder = new ChunkPriorityHolder(chunkX, chunkZ, manhattanDistance, priority); -+ -+ if (!this.loader.isChunkPlayerLoaded(chunkX, chunkZ)) { -+ if (loadChunk) { -+ loadQueue.add(holder); -+ } -+ } else { -+ // loaded but not sent: so queue it! -+ if (sendChunk) { -+ this.sendQueue.add(holder); -+ } -+ } -+ } -+ } -+ -+ loadQueue.sort((final ChunkPriorityHolder p1, final ChunkPriorityHolder p2) -> { -+ return Double.compare(p1.priority, p2.priority); -+ }); -+ -+ // we're modifying loadQueue, must remove -+ this.loader.chunkLoadQueue.remove(this); -+ -+ this.loadQueue.clear(); -+ this.loadQueue.addAll(loadQueue); -+ -+ // must re-add -+ this.loader.chunkLoadQueue.add(this); -+ } -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/chunk/SingleThreadChunkRegionManager.java b/src/main/java/com/tuinity/tuinity/chunk/SingleThreadChunkRegionManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..49dc783a312ed62415d28cdd801dad6a96f3cc16 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/chunk/SingleThreadChunkRegionManager.java -@@ -0,0 +1,477 @@ -+package com.tuinity.tuinity.chunk; -+ -+import com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet; -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -+import net.minecraft.server.MCUtil; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.level.ChunkPos; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Iterator; -+import java.util.List; -+import java.util.function.Supplier; -+ -+public final class SingleThreadChunkRegionManager { -+ -+ protected final int regionSectionMergeRadius; -+ protected final int regionSectionChunkSize; -+ public final int regionChunkShift; // log2(REGION_CHUNK_SIZE) -+ -+ public final ServerLevel world; -+ public final String name; -+ -+ protected final Long2ObjectOpenHashMap regionsBySection = new Long2ObjectOpenHashMap<>(); -+ protected final ReferenceLinkedOpenHashSet needsRecalculation = new ReferenceLinkedOpenHashSet<>(); -+ protected final int minSectionRecalcCount; -+ protected final double maxDeadRegionPercent; -+ protected final Supplier regionDataSupplier; -+ protected final Supplier regionSectionDataSupplier; -+ -+ public SingleThreadChunkRegionManager(final ServerLevel world, final int minSectionRecalcCount, -+ final double maxDeadRegionPercent, final int sectionMergeRadius, -+ final int regionSectionChunkShift, -+ final String name, final Supplier regionDataSupplier, -+ final Supplier regionSectionDataSupplier) { -+ this.regionSectionMergeRadius = sectionMergeRadius; -+ this.regionSectionChunkSize = 1 << regionSectionChunkShift; -+ this.regionChunkShift = regionSectionChunkShift; -+ this.world = world; -+ this.name = name; -+ this.minSectionRecalcCount = Math.max(2, minSectionRecalcCount); -+ this.maxDeadRegionPercent = maxDeadRegionPercent; -+ this.regionDataSupplier = regionDataSupplier; -+ this.regionSectionDataSupplier = regionSectionDataSupplier; -+ } -+ -+ // tested via https://gist.github.com/Spottedleaf/aa7ade3451c37b4cac061fc77074db2f -+ -+ /* -+ protected void check() { -+ ReferenceOpenHashSet> checked = new ReferenceOpenHashSet<>(); -+ -+ for (RegionSection section : this.regionsBySection.values()) { -+ if (!checked.add(section.region)) { -+ section.region.check(); -+ } -+ } -+ for (Region region : this.needsRecalculation) { -+ region.check(); -+ } -+ } -+ */ -+ -+ protected void addToRecalcQueue(final Region region) { -+ this.needsRecalculation.add(region); -+ } -+ -+ protected void removeFromRecalcQueue(final Region region) { -+ this.needsRecalculation.remove(region); -+ } -+ -+ public RegionSection getRegionSection(final int chunkX, final int chunkZ) { -+ return this.regionsBySection.get(MCUtil.getCoordinateKey(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift)); -+ } -+ -+ public Region getRegion(final int chunkX, final int chunkZ) { -+ final RegionSection section = this.regionsBySection.get(MCUtil.getCoordinateKey(chunkX >> regionChunkShift, chunkZ >> regionChunkShift)); -+ return section != null ? section.region : null; -+ } -+ -+ private final List toMerge = new ArrayList<>(); -+ -+ protected RegionSection getOrCreateAndMergeSection(final int sectionX, final int sectionZ, final RegionSection force) { -+ final long sectionKey = MCUtil.getCoordinateKey(sectionX, sectionZ); -+ -+ if (force == null) { -+ RegionSection region = this.regionsBySection.get(sectionKey); -+ if (region != null) { -+ return region; -+ } -+ } -+ -+ int mergeCandidateSectionSize = -1; -+ Region mergeIntoCandidate = null; -+ -+ // find optimal candidate to merge into -+ -+ final int minX = sectionX - this.regionSectionMergeRadius; -+ final int maxX = sectionX + this.regionSectionMergeRadius; -+ final int minZ = sectionZ - this.regionSectionMergeRadius; -+ final int maxZ = sectionZ + this.regionSectionMergeRadius; -+ for (int currX = minX; currX <= maxX; ++currX) { -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ final RegionSection section = this.regionsBySection.get(MCUtil.getCoordinateKey(currX, currZ)); -+ if (section == null) { -+ continue; -+ } -+ final Region region = section.region; -+ if (region.dead) { -+ throw new IllegalStateException("Dead region should not be in live region manager state: " + region); -+ } -+ final int sections = region.sections.size(); -+ -+ if (sections > mergeCandidateSectionSize) { -+ mergeCandidateSectionSize = sections; -+ mergeIntoCandidate = region; -+ } -+ this.toMerge.add(region); -+ } -+ } -+ -+ // merge -+ if (mergeIntoCandidate != null) { -+ for (int i = 0; i < this.toMerge.size(); ++i) { -+ final Region region = this.toMerge.get(i); -+ if (region.dead || mergeIntoCandidate == region) { -+ continue; -+ } -+ region.mergeInto(mergeIntoCandidate); -+ } -+ this.toMerge.clear(); -+ } else { -+ mergeIntoCandidate = new Region(this); -+ } -+ -+ final RegionSection section; -+ if (force == null) { -+ this.regionsBySection.put(sectionKey, section = new RegionSection(sectionKey, this)); -+ } else { -+ final RegionSection existing = this.regionsBySection.putIfAbsent(sectionKey, force); -+ if (existing != null) { -+ throw new IllegalStateException("Attempting to override section '" + existing.toStringWithRegion() + -+ ", with " + force.toStringWithRegion()); -+ } -+ -+ section = force; -+ } -+ -+ mergeIntoCandidate.addRegionSection(section); -+ //mergeIntoCandidate.check(); -+ //this.check(); -+ -+ return section; -+ } -+ -+ public void addChunk(final int chunkX, final int chunkZ) { -+ this.getOrCreateAndMergeSection(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift, null).addChunk(chunkX, chunkZ); -+ } -+ -+ public void removeChunk(final int chunkX, final int chunkZ) { -+ final RegionSection section = this.regionsBySection.get( -+ MCUtil.getCoordinateKey(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift) -+ ); -+ if (section != null) { -+ section.removeChunk(chunkX, chunkZ); -+ } else { -+ throw new IllegalStateException("Cannot remove chunk at (" + chunkX + "," + chunkZ + ") from region state, section does not exist"); -+ } -+ } -+ -+ public void recalculateRegions() { -+ for (int i = 0, len = this.needsRecalculation.size(); i < len; ++i) { -+ final Region region = this.needsRecalculation.removeFirst(); -+ -+ this.recalculateRegion(region); -+ //this.check(); -+ } -+ } -+ -+ protected void recalculateRegion(final Region region) { -+ region.markedForRecalc = false; -+ //region.check(); -+ // clear unused regions -+ for (final Iterator iterator = region.deadSections.iterator(); iterator.hasNext();) { -+ final RegionSection deadSection = iterator.next(); -+ -+ if (deadSection.hasChunks()) { -+ throw new IllegalStateException("Dead section '" + deadSection.toStringWithRegion() + "' is marked dead but has chunks!"); -+ } -+ if (!region.removeRegionSection(deadSection)) { -+ throw new IllegalStateException("Region " + region + " has inconsistent state, it should contain section " + deadSection); -+ } -+ if (!this.regionsBySection.remove(deadSection.regionCoordinate, deadSection)) { -+ throw new IllegalStateException("Cannot remove dead section '" + -+ deadSection.toStringWithRegion() + "' from section state! State at section coordinate: " + -+ this.regionsBySection.get(deadSection.regionCoordinate)); -+ } -+ } -+ region.deadSections.clear(); -+ -+ // implicitly cover cases where size == 0 -+ if (region.sections.size() < this.minSectionRecalcCount) { -+ //region.check(); -+ return; -+ } -+ -+ // run a test to see if we actually need to recalculate -+ // TODO -+ -+ // destroy and rebuild the region -+ region.dead = true; -+ -+ // destroy region state -+ for (final Iterator iterator = region.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection aliveSection = iterator.next(); -+ if (!aliveSection.hasChunks()) { -+ throw new IllegalStateException("Alive section '" + aliveSection.toStringWithRegion() + "' has no chunks!"); -+ } -+ if (!this.regionsBySection.remove(aliveSection.regionCoordinate, aliveSection)) { -+ throw new IllegalStateException("Cannot remove alive section '" + -+ aliveSection.toStringWithRegion() + "' from section state! State at section coordinate: " + -+ this.regionsBySection.get(aliveSection.regionCoordinate)); -+ } -+ } -+ -+ // rebuild regions -+ for (final Iterator iterator = region.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection aliveSection = iterator.next(); -+ this.getOrCreateAndMergeSection(aliveSection.getSectionX(), aliveSection.getSectionZ(), aliveSection); -+ } -+ } -+ -+ public static final class Region { -+ protected final IteratorSafeOrderedReferenceSet sections = new IteratorSafeOrderedReferenceSet<>(); -+ protected final ReferenceOpenHashSet deadSections = new ReferenceOpenHashSet<>(16, 0.7f); -+ protected boolean dead; -+ protected boolean markedForRecalc; -+ -+ public final SingleThreadChunkRegionManager regionManager; -+ public final RegionData regionData; -+ -+ protected Region(final SingleThreadChunkRegionManager regionManager) { -+ this.regionManager = regionManager; -+ this.regionData = regionManager.regionDataSupplier.get(); -+ } -+ -+ public IteratorSafeOrderedReferenceSet.Iterator getSections() { -+ return this.sections.iterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); -+ } -+ -+ protected final double getDeadSectionPercent() { -+ return (double)this.deadSections.size() / (double)this.sections.size(); -+ } -+ -+ /* -+ protected void check() { -+ if (this.dead) { -+ throw new IllegalStateException("Dead region!"); -+ } -+ for (final Iterator> iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection section = iterator.next(); -+ if (section.region != this) { -+ throw new IllegalStateException("Region section must point to us!"); -+ } -+ if (this.regionManager.regionsBySection.get(section.regionCoordinate) != section) { -+ throw new IllegalStateException("Region section must match the regionmanager state!"); -+ } -+ } -+ } -+ */ -+ -+ // note: it is not true that the region at this point is not in any region. use the region field on the section -+ // to see if it is currently in another region. -+ protected final boolean addRegionSection(final RegionSection section) { -+ if (!this.sections.add(section)) { -+ return false; -+ } -+ -+ section.sectionData.addToRegion(section, section.region, this); -+ -+ section.region = this; -+ return true; -+ } -+ -+ protected final boolean removeRegionSection(final RegionSection section) { -+ if (!this.sections.remove(section)) { -+ return false; -+ } -+ -+ section.sectionData.removeFromRegion(section, this); -+ -+ return true; -+ } -+ -+ protected void mergeInto(final Region mergeTarget) { -+ if (this == mergeTarget) { -+ throw new IllegalStateException("Cannot merge a region onto itself"); -+ } -+ if (this.dead) { -+ throw new IllegalStateException("Source region is dead! Source " + this + ", target " + mergeTarget); -+ } else if (mergeTarget.dead) { -+ throw new IllegalStateException("Target region is dead! Source " + this + ", target " + mergeTarget); -+ } -+ this.dead = true; -+ if (this.markedForRecalc) { -+ this.regionManager.removeFromRecalcQueue(this); -+ } -+ -+ for (final Iterator iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection section = iterator.next(); -+ -+ if (!mergeTarget.addRegionSection(section)) { -+ throw new IllegalStateException("Target cannot contain source's sections! Source " + this + ", target " + mergeTarget); -+ } -+ } -+ -+ for (final RegionSection deadSection : this.deadSections) { -+ if (!this.sections.contains(deadSection)) { -+ throw new IllegalStateException("Source region does not even contain its own dead sections! Missing " + deadSection + " from region " + this); -+ } -+ mergeTarget.deadSections.add(deadSection); -+ } -+ //mergeTarget.check(); -+ } -+ -+ protected void markSectionAlive(final RegionSection section) { -+ this.deadSections.remove(section); -+ if (this.markedForRecalc && (this.sections.size() < this.regionManager.minSectionRecalcCount || this.getDeadSectionPercent() < this.regionManager.maxDeadRegionPercent)) { -+ this.regionManager.removeFromRecalcQueue(this); -+ this.markedForRecalc = false; -+ } -+ } -+ -+ protected void markSectionDead(final RegionSection section) { -+ this.deadSections.add(section); -+ if (!this.markedForRecalc && (this.sections.size() >= this.regionManager.minSectionRecalcCount || this.sections.size() == this.deadSections.size()) && this.getDeadSectionPercent() >= this.regionManager.maxDeadRegionPercent) { -+ this.regionManager.addToRecalcQueue(this); -+ this.markedForRecalc = true; -+ } -+ } -+ -+ @Override -+ public String toString() { -+ final StringBuilder ret = new StringBuilder(128); -+ -+ ret.append("Region{"); -+ ret.append("dead=").append(this.dead).append(','); -+ ret.append("markedForRecalc=").append(this.markedForRecalc).append(','); -+ -+ ret.append("sectionCount=").append(this.sections.size()).append(','); -+ ret.append("sections=["); -+ for (final Iterator iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection section = iterator.next(); -+ ret.append(section); -+ if (iterator.hasNext()) { -+ ret.append(','); -+ } -+ } -+ ret.append(']'); -+ -+ ret.append('}'); -+ return ret.toString(); -+ } -+ } -+ -+ public static final class RegionSection { -+ protected final long regionCoordinate; -+ protected final long[] chunksBitset; -+ protected int chunkCount; -+ protected Region region; -+ -+ public final SingleThreadChunkRegionManager regionManager; -+ public final RegionSectionData sectionData; -+ -+ protected RegionSection(final long regionCoordinate, final SingleThreadChunkRegionManager regionManager) { -+ this.regionCoordinate = regionCoordinate; -+ this.regionManager = regionManager; -+ this.chunksBitset = new long[Math.max(1, regionManager.regionSectionChunkSize * regionManager.regionSectionChunkSize / Long.SIZE)]; -+ this.sectionData = regionManager.regionSectionDataSupplier.get(); -+ } -+ -+ public int getSectionX() { -+ return MCUtil.getCoordinateX(this.regionCoordinate); -+ } -+ -+ public int getSectionZ() { -+ return MCUtil.getCoordinateZ(this.regionCoordinate); -+ } -+ -+ public Region getRegion() { -+ return this.region; -+ } -+ -+ private int getChunkIndex(final int chunkX, final int chunkZ) { -+ return (chunkX & (this.regionManager.regionSectionChunkSize - 1)) | ((chunkZ & (this.regionManager.regionSectionChunkSize - 1)) << this.regionManager.regionChunkShift); -+ } -+ -+ protected boolean hasChunks() { -+ return this.chunkCount != 0; -+ } -+ -+ protected void addChunk(final int chunkX, final int chunkZ) { -+ final int index = this.getChunkIndex(chunkX, chunkZ); -+ final long bitset = this.chunksBitset[index >>> 6]; // index / Long.SIZE -+ final long after = this.chunksBitset[index >>> 6] = bitset | (1L << (index & (Long.SIZE - 1))); -+ if (after == bitset) { -+ throw new IllegalStateException("Cannot add a chunk to a section which already has the chunk! RegionSection: " + this + ", global chunk: " + new ChunkPos(chunkX, chunkZ).toString()); -+ } -+ if (++this.chunkCount != 1) { -+ return; -+ } -+ this.region.markSectionAlive(this); -+ } -+ -+ protected void removeChunk(final int chunkX, final int chunkZ) { -+ final int index = this.getChunkIndex(chunkX, chunkZ); -+ final long before = this.chunksBitset[index >>> 6]; // index / Long.SIZE -+ final long bitset = this.chunksBitset[index >>> 6] = before & ~(1L << (index & (Long.SIZE - 1))); -+ if (before == bitset) { -+ throw new IllegalStateException("Cannot remove a chunk from a section which does not have that chunk! RegionSection: " + this + ", global chunk: " + new ChunkPos(chunkX, chunkZ).toString()); -+ } -+ if (--this.chunkCount != 0) { -+ return; -+ } -+ this.region.markSectionDead(this); -+ } -+ -+ @Override -+ public String toString() { -+ return "RegionSection{" + -+ "regionCoordinate=" + new ChunkPos(this.regionCoordinate).toString() + "," + -+ "chunkCount=" + this.chunkCount + "," + -+ "chunksBitset=" + toString(this.chunksBitset) + "," + -+ "hash=" + this.hashCode() + -+ "}"; -+ } -+ -+ public String toStringWithRegion() { -+ return "RegionSection{" + -+ "regionCoordinate=" + new ChunkPos(this.regionCoordinate).toString() + "," + -+ "chunkCount=" + this.chunkCount + "," + -+ "chunksBitset=" + toString(this.chunksBitset) + "," + -+ "hash=" + this.hashCode() + "," + -+ "region=" + this.region + -+ "}"; -+ } -+ -+ private static String toString(final long[] array) { -+ final StringBuilder ret = new StringBuilder(); -+ for (final long value : array) { -+ // zero pad the hex string -+ final char[] zeros = new char[Long.SIZE / 4]; -+ Arrays.fill(zeros, '0'); -+ final String string = Long.toHexString(value); -+ System.arraycopy(string.toCharArray(), 0, zeros, zeros.length - string.length(), string.length()); -+ -+ ret.append(zeros); -+ } -+ -+ return ret.toString(); -+ } -+ } -+ -+ public static interface RegionData { -+ -+ } -+ -+ public static interface RegionSectionData { -+ -+ public void removeFromRegion(final RegionSection section, final Region from); -+ -+ // removal from the old region is handled via removeFromRegion -+ public void addToRegion(final RegionSection section, final Region oldRegion, final Region newRegion); -+ -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java b/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7b437109a1da79a916f194a2802bef68eccc06ab ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java -@@ -0,0 +1,441 @@ -+package com.tuinity.tuinity.config; -+ -+import com.destroystokyo.paper.util.SneakyThrow; -+import io.papermc.paper.util.ObfHelper; -+import java.util.HashMap; -+import java.util.Map; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.Bukkit; -+import org.bukkit.configuration.ConfigurationSection; -+import org.bukkit.configuration.file.YamlConfiguration; -+import java.io.File; -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; -+import java.util.List; -+import java.util.logging.Level; -+ -+public final class TuinityConfig { -+ -+ public static final String CONFIG_HEADER = "Configuration file for Tuinity."; -+ public static final int CURRENT_CONFIG_VERSION = 2; -+ -+ private static final Object[] EMPTY = new Object[0]; -+ -+ private static File configFile; -+ public static YamlConfiguration config; -+ private static int configVersion; -+ public static boolean createWorldSections = true; -+ -+ public static void init(final File file) { -+ // TODO remove this in the future... -+ final File tuinityConfig = new File(file.getParent(), "tuinity.yml"); -+ if (!tuinityConfig.exists()) { -+ final File oldConfig = new File(file.getParent(), "concrete.yml"); -+ oldConfig.renameTo(tuinityConfig); -+ } -+ TuinityConfig.configFile = file; -+ final YamlConfiguration config = new YamlConfiguration(); -+ config.options().header(CONFIG_HEADER); -+ config.options().copyDefaults(true); -+ -+ if (!file.exists()) { -+ try { -+ file.createNewFile(); -+ } catch (final Exception ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Failure to create tuinity config", ex); -+ } -+ } else { -+ try { -+ config.load(file); -+ } catch (final Exception ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Failure to load tuinity config", ex); -+ SneakyThrow.sneaky(ex); /* Rethrow, this is critical */ -+ throw new RuntimeException(ex); // unreachable -+ } -+ } -+ -+ TuinityConfig.load(config); -+ } -+ -+ public static void load(final YamlConfiguration config) { -+ TuinityConfig.config = config; -+ TuinityConfig.configVersion = TuinityConfig.getInt("config-version-please-do-not-modify-me", CURRENT_CONFIG_VERSION); -+ TuinityConfig.set("config-version-please-do-not-modify-me", CURRENT_CONFIG_VERSION); -+ -+ for (final Method method : TuinityConfig.class.getDeclaredMethods()) { -+ if (method.getReturnType() != void.class || method.getParameterCount() != 0 || -+ !Modifier.isPrivate(method.getModifiers()) || !Modifier.isStatic(method.getModifiers())) { -+ continue; -+ } -+ -+ try { -+ method.setAccessible(true); -+ method.invoke(null, EMPTY); -+ } catch (final Exception ex) { -+ SneakyThrow.sneaky(ex); /* Rethrow, this is critical */ -+ throw new RuntimeException(ex); // unreachable -+ } -+ } -+ -+ /* We re-save to add new options */ -+ try { -+ config.save(TuinityConfig.configFile); -+ } catch (final Exception ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Unable to save tuinity config", ex); -+ } -+ } -+ -+ static void set(final String path, final Object value) { -+ TuinityConfig.config.set(path, value); -+ } -+ -+ static boolean getBoolean(final String path, final boolean dfl) { -+ TuinityConfig.config.addDefault(path, Boolean.valueOf(dfl)); -+ return TuinityConfig.config.getBoolean(path, dfl); -+ } -+ -+ static int getInt(final String path, final int dfl) { -+ TuinityConfig.config.addDefault(path, Integer.valueOf(dfl)); -+ return TuinityConfig.config.getInt(path, dfl); -+ } -+ -+ static long getLong(final String path, final long dfl) { -+ TuinityConfig.config.addDefault(path, Long.valueOf(dfl)); -+ return TuinityConfig.config.getLong(path, dfl); -+ } -+ -+ static double getDouble(final String path, final double dfl) { -+ TuinityConfig.config.addDefault(path, Double.valueOf(dfl)); -+ return TuinityConfig.config.getDouble(path, dfl); -+ } -+ -+ static String getString(final String path, final String dfl) { -+ TuinityConfig.config.addDefault(path, dfl); -+ return TuinityConfig.config.getString(path, dfl); -+ } -+ -+ public static int playerMinChunkLoadRadius; -+ public static double playerMaxConcurrentChunkSends; -+ public static double playerMaxConcurrentChunkLoads; -+ public static boolean playerAutoConfigureSendViewDistance; -+ public static boolean enableMC162253Workaround; -+ public static double playerTargetChunkSendRate; -+ public static boolean playerFrustumPrioritisation; -+ -+ private static void newPlayerChunkManagement() { -+ playerMinChunkLoadRadius = TuinityConfig.getInt("player-chunks.min-load-radius", 2); -+ playerMaxConcurrentChunkSends = TuinityConfig.getDouble("player-chunks.max-concurrent-sends", 5.0); -+ playerMaxConcurrentChunkLoads = TuinityConfig.getDouble("player-chunks.max-concurrent-loads", -6.0); -+ playerAutoConfigureSendViewDistance = TuinityConfig.getBoolean("player-chunks.autoconfig-send-distance", true); -+ // this costs server bandwidth. latest phosphor or starlight on the client fixes mc162253 anyways. -+ enableMC162253Workaround = TuinityConfig.getBoolean("player-chunks.enable-mc162253-workaround", true); -+ playerTargetChunkSendRate = TuinityConfig.getDouble("player-chunks.target-chunk-send-rate", -35.0); -+ playerFrustumPrioritisation = TuinityConfig.getBoolean("player-chunks.enable-frustum-priority", false); -+ } -+ -+ public static final class PacketLimit { -+ public final double packetLimitInterval; -+ public final double maxPacketRate; -+ public final ViolateAction violateAction; -+ -+ public PacketLimit(final double packetLimitInterval, final double maxPacketRate, final ViolateAction violateAction) { -+ this.packetLimitInterval = packetLimitInterval; -+ this.maxPacketRate = maxPacketRate; -+ this.violateAction = violateAction; -+ } -+ -+ public static enum ViolateAction { -+ KICK, DROP; -+ } -+ } -+ -+ public static String kickMessage; -+ public static PacketLimit allPacketsLimit; -+ public static java.util.Map>, PacketLimit> packetSpecificLimits = new java.util.HashMap<>(); -+ -+ private static void packetLimiter() { -+ packetSpecificLimits.clear(); -+ kickMessage = org.bukkit.ChatColor.translateAlternateColorCodes('&', TuinityConfig.getString("packet-limiter.kick-message", "&cSent too many packets")); -+ allPacketsLimit = new PacketLimit( -+ TuinityConfig.getDouble("packet-limiter.limits.all.interval", 7.0), -+ TuinityConfig.getDouble("packet-limiter.limits.all.max-packet-rate", 500.0), -+ PacketLimit.ViolateAction.KICK -+ ); -+ if (allPacketsLimit.maxPacketRate <= 0.0 || allPacketsLimit.packetLimitInterval <= 0.0) { -+ allPacketsLimit = null; -+ } -+ final ConfigurationSection section = TuinityConfig.config.getConfigurationSection("packet-limiter.limits"); -+ -+ // add default packets -+ -+ // auto recipe limiting -+ TuinityConfig.getDouble("packet-limiter.limits." + -+ "PacketPlayInAutoRecipe" + ".interval", 4.0); -+ TuinityConfig.getDouble("packet-limiter.limits." + -+ "PacketPlayInAutoRecipe" + ".max-packet-rate", 5.0); -+ TuinityConfig.getString("packet-limiter.limits." + -+ "PacketPlayInAutoRecipe" + ".action", PacketLimit.ViolateAction.DROP.name()); -+ -+ final Map mojangToSpigot = new HashMap<>(); -+ final Map maps = ObfHelper.INSTANCE.mappingsByObfName(); -+ if (maps != null) { -+ maps.forEach((spigotName, classMapping) -> -+ mojangToSpigot.put(classMapping.mojangName(), classMapping.obfName())); -+ } -+ -+ for (final String packetClassName : section.getKeys(false)) { -+ if (packetClassName.equals("all")) { -+ continue; -+ } -+ Class packetClazz = null; -+ -+ for (final String subpackage : List.of("game", "handshake", "login", "status")) { -+ final String fullName = "net.minecraft.network.protocol." + subpackage + "." + packetClassName; -+ try { -+ packetClazz = Class.forName(fullName); -+ break; -+ } catch (final ClassNotFoundException ex) { -+ try { -+ final String spigot = mojangToSpigot.get(fullName); -+ if (spigot != null) { -+ packetClazz = Class.forName(spigot); -+ } -+ } catch (final ClassNotFoundException ignore) {} -+ } -+ } -+ -+ if (packetClazz == null || !net.minecraft.network.protocol.Packet.class.isAssignableFrom(packetClazz)) { -+ MinecraftServer.LOGGER.warn("Packet '" + packetClassName + "' does not exist, cannot limit it! Please update tuinity.yml"); -+ continue; -+ } -+ -+ if (!(section.get(packetClassName.concat(".interval")) instanceof Number) || !(section.get(packetClassName.concat(".max-packet-rate")) instanceof Number)) { -+ throw new RuntimeException("Packet limit setting " + packetClassName + " is missing interval or max-packet-rate!"); -+ } -+ -+ final String actionString = section.getString(packetClassName.concat(".action"), "KICK"); -+ PacketLimit.ViolateAction action = PacketLimit.ViolateAction.KICK; -+ for (PacketLimit.ViolateAction test : PacketLimit.ViolateAction.values()) { -+ if (actionString.equalsIgnoreCase(test.name())) { -+ action = test; -+ break; -+ } -+ } -+ -+ final double interval = section.getDouble(packetClassName.concat(".interval")); -+ final double rate = section.getDouble(packetClassName.concat(".max-packet-rate")); -+ -+ if (interval > 0.0 && rate > 0.0) { -+ packetSpecificLimits.put((Class)packetClazz, new PacketLimit(interval, rate, action)); -+ } -+ } -+ } -+ -+ public static boolean lagCompensateBlockBreaking; -+ -+ private static void lagCompensateBlockBreaking() { -+ lagCompensateBlockBreaking = TuinityConfig.getBoolean("lag-compensate-block-breaking", true); -+ } -+ -+ public static boolean sendFullPosForHardCollidingEntities; -+ -+ private static void sendFullPosForHardCollidingEntities() { -+ sendFullPosForHardCollidingEntities = TuinityConfig.getBoolean("send-full-pos-for-hard-colliding-entities", true); -+ } -+ -+ public static final class WorldConfig { -+ -+ public final String worldName; -+ public String configPath; -+ ConfigurationSection worldDefaults; -+ -+ public WorldConfig(final String worldName) { -+ this.worldName = worldName; -+ this.init(); -+ } -+ -+ public void init() { -+ this.worldDefaults = TuinityConfig.config.getConfigurationSection("world-settings.default"); -+ if (this.worldDefaults == null) { -+ this.worldDefaults = TuinityConfig.config.createSection("world-settings.default"); -+ } -+ -+ String worldSectionPath = TuinityConfig.configVersion < 1 ? this.worldName : "world-settings.".concat(this.worldName); -+ ConfigurationSection section = TuinityConfig.config.getConfigurationSection(worldSectionPath); -+ this.configPath = worldSectionPath; -+ if (TuinityConfig.createWorldSections) { -+ if (section == null) { -+ section = TuinityConfig.config.createSection(worldSectionPath); -+ } -+ TuinityConfig.config.set(worldSectionPath, section); -+ } -+ -+ this.load(); -+ } -+ -+ public void load() { -+ for (final Method method : TuinityConfig.WorldConfig.class.getDeclaredMethods()) { -+ if (method.getReturnType() != void.class || method.getParameterCount() != 0 || -+ !Modifier.isPrivate(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { -+ continue; -+ } -+ -+ try { -+ method.setAccessible(true); -+ method.invoke(this, EMPTY); -+ } catch (final Exception ex) { -+ SneakyThrow.sneaky(ex); /* Rethrow, this is critical */ -+ throw new RuntimeException(ex); // unreachable -+ } -+ } -+ -+ if (TuinityConfig.configVersion < 1) { -+ ConfigurationSection oldSection = TuinityConfig.config.getConfigurationSection(this.worldName); -+ TuinityConfig.config.set("world-settings.".concat(this.worldName), oldSection); -+ TuinityConfig.config.set(this.worldName, null); -+ } -+ -+ /* We re-save to add new options */ -+ try { -+ TuinityConfig.config.save(TuinityConfig.configFile); -+ } catch (final Exception ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Unable to save tuinity config", ex); -+ } -+ } -+ -+ /** -+ * update world defaults for the specified path, but also sets this world's config value for the path -+ * if it exists -+ */ -+ void set(final String path, final Object val) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.set(path, val); -+ if (config != null && config.get(path) != null) { -+ config.set(path, val); -+ } -+ } -+ -+ boolean getBoolean(final String path, final boolean dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.addDefault(path, Boolean.valueOf(dfl)); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getBoolean(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getBoolean(path) : config.getBoolean(path, this.worldDefaults.getBoolean(path)); -+ } -+ -+ boolean getBooleanRaw(final String path, final boolean dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getBoolean(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getBoolean(path, dfl) : config.getBoolean(path, this.worldDefaults.getBoolean(path, dfl)); -+ } -+ -+ int getInt(final String path, final int dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.addDefault(path, Integer.valueOf(dfl)); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getInt(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getInt(path) : config.getInt(path, this.worldDefaults.getInt(path)); -+ } -+ -+ int getIntRaw(final String path, final int dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getInt(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getInt(path, dfl) : config.getInt(path, this.worldDefaults.getInt(path, dfl)); -+ } -+ -+ long getLong(final String path, final long dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.addDefault(path, Long.valueOf(dfl)); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getLong(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getLong(path) : config.getLong(path, this.worldDefaults.getLong(path)); -+ } -+ -+ long getLongRaw(final String path, final long dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getLong(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getLong(path, dfl) : config.getLong(path, this.worldDefaults.getLong(path, dfl)); -+ } -+ -+ double getDouble(final String path, final double dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.addDefault(path, Double.valueOf(dfl)); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getDouble(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getDouble(path) : config.getDouble(path, this.worldDefaults.getDouble(path)); -+ } -+ -+ double getDoubleRaw(final String path, final double dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ if (TuinityConfig.configVersion < 1) { -+ if (config != null && config.getDouble(path) == dfl) { -+ config.set(path, null); -+ } -+ } -+ return config == null ? this.worldDefaults.getDouble(path, dfl) : config.getDouble(path, this.worldDefaults.getDouble(path, dfl)); -+ } -+ -+ String getString(final String path, final String dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.addDefault(path, dfl); -+ return config == null ? this.worldDefaults.getString(path) : config.getString(path, this.worldDefaults.getString(path)); -+ } -+ -+ String getStringRaw(final String path, final String dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ return config == null ? this.worldDefaults.getString(path, dfl) : config.getString(path, this.worldDefaults.getString(path, dfl)); -+ } -+ -+ List getList(final String path, final List dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ this.worldDefaults.addDefault(path, dfl); -+ return config == null ? this.worldDefaults.getList(path) : config.getList(path, this.worldDefaults.getList(path)); -+ } -+ -+ List getListRaw(final String path, final List dfl) { -+ final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath); -+ return config == null ? this.worldDefaults.getList(path, dfl) : config.getList(path, this.worldDefaults.getList(path, dfl)); -+ } -+ -+ public int spawnLimitMonsters; -+ public int spawnLimitAnimals; -+ public int spawnLimitWaterAmbient; -+ public int spawnLimitWaterAnimals; -+ public int spawnLimitAmbient; -+ -+ private void perWorldSpawnLimit() { -+ final String path = "spawn-limits"; -+ -+ this.spawnLimitMonsters = this.getIntRaw(path + ".monsters", -1); -+ this.spawnLimitAnimals = this.getIntRaw(path + ".animals", -1); -+ this.spawnLimitWaterAmbient = this.getIntRaw(path + ".water-ambient", -1); -+ this.spawnLimitWaterAnimals = this.getIntRaw(path + ".water-animals", -1); -+ this.spawnLimitAmbient = this.getIntRaw(path + ".ambient", -1); -+ } -+ } -+ -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/CachedLists.java b/src/main/java/com/tuinity/tuinity/util/CachedLists.java -new file mode 100644 -index 0000000000000000000000000000000000000000..01320aea07b51c97ae5f0654b81d2332f545d42e ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/CachedLists.java -@@ -0,0 +1,57 @@ -+package com.tuinity.tuinity.util; -+ -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.phys.AABB; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.util.UnsafeList; -+import java.util.List; -+ -+public final class CachedLists { -+ -+ // Tuinity start - optimise collisions -+ static final UnsafeList TEMP_COLLISION_LIST = new UnsafeList<>(1024); -+ static boolean tempCollisionListInUse; -+ -+ public static UnsafeList getTempCollisionList() { -+ if (!Bukkit.isPrimaryThread() || tempCollisionListInUse) { -+ return new UnsafeList<>(16); -+ } -+ tempCollisionListInUse = true; -+ return TEMP_COLLISION_LIST; -+ } -+ -+ public static void returnTempCollisionList(List list) { -+ if (list != TEMP_COLLISION_LIST) { -+ return; -+ } -+ ((UnsafeList)list).setSize(0); -+ tempCollisionListInUse = false; -+ } -+ -+ static final UnsafeList TEMP_GET_ENTITIES_LIST = new UnsafeList<>(1024); -+ static boolean tempGetEntitiesListInUse; -+ -+ public static UnsafeList getTempGetEntitiesList() { -+ if (!Bukkit.isPrimaryThread() || tempGetEntitiesListInUse) { -+ return new UnsafeList<>(16); -+ } -+ tempGetEntitiesListInUse = true; -+ return TEMP_GET_ENTITIES_LIST; -+ } -+ -+ public static void returnTempGetEntitiesList(List list) { -+ if (list != TEMP_GET_ENTITIES_LIST) { -+ return; -+ } -+ ((UnsafeList)list).setSize(0); -+ tempGetEntitiesListInUse = false; -+ } -+ // Tuinity end - optimise collisions -+ -+ public static void reset() { -+ // Tuinity start - optimise collisions -+ TEMP_COLLISION_LIST.completeReset(); -+ TEMP_GET_ENTITIES_LIST.completeReset(); -+ // Tuinity end - optimise collisions -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java b/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a2f52a68420a2d23d8f54f61f7aeede41567dc0f ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/CollisionUtil.java -@@ -0,0 +1,645 @@ -+package com.tuinity.tuinity.util; -+ -+import com.tuinity.tuinity.voxel.AABBVoxelShape; -+import net.minecraft.core.BlockPos; -+import net.minecraft.server.level.ServerChunkCache; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.WorldGenRegion; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.CollisionGetter; -+import net.minecraft.world.level.EntityGetter; -+import net.minecraft.world.level.block.Blocks; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.border.WorldBorder; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.LevelChunkSection; -+import net.minecraft.world.level.material.FlowingFluid; -+import net.minecraft.world.level.material.FluidState; -+import net.minecraft.world.phys.AABB; -+import net.minecraft.world.phys.Vec3; -+import net.minecraft.world.phys.shapes.ArrayVoxelShape; -+import net.minecraft.world.phys.shapes.CollisionContext; -+import net.minecraft.world.phys.shapes.EntityCollisionContext; -+import net.minecraft.world.phys.shapes.Shapes; -+import net.minecraft.world.phys.shapes.VoxelShape; -+import java.util.List; -+import java.util.Optional; -+import java.util.function.BiPredicate; -+import java.util.function.Predicate; -+ -+public final class CollisionUtil { -+ -+ public static final double COLLISION_EPSILON = 1.0E-7; -+ -+ public static boolean isEmpty(final AABB aabb) { -+ return (aabb.maxX - aabb.minX) < COLLISION_EPSILON && (aabb.maxY - aabb.minY) < COLLISION_EPSILON && (aabb.maxZ - aabb.minZ) < COLLISION_EPSILON; -+ } -+ -+ public static boolean isEmpty(final double minX, final double minY, final double minZ, -+ final double maxX, final double maxY, final double maxZ) { -+ return (maxX - minX) < COLLISION_EPSILON && (maxY - minY) < COLLISION_EPSILON && (maxZ - minZ) < COLLISION_EPSILON; -+ } -+ -+ public static AABB getBoxForChunk(final int chunkX, final int chunkZ) { -+ double x = (double)(chunkX << 4); -+ double z = (double)(chunkZ << 4); -+ // use a bounding box bigger than the chunk to prevent entities from entering it on move -+ return new AABB(x - 3*COLLISION_EPSILON, Double.NEGATIVE_INFINITY, z - 3*COLLISION_EPSILON, -+ x + (16.0 + 3*COLLISION_EPSILON), Double.POSITIVE_INFINITY, z + (16.0 + 3*COLLISION_EPSILON), false); -+ } -+ -+ /* -+ A couple of rules for VoxelShape collisions: -+ Two shapes only intersect if they are actually more than EPSILON units into each other. This also applies to movement -+ checks. -+ If the two shapes strictly collide, then the return value of a collide call will return a value in the opposite -+ direction of the source move. However, this value will not be greater in magnitude than EPSILON. Collision code -+ will automatically round it to 0. -+ */ -+ -+ public static boolean voxelShapeIntersect(final double minX1, final double minY1, final double minZ1, final double maxX1, -+ final double maxY1, final double maxZ1, final double minX2, final double minY2, -+ final double minZ2, final double maxX2, final double maxY2, final double maxZ2) { -+ return (minX1 - maxX2) < -COLLISION_EPSILON && (maxX1 - minX2) > COLLISION_EPSILON && -+ (minY1 - maxY2) < -COLLISION_EPSILON && (maxY1 - minY2) > COLLISION_EPSILON && -+ (minZ1 - maxZ2) < -COLLISION_EPSILON && (maxZ1 - minZ2) > COLLISION_EPSILON; -+ } -+ -+ public static boolean voxelShapeIntersect(final AABB box, final double minX, final double minY, final double minZ, -+ final double maxX, final double maxY, final double maxZ) { -+ return (box.minX - maxX) < -COLLISION_EPSILON && (box.maxX - minX) > COLLISION_EPSILON && -+ (box.minY - maxY) < -COLLISION_EPSILON && (box.maxY - minY) > COLLISION_EPSILON && -+ (box.minZ - maxZ) < -COLLISION_EPSILON && (box.maxZ - minZ) > COLLISION_EPSILON; -+ } -+ -+ public static boolean voxelShapeIntersect(final AABB box1, final AABB box2) { -+ return (box1.minX - box2.maxX) < -COLLISION_EPSILON && (box1.maxX - box2.minX) > COLLISION_EPSILON && -+ (box1.minY - box2.maxY) < -COLLISION_EPSILON && (box1.maxY - box2.minY) > COLLISION_EPSILON && -+ (box1.minZ - box2.maxZ) < -COLLISION_EPSILON && (box1.maxZ - box2.minZ) > COLLISION_EPSILON; -+ } -+ -+ public static double collideX(final AABB target, final AABB source, final double source_move) { -+ if (source_move == 0.0) { -+ return 0.0; -+ } -+ -+ if ((source.minY - target.maxY) < -COLLISION_EPSILON && (source.maxY - target.minY) > COLLISION_EPSILON && -+ (source.minZ - target.maxZ) < -COLLISION_EPSILON && (source.maxZ - target.minZ) > COLLISION_EPSILON) { -+ if (source_move >= 0.0) { -+ final double max_move = target.minX - source.maxX; // < 0.0 if no strict collision -+ if (max_move < -COLLISION_EPSILON) { -+ return source_move; -+ } -+ return Math.min(max_move, source_move); -+ } else { -+ final double max_move = target.maxX - source.minX; // > 0.0 if no strict collision -+ if (max_move > COLLISION_EPSILON) { -+ return source_move; -+ } -+ return Math.max(max_move, source_move); -+ } -+ } -+ return source_move; -+ } -+ -+ public static double collideY(final AABB target, final AABB source, final double source_move) { -+ if (source_move == 0.0) { -+ return 0.0; -+ } -+ -+ if ((source.minX - target.maxX) < -COLLISION_EPSILON && (source.maxX - target.minX) > COLLISION_EPSILON && -+ (source.minZ - target.maxZ) < -COLLISION_EPSILON && (source.maxZ - target.minZ) > COLLISION_EPSILON) { -+ if (source_move >= 0.0) { -+ final double max_move = target.minY - source.maxY; // < 0.0 if no strict collision -+ if (max_move < -COLLISION_EPSILON) { -+ return source_move; -+ } -+ return Math.min(max_move, source_move); -+ } else { -+ final double max_move = target.maxY - source.minY; // > 0.0 if no strict collision -+ if (max_move > COLLISION_EPSILON) { -+ return source_move; -+ } -+ return Math.max(max_move, source_move); -+ } -+ } -+ return source_move; -+ } -+ -+ public static double collideZ(final AABB target, final AABB source, final double source_move) { -+ if (source_move == 0.0) { -+ return 0.0; -+ } -+ -+ if ((source.minX - target.maxX) < -COLLISION_EPSILON && (source.maxX - target.minX) > COLLISION_EPSILON && -+ (source.minY - target.maxY) < -COLLISION_EPSILON && (source.maxY - target.minY) > COLLISION_EPSILON) { -+ if (source_move >= 0.0) { -+ final double max_move = target.minZ - source.maxZ; // < 0.0 if no strict collision -+ if (max_move < -COLLISION_EPSILON) { -+ return source_move; -+ } -+ return Math.min(max_move, source_move); -+ } else { -+ final double max_move = target.maxZ - source.minZ; // > 0.0 if no strict collision -+ if (max_move > COLLISION_EPSILON) { -+ return source_move; -+ } -+ return Math.max(max_move, source_move); -+ } -+ } -+ return source_move; -+ } -+ -+ public static AABB offsetX(final AABB box, final double dx) { -+ return new AABB(box.minX + dx, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB offsetY(final AABB box, final double dy) { -+ return new AABB(box.minX, box.minY + dy, box.minZ, box.maxX, box.maxY + dy, box.maxZ, false); -+ } -+ -+ public static AABB offsetZ(final AABB box, final double dz) { -+ return new AABB(box.minX, box.minY, box.minZ + dz, box.maxX, box.maxY, box.maxZ + dz, false); -+ } -+ -+ public static AABB expandRight(final AABB box, final double dx) { // dx > 0.0 -+ return new AABB(box.minX, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB expandLeft(final AABB box, final double dx) { // dx < 0.0 -+ return new AABB(box.minX - dx, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB expandUpwards(final AABB box, final double dy) { // dy > 0.0 -+ return new AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY + dy, box.maxZ, false); -+ } -+ -+ public static AABB expandDownwards(final AABB box, final double dy) { // dy < 0.0 -+ return new AABB(box.minX, box.minY - dy, box.minZ, box.maxX, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB expandForwards(final AABB box, final double dz) { // dz > 0.0 -+ return new AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ + dz, false); -+ } -+ -+ public static AABB expandBackwards(final AABB box, final double dz) { // dz < 0.0 -+ return new AABB(box.minX, box.minY, box.minZ - dz, box.maxX, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB cutRight(final AABB box, final double dx) { // dx > 0.0 -+ return new AABB(box.maxX, box.minY, box.minZ, box.maxX + dx, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB cutLeft(final AABB box, final double dx) { // dx < 0.0 -+ return new AABB(box.minX + dx, box.minY, box.minZ, box.minX, box.maxY, box.maxZ, false); -+ } -+ -+ public static AABB cutUpwards(final AABB box, final double dy) { // dy > 0.0 -+ return new AABB(box.minX, box.maxY, box.minZ, box.maxX, box.maxY + dy, box.maxZ, false); -+ } -+ -+ public static AABB cutDownwards(final AABB box, final double dy) { // dy < 0.0 -+ return new AABB(box.minX, box.minY + dy, box.minZ, box.maxX, box.minY, box.maxZ, false); -+ } -+ -+ public static AABB cutForwards(final AABB box, final double dz) { // dz > 0.0 -+ return new AABB(box.minX, box.minY, box.maxZ, box.maxX, box.maxY, box.maxZ + dz, false); -+ } -+ -+ public static AABB cutBackwards(final AABB box, final double dz) { // dz < 0.0 -+ return new AABB(box.minX, box.minY, box.minZ + dz, box.maxX, box.maxY, box.minZ, false); -+ } -+ -+ public static double performCollisionsX(final AABB currentBoundingBox, double value, final List potentialCollisions) { -+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) { -+ final AABB target = potentialCollisions.get(i); -+ value = collideX(target, currentBoundingBox, value); -+ } -+ -+ return value; -+ } -+ -+ public static double performCollisionsY(final AABB currentBoundingBox, double value, final List potentialCollisions) { -+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) { -+ final AABB target = potentialCollisions.get(i); -+ value = collideY(target, currentBoundingBox, value); -+ } -+ -+ return value; -+ } -+ -+ public static double performCollisionsZ(final AABB currentBoundingBox, double value, final List potentialCollisions) { -+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) { -+ final AABB target = potentialCollisions.get(i); -+ value = collideZ(target, currentBoundingBox, value); -+ } -+ -+ return value; -+ } -+ -+ public static Vec3 performCollisions(final Vec3 moveVector, AABB axisalignedbb, final List potentialCollisions) { -+ double x = moveVector.x; -+ double y = moveVector.y; -+ double z = moveVector.z; -+ -+ if (y != 0.0) { -+ y = performCollisionsY(axisalignedbb, y, potentialCollisions); -+ if (y != 0.0) { -+ axisalignedbb = offsetY(axisalignedbb, y); -+ } -+ } -+ -+ final boolean xSmaller = Math.abs(x) < Math.abs(z); -+ -+ if (xSmaller && z != 0.0) { -+ z = performCollisionsZ(axisalignedbb, z, potentialCollisions); -+ if (z != 0.0) { -+ axisalignedbb = offsetZ(axisalignedbb, z); -+ } -+ } -+ -+ if (x != 0.0) { -+ x = performCollisionsX(axisalignedbb, x, potentialCollisions); -+ if (!xSmaller && x != 0.0) { -+ axisalignedbb = offsetX(axisalignedbb, x); -+ } -+ } -+ -+ if (!xSmaller && z != 0.0) { -+ z = performCollisionsZ(axisalignedbb, z, potentialCollisions); -+ } -+ -+ return new Vec3(x, y, z); -+ } -+ -+ public static boolean addBoxesToIfIntersects(final VoxelShape shape, final AABB aabb, final List list) { -+ if (shape instanceof AABBVoxelShape) { -+ final AABBVoxelShape shapeCasted = (AABBVoxelShape)shape; -+ if (voxelShapeIntersect(shapeCasted.aabb, aabb) && !isEmpty(shapeCasted.aabb)) { -+ list.add(shapeCasted.aabb); -+ return true; -+ } -+ return false; -+ } else if (shape instanceof ArrayVoxelShape) { -+ final ArrayVoxelShape shapeCasted = (ArrayVoxelShape)shape; -+ // this can be optimised by checking an "overall shape" first, but not needed -+ -+ final double offX = shapeCasted.getOffsetX(); -+ final double offY = shapeCasted.getOffsetY(); -+ final double offZ = shapeCasted.getOffsetZ(); -+ -+ boolean ret = false; -+ -+ for (final AABB boundingBox : shapeCasted.getBoundingBoxesRepresentation()) { -+ final double minX, minY, minZ, maxX, maxY, maxZ; -+ if (voxelShapeIntersect(aabb, minX = boundingBox.minX + offX, minY = boundingBox.minY + offY, minZ = boundingBox.minZ + offZ, -+ maxX = boundingBox.maxX + offX, maxY = boundingBox.maxY + offY, maxZ = boundingBox.maxZ + offZ) -+ && !isEmpty(minX, minY, minZ, maxX, maxY, maxZ)) { -+ list.add(new AABB(minX, minY, minZ, maxX, maxY, maxZ, false)); -+ ret = true; -+ } -+ } -+ -+ return ret; -+ } else { -+ final List boxes = shape.toAabbs(); -+ -+ boolean ret = false; -+ -+ for (int i = 0, len = boxes.size(); i < len; ++i) { -+ final AABB box = boxes.get(i); -+ if (voxelShapeIntersect(box, aabb) && !isEmpty(box)) { -+ list.add(box); -+ ret = true; -+ } -+ } -+ -+ return ret; -+ } -+ } -+ -+ public static void addBoxesTo(final VoxelShape shape, final List list) { -+ if (shape instanceof AABBVoxelShape) { -+ final AABBVoxelShape shapeCasted = (AABBVoxelShape)shape; -+ if (!isEmpty(shapeCasted.aabb)) { -+ list.add(shapeCasted.aabb); -+ } -+ } else if (shape instanceof ArrayVoxelShape) { -+ final ArrayVoxelShape shapeCasted = (ArrayVoxelShape)shape; -+ -+ final double offX = shapeCasted.getOffsetX(); -+ final double offY = shapeCasted.getOffsetY(); -+ final double offZ = shapeCasted.getOffsetZ(); -+ -+ for (final AABB boundingBox : shapeCasted.getBoundingBoxesRepresentation()) { -+ final AABB box = boundingBox.move(offX, offY, offZ); -+ if (!isEmpty(box)) { -+ list.add(box); -+ } -+ } -+ } else { -+ final List boxes = shape.toAabbs(); -+ for (int i = 0, len = boxes.size(); i < len; ++i) { -+ final AABB box = boxes.get(i); -+ if (!isEmpty(box)) { -+ list.add(box); -+ } -+ } -+ } -+ } -+ -+ public static boolean isAlmostCollidingOnBorder(final WorldBorder worldborder, final AABB boundingBox) { -+ return isAlmostCollidingOnBorder(worldborder, boundingBox.minX, boundingBox.maxX, boundingBox.minZ, boundingBox.maxZ); -+ } -+ -+ public static boolean isAlmostCollidingOnBorder(final WorldBorder worldborder, final double boxMinX, final double boxMaxX, -+ final double boxMinZ, final double boxMaxZ) { -+ final double borderMinX = worldborder.getMinX(); // -X -+ final double borderMaxX = worldborder.getMaxX(); // +X -+ -+ final double borderMinZ = worldborder.getMinZ(); // -Z -+ final double borderMaxZ = worldborder.getMaxZ(); // +Z -+ -+ return -+ // Not intersecting if we're smaller -+ !voxelShapeIntersect( -+ boxMinX + COLLISION_EPSILON, Double.NEGATIVE_INFINITY, boxMinZ + COLLISION_EPSILON, -+ boxMaxX - COLLISION_EPSILON, Double.POSITIVE_INFINITY, boxMaxZ - COLLISION_EPSILON, -+ borderMinX, Double.NEGATIVE_INFINITY, borderMinZ, borderMaxX, Double.POSITIVE_INFINITY, borderMaxZ -+ ) -+ && -+ -+ // Are intersecting if we're larger -+ voxelShapeIntersect( -+ boxMinX - COLLISION_EPSILON, Double.NEGATIVE_INFINITY, boxMinZ - COLLISION_EPSILON, -+ boxMaxX + COLLISION_EPSILON, Double.POSITIVE_INFINITY, boxMaxZ + COLLISION_EPSILON, -+ borderMinX, Double.NEGATIVE_INFINITY, borderMinZ, borderMaxX, Double.POSITIVE_INFINITY, borderMaxZ -+ ); -+ } -+ -+ public static boolean isCollidingWithBorderEdge(final WorldBorder worldborder, final AABB boundingBox) { -+ return isCollidingWithBorderEdge(worldborder, boundingBox.minX, boundingBox.maxX, boundingBox.minZ, boundingBox.maxZ); -+ } -+ -+ public static boolean isCollidingWithBorderEdge(final WorldBorder worldborder, final double boxMinX, final double boxMaxX, -+ final double boxMinZ, final double boxMaxZ) { -+ final double borderMinX = worldborder.getMinX() + COLLISION_EPSILON; // -X -+ final double borderMaxX = worldborder.getMaxX() - COLLISION_EPSILON; // +X -+ -+ final double borderMinZ = worldborder.getMinZ() + COLLISION_EPSILON; // -Z -+ final double borderMaxZ = worldborder.getMaxZ() - COLLISION_EPSILON; // +Z -+ -+ return boxMinX < borderMinX || boxMaxX > borderMaxX || boxMinZ < borderMinZ || boxMaxZ > borderMaxZ; -+ } -+ -+ public static boolean getCollisionsForBlocksOrWorldBorder(final CollisionGetter getter, final Entity entity, final AABB aabb, -+ final List into, final boolean loadChunks, final boolean collidesWithUnloaded, -+ final boolean checkBorder, final boolean checkOnly, final BiPredicate predicate) { -+ boolean ret = false; -+ -+ if (checkBorder) { -+ if (CollisionUtil.isAlmostCollidingOnBorder(getter.getWorldBorder(), aabb)) { -+ if (checkOnly) { -+ return true; -+ } else { -+ CollisionUtil.addBoxesTo(getter.getWorldBorder().getCollisionShape(), into); -+ ret = true; -+ } -+ } -+ } -+ -+ int minBlockX = Mth.floor(aabb.minX - COLLISION_EPSILON) - 1; -+ int maxBlockX = Mth.floor(aabb.maxX + COLLISION_EPSILON) + 1; -+ -+ int minBlockY = Mth.floor(aabb.minY - COLLISION_EPSILON) - 1; -+ int maxBlockY = Mth.floor(aabb.maxY + COLLISION_EPSILON) + 1; -+ -+ int minBlockZ = Mth.floor(aabb.minZ - COLLISION_EPSILON) - 1; -+ int maxBlockZ = Mth.floor(aabb.maxZ + COLLISION_EPSILON) + 1; -+ -+ final int minSection = WorldUtil.getMinSection(getter); -+ final int maxSection = WorldUtil.getMaxSection(getter); -+ final int minBlock = minSection << 4; -+ final int maxBlock = (maxSection << 4) | 15; -+ -+ BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); -+ CollisionContext collisionShape = null; -+ -+ // special cases: -+ if (minBlockY > maxBlock || maxBlockY < minBlock) { -+ // no point in checking -+ return ret; -+ } -+ -+ int minYIterate = Math.max(minBlock, minBlockY); -+ int maxYIterate = Math.min(maxBlock, maxBlockY); -+ -+ int minChunkX = minBlockX >> 4; -+ int maxChunkX = maxBlockX >> 4; -+ -+ int minChunkZ = minBlockZ >> 4; -+ int maxChunkZ = maxBlockZ >> 4; -+ -+ ServerChunkCache chunkProvider; -+ if (getter instanceof WorldGenRegion) { -+ chunkProvider = null; -+ } else if (getter instanceof ServerLevel) { -+ chunkProvider = ((ServerLevel)getter).getChunkSource(); -+ } else { -+ chunkProvider = null; -+ } -+ // TODO special case single chunk? -+ -+ for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { -+ int minZ = currChunkZ == minChunkZ ? minBlockZ & 15 : 0; // coordinate in chunk -+ int maxZ = currChunkZ == maxChunkZ ? maxBlockZ & 15 : 15; // coordinate in chunk -+ -+ for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { -+ int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk -+ int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 15; // coordinate in chunk -+ -+ int chunkXGlobalPos = currChunkX << 4; -+ int chunkZGlobalPos = currChunkZ << 4; -+ ChunkAccess chunk; -+ if (chunkProvider == null) { -+ chunk = (ChunkAccess)getter.getChunkForCollisions(currChunkX, currChunkZ); -+ } else { -+ chunk = loadChunks ? chunkProvider.getChunk(currChunkX, currChunkZ, true) : chunkProvider.getChunkAtIfLoadedImmediately(currChunkX, currChunkZ); -+ } -+ -+ -+ if (chunk == null) { -+ if (collidesWithUnloaded) { -+ if (checkOnly) { -+ return true; -+ } else { -+ into.add(getBoxForChunk(currChunkX, currChunkZ)); -+ ret = true; -+ } -+ } -+ continue; -+ } -+ -+ LevelChunkSection[] sections = chunk.getSections(); -+ -+ // bound y -+ -+ for (int currY = minYIterate; currY <= maxYIterate; ++currY) { -+ LevelChunkSection section = sections[(currY >> 4) - minSection]; -+ if (section == null || section.isEmpty()) { -+ // empty -+ // skip to next section -+ currY = (currY & ~(15)) + 15; // increment by 15: iterator loop increments by the extra one -+ continue; -+ } -+ -+ net.minecraft.world.level.chunk.PalettedContainer blocks = section.states; -+ -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ int localBlockIndex = (currX) | (currZ << 4) | ((currY & 15) << 8); -+ int blockX = currX | chunkXGlobalPos; -+ int blockY = currY; -+ int blockZ = currZ | chunkZGlobalPos; -+ -+ int edgeCount = ((blockX == minBlockX || blockX == maxBlockX) ? 1 : 0) + -+ ((blockY == minBlockY || blockY == maxBlockY) ? 1 : 0) + -+ ((blockZ == minBlockZ || blockZ == maxBlockZ) ? 1 : 0); -+ if (edgeCount == 3) { -+ continue; -+ } -+ -+ BlockState blockData = blocks.get(localBlockIndex); -+ if (blockData.isAir()) { -+ continue; -+ } -+ -+ if ((edgeCount != 1 || blockData.shapeExceedsCube()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON)) { -+ mutablePos.set(blockX, blockY, blockZ); -+ if (collisionShape == null) { -+ collisionShape = new LazyEntityCollisionContext(entity); -+ } -+ VoxelShape voxelshape2 = blockData.getCollisionShape(getter, mutablePos, collisionShape); -+ if (voxelshape2 != Shapes.empty()) { -+ VoxelShape voxelshape3 = voxelshape2.move((double)blockX, (double)blockY, (double)blockZ); -+ -+ if (predicate != null && !predicate.test(blockData, mutablePos)) { -+ continue; -+ } -+ -+ if (checkOnly) { -+ if (voxelshape3.intersects(aabb)) { -+ return true; -+ } -+ } else { -+ ret |= addBoxesToIfIntersects(voxelshape3, aabb, into); -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ return ret; -+ } -+ -+ public static boolean getEntityHardCollisions(final CollisionGetter getter, final Entity entity, AABB aabb, -+ final List into, final boolean checkOnly, final Predicate predicate) { -+ if (isEmpty(aabb) || !(getter instanceof EntityGetter entityGetter)) { -+ return false; -+ } -+ -+ boolean ret = false; -+ -+ // to comply with vanilla intersection rules, expand by -epsilon so we only get stuff we definitely collide with. -+ // Vanilla for hard collisions has this backwards, and they expand by +epsilon but this causes terrible problems -+ // specifically with boat collisions. -+ aabb = aabb.inflate(-COLLISION_EPSILON, -COLLISION_EPSILON, -COLLISION_EPSILON); -+ final List entities = CachedLists.getTempGetEntitiesList(); -+ try { -+ if (entity != null && entity.hardCollides()) { -+ entityGetter.getEntities(entity, aabb, predicate, entities); -+ } else { -+ entityGetter.getHardCollidingEntities(entity, aabb, predicate, entities); -+ } -+ -+ for (int i = 0, len = entities.size(); i < len; ++i) { -+ final Entity otherEntity = entities.get(i); -+ -+ if ((entity == null && otherEntity.canBeCollidedWith()) || (entity != null && entity.canCollideWith(otherEntity))) { -+ if (checkOnly) { -+ return true; -+ } else { -+ into.add(otherEntity.getBoundingBox()); -+ ret = true; -+ } -+ } -+ } -+ } finally { -+ CachedLists.returnTempGetEntitiesList(entities); -+ } -+ -+ return ret; -+ } -+ -+ public static boolean getCollisions(final CollisionGetter view, final Entity entity, final AABB aabb, -+ final List into, final boolean loadChunks, final boolean collidesWithUnloadedChunks, -+ final boolean checkBorder, final boolean checkOnly, final BiPredicate blockPredicate, -+ final Predicate entityPredicate) { -+ if (checkOnly) { -+ return getCollisionsForBlocksOrWorldBorder(view, entity, aabb, into, loadChunks, collidesWithUnloadedChunks, checkBorder, checkOnly, blockPredicate) -+ || getEntityHardCollisions(view, entity, aabb, into, checkOnly, entityPredicate); -+ } else { -+ return getCollisionsForBlocksOrWorldBorder(view, entity, aabb, into, loadChunks, collidesWithUnloadedChunks, checkBorder, checkOnly, blockPredicate) -+ | getEntityHardCollisions(view, entity, aabb, into, checkOnly, entityPredicate); -+ } -+ } -+ -+ public static final class LazyEntityCollisionContext extends EntityCollisionContext { -+ -+ private CollisionContext delegate; -+ private final Entity entity; -+ -+ public LazyEntityCollisionContext(final Entity entity) { -+ super(false, 0.0, null, null, null, Optional.ofNullable(entity)); -+ this.entity = entity; -+ } -+ -+ public CollisionContext getDelegate() { -+ return this.delegate == null ? this.delegate = (this.entity == null ? CollisionContext.empty() : CollisionContext.of(this.entity)) : this.delegate; -+ } -+ -+ @Override -+ public boolean isDescending() { -+ return this.getDelegate().isDescending(); -+ } -+ -+ @Override -+ public boolean isAbove(final VoxelShape shape, final BlockPos pos, final boolean defaultValue) { -+ return this.getDelegate().isAbove(shape, pos, defaultValue); -+ } -+ -+ @Override -+ public boolean hasItemOnFeet(final Item item) { -+ return this.getDelegate().hasItemOnFeet(item); -+ } -+ -+ @Override -+ public boolean isHoldingItem(final Item item) { -+ return this.getDelegate().isHoldingItem(item); -+ } -+ -+ @Override -+ public boolean canStandOnFluid(final FluidState state, final FlowingFluid fluid) { -+ return this.getDelegate().canStandOnFluid(state, fluid); -+ } -+ } -+ -+ private CollisionUtil() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/CoordinateUtils.java b/src/main/java/com/tuinity/tuinity/util/CoordinateUtils.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f84060952c947d79bf2dffc61c96a300e8d7fac2 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/CoordinateUtils.java -@@ -0,0 +1,128 @@ -+package com.tuinity.tuinity.util; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.SectionPos; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.ChunkPos; -+ -+public final class CoordinateUtils { -+ -+ // dx, dz are relative to the target chunk -+ // dx, dz in [-radius, radius] -+ public static int getNeighbourMappedIndex(final int dx, final int dz, final int radius) { -+ return (dx + radius) + (2 * radius + 1)*(dz + radius); -+ } -+ -+ // the chunk keys are compatible with vanilla -+ -+ public static long getChunkKey(final BlockPos pos) { -+ return ((long)(pos.getZ() >> 4) << 32) | ((pos.getX() >> 4) & 0xFFFFFFFFL); -+ } -+ -+ public static long getChunkKey(final Entity entity) { -+ return ((Mth.lfloor(entity.getZ()) >> 4) << 32) | ((Mth.lfloor(entity.getX()) >> 4) & 0xFFFFFFFFL); -+ } -+ -+ public static long getChunkKey(final ChunkPos pos) { -+ return ((long)pos.z << 32) | (pos.x & 0xFFFFFFFFL); -+ } -+ -+ public static long getChunkKey(final SectionPos pos) { -+ return ((long)pos.getZ() << 32) | (pos.getX() & 0xFFFFFFFFL); -+ } -+ -+ public static long getChunkKey(final int x, final int z) { -+ return ((long)z << 32) | (x & 0xFFFFFFFFL); -+ } -+ -+ public static int getChunkX(final long chunkKey) { -+ return (int)chunkKey; -+ } -+ -+ public static int getChunkZ(final long chunkKey) { -+ return (int)(chunkKey >>> 32); -+ } -+ -+ public static int getChunkCoordinate(final double blockCoordinate) { -+ return Mth.floor(blockCoordinate) >> 4; -+ } -+ -+ // the section keys are compatible with vanilla's -+ -+ static final int SECTION_X_BITS = 22; -+ static final long SECTION_X_MASK = (1L << SECTION_X_BITS) - 1; -+ static final int SECTION_Y_BITS = 20; -+ static final long SECTION_Y_MASK = (1L << SECTION_Y_BITS) - 1; -+ static final int SECTION_Z_BITS = 22; -+ static final long SECTION_Z_MASK = (1L << SECTION_Z_BITS) - 1; -+ // format is y,z,x (in order of LSB to MSB) -+ static final int SECTION_Y_SHIFT = 0; -+ static final int SECTION_Z_SHIFT = SECTION_Y_SHIFT + SECTION_Y_BITS; -+ static final int SECTION_X_SHIFT = SECTION_Z_SHIFT + SECTION_X_BITS; -+ static final int SECTION_TO_BLOCK_SHIFT = 4; -+ -+ public static long getChunkSectionKey(final int x, final int y, final int z) { -+ return ((x & SECTION_X_MASK) << SECTION_X_SHIFT) -+ | ((y & SECTION_Y_MASK) << SECTION_Y_SHIFT) -+ | ((z & SECTION_Z_MASK) << SECTION_Z_SHIFT); -+ } -+ -+ public static long getChunkSectionKey(final SectionPos pos) { -+ return ((pos.getX() & SECTION_X_MASK) << SECTION_X_SHIFT) -+ | ((pos.getY() & SECTION_Y_MASK) << SECTION_Y_SHIFT) -+ | ((pos.getZ() & SECTION_Z_MASK) << SECTION_Z_SHIFT); -+ } -+ -+ public static long getChunkSectionKey(final ChunkPos pos, final int y) { -+ return ((pos.x & SECTION_X_MASK) << SECTION_X_SHIFT) -+ | ((y & SECTION_Y_MASK) << SECTION_Y_SHIFT) -+ | ((pos.z & SECTION_Z_MASK) << SECTION_Z_SHIFT); -+ } -+ -+ public static long getChunkSectionKey(final BlockPos pos) { -+ return (((long)pos.getX() << (SECTION_X_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_X_MASK << SECTION_X_SHIFT)) | -+ ((pos.getY() >> SECTION_TO_BLOCK_SHIFT) & (SECTION_Y_MASK << SECTION_Y_SHIFT)) | -+ (((long)pos.getZ() << (SECTION_Z_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_Z_MASK << SECTION_Z_SHIFT)); -+ } -+ -+ public static long getChunkSectionKey(final Entity entity) { -+ return ((Mth.lfloor(entity.getX()) << (SECTION_X_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_X_MASK << SECTION_X_SHIFT)) | -+ ((Mth.lfloor(entity.getY()) >> SECTION_TO_BLOCK_SHIFT) & (SECTION_Y_MASK << SECTION_Y_SHIFT)) | -+ ((Mth.lfloor(entity.getZ()) << (SECTION_Z_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_Z_MASK << SECTION_Z_SHIFT)); -+ } -+ -+ public static int getChunkSectionX(final long key) { -+ return (int)(key << (Long.SIZE - (SECTION_X_SHIFT + SECTION_X_BITS)) >> (Long.SIZE - SECTION_X_BITS)); -+ } -+ -+ public static int getChunkSectionY(final long key) { -+ return (int)(key << (Long.SIZE - (SECTION_Y_SHIFT + SECTION_Y_BITS)) >> (Long.SIZE - SECTION_Y_BITS)); -+ } -+ -+ public static int getChunkSectionZ(final long key) { -+ return (int)(key << (Long.SIZE - (SECTION_Z_SHIFT + SECTION_Z_BITS)) >> (Long.SIZE - SECTION_Z_BITS)); -+ } -+ -+ // the block coordinates are not necessarily compatible with vanilla's -+ -+ public static int getBlockCoordinate(final double blockCoordinate) { -+ return Mth.floor(blockCoordinate); -+ } -+ -+ public static long getBlockKey(final int x, final int y, final int z) { -+ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); -+ } -+ -+ public static long getBlockKey(final BlockPos pos) { -+ return ((long)pos.getX() & 0x7FFFFFF) | (((long)pos.getZ() & 0x7FFFFFF) << 27) | ((long)pos.getY() << 54); -+ } -+ -+ public static long getBlockKey(final Entity entity) { -+ return ((long)entity.getX() & 0x7FFFFFF) | (((long)entity.getZ() & 0x7FFFFFF) << 27) | ((long)entity.getY() << 54); -+ } -+ -+ private CoordinateUtils() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/IntegerUtil.java b/src/main/java/com/tuinity/tuinity/util/IntegerUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..695444a510e616180734f5fd284f1a00a2d73ea6 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/IntegerUtil.java -@@ -0,0 +1,226 @@ -+package com.tuinity.tuinity.util; -+ -+public final class IntegerUtil { -+ -+ public static final int HIGH_BIT_U32 = Integer.MIN_VALUE; -+ public static final long HIGH_BIT_U64 = Long.MIN_VALUE; -+ -+ public static int ceilLog2(final int value) { -+ return Integer.SIZE - Integer.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros -+ } -+ -+ public static long ceilLog2(final long value) { -+ return Long.SIZE - Long.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros -+ } -+ -+ public static int floorLog2(final int value) { -+ // xor is optimized subtract for 2^n -1 -+ // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1) -+ return (Integer.SIZE - 1) ^ Integer.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros -+ } -+ -+ public static int floorLog2(final long value) { -+ // xor is optimized subtract for 2^n -1 -+ // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1) -+ return (Long.SIZE - 1) ^ Long.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros -+ } -+ -+ public static int roundCeilLog2(final int value) { -+ // optimized variant of 1 << (32 - leading(val - 1)) -+ // given -+ // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32) -+ // 1 << (32 - leading(val - 1)) = HIGH_BIT_32 >>> (31 - (32 - leading(val - 1))) -+ // HIGH_BIT_32 >>> (31 - (32 - leading(val - 1))) -+ // HIGH_BIT_32 >>> (31 - 32 + leading(val - 1)) -+ // HIGH_BIT_32 >>> (-1 + leading(val - 1)) -+ return HIGH_BIT_U32 >>> (Integer.numberOfLeadingZeros(value - 1) - 1); -+ } -+ -+ public static long roundCeilLog2(final long value) { -+ // see logic documented above -+ return HIGH_BIT_U64 >>> (Long.numberOfLeadingZeros(value - 1) - 1); -+ } -+ -+ public static int roundFloorLog2(final int value) { -+ // optimized variant of 1 << (31 - leading(val)) -+ // given -+ // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32) -+ // 1 << (31 - leading(val)) = HIGH_BIT_32 >> (31 - (31 - leading(val))) -+ // HIGH_BIT_32 >> (31 - (31 - leading(val))) -+ // HIGH_BIT_32 >> (31 - 31 + leading(val)) -+ return HIGH_BIT_U32 >>> Integer.numberOfLeadingZeros(value); -+ } -+ -+ public static long roundFloorLog2(final long value) { -+ // see logic documented above -+ return HIGH_BIT_U64 >>> Long.numberOfLeadingZeros(value); -+ } -+ -+ public static boolean isPowerOfTwo(final int n) { -+ // 2^n has one bit -+ // note: this rets true for 0 still -+ return IntegerUtil.getTrailingBit(n) == n; -+ } -+ -+ public static boolean isPowerOfTwo(final long n) { -+ // 2^n has one bit -+ // note: this rets true for 0 still -+ return IntegerUtil.getTrailingBit(n) == n; -+ } -+ -+ public static int getTrailingBit(final int n) { -+ return -n & n; -+ } -+ -+ public static long getTrailingBit(final long n) { -+ return -n & n; -+ } -+ -+ public static int trailingZeros(final int n) { -+ return Integer.numberOfTrailingZeros(n); -+ } -+ -+ public static int trailingZeros(final long n) { -+ return Long.numberOfTrailingZeros(n); -+ } -+ -+ // from hacker's delight (signed division magic value) -+ public static int getDivisorMultiple(final long numbers) { -+ return (int)(numbers >>> 32); -+ } -+ -+ // from hacker's delight (signed division magic value) -+ public static int getDivisorShift(final long numbers) { -+ return (int)numbers; -+ } -+ -+ // copied from hacker's delight (signed division magic value) -+ // http://www.hackersdelight.org/hdcodetxt/magic.c.txt -+ public static long getDivisorNumbers(final int d) { -+ final int ad = IntegerUtil.branchlessAbs(d); -+ -+ if (ad < 2) { -+ throw new IllegalArgumentException("|number| must be in [2, 2^31 -1], not: " + d); -+ } -+ -+ final int two31 = 0x80000000; -+ final long mask = 0xFFFFFFFFL; // mask for enforcing unsigned behaviour -+ -+ int p = 31; -+ -+ // all these variables are UNSIGNED! -+ int t = two31 + (d >>> 31); -+ int anc = t - 1 - t%ad; -+ int q1 = (int)((two31 & mask)/(anc & mask)); -+ int r1 = two31 - q1*anc; -+ int q2 = (int)((two31 & mask)/(ad & mask)); -+ int r2 = two31 - q2*ad; -+ int delta; -+ -+ do { -+ p = p + 1; -+ q1 = 2*q1; // Update q1 = 2**p/|nc|. -+ r1 = 2*r1; // Update r1 = rem(2**p, |nc|). -+ if ((r1 & mask) >= (anc & mask)) {// (Must be an unsigned comparison here) -+ q1 = q1 + 1; -+ r1 = r1 - anc; -+ } -+ q2 = 2*q2; // Update q2 = 2**p/|d|. -+ r2 = 2*r2; // Update r2 = rem(2**p, |d|). -+ if ((r2 & mask) >= (ad & mask)) {// (Must be an unsigned comparison here) -+ q2 = q2 + 1; -+ r2 = r2 - ad; -+ } -+ delta = ad - r2; -+ } while ((q1 & mask) < (delta & mask) || (q1 == delta && r1 == 0)); -+ -+ int magicNum = q2 + 1; -+ if (d < 0) { -+ magicNum = -magicNum; -+ } -+ int shift = p - 32; -+ return ((long)magicNum << 32) | shift; -+ } -+ -+ public static int branchlessAbs(final int val) { -+ // -n = -1 ^ n + 1 -+ final int mask = val >> (Integer.SIZE - 1); // -1 if < 0, 0 if >= 0 -+ return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1 -+ } -+ -+ public static long branchlessAbs(final long val) { -+ // -n = -1 ^ n + 1 -+ final long mask = val >> (Long.SIZE - 1); // -1 if < 0, 0 if >= 0 -+ return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1 -+ } -+ -+ //https://github.com/skeeto/hash-prospector for hash functions -+ -+ //score = ~590.47984224483832 -+ public static int hash0(int x) { -+ x *= 0x36935555; -+ x ^= x >>> 16; -+ return x; -+ } -+ -+ //score = ~310.01596637036749 -+ public static int hash1(int x) { -+ x ^= x >>> 15; -+ x *= 0x356aaaad; -+ x ^= x >>> 17; -+ return x; -+ } -+ -+ public static int hash2(int x) { -+ x ^= x >>> 16; -+ x *= 0x7feb352d; -+ x ^= x >>> 15; -+ x *= 0x846ca68b; -+ x ^= x >>> 16; -+ return x; -+ } -+ -+ public static int hash3(int x) { -+ x ^= x >>> 17; -+ x *= 0xed5ad4bb; -+ x ^= x >>> 11; -+ x *= 0xac4c1b51; -+ x ^= x >>> 15; -+ x *= 0x31848bab; -+ x ^= x >>> 14; -+ return x; -+ } -+ -+ //score = ~365.79959673201887 -+ public static long hash1(long x) { -+ x ^= x >>> 27; -+ x *= 0xb24924b71d2d354bL; -+ x ^= x >>> 28; -+ return x; -+ } -+ -+ //h2 hash -+ public static long hash2(long x) { -+ x ^= x >>> 32; -+ x *= 0xd6e8feb86659fd93L; -+ x ^= x >>> 32; -+ x *= 0xd6e8feb86659fd93L; -+ x ^= x >>> 32; -+ return x; -+ } -+ -+ public static long hash3(long x) { -+ x ^= x >>> 45; -+ x *= 0xc161abe5704b6c79L; -+ x ^= x >>> 41; -+ x *= 0xe3e5389aedbc90f7L; -+ x ^= x >>> 56; -+ x *= 0x1f9aba75a52db073L; -+ x ^= x >>> 53; -+ return x; -+ } -+ -+ private IntegerUtil() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/IntervalledCounter.java b/src/main/java/com/tuinity/tuinity/util/IntervalledCounter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d2c7d2c7920324d7207225ed19484e804368489d ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/IntervalledCounter.java -@@ -0,0 +1,100 @@ -+package com.tuinity.tuinity.util; -+ -+public final class IntervalledCounter { -+ -+ protected long[] times; -+ protected final long interval; -+ protected long minTime; -+ protected int sum; -+ protected int head; // inclusive -+ protected int tail; // exclusive -+ -+ public IntervalledCounter(final long interval) { -+ this.times = new long[8]; -+ this.interval = interval; -+ } -+ -+ public void updateCurrentTime() { -+ this.updateCurrentTime(System.nanoTime()); -+ } -+ -+ public void updateCurrentTime(final long currentTime) { -+ int sum = this.sum; -+ int head = this.head; -+ final int tail = this.tail; -+ final long minTime = currentTime - this.interval; -+ -+ final int arrayLen = this.times.length; -+ -+ // guard against overflow by using subtraction -+ while (head != tail && this.times[head] - minTime < 0) { -+ head = (head + 1) % arrayLen; -+ --sum; -+ } -+ -+ this.sum = sum; -+ this.head = head; -+ this.minTime = minTime; -+ } -+ -+ public void addTime(final long currTime) { -+ // guard against overflow by using subtraction -+ if (currTime - this.minTime < 0) { -+ return; -+ } -+ int nextTail = (this.tail + 1) % this.times.length; -+ if (nextTail == this.head) { -+ this.resize(); -+ nextTail = (this.tail + 1) % this.times.length; -+ } -+ -+ this.times[this.tail] = currTime; -+ this.tail = nextTail; -+ } -+ -+ public void updateAndAdd(final int count) { -+ final long currTime = System.nanoTime(); -+ this.updateCurrentTime(currTime); -+ for (int i = 0; i < count; ++i) { -+ this.addTime(currTime); -+ } -+ } -+ -+ public void updateAndAdd(final int count, final long currTime) { -+ this.updateCurrentTime(currTime); -+ for (int i = 0; i < count; ++i) { -+ this.addTime(currTime); -+ } -+ } -+ -+ private void resize() { -+ final long[] oldElements = this.times; -+ final long[] newElements = new long[this.times.length * 2]; -+ this.times = newElements; -+ -+ final int head = this.head; -+ final int tail = this.tail; -+ final int size = tail >= head ? (tail - head) : (tail + (oldElements.length - head)); -+ this.head = 0; -+ this.tail = size; -+ -+ if (tail >= head) { -+ System.arraycopy(oldElements, head, newElements, 0, size); -+ } else { -+ System.arraycopy(oldElements, head, newElements, 0, oldElements.length - head); -+ System.arraycopy(oldElements, 0, newElements, oldElements.length - head, tail); -+ } -+ } -+ -+ // returns in units per second -+ public double getRate() { -+ return this.size() / (this.interval * 1.0e-9); -+ } -+ -+ public int size() { -+ final int head = this.head; -+ final int tail = this.tail; -+ -+ return tail >= head ? (tail - head) : (tail + (this.times.length - head)); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/PoiAccess.java b/src/main/java/com/tuinity/tuinity/util/PoiAccess.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a7ae9f0f4e56138465b0d8913d3cea9d5e9b56f2 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/PoiAccess.java -@@ -0,0 +1,748 @@ -+package com.tuinity.tuinity.util; -+ -+import it.unimi.dsi.fastutil.doubles.Double2ObjectMap; -+import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; -+import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; -+import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -+import net.minecraft.core.BlockPos; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.ai.village.poi.PoiManager; -+import net.minecraft.world.entity.ai.village.poi.PoiRecord; -+import net.minecraft.world.entity.ai.village.poi.PoiSection; -+import net.minecraft.world.entity.ai.village.poi.PoiType; -+import java.util.ArrayList; -+import java.util.HashSet; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Map; -+import java.util.Optional; -+import java.util.Set; -+import java.util.function.Predicate; -+ -+/** -+ * Provides optimised access to POI data. All returned values will be identical to vanilla. -+ */ -+public final class PoiAccess { -+ -+ protected static double clamp(final double val, final double min, final double max) { -+ return (val < min ? min : (val > max ? max : val)); -+ } -+ -+ protected static double getSmallestDistanceSquared(final double boxMinX, final double boxMinY, final double boxMinZ, -+ final double boxMaxX, final double boxMaxY, final double boxMaxZ, -+ -+ final double circleX, final double circleY, final double circleZ) { -+ // is the circle center inside the box? -+ if (circleX >= boxMinX && circleX <= boxMaxX && circleY >= boxMinY && circleY <= boxMaxY && circleZ >= boxMinZ && circleZ <= boxMaxZ) { -+ return 0.0; -+ } -+ -+ final double boxWidthX = (boxMaxX - boxMinX) / 2.0; -+ final double boxWidthY = (boxMaxY - boxMinY) / 2.0; -+ final double boxWidthZ = (boxMaxZ - boxMinZ) / 2.0; -+ -+ final double boxCenterX = (boxMinX + boxMaxX) / 2.0; -+ final double boxCenterY = (boxMinY + boxMaxY) / 2.0; -+ final double boxCenterZ = (boxMinZ + boxMaxZ) / 2.0; -+ -+ double centerDiffX = circleX - boxCenterX; -+ double centerDiffY = circleY - boxCenterY; -+ double centerDiffZ = circleZ - boxCenterZ; -+ -+ centerDiffX = circleX - (clamp(centerDiffX, -boxWidthX, boxWidthX) + boxCenterX); -+ centerDiffY = circleY - (clamp(centerDiffY, -boxWidthY, boxWidthY) + boxCenterY); -+ centerDiffZ = circleZ - (clamp(centerDiffZ, -boxWidthZ, boxWidthZ) + boxCenterZ); -+ -+ return (centerDiffX * centerDiffX) + (centerDiffY * centerDiffY) + (centerDiffZ * centerDiffZ); -+ } -+ -+ -+ // key is: -+ // upper 32 bits: -+ // upper 16 bits: max y section -+ // lower 16 bits: min y section -+ // lower 32 bits: -+ // upper 16 bits: section -+ // lower 16 bits: radius -+ protected static long getKey(final int minSection, final int maxSection, final int section, final int radius) { -+ return ( -+ (maxSection & 0xFFFFL) << (64 - 16) -+ | (minSection & 0xFFFFL) << (64 - 32) -+ | (section & 0xFFFFL) << (64 - 48) -+ | (radius & 0xFFFFL) << (64 - 64) -+ ); -+ } -+ -+ // only includes x/z axis -+ // finds the closest poi data by distance. -+ public static BlockPos findClosestPoiDataPosition(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load) { -+ final PoiRecord ret = findClosestPoiDataRecord( -+ poiStorage, villagePlaceType, positionPredicate, sourcePosition, range, maxDistance, occupancy, load -+ ); -+ -+ return ret == null ? null : ret.getPos(); -+ } -+ -+ // only includes x/z axis -+ // finds the closest poi data by distance. if multiple match the same distance, then they all are returned. -+ public static void findClosestPoiDataPositions(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load, -+ final Set ret) { -+ final Set positions = new HashSet<>(); -+ // pos predicate is last thing that runs before adding to ret. -+ final Predicate newPredicate = (final BlockPos pos) -> { -+ if (positionPredicate != null && !positionPredicate.test(pos)) { -+ return false; -+ } -+ return positions.add(pos.immutable()); -+ }; -+ -+ final List toConvert = new ArrayList<>(); -+ findClosestPoiDataRecords( -+ poiStorage, villagePlaceType, newPredicate, sourcePosition, range, maxDistance, occupancy, load, toConvert -+ ); -+ -+ for (final PoiRecord record : toConvert) { -+ ret.add(record.getPos()); -+ } -+ } -+ -+ // only includes x/z axis -+ // finds the closest poi data by distance. -+ public static PoiRecord findClosestPoiDataRecord(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load) { -+ final List ret = new ArrayList<>(); -+ findClosestPoiDataRecords( -+ poiStorage, villagePlaceType, positionPredicate, sourcePosition, range, maxDistance, occupancy, load, ret -+ ); -+ return ret.isEmpty() ? null : ret.get(0); -+ } -+ -+ // only includes x/z axis -+ // finds the closest poi data by distance. if multiple match the same distance, then they all are returned. -+ public static void findClosestPoiDataRecords(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load, -+ final List ret) { -+ final Predicate occupancyFilter = occupancy.getTest(); -+ -+ final List closestRecords = new ArrayList<>(); -+ double closestDistanceSquared = maxDistance * maxDistance; -+ -+ final int lowerX = Mth.floor(sourcePosition.getX() - range) >> 4; -+ final int lowerY = WorldUtil.getMinSection(poiStorage.world); -+ final int lowerZ = Mth.floor(sourcePosition.getZ() - range) >> 4; -+ final int upperX = Mth.floor(sourcePosition.getX() + range) >> 4; -+ final int upperY = WorldUtil.getMaxSection(poiStorage.world); -+ final int upperZ = Mth.floor(sourcePosition.getZ() + range) >> 4; -+ -+ final int centerX = sourcePosition.getX() >> 4; -+ final int centerY = Mth.clamp(sourcePosition.getY() >> 4, lowerY, upperY); -+ final int centerZ = sourcePosition.getZ() >> 4; -+ -+ final LongArrayFIFOQueue queue = new LongArrayFIFOQueue(); -+ queue.enqueue(CoordinateUtils.getChunkSectionKey(centerX, centerY, centerZ)); -+ final LongOpenHashSet seen = new LongOpenHashSet(); -+ -+ while (!queue.isEmpty()) { -+ final long key = queue.dequeueLong(); -+ final int sectionX = CoordinateUtils.getChunkSectionX(key); -+ final int sectionY = CoordinateUtils.getChunkSectionY(key); -+ final int sectionZ = CoordinateUtils.getChunkSectionZ(key); -+ -+ if (sectionX < lowerX || sectionX > upperX || sectionY < lowerY || sectionY > upperY || sectionZ < lowerZ || sectionZ > upperZ) { -+ // out of bound chunk -+ continue; -+ } -+ -+ final double sectionDistanceSquared = getSmallestDistanceSquared( -+ (sectionX << 4) + 0.5, -+ (sectionY << 4) + 0.5, -+ (sectionZ << 4) + 0.5, -+ (sectionX << 4) + 15.5, -+ (sectionY << 4) + 15.5, -+ (sectionZ << 4) + 15.5, -+ (double)sourcePosition.getX(), (double)sourcePosition.getY(), (double)sourcePosition.getZ() -+ ); -+ if (sectionDistanceSquared > closestDistanceSquared) { -+ continue; -+ } -+ -+ // queue all neighbours -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dy = -1; dy <= 1; ++dy) { -+ // -1 and 1 have the 1st bit set. so just add up the first bits, and it will tell us how many -+ // values are set. we only care about cardinal neighbours, so, we only care if one value is set -+ if ((dx & 1) + (dy & 1) + (dz & 1) != 1) { -+ continue; -+ } -+ -+ final int neighbourX = sectionX + dx; -+ final int neighbourY = sectionY + dy; -+ final int neighbourZ = sectionZ + dz; -+ -+ final long neighbourKey = CoordinateUtils.getChunkSectionKey(neighbourX, neighbourY, neighbourZ); -+ if (seen.add(neighbourKey)) { -+ queue.enqueue(neighbourKey); -+ } -+ } -+ } -+ } -+ -+ final Optional poiSectionOptional = load ? poiStorage.getOrLoad(key) : poiStorage.get(key); -+ -+ if (poiSectionOptional == null || !poiSectionOptional.isPresent()) { -+ continue; -+ } -+ -+ final PoiSection poiSection = poiSectionOptional.orElse(null); -+ -+ final Map> sectionData = poiSection.getData(); -+ if (sectionData.isEmpty()) { -+ continue; -+ } -+ -+ // now we search the section data -+ for (final Map.Entry> entry : sectionData.entrySet()) { -+ if (!villagePlaceType.test(entry.getKey())) { -+ // filter out by poi type -+ continue; -+ } -+ -+ // now we can look at the poi data -+ for (final PoiRecord poiData : entry.getValue()) { -+ if (!occupancyFilter.test(poiData)) { -+ // filter by occupancy -+ continue; -+ } -+ -+ final BlockPos poiPosition = poiData.getPos(); -+ -+ if (Math.abs(poiPosition.getX() - sourcePosition.getX()) > range -+ || Math.abs(poiPosition.getZ() - sourcePosition.getZ()) > range) { -+ // out of range for square radius -+ continue; -+ } -+ -+ // it's important that it's poiPosition.distSqr(source) : the value actually is different IF the values are swapped! -+ final double dataRange = poiPosition.distSqr(sourcePosition); -+ -+ if (dataRange > closestDistanceSquared) { -+ // out of range for distance check -+ continue; -+ } -+ -+ if (positionPredicate != null && !positionPredicate.test(poiPosition)) { -+ // filter by position -+ continue; -+ } -+ -+ if (dataRange < closestDistanceSquared) { -+ closestRecords.clear(); -+ closestDistanceSquared = dataRange; -+ } -+ closestRecords.add(poiData); -+ } -+ } -+ } -+ -+ // uh oh! we might have multiple records that match the distance sorting! -+ // we need to re-order our results by the way vanilla would have iterated over them. -+ closestRecords.sort((record1, record2) -> { -+ // vanilla iterates the same way we do for data inside sections, so we know the ordering inside a section -+ // is fine and should be preserved (this sort is stable so we're good there) -+ // but they iterate sections by x then by z (like the following) -+ // for (int x = -dx; x <= dx; ++x) -+ // for (int z = -dz; z <= dz; ++z) -+ // .... -+ // so we need to reorder such that records with lower chunk z, then lower chunk x come first -+ final BlockPos pos1 = record1.getPos(); -+ final BlockPos pos2 = record2.getPos(); -+ -+ final int cx1 = pos1.getX() >> 4; -+ final int cz1 = pos1.getZ() >> 4; -+ -+ final int cx2 = pos2.getX() >> 4; -+ final int cz2 = pos2.getZ() >> 4; -+ -+ if (cz2 != cz1) { -+ // want smaller z -+ return Integer.compare(cz1, cz2); -+ } -+ -+ if (cx2 != cx1) { -+ // want smaller x -+ return Integer.compare(cx1, cx2); -+ } -+ -+ // same chunk -+ // once vanilla has the chunk, it will iterate from all of the chunk sections starting from smaller y -+ // so now we just compare section y, wanting smaller y -+ -+ return Integer.compare(pos1.getY() >> 4, pos2.getY() >> 4); -+ }); -+ -+ // now we match perfectly what vanilla would have outputted, without having to search the whole radius (hopefully). -+ ret.addAll(closestRecords); -+ } -+ -+ // finds the closest poi entry pos. -+ public static BlockPos findNearestPoiPosition(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load) { -+ final PoiRecord ret = findNearestPoiRecord( -+ poiStorage, villagePlaceType, positionPredicate, sourcePosition, range, maxDistance, occupancy, load -+ ); -+ return ret == null ? null : ret.getPos(); -+ } -+ -+ // finds the closest `max` poi entry positions. -+ public static void findNearestPoiPositions(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load, -+ final int max, -+ final List ret) { -+ final Set positions = new HashSet<>(); -+ // pos predicate is last thing that runs before adding to ret. -+ final Predicate newPredicate = (final BlockPos pos) -> { -+ if (positionPredicate != null && !positionPredicate.test(pos)) { -+ return false; -+ } -+ return positions.add(pos.immutable()); -+ }; -+ -+ final List toConvert = new ArrayList<>(); -+ findNearestPoiRecords( -+ poiStorage, villagePlaceType, newPredicate, sourcePosition, range, maxDistance, occupancy, load, max, toConvert -+ ); -+ -+ for (final PoiRecord record : toConvert) { -+ ret.add(record.getPos()); -+ } -+ } -+ -+ // finds the closest poi entry. -+ public static PoiRecord findNearestPoiRecord(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load) { -+ final List ret = new ArrayList<>(); -+ findNearestPoiRecords( -+ poiStorage, villagePlaceType, positionPredicate, sourcePosition, range, maxDistance, occupancy, load, -+ 1, ret -+ ); -+ return ret.isEmpty() ? null : ret.get(0); -+ } -+ -+ // finds the closest `max` poi entries. -+ public static void findNearestPoiRecords(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ // position predicate must not modify chunk POI -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final double maxDistance, -+ final PoiManager.Occupancy occupancy, -+ final boolean load, -+ final int max, -+ final List ret) { -+ final Predicate occupancyFilter = occupancy.getTest(); -+ -+ final double maxDistanceSquared = maxDistance * maxDistance; -+ final Double2ObjectRBTreeMap> closestRecords = new Double2ObjectRBTreeMap<>(); -+ int totalRecords = 0; -+ double furthestDistanceSquared = maxDistanceSquared; -+ -+ final int lowerX = Mth.floor(sourcePosition.getX() - range) >> 4; -+ final int lowerY = WorldUtil.getMinSection(poiStorage.world); -+ final int lowerZ = Mth.floor(sourcePosition.getZ() - range) >> 4; -+ final int upperX = Mth.floor(sourcePosition.getX() + range) >> 4; -+ final int upperY = WorldUtil.getMaxSection(poiStorage.world); -+ final int upperZ = Mth.floor(sourcePosition.getZ() + range) >> 4; -+ -+ final int centerX = sourcePosition.getX() >> 4; -+ final int centerY = Mth.clamp(sourcePosition.getY() >> 4, lowerY, upperY); -+ final int centerZ = sourcePosition.getZ() >> 4; -+ -+ final LongArrayFIFOQueue queue = new LongArrayFIFOQueue(); -+ queue.enqueue(CoordinateUtils.getChunkSectionKey(centerX, centerY, centerZ)); -+ final LongOpenHashSet seen = new LongOpenHashSet(); -+ -+ while (!queue.isEmpty()) { -+ final long key = queue.dequeueLong(); -+ final int sectionX = CoordinateUtils.getChunkSectionX(key); -+ final int sectionY = CoordinateUtils.getChunkSectionY(key); -+ final int sectionZ = CoordinateUtils.getChunkSectionZ(key); -+ -+ if (sectionX < lowerX || sectionX > upperX || sectionY < lowerY || sectionY > upperY || sectionZ < lowerZ || sectionZ > upperZ) { -+ // out of bound chunk -+ continue; -+ } -+ -+ final double sectionDistanceSquared = getSmallestDistanceSquared( -+ (sectionX << 4) + 0.5, -+ (sectionY << 4) + 0.5, -+ (sectionZ << 4) + 0.5, -+ (sectionX << 4) + 15.5, -+ (sectionY << 4) + 15.5, -+ (sectionZ << 4) + 15.5, -+ (double) sourcePosition.getX(), (double) sourcePosition.getY(), (double) sourcePosition.getZ() -+ ); -+ -+ if (sectionDistanceSquared > (totalRecords >= max ? furthestDistanceSquared : maxDistanceSquared)) { -+ continue; -+ } -+ -+ // queue all neighbours -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dy = -1; dy <= 1; ++dy) { -+ // -1 and 1 have the 1st bit set. so just add up the first bits, and it will tell us how many -+ // values are set. we only care about cardinal neighbours, so, we only care if one value is set -+ if ((dx & 1) + (dy & 1) + (dz & 1) != 1) { -+ continue; -+ } -+ -+ final int neighbourX = sectionX + dx; -+ final int neighbourY = sectionY + dy; -+ final int neighbourZ = sectionZ + dz; -+ -+ final long neighbourKey = CoordinateUtils.getChunkSectionKey(neighbourX, neighbourY, neighbourZ); -+ if (seen.add(neighbourKey)) { -+ queue.enqueue(neighbourKey); -+ } -+ } -+ } -+ } -+ -+ final Optional poiSectionOptional = load ? poiStorage.getOrLoad(key) : poiStorage.get(key); -+ -+ if (poiSectionOptional == null || !poiSectionOptional.isPresent()) { -+ continue; -+ } -+ -+ final PoiSection poiSection = poiSectionOptional.orElse(null); -+ -+ final Map> sectionData = poiSection.getData(); -+ if (sectionData.isEmpty()) { -+ continue; -+ } -+ -+ // now we search the section data -+ for (final Map.Entry> entry : sectionData.entrySet()) { -+ if (!villagePlaceType.test(entry.getKey())) { -+ // filter out by poi type -+ continue; -+ } -+ -+ // now we can look at the poi data -+ for (final PoiRecord poiData : entry.getValue()) { -+ if (!occupancyFilter.test(poiData)) { -+ // filter by occupancy -+ continue; -+ } -+ -+ final BlockPos poiPosition = poiData.getPos(); -+ -+ if (Math.abs(poiPosition.getX() - sourcePosition.getX()) > range -+ || Math.abs(poiPosition.getZ() - sourcePosition.getZ()) > range) { -+ // out of range for square radius -+ continue; -+ } -+ -+ // it's important that it's poiPosition.distSqr(source) : the value actually is different IF the values are swapped! -+ final double dataRange = poiPosition.distSqr(sourcePosition); -+ -+ if (dataRange > maxDistanceSquared) { -+ // out of range for distance check -+ continue; -+ } -+ -+ if (dataRange > furthestDistanceSquared && totalRecords >= max) { -+ // out of range for distance check -+ continue; -+ } -+ -+ if (positionPredicate != null && !positionPredicate.test(poiPosition)) { -+ // filter by position -+ continue; -+ } -+ -+ if (dataRange > furthestDistanceSquared) { -+ // we know totalRecords < max, so this entry is now our furthest -+ furthestDistanceSquared = dataRange; -+ } -+ -+ closestRecords.computeIfAbsent(dataRange, (final double unused) -> { -+ return new ArrayList<>(); -+ }).add(poiData); -+ -+ if (++totalRecords >= max) { -+ if (closestRecords.size() >= 2) { -+ int entriesInClosest = 0; -+ final Iterator>> iterator = closestRecords.double2ObjectEntrySet().iterator(); -+ double nextFurthestDistanceSquared = 0.0; -+ -+ for (int i = 0, len = closestRecords.size() - 1; i < len; ++i) { -+ final Double2ObjectMap.Entry> recordEntry = iterator.next(); -+ entriesInClosest += recordEntry.getValue().size(); -+ nextFurthestDistanceSquared = recordEntry.getDoubleKey(); -+ } -+ -+ if (entriesInClosest >= max) { -+ // the last set of entries at range wont even be considered for sure... nuke em -+ final Double2ObjectMap.Entry> recordEntry = iterator.next(); -+ totalRecords -= recordEntry.getValue().size(); -+ iterator.remove(); -+ -+ furthestDistanceSquared = nextFurthestDistanceSquared; -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ final List closestRecordsUnsorted = new ArrayList<>(); -+ -+ // we're done here, so now just flatten the map and sort it. -+ -+ for (final List records : closestRecords.values()) { -+ closestRecordsUnsorted.addAll(records); -+ } -+ -+ // uh oh! we might have multiple records that match the distance sorting! -+ // we need to re-order our results by the way vanilla would have iterated over them. -+ closestRecordsUnsorted.sort((record1, record2) -> { -+ // vanilla iterates the same way we do for data inside sections, so we know the ordering inside a section -+ // is fine and should be preserved (this sort is stable so we're good there) -+ // but they iterate sections by x then by z (like the following) -+ // for (int x = -dx; x <= dx; ++x) -+ // for (int z = -dz; z <= dz; ++z) -+ // .... -+ // so we need to reorder such that records with lower chunk z, then lower chunk x come first -+ final BlockPos pos1 = record1.getPos(); -+ final BlockPos pos2 = record2.getPos(); -+ -+ final int cx1 = pos1.getX() >> 4; -+ final int cz1 = pos1.getZ() >> 4; -+ -+ final int cx2 = pos2.getX() >> 4; -+ final int cz2 = pos2.getZ() >> 4; -+ -+ if (cz2 != cz1) { -+ // want smaller z -+ return Integer.compare(cz1, cz2); -+ } -+ -+ if (cx2 != cx1) { -+ // want smaller x -+ return Integer.compare(cx1, cx2); -+ } -+ -+ // same chunk -+ // once vanilla has the chunk, it will iterate from all of the chunk sections starting from smaller y -+ // so now we just compare section y, wanting smaller section y -+ -+ return Integer.compare(pos1.getY() >> 4, pos2.getY() >> 4); -+ }); -+ -+ // trim out any entries exceeding our maximum -+ for (int i = closestRecordsUnsorted.size() - 1; i >= max; --i) { -+ closestRecordsUnsorted.remove(i); -+ } -+ -+ // now we match perfectly what vanilla would have outputted, without having to search the whole radius (hopefully). -+ ret.addAll(closestRecordsUnsorted); -+ } -+ -+ public static BlockPos findAnyPoiPosition(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final PoiManager.Occupancy occupancy, -+ final boolean load) { -+ final PoiRecord ret = findAnyPoiRecord( -+ poiStorage, villagePlaceType, positionPredicate, sourcePosition, range, occupancy, load -+ ); -+ -+ return ret == null ? null : ret.getPos(); -+ } -+ -+ public static void findAnyPoiPositions(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final PoiManager.Occupancy occupancy, -+ final boolean load, -+ final int max, -+ final List ret) { -+ final Set positions = new HashSet<>(); -+ // pos predicate is last thing that runs before adding to ret. -+ final Predicate newPredicate = (final BlockPos pos) -> { -+ if (positionPredicate != null && !positionPredicate.test(pos)) { -+ return false; -+ } -+ return positions.add(pos.immutable()); -+ }; -+ -+ final List toConvert = new ArrayList<>(); -+ findAnyPoiRecords( -+ poiStorage, villagePlaceType, newPredicate, sourcePosition, range, occupancy, load, max, toConvert -+ ); -+ -+ for (final PoiRecord record : toConvert) { -+ ret.add(record.getPos()); -+ } -+ } -+ -+ public static PoiRecord findAnyPoiRecord(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final PoiManager.Occupancy occupancy, -+ final boolean load) { -+ final List ret = new ArrayList<>(); -+ findAnyPoiRecords(poiStorage, villagePlaceType, positionPredicate, sourcePosition, range, occupancy, load, 1, ret); -+ return ret.isEmpty() ? null : ret.get(0); -+ } -+ -+ public static void findAnyPoiRecords(final PoiManager poiStorage, -+ final Predicate villagePlaceType, -+ final Predicate positionPredicate, -+ final BlockPos sourcePosition, -+ final int range, // distance on x y z axis -+ final PoiManager.Occupancy occupancy, -+ final boolean load, -+ final int max, -+ final List ret) { -+ // the biggest issue with the original mojang implementation is that they chain so many streams together -+ // the amount of streams chained just rolls performance, even if nothing is iterated over -+ final Predicate occupancyFilter = occupancy.getTest(); -+ final double rangeSquared = range * range; -+ -+ int added = 0; -+ -+ // First up, we need to iterate the chunks -+ // all the values here are in chunk sections -+ final int lowerX = Mth.floor(sourcePosition.getX() - range) >> 4; -+ final int lowerY = Math.max(WorldUtil.getMinSection(poiStorage.world), Mth.floor(sourcePosition.getY() - range) >> 4); -+ final int lowerZ = Mth.floor(sourcePosition.getZ() - range) >> 4; -+ final int upperX = Mth.floor(sourcePosition.getX() + range) >> 4; -+ final int upperY = Math.min(WorldUtil.getMaxSection(poiStorage.world), Mth.floor(sourcePosition.getY() + range) >> 4); -+ final int upperZ = Mth.floor(sourcePosition.getZ() + range) >> 4; -+ -+ // Vanilla iterates by x until max is reached then increases z -+ // vanilla also searches by increasing Y section value -+ for (int currZ = lowerZ; currZ <= upperZ; ++currZ) { -+ for (int currX = lowerX; currX <= upperX; ++currX) { -+ for (int currY = lowerY; currY <= upperY; ++currY) { // vanilla searches the entire chunk because they're actually stupid. just search the sections we need -+ final Optional poiSectionOptional = load ? poiStorage.getOrLoad(CoordinateUtils.getChunkSectionKey(currX, currY, currZ)) : -+ poiStorage.get(CoordinateUtils.getChunkSectionKey(currX, currY, currZ)); -+ final PoiSection poiSection = poiSectionOptional == null ? null : poiSectionOptional.orElse(null); -+ if (poiSection == null) { -+ continue; -+ } -+ -+ final Map> sectionData = poiSection.getData(); -+ if (sectionData.isEmpty()) { -+ continue; -+ } -+ -+ // now we search the section data -+ for (final Map.Entry> entry : sectionData.entrySet()) { -+ if (!villagePlaceType.test(entry.getKey())) { -+ // filter out by poi type -+ continue; -+ } -+ -+ // now we can look at the poi data -+ for (final PoiRecord poiData : entry.getValue()) { -+ if (!occupancyFilter.test(poiData)) { -+ // filter by occupancy -+ continue; -+ } -+ -+ final BlockPos poiPosition = poiData.getPos(); -+ -+ if (Math.abs(poiPosition.getX() - sourcePosition.getX()) > range -+ || Math.abs(poiPosition.getZ() - sourcePosition.getZ()) > range) { -+ // out of range for square radius -+ continue; -+ } -+ -+ if (poiPosition.distSqr(sourcePosition) > rangeSquared) { -+ // out of range for distance check -+ continue; -+ } -+ -+ if (positionPredicate != null && !positionPredicate.test(poiPosition)) { -+ // filter by position -+ continue; -+ } -+ -+ // found one! -+ ret.add(poiData); -+ if (++added >= max) { -+ return; -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ private PoiAccess() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/TickThread.java b/src/main/java/com/tuinity/tuinity/util/TickThread.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a08377e4b0d9c2d78cf851e2c72770cf623de51a ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/TickThread.java -@@ -0,0 +1,41 @@ -+package com.tuinity.tuinity.util; -+ -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.Bukkit; -+ -+public final class TickThread extends Thread { -+ -+ public static final boolean STRICT_THREAD_CHECKS = Boolean.getBoolean("tuinity.strict-thread-checks"); -+ -+ static { -+ if (STRICT_THREAD_CHECKS) { -+ MinecraftServer.LOGGER.warn("Strict thread checks enabled - performance may suffer"); -+ } -+ } -+ -+ public static void softEnsureTickThread(final String reason) { -+ if (!STRICT_THREAD_CHECKS) { -+ return; -+ } -+ ensureTickThread(reason); -+ } -+ -+ -+ public static void ensureTickThread(final String reason) { -+ if (!Bukkit.isPrimaryThread()) { -+ MinecraftServer.LOGGER.fatal("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); -+ throw new IllegalStateException(reason); -+ } -+ } -+ -+ public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */ -+ -+ public TickThread(final Runnable run, final String name, final int id) { -+ super(run, name); -+ this.id = id; -+ } -+ -+ public static TickThread getCurrentTickThread() { -+ return (TickThread)Thread.currentThread(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/WorldUtil.java b/src/main/java/com/tuinity/tuinity/util/WorldUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..958b3aff3dda64323456d7e0ef0346a72d43f3f1 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/WorldUtil.java -@@ -0,0 +1,46 @@ -+package com.tuinity.tuinity.util; -+ -+import net.minecraft.world.level.LevelHeightAccessor; -+ -+public final class WorldUtil { -+ -+ // min, max are inclusive -+ -+ public static int getMaxSection(final LevelHeightAccessor world) { -+ return world.getMaxSection() - 1; // getMaxSection() is exclusive -+ } -+ -+ public static int getMinSection(final LevelHeightAccessor world) { -+ return world.getMinSection(); -+ } -+ -+ public static int getMaxLightSection(final LevelHeightAccessor world) { -+ return getMaxSection(world) + 1; -+ } -+ -+ public static int getMinLightSection(final LevelHeightAccessor world) { -+ return getMinSection(world) - 1; -+ } -+ -+ -+ -+ public static int getTotalSections(final LevelHeightAccessor world) { -+ return getMaxSection(world) - getMinSection(world) + 1; -+ } -+ -+ public static int getTotalLightSections(final LevelHeightAccessor world) { -+ return getMaxLightSection(world) - getMinLightSection(world) + 1; -+ } -+ -+ public static int getMinBlockY(final LevelHeightAccessor world) { -+ return getMinSection(world) << 4; -+ } -+ -+ public static int getMaxBlockY(final LevelHeightAccessor world) { -+ return (getMaxSection(world) << 4) | 15; -+ } -+ -+ private WorldUtil() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java b/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java -new file mode 100644 -index 0000000000000000000000000000000000000000..98a1be343d81d6431476fea6a68014def8ce923b ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java -@@ -0,0 +1,334 @@ -+package com.tuinity.tuinity.util.maplist; -+ -+import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap; -+import it.unimi.dsi.fastutil.objects.Reference2IntMap; -+import org.bukkit.Bukkit; -+import java.util.Arrays; -+import java.util.NoSuchElementException; -+ -+public final class IteratorSafeOrderedReferenceSet { -+ -+ public static final int ITERATOR_FLAG_SEE_ADDITIONS = 1 << 0; -+ -+ protected final Reference2IntLinkedOpenHashMap indexMap; -+ protected int firstInvalidIndex = -1; -+ -+ /* list impl */ -+ protected E[] listElements; -+ protected int listSize; -+ -+ protected final double maxFragFactor; -+ -+ protected int iteratorCount; -+ -+ private final boolean threadRestricted; -+ -+ public IteratorSafeOrderedReferenceSet() { -+ this(16, 0.75f, 16, 0.2); -+ } -+ -+ public IteratorSafeOrderedReferenceSet(final boolean threadRestricted) { -+ this(16, 0.75f, 16, 0.2, threadRestricted); -+ } -+ -+ public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity, -+ final double maxFragFactor) { -+ this(setCapacity, setLoadFactor, arrayCapacity, maxFragFactor, false); -+ } -+ public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity, -+ final double maxFragFactor, final boolean threadRestricted) { -+ this.indexMap = new Reference2IntLinkedOpenHashMap<>(setCapacity, setLoadFactor); -+ this.indexMap.defaultReturnValue(-1); -+ this.maxFragFactor = maxFragFactor; -+ this.listElements = (E[])new Object[arrayCapacity]; -+ this.threadRestricted = threadRestricted; -+ } -+ -+ /* -+ public void check() { -+ int iterated = 0; -+ ReferenceOpenHashSet check = new ReferenceOpenHashSet<>(); -+ if (this.listElements != null) { -+ for (int i = 0; i < this.listSize; ++i) { -+ Object obj = this.listElements[i]; -+ if (obj != null) { -+ iterated++; -+ if (!check.add((E)obj)) { -+ throw new IllegalStateException("contains duplicate"); -+ } -+ if (!this.contains((E)obj)) { -+ throw new IllegalStateException("desync"); -+ } -+ } -+ } -+ } -+ -+ if (iterated != this.size()) { -+ throw new IllegalStateException("Size is mismatched! Got " + iterated + ", expected " + this.size()); -+ } -+ -+ check.clear(); -+ iterated = 0; -+ for (final java.util.Iterator iterator = this.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final E element = iterator.next(); -+ iterated++; -+ if (!check.add(element)) { -+ throw new IllegalStateException("contains duplicate (iterator is wrong)"); -+ } -+ if (!this.contains(element)) { -+ throw new IllegalStateException("desync (iterator is wrong)"); -+ } -+ } -+ -+ if (iterated != this.size()) { -+ throw new IllegalStateException("Size is mismatched! (iterator is wrong) Got " + iterated + ", expected " + this.size()); -+ } -+ } -+ */ -+ -+ protected final boolean allowSafeIteration() { -+ return !this.threadRestricted || Bukkit.isPrimaryThread(); -+ } -+ -+ protected final double getFragFactor() { -+ return 1.0 - ((double)this.indexMap.size() / (double)this.listSize); -+ } -+ -+ public int createRawIterator() { -+ if (this.allowSafeIteration()) { -+ ++this.iteratorCount; -+ } -+ if (this.indexMap.isEmpty()) { -+ return -1; -+ } else { -+ return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0; -+ } -+ } -+ -+ public int advanceRawIterator(final int index) { -+ final E[] elements = this.listElements; -+ int ret = index + 1; -+ for (int len = this.listSize; ret < len; ++ret) { -+ if (elements[ret] != null) { -+ return ret; -+ } -+ } -+ -+ return -1; -+ } -+ -+ public void finishRawIterator() { -+ if (this.allowSafeIteration() && --this.iteratorCount == 0) { -+ if (this.getFragFactor() >= this.maxFragFactor) { -+ this.defrag(); -+ } -+ } -+ } -+ -+ public boolean remove(final E element) { -+ final int index = this.indexMap.removeInt(element); -+ if (index >= 0) { -+ if (this.firstInvalidIndex < 0 || index < this.firstInvalidIndex) { -+ this.firstInvalidIndex = index; -+ } -+ if (this.listElements[index] != element) { -+ throw new IllegalStateException(); -+ } -+ this.listElements[index] = null; -+ if (this.allowSafeIteration() && this.iteratorCount == 0 && this.getFragFactor() >= this.maxFragFactor) { -+ this.defrag(); -+ } -+ //this.check(); -+ return true; -+ } -+ return false; -+ } -+ -+ public boolean contains(final E element) { -+ return this.indexMap.containsKey(element); -+ } -+ -+ public boolean add(final E element) { -+ final int listSize = this.listSize; -+ -+ final int previous = this.indexMap.putIfAbsent(element, listSize); -+ if (previous != -1) { -+ return false; -+ } -+ -+ if (listSize >= this.listElements.length) { -+ this.listElements = Arrays.copyOf(this.listElements, listSize * 2); -+ } -+ this.listElements[listSize] = element; -+ this.listSize = listSize + 1; -+ -+ //this.check(); -+ return true; -+ } -+ -+ protected void defrag() { -+ if (this.firstInvalidIndex < 0) { -+ return; // nothing to do -+ } -+ -+ if (this.indexMap.isEmpty()) { -+ Arrays.fill(this.listElements, 0, this.listSize, null); -+ this.listSize = 0; -+ this.firstInvalidIndex = -1; -+ //this.check(); -+ return; -+ } -+ -+ final E[] backingArray = this.listElements; -+ -+ int lastValidIndex; -+ java.util.Iterator> iterator; -+ -+ if (this.firstInvalidIndex == 0) { -+ iterator = this.indexMap.reference2IntEntrySet().fastIterator(); -+ lastValidIndex = 0; -+ } else { -+ lastValidIndex = this.firstInvalidIndex; -+ final E key = backingArray[lastValidIndex - 1]; -+ iterator = this.indexMap.reference2IntEntrySet().fastIterator(new Reference2IntMap.Entry() { -+ @Override -+ public int getIntValue() { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public int setValue(int i) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public E getKey() { -+ return key; -+ } -+ }); -+ } -+ -+ while (iterator.hasNext()) { -+ final Reference2IntMap.Entry entry = iterator.next(); -+ -+ final int newIndex = lastValidIndex++; -+ backingArray[newIndex] = entry.getKey(); -+ entry.setValue(newIndex); -+ } -+ -+ // cleanup end -+ Arrays.fill(backingArray, lastValidIndex, this.listSize, null); -+ this.listSize = lastValidIndex; -+ this.firstInvalidIndex = -1; -+ //this.check(); -+ } -+ -+ public E rawGet(final int index) { -+ return this.listElements[index]; -+ } -+ -+ public int size() { -+ // always returns the correct amount - listSize can be different -+ return this.indexMap.size(); -+ } -+ -+ public IteratorSafeOrderedReferenceSet.Iterator iterator() { -+ return this.iterator(0); -+ } -+ -+ public IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { -+ if (this.allowSafeIteration()) { -+ ++this.iteratorCount; -+ } -+ return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); -+ } -+ -+ public java.util.Iterator unsafeIterator() { -+ return this.unsafeIterator(0); -+ } -+ public java.util.Iterator unsafeIterator(final int flags) { -+ return new BaseIterator<>(this, false, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); -+ } -+ -+ public static interface Iterator extends java.util.Iterator { -+ -+ public void finishedIterating(); -+ -+ } -+ -+ protected static final class BaseIterator implements IteratorSafeOrderedReferenceSet.Iterator { -+ -+ protected final IteratorSafeOrderedReferenceSet set; -+ protected final boolean canFinish; -+ protected final int maxIndex; -+ protected int nextIndex; -+ protected E pendingValue; -+ protected boolean finished; -+ protected E lastReturned; -+ -+ protected BaseIterator(final IteratorSafeOrderedReferenceSet set, final boolean canFinish, final int maxIndex) { -+ this.set = set; -+ this.canFinish = canFinish; -+ this.maxIndex = maxIndex; -+ } -+ -+ @Override -+ public boolean hasNext() { -+ if (this.finished) { -+ return false; -+ } -+ if (this.pendingValue != null) { -+ return true; -+ } -+ -+ final E[] elements = this.set.listElements; -+ int index, len; -+ for (index = this.nextIndex, len = Math.min(this.maxIndex, this.set.listSize); index < len; ++index) { -+ final E element = elements[index]; -+ if (element != null) { -+ this.pendingValue = element; -+ this.nextIndex = index + 1; -+ return true; -+ } -+ } -+ -+ this.nextIndex = index; -+ return false; -+ } -+ -+ @Override -+ public E next() { -+ if (!this.hasNext()) { -+ throw new NoSuchElementException(); -+ } -+ final E ret = this.pendingValue; -+ -+ this.pendingValue = null; -+ this.lastReturned = ret; -+ -+ return ret; -+ } -+ -+ @Override -+ public void remove() { -+ final E lastReturned = this.lastReturned; -+ if (lastReturned == null) { -+ throw new IllegalStateException(); -+ } -+ this.lastReturned = null; -+ this.set.remove(lastReturned); -+ } -+ -+ @Override -+ public void finishedIterating() { -+ if (this.finished || !this.canFinish) { -+ throw new IllegalStateException(); -+ } -+ this.lastReturned = null; -+ this.finished = true; -+ if (this.set.allowSafeIteration()) { -+ this.set.finishRawIterator(); -+ } -+ } -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/math/ThreadUnsafeRandom.java b/src/main/java/com/tuinity/tuinity/util/math/ThreadUnsafeRandom.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7f2aeb5ed6775ddf38f2561aae8a82f99c8413a7 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/math/ThreadUnsafeRandom.java -@@ -0,0 +1,46 @@ -+package com.tuinity.tuinity.util.math; -+ -+import java.util.Random; -+ -+public final class ThreadUnsafeRandom extends Random { -+ -+ // See javadoc and internal comments for java.util.Random where these values come from, how they are used, and the author for them. -+ private static final long multiplier = 0x5DEECE66DL; -+ private static final long addend = 0xBL; -+ private static final long mask = (1L << 48) - 1; -+ -+ private static long initialScramble(long seed) { -+ return (seed ^ multiplier) & mask; -+ } -+ -+ private long seed; -+ -+ @Override -+ public void setSeed(long seed) { -+ // note: called by Random constructor -+ this.seed = initialScramble(seed); -+ } -+ -+ @Override -+ protected int next(int bits) { -+ // avoid the expensive CAS logic used by superclass -+ return (int) (((this.seed = this.seed * multiplier + addend) & mask) >>> (48 - bits)); -+ } -+ -+ // Taken from -+ // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ -+ // https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2016/06/25/fastrange.c -+ // Original license is public domain -+ public static int fastRandomBounded(final long randomInteger, final long limit) { -+ // randomInteger must be [0, pow(2, 32)) -+ // limit must be [0, pow(2, 32)) -+ return (int)((randomInteger * limit) >>> 32); -+ } -+ -+ @Override -+ public int nextInt(int bound) { -+ // yes this breaks random's spec -+ // however there's nothing that uses this class that relies on it -+ return fastRandomBounded(this.next(32) & 0xFFFFFFFFL, bound); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/com/tuinity/tuinity/util/misc/Delayed26WayDistancePropagator3D.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b8fa9cd9bce312fc85b90e17094241216c620a9e ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/misc/Delayed26WayDistancePropagator3D.java -@@ -0,0 +1,297 @@ -+package com.tuinity.tuinity.util.misc; -+ -+import com.tuinity.tuinity.util.CoordinateUtils; -+import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongIterator; -+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -+ -+public final class Delayed26WayDistancePropagator3D { -+ -+ // this map is considered "stale" unless updates are propagated. -+ protected final Delayed8WayDistancePropagator2D.LevelMap levels = new Delayed8WayDistancePropagator2D.LevelMap(8192*2, 0.6f); -+ -+ // this map is never stale -+ protected final Long2ByteOpenHashMap sources = new Long2ByteOpenHashMap(4096, 0.6f); -+ -+ // Generally updates to positions are made close to other updates, so we link to decrease cache misses when -+ // propagating updates -+ protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); -+ -+ @FunctionalInterface -+ public static interface LevelChangeCallback { -+ -+ /** -+ * This can be called for intermediate updates. So do not rely on newLevel being close to or -+ * the exact level that is expected after a full propagation has occured. -+ */ -+ public void onLevelUpdate(final long coordinate, final byte oldLevel, final byte newLevel); -+ -+ } -+ -+ protected final LevelChangeCallback changeCallback; -+ -+ public Delayed26WayDistancePropagator3D() { -+ this(null); -+ } -+ -+ public Delayed26WayDistancePropagator3D(final LevelChangeCallback changeCallback) { -+ this.changeCallback = changeCallback; -+ } -+ -+ public int getLevel(final long pos) { -+ return this.levels.get(pos); -+ } -+ -+ public int getLevel(final int x, final int y, final int z) { -+ return this.levels.get(CoordinateUtils.getChunkSectionKey(x, y, z)); -+ } -+ -+ public void setSource(final int x, final int y, final int z, final int level) { -+ this.setSource(CoordinateUtils.getChunkSectionKey(x, y, z), level); -+ } -+ -+ public void setSource(final long coordinate, final int level) { -+ if ((level & 63) != level || level == 0) { -+ throw new IllegalArgumentException("Level must be in (0, 63], not " + level); -+ } -+ -+ final byte byteLevel = (byte)level; -+ final byte oldLevel = this.sources.put(coordinate, byteLevel); -+ -+ if (oldLevel == byteLevel) { -+ return; // nothing to do -+ } -+ -+ // queue to update later -+ this.updatedSources.add(coordinate); -+ } -+ -+ public void removeSource(final int x, final int y, final int z) { -+ this.removeSource(CoordinateUtils.getChunkSectionKey(x, y, z)); -+ } -+ -+ public void removeSource(final long coordinate) { -+ if (this.sources.remove(coordinate) != 0) { -+ this.updatedSources.add(coordinate); -+ } -+ } -+ -+ // queues used for BFS propagating levels -+ protected final Delayed8WayDistancePropagator2D.WorkQueue[] levelIncreaseWorkQueues = new Delayed8WayDistancePropagator2D.WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelIncreaseWorkQueues.length; ++i) { -+ this.levelIncreaseWorkQueues[i] = new Delayed8WayDistancePropagator2D.WorkQueue(); -+ } -+ } -+ protected final Delayed8WayDistancePropagator2D.WorkQueue[] levelRemoveWorkQueues = new Delayed8WayDistancePropagator2D.WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelRemoveWorkQueues.length; ++i) { -+ this.levelRemoveWorkQueues[i] = new Delayed8WayDistancePropagator2D.WorkQueue(); -+ } -+ } -+ protected long levelIncreaseWorkQueueBitset; -+ protected long levelRemoveWorkQueueBitset; -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) { -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << level); -+ } -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << index); -+ } -+ -+ protected final void addToRemoveWorkQueue(final long coordinate, final byte level) { -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelRemoveWorkQueueBitset |= (1L << level); -+ } -+ -+ public boolean propagateUpdates() { -+ if (this.updatedSources.isEmpty()) { -+ return false; -+ } -+ -+ boolean ret = false; -+ -+ for (final LongIterator iterator = this.updatedSources.iterator(); iterator.hasNext();) { -+ final long coordinate = iterator.nextLong(); -+ -+ final byte currentLevel = this.levels.get(coordinate); -+ final byte updatedSource = this.sources.get(coordinate); -+ -+ if (currentLevel == updatedSource) { -+ continue; -+ } -+ ret = true; -+ -+ if (updatedSource > currentLevel) { -+ // level increase -+ this.addToIncreaseWorkQueue(coordinate, updatedSource); -+ } else { -+ // level decrease -+ this.addToRemoveWorkQueue(coordinate, currentLevel); -+ // if the current coordinate is a source, then the decrease propagation will detect that and queue -+ // the source propagation -+ } -+ } -+ -+ this.updatedSources.clear(); -+ -+ // propagate source level increases first for performance reasons (in crowded areas hopefully the additions -+ // make the removes remove less) -+ this.propagateIncreases(); -+ -+ // now we propagate the decreases (which will then re-propagate clobbered sources) -+ this.propagateDecreases(); -+ -+ return ret; -+ } -+ -+ protected void propagateIncreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); -+ this.levelIncreaseWorkQueueBitset != 0L; -+ this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { -+ -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final boolean neighbourCheck = level < 0; -+ -+ final byte currentLevel; -+ if (neighbourCheck) { -+ level = (byte)-level; -+ currentLevel = this.levels.get(coordinate); -+ } else { -+ currentLevel = this.levels.putIfGreater(coordinate, level); -+ } -+ -+ if (neighbourCheck) { -+ // used when propagating from decrease to indicate that this level needs to check its neighbours -+ // this means the level at coordinate could be equal, but would still need neighbours checked -+ -+ if (currentLevel != level) { -+ // something caused the level to change, which means something propagated to it (which means -+ // us propagating here is redundant), or something removed the level (which means we -+ // cannot propagate further) -+ continue; -+ } -+ } else if (currentLevel >= level) { -+ // something higher/equal propagated -+ continue; -+ } -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, level); -+ } -+ -+ if (level == 1) { -+ // can't propagate 0 to neighbours -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = CoordinateUtils.getChunkSectionX(coordinate); -+ final int y = CoordinateUtils.getChunkSectionY(coordinate); -+ final int z = CoordinateUtils.getChunkSectionZ(coordinate); -+ -+ for (int dy = -1; dy <= 1; ++dy) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ if ((dy | dz | dx) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = CoordinateUtils.getChunkSectionKey(dx + x, dy + y, dz + z); -+ this.addToIncreaseWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ protected void propagateDecreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); -+ this.levelRemoveWorkQueueBitset != 0L; -+ this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { -+ -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ final byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); -+ if (currentLevel == 0) { -+ // something else removed -+ continue; -+ } -+ -+ if (currentLevel > level) { -+ // something higher propagated here or we hit the propagation of another source -+ // in the second case we need to re-propagate because we could have just clobbered another source's -+ // propagation -+ this.addToIncreaseWorkQueue(coordinate, currentLevel, (byte)-currentLevel); // indicate to the increase code that the level's neighbours need checking -+ continue; -+ } -+ -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, (byte)0); -+ } -+ -+ final byte source = this.sources.get(coordinate); -+ if (source != 0) { -+ // must re-propagate source later -+ this.addToIncreaseWorkQueue(coordinate, source); -+ } -+ -+ if (level == 0) { -+ // can't propagate -1 to neighbours -+ // we have to check neighbours for removing 1 just in case the neighbour is 2 -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = CoordinateUtils.getChunkSectionX(coordinate); -+ final int y = CoordinateUtils.getChunkSectionY(coordinate); -+ final int z = CoordinateUtils.getChunkSectionZ(coordinate); -+ -+ for (int dy = -1; dy <= 1; ++dy) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ if ((dy | dz | dx) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = CoordinateUtils.getChunkSectionKey(dx + x, dy + y, dz + z); -+ this.addToRemoveWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ } -+ -+ // propagate sources we clobbered in the process -+ this.propagateIncreases(); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/com/tuinity/tuinity/util/misc/Delayed8WayDistancePropagator2D.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cdd3c4032c1d6b34a10ba415bd4d0e377aa9af3c ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/misc/Delayed8WayDistancePropagator2D.java -@@ -0,0 +1,718 @@ -+package com.tuinity.tuinity.util.misc; -+ -+import it.unimi.dsi.fastutil.HashCommon; -+import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue; -+import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; -+import it.unimi.dsi.fastutil.longs.LongIterator; -+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -+import net.minecraft.server.MCUtil; -+ -+public final class Delayed8WayDistancePropagator2D { -+ -+ // Test -+ /* -+ protected static void test(int x, int z, com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap reference, Delayed8WayDistancePropagator2D test) { -+ int got = test.getLevel(x, z); -+ -+ int expect = 0; -+ Object[] nearest = reference.getObjectsInRange(x, z) == null ? null : reference.getObjectsInRange(x, z).getBackingSet(); -+ if (nearest != null) { -+ for (Object _obj : nearest) { -+ if (_obj instanceof Ticket) { -+ Ticket ticket = (Ticket)_obj; -+ long ticketCoord = reference.getLastCoordinate(ticket); -+ int viewDistance = reference.getLastViewDistance(ticket); -+ int distance = Math.max(com.destroystokyo.paper.util.math.IntegerUtil.branchlessAbs(MCUtil.getCoordinateX(ticketCoord) - x), -+ com.destroystokyo.paper.util.math.IntegerUtil.branchlessAbs(MCUtil.getCoordinateZ(ticketCoord) - z)); -+ int level = viewDistance - distance; -+ if (level > expect) { -+ expect = level; -+ } -+ } -+ } -+ } -+ -+ if (expect != got) { -+ throw new IllegalStateException("Expected " + expect + " at pos (" + x + "," + z + ") but got " + got); -+ } -+ } -+ -+ static class Ticket { -+ -+ int x; -+ int z; -+ -+ final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet empty -+ = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); -+ -+ } -+ -+ public static void main(final String[] args) { -+ com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap reference = new com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap() { -+ @Override -+ protected com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(Ticket object) { -+ return object.empty; -+ } -+ }; -+ Delayed8WayDistancePropagator2D test = new Delayed8WayDistancePropagator2D(); -+ -+ final int maxDistance = 64; -+ // test origin -+ { -+ Ticket originTicket = new Ticket(); -+ int originDistance = 31; -+ // test single source -+ reference.add(originTicket, 0, 0, originDistance); -+ test.setSource(0, 0, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ // test single source decrease -+ reference.update(originTicket, 0, 0, originDistance/2); -+ test.setSource(0, 0, originDistance/2); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ // test source increase -+ originDistance = 2*originDistance; -+ reference.update(originTicket, 0, 0, originDistance); -+ test.setSource(0, 0, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -4*originDistance; dx <= 4*originDistance; ++dx) { -+ for (int dz = -4*originDistance; dz <= 4*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ reference.remove(originTicket); -+ test.removeSource(0, 0); test.propagateUpdates(); -+ } -+ -+ // test multiple sources at origin -+ { -+ int originDistance = 31; -+ java.util.List list = new java.util.ArrayList<>(); -+ for (int i = 0; i < 10; ++i) { -+ Ticket a = new Ticket(); -+ list.add(a); -+ a.x = (i & 1) == 1 ? -i : i; -+ a.z = (i & 1) == 1 ? -i : i; -+ } -+ for (Ticket ticket : list) { -+ reference.add(ticket, ticket.x, ticket.z, originDistance); -+ test.setSource(ticket.x, ticket.z, originDistance); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level decrease -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance/2); -+ test.setSource(ticket.x, ticket.z, originDistance/2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level increase -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance*2); -+ test.setSource(ticket.x, ticket.z, originDistance*2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket remove -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ if ((i & 3) != 0) { -+ continue; -+ } -+ Ticket ticket = list.get(i); -+ reference.remove(ticket); -+ test.removeSource(ticket.x, ticket.z); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ } -+ -+ // now test at coordinate offsets -+ // test offset -+ { -+ Ticket originTicket = new Ticket(); -+ int originDistance = 31; -+ int offX = 54432; -+ int offZ = -134567; -+ // test single source -+ reference.add(originTicket, offX, offZ, originDistance); -+ test.setSource(offX, offZ, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx + offX, dz + offZ, reference, test); -+ } -+ } -+ // test single source decrease -+ reference.update(originTicket, offX, offZ, originDistance/2); -+ test.setSource(offX, offZ, originDistance/2); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx + offX, dz + offZ, reference, test); -+ } -+ } -+ // test source increase -+ originDistance = 2*originDistance; -+ reference.update(originTicket, offX, offZ, originDistance); -+ test.setSource(offX, offZ, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -4*originDistance; dx <= 4*originDistance; ++dx) { -+ for (int dz = -4*originDistance; dz <= 4*originDistance; ++dz) { -+ test(dx + offX, dz + offZ, reference, test); -+ } -+ } -+ -+ reference.remove(originTicket); -+ test.removeSource(offX, offZ); test.propagateUpdates(); -+ } -+ -+ // test multiple sources at origin -+ { -+ int originDistance = 31; -+ int offX = 54432; -+ int offZ = -134567; -+ java.util.List list = new java.util.ArrayList<>(); -+ for (int i = 0; i < 10; ++i) { -+ Ticket a = new Ticket(); -+ list.add(a); -+ a.x = offX + ((i & 1) == 1 ? -i : i); -+ a.z = offZ + ((i & 1) == 1 ? -i : i); -+ } -+ for (Ticket ticket : list) { -+ reference.add(ticket, ticket.x, ticket.z, originDistance); -+ test.setSource(ticket.x, ticket.z, originDistance); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level decrease -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance/2); -+ test.setSource(ticket.x, ticket.z, originDistance/2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level increase -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance*2); -+ test.setSource(ticket.x, ticket.z, originDistance*2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket remove -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ if ((i & 3) != 0) { -+ continue; -+ } -+ Ticket ticket = list.get(i); -+ reference.remove(ticket); -+ test.removeSource(ticket.x, ticket.z); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ } -+ } -+ */ -+ -+ // this map is considered "stale" unless updates are propagated. -+ protected final LevelMap levels = new LevelMap(8192*2, 0.6f); -+ -+ // this map is never stale -+ protected final Long2ByteOpenHashMap sources = new Long2ByteOpenHashMap(4096, 0.6f); -+ -+ // Generally updates to positions are made close to other updates, so we link to decrease cache misses when -+ // propagating updates -+ protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); -+ -+ @FunctionalInterface -+ public static interface LevelChangeCallback { -+ -+ /** -+ * This can be called for intermediate updates. So do not rely on newLevel being close to or -+ * the exact level that is expected after a full propagation has occured. -+ */ -+ public void onLevelUpdate(final long coordinate, final byte oldLevel, final byte newLevel); -+ -+ } -+ -+ protected final LevelChangeCallback changeCallback; -+ -+ public Delayed8WayDistancePropagator2D() { -+ this(null); -+ } -+ -+ public Delayed8WayDistancePropagator2D(final LevelChangeCallback changeCallback) { -+ this.changeCallback = changeCallback; -+ } -+ -+ public int getLevel(final long pos) { -+ return this.levels.get(pos); -+ } -+ -+ public int getLevel(final int x, final int z) { -+ return this.levels.get(MCUtil.getCoordinateKey(x, z)); -+ } -+ -+ public void setSource(final int x, final int z, final int level) { -+ this.setSource(MCUtil.getCoordinateKey(x, z), level); -+ } -+ -+ public void setSource(final long coordinate, final int level) { -+ if ((level & 63) != level || level == 0) { -+ throw new IllegalArgumentException("Level must be in (0, 63], not " + level); -+ } -+ -+ final byte byteLevel = (byte)level; -+ final byte oldLevel = this.sources.put(coordinate, byteLevel); -+ -+ if (oldLevel == byteLevel) { -+ return; // nothing to do -+ } -+ -+ // queue to update later -+ this.updatedSources.add(coordinate); -+ } -+ -+ public void removeSource(final int x, final int z) { -+ this.removeSource(MCUtil.getCoordinateKey(x, z)); -+ } -+ -+ public void removeSource(final long coordinate) { -+ if (this.sources.remove(coordinate) != 0) { -+ this.updatedSources.add(coordinate); -+ } -+ } -+ -+ // queues used for BFS propagating levels -+ protected final WorkQueue[] levelIncreaseWorkQueues = new WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelIncreaseWorkQueues.length; ++i) { -+ this.levelIncreaseWorkQueues[i] = new WorkQueue(); -+ } -+ } -+ protected final WorkQueue[] levelRemoveWorkQueues = new WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelRemoveWorkQueues.length; ++i) { -+ this.levelRemoveWorkQueues[i] = new WorkQueue(); -+ } -+ } -+ protected long levelIncreaseWorkQueueBitset; -+ protected long levelRemoveWorkQueueBitset; -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) { -+ final WorkQueue queue = this.levelIncreaseWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << level); -+ } -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { -+ final WorkQueue queue = this.levelIncreaseWorkQueues[index]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << index); -+ } -+ -+ protected final void addToRemoveWorkQueue(final long coordinate, final byte level) { -+ final WorkQueue queue = this.levelRemoveWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelRemoveWorkQueueBitset |= (1L << level); -+ } -+ -+ public boolean propagateUpdates() { -+ if (this.updatedSources.isEmpty()) { -+ return false; -+ } -+ -+ boolean ret = false; -+ -+ for (final LongIterator iterator = this.updatedSources.iterator(); iterator.hasNext();) { -+ final long coordinate = iterator.nextLong(); -+ -+ final byte currentLevel = this.levels.get(coordinate); -+ final byte updatedSource = this.sources.get(coordinate); -+ -+ if (currentLevel == updatedSource) { -+ continue; -+ } -+ ret = true; -+ -+ if (updatedSource > currentLevel) { -+ // level increase -+ this.addToIncreaseWorkQueue(coordinate, updatedSource); -+ } else { -+ // level decrease -+ this.addToRemoveWorkQueue(coordinate, currentLevel); -+ // if the current coordinate is a source, then the decrease propagation will detect that and queue -+ // the source propagation -+ } -+ } -+ -+ this.updatedSources.clear(); -+ -+ // propagate source level increases first for performance reasons (in crowded areas hopefully the additions -+ // make the removes remove less) -+ this.propagateIncreases(); -+ -+ // now we propagate the decreases (which will then re-propagate clobbered sources) -+ this.propagateDecreases(); -+ -+ return ret; -+ } -+ -+ protected void propagateIncreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); -+ this.levelIncreaseWorkQueueBitset != 0L; -+ this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { -+ -+ final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final boolean neighbourCheck = level < 0; -+ -+ final byte currentLevel; -+ if (neighbourCheck) { -+ level = (byte)-level; -+ currentLevel = this.levels.get(coordinate); -+ } else { -+ currentLevel = this.levels.putIfGreater(coordinate, level); -+ } -+ -+ if (neighbourCheck) { -+ // used when propagating from decrease to indicate that this level needs to check its neighbours -+ // this means the level at coordinate could be equal, but would still need neighbours checked -+ -+ if (currentLevel != level) { -+ // something caused the level to change, which means something propagated to it (which means -+ // us propagating here is redundant), or something removed the level (which means we -+ // cannot propagate further) -+ continue; -+ } -+ } else if (currentLevel >= level) { -+ // something higher/equal propagated -+ continue; -+ } -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, level); -+ } -+ -+ if (level == 1) { -+ // can't propagate 0 to neighbours -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = (int)coordinate; -+ final int z = (int)(coordinate >>> 32); -+ -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ if ((dx | dz) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = MCUtil.getCoordinateKey(x + dx, z + dz); -+ this.addToIncreaseWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ } -+ -+ protected void propagateDecreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); -+ this.levelRemoveWorkQueueBitset != 0L; -+ this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { -+ -+ final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ final byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); -+ if (currentLevel == 0) { -+ // something else removed -+ continue; -+ } -+ -+ if (currentLevel > level) { -+ // something higher propagated here or we hit the propagation of another source -+ // in the second case we need to re-propagate because we could have just clobbered another source's -+ // propagation -+ this.addToIncreaseWorkQueue(coordinate, currentLevel, (byte)-currentLevel); // indicate to the increase code that the level's neighbours need checking -+ continue; -+ } -+ -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, (byte)0); -+ } -+ -+ final byte source = this.sources.get(coordinate); -+ if (source != 0) { -+ // must re-propagate source later -+ this.addToIncreaseWorkQueue(coordinate, source); -+ } -+ -+ if (level == 0) { -+ // can't propagate -1 to neighbours -+ // we have to check neighbours for removing 1 just in case the neighbour is 2 -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = (int)coordinate; -+ final int z = (int)(coordinate >>> 32); -+ -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ if ((dx | dz) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = MCUtil.getCoordinateKey(x + dx, z + dz); -+ this.addToRemoveWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ -+ // propagate sources we clobbered in the process -+ this.propagateIncreases(); -+ } -+ -+ protected static final class LevelMap extends Long2ByteOpenHashMap { -+ public LevelMap() { -+ super(); -+ } -+ -+ public LevelMap(final int expected, final float loadFactor) { -+ super(expected, loadFactor); -+ } -+ -+ // copied from superclass -+ private int find(final long k) { -+ if (k == 0L) { -+ return this.containsNullKey ? this.n : -(this.n + 1); -+ } else { -+ final long[] key = this.key; -+ long curr; -+ int pos; -+ if ((curr = key[pos = (int)HashCommon.mix(k) & this.mask]) == 0L) { -+ return -(pos + 1); -+ } else if (k == curr) { -+ return pos; -+ } else { -+ while((curr = key[pos = pos + 1 & this.mask]) != 0L) { -+ if (k == curr) { -+ return pos; -+ } -+ } -+ -+ return -(pos + 1); -+ } -+ } -+ } -+ -+ // copied from superclass -+ private void insert(final int pos, final long k, final byte v) { -+ if (pos == this.n) { -+ this.containsNullKey = true; -+ } -+ -+ this.key[pos] = k; -+ this.value[pos] = v; -+ if (this.size++ >= this.maxFill) { -+ this.rehash(HashCommon.arraySize(this.size + 1, this.f)); -+ } -+ } -+ -+ // copied from superclass -+ public byte putIfGreater(final long key, final byte value) { -+ final int pos = this.find(key); -+ if (pos < 0) { -+ if (this.defRetValue < value) { -+ this.insert(-pos - 1, key, value); -+ } -+ return this.defRetValue; -+ } else { -+ final byte curr = this.value[pos]; -+ if (value > curr) { -+ this.value[pos] = value; -+ return curr; -+ } -+ return curr; -+ } -+ } -+ -+ // copied from superclass -+ private void removeEntry(final int pos) { -+ --this.size; -+ this.shiftKeys(pos); -+ if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { -+ this.rehash(this.n / 2); -+ } -+ } -+ -+ // copied from superclass -+ private void removeNullEntry() { -+ this.containsNullKey = false; -+ --this.size; -+ if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { -+ this.rehash(this.n / 2); -+ } -+ } -+ -+ // copied from superclass -+ public byte removeIfGreaterOrEqual(final long key, final byte value) { -+ if (key == 0L) { -+ if (!this.containsNullKey) { -+ return this.defRetValue; -+ } -+ final byte current = this.value[this.n]; -+ if (value >= current) { -+ this.removeNullEntry(); -+ return current; -+ } -+ return current; -+ } else { -+ long[] keys = this.key; -+ byte[] values = this.value; -+ long curr; -+ int pos; -+ if ((curr = keys[pos = (int)HashCommon.mix(key) & this.mask]) == 0L) { -+ return this.defRetValue; -+ } else if (key == curr) { -+ final byte current = values[pos]; -+ if (value >= current) { -+ this.removeEntry(pos); -+ return current; -+ } -+ return current; -+ } else { -+ while((curr = keys[pos = pos + 1 & this.mask]) != 0L) { -+ if (key == curr) { -+ final byte current = values[pos]; -+ if (value >= current) { -+ this.removeEntry(pos); -+ return current; -+ } -+ return current; -+ } -+ } -+ -+ return this.defRetValue; -+ } -+ } -+ } -+ } -+ -+ protected static final class WorkQueue { -+ -+ public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque(); -+ public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque(); -+ -+ } -+ -+ protected static final class NoResizeLongArrayFIFODeque extends LongArrayFIFOQueue { -+ -+ /** -+ * Assumes non-empty. If empty, undefined behaviour. -+ */ -+ public long removeFirstLong() { -+ // copied from superclass -+ long t = this.array[this.start]; -+ if (++this.start == this.length) { -+ this.start = 0; -+ } -+ -+ return t; -+ } -+ } -+ -+ protected static final class NoResizeByteArrayFIFODeque extends ByteArrayFIFOQueue { -+ -+ /** -+ * Assumes non-empty. If empty, undefined behaviour. -+ */ -+ public byte removeFirstByte() { -+ // copied from superclass -+ byte t = this.array[this.start]; -+ if (++this.start == this.length) { -+ this.start = 0; -+ } -+ -+ return t; -+ } -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/util/table/ZeroCollidingReferenceStateTable.java b/src/main/java/com/tuinity/tuinity/util/table/ZeroCollidingReferenceStateTable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3bd1bfab37c8a3b981c86ff09941590f028d24bc ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/util/table/ZeroCollidingReferenceStateTable.java -@@ -0,0 +1,160 @@ -+package com.tuinity.tuinity.util.table; -+ -+import com.google.common.collect.Table; -+import net.minecraft.world.level.block.state.StateHolder; -+import net.minecraft.world.level.block.state.properties.Property; -+import java.util.Collection; -+import java.util.HashSet; -+import java.util.Map; -+import java.util.Set; -+ -+public final class ZeroCollidingReferenceStateTable { -+ -+ // upper 32 bits: starting index -+ // lower 32 bits: bitset for contained ids -+ protected final long[] this_index_table; -+ protected final Comparable[] this_table; -+ protected final StateHolder this_state; -+ -+ protected long[] index_table; -+ protected StateHolder[][] value_table; -+ -+ public ZeroCollidingReferenceStateTable(final StateHolder state, final Map, Comparable> this_map) { -+ this.this_state = state; -+ this.this_index_table = this.create_table(this_map.keySet()); -+ -+ int max_id = -1; -+ for (final Property property : this_map.keySet()) { -+ final int id = lookup_vindex(property, this.this_index_table); -+ if (id > max_id) { -+ max_id = id; -+ } -+ } -+ -+ this.this_table = new Comparable[max_id + 1]; -+ for (final Map.Entry, Comparable> entry : this_map.entrySet()) { -+ this.this_table[lookup_vindex(entry.getKey(), this.this_index_table)] = entry.getValue(); -+ } -+ } -+ -+ public void loadInTable(final Table, Comparable, StateHolder> table, -+ final Map, Comparable> this_map) { -+ final Set> combined = new HashSet<>(table.rowKeySet()); -+ combined.addAll(this_map.keySet()); -+ -+ this.index_table = this.create_table(combined); -+ -+ int max_id = -1; -+ for (final Property property : combined) { -+ final int id = lookup_vindex(property, this.index_table); -+ if (id > max_id) { -+ max_id = id; -+ } -+ } -+ -+ this.value_table = new StateHolder[max_id + 1][]; -+ -+ final Map, Map, StateHolder>> map = table.rowMap(); -+ for (final Property property : map.keySet()) { -+ final Map, StateHolder> propertyMap = map.get(property); -+ -+ final int id = lookup_vindex(property, this.index_table); -+ final StateHolder[] states = this.value_table[id] = new StateHolder[property.getPossibleValues().size()]; -+ -+ for (final Map.Entry, StateHolder> entry : propertyMap.entrySet()) { -+ if (entry.getValue() == null) { -+ // TODO what -+ continue; -+ } -+ -+ states[((Property)property).getIdFor(entry.getKey())] = entry.getValue(); -+ } -+ } -+ -+ -+ for (final Map.Entry, Comparable> entry : this_map.entrySet()) { -+ final Property property = entry.getKey(); -+ final int index = lookup_vindex(property, this.index_table); -+ -+ if (this.value_table[index] == null) { -+ this.value_table[index] = new StateHolder[property.getPossibleValues().size()]; -+ } -+ -+ this.value_table[index][((Property)property).getIdFor(entry.getValue())] = this.this_state; -+ } -+ } -+ -+ -+ protected long[] create_table(final Collection> collection) { -+ int max_id = -1; -+ for (final Property property : collection) { -+ final int id = property.getId(); -+ if (id > max_id) { -+ max_id = id; -+ } -+ } -+ -+ final long[] ret = new long[((max_id + 1) + 31) >>> 5]; // ceil((max_id + 1) / 32) -+ -+ for (final Property property : collection) { -+ final int id = property.getId(); -+ -+ ret[id >>> 5] |= (1L << (id & 31)); -+ } -+ -+ int total = 0; -+ for (int i = 1, len = ret.length; i < len; ++i) { -+ ret[i] |= (long)(total += Long.bitCount(ret[i - 1] & 0xFFFFFFFFL)) << 32; -+ } -+ -+ return ret; -+ } -+ -+ public Comparable get(final Property state) { -+ final Comparable[] table = this.this_table; -+ final int index = lookup_vindex(state, this.this_index_table); -+ -+ if (index < 0 || index >= table.length) { -+ return null; -+ } -+ return table[index]; -+ } -+ -+ public StateHolder get(final Property property, final Comparable with) { -+ final int withId = ((Property)property).getIdFor(with); -+ if (withId < 0) { -+ return null; -+ } -+ -+ final int index = lookup_vindex(property, this.index_table); -+ final StateHolder[][] table = this.value_table; -+ if (index < 0 || index >= table.length) { -+ return null; -+ } -+ -+ final StateHolder[] values = table[index]; -+ -+ if (withId >= values.length) { -+ return null; -+ } -+ -+ return values[withId]; -+ } -+ -+ protected static int lookup_vindex(final Property property, final long[] index_table) { -+ final int id = property.getId(); -+ final long bitset_mask = (1L << (id & 31)); -+ final long lower_mask = bitset_mask - 1; -+ final int index = id >>> 5; -+ if (index >= index_table.length) { -+ return -1; -+ } -+ final long index_value = index_table[index]; -+ final long contains_check = ((index_value & bitset_mask) - 1) >> (Long.SIZE - 1); // -1L if doesn't contain -+ -+ // index = total bits set in lower table values (upper 32 bits of index_value) plus total bits set in lower indices below id -+ // contains_check is 0 if the bitset had id set, else it's -1: so index is unaffected if contains_check == 0, -+ // otherwise it comes out as -1. -+ return (int)(((index_value >>> 32) + Long.bitCount(index_value & lower_mask)) | contains_check); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/voxel/AABBVoxelShape.java b/src/main/java/com/tuinity/tuinity/voxel/AABBVoxelShape.java -new file mode 100644 -index 0000000000000000000000000000000000000000..370c070dedd169fe85ad2cb488dae7aa1dcf28fc ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/voxel/AABBVoxelShape.java -@@ -0,0 +1,200 @@ -+package com.tuinity.tuinity.voxel; -+ -+import com.tuinity.tuinity.util.CollisionUtil; -+import it.unimi.dsi.fastutil.doubles.DoubleArrayList; -+import it.unimi.dsi.fastutil.doubles.DoubleList; -+import net.minecraft.core.Direction; -+import net.minecraft.world.phys.AABB; -+import net.minecraft.world.phys.shapes.Shapes; -+import net.minecraft.world.phys.shapes.VoxelShape; -+import java.util.ArrayList; -+import java.util.List; -+ -+public final class AABBVoxelShape extends VoxelShape { -+ -+ public final AABB aabb; -+ -+ public AABBVoxelShape(AABB aabb) { -+ super(Shapes.getFullUnoptimisedCube().shape); -+ this.aabb = aabb; -+ } -+ -+ @Override -+ public boolean isEmpty() { -+ return CollisionUtil.isEmpty(this.aabb); -+ } -+ -+ @Override -+ public double min(Direction.Axis enumdirection_enumaxis) { -+ switch (enumdirection_enumaxis.ordinal()) { -+ case 0: -+ return this.aabb.minX; -+ case 1: -+ return this.aabb.minY; -+ case 2: -+ return this.aabb.minZ; -+ default: -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ -+ @Override -+ public double max(Direction.Axis enumdirection_enumaxis) { -+ switch (enumdirection_enumaxis.ordinal()) { -+ case 0: -+ return this.aabb.maxX; -+ case 1: -+ return this.aabb.maxY; -+ case 2: -+ return this.aabb.maxZ; -+ default: -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ -+ @Override -+ public AABB bounds() { -+ return this.aabb; -+ } -+ -+ // enum direction axis is from 0 -> 2, so we keep the lower bits for direction axis. -+ @Override -+ protected double get(Direction.Axis enumdirection_enumaxis, int i) { -+ switch (enumdirection_enumaxis.ordinal() | (i << 2)) { -+ case (0 | (0 << 2)): -+ return this.aabb.minX; -+ case (1 | (0 << 2)): -+ return this.aabb.minY; -+ case (2 | (0 << 2)): -+ return this.aabb.minZ; -+ case (0 | (1 << 2)): -+ return this.aabb.maxX; -+ case (1 | (1 << 2)): -+ return this.aabb.maxY; -+ case (2 | (1 << 2)): -+ return this.aabb.maxZ; -+ default: -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ -+ private DoubleList cachedListX; -+ private DoubleList cachedListY; -+ private DoubleList cachedListZ; -+ -+ @Override -+ protected DoubleList getCoords(Direction.Axis enumdirection_enumaxis) { -+ switch (enumdirection_enumaxis.ordinal()) { -+ case 0: -+ return this.cachedListX == null ? this.cachedListX = DoubleArrayList.wrap(new double[] { this.aabb.minX, this.aabb.maxX }) : this.cachedListX; -+ case 1: -+ return this.cachedListY == null ? this.cachedListY = DoubleArrayList.wrap(new double[] { this.aabb.minY, this.aabb.maxY }) : this.cachedListY; -+ case 2: -+ return this.cachedListZ == null ? this.cachedListZ = DoubleArrayList.wrap(new double[] { this.aabb.minZ, this.aabb.maxZ }) : this.cachedListZ; -+ default: -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ -+ @Override -+ public VoxelShape move(double d0, double d1, double d2) { -+ return new AABBVoxelShape(this.aabb.move(d0, d1, d2)); -+ } -+ -+ @Override -+ public VoxelShape optimize() { -+ if (this.isEmpty()) { -+ return Shapes.empty(); -+ } else if (this == Shapes.BLOCK_OPTIMISED || this.aabb.equals(Shapes.BLOCK_OPTIMISED.aabb)) { -+ return Shapes.BLOCK_OPTIMISED; -+ } -+ return this; -+ } -+ -+ @Override -+ public void forAllBoxes(Shapes.DoubleLineConsumer voxelshapes_a) { -+ voxelshapes_a.consume(this.aabb.minX, this.aabb.minY, this.aabb.minZ, this.aabb.maxX, this.aabb.maxY, this.aabb.maxZ); -+ } -+ -+ @Override -+ public List toAabbs() { // getAABBs -+ List ret = new ArrayList<>(1); -+ ret.add(this.aabb); -+ return ret; -+ } -+ -+ @Override -+ protected int findIndex(Direction.Axis enumdirection_enumaxis, double d0) { // findPointIndexAfterOffset -+ switch (enumdirection_enumaxis.ordinal()) { -+ case 0: -+ return d0 < this.aabb.maxX ? (d0 < this.aabb.minX ? -1 : 0) : 1; -+ case 1: -+ return d0 < this.aabb.maxY ? (d0 < this.aabb.minY ? -1 : 0) : 1; -+ case 2: -+ return d0 < this.aabb.maxZ ? (d0 < this.aabb.minZ ? -1 : 0) : 1; -+ default: -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ -+ @Override -+ protected VoxelShape calculateFace(Direction direction) { -+ if (this.isEmpty()) { -+ return Shapes.empty(); -+ } -+ if (this == Shapes.BLOCK_OPTIMISED) { -+ return this; -+ } -+ switch (direction) { -+ case EAST: // +X -+ case WEST: { // -X -+ final double from = direction == Direction.EAST ? 1.0 - CollisionUtil.COLLISION_EPSILON : CollisionUtil.COLLISION_EPSILON; -+ if (from > this.aabb.maxX || this.aabb.minX > from) { -+ return Shapes.empty(); -+ } -+ return new AABBVoxelShape(new AABB(0.0, this.aabb.minY, this.aabb.minZ, 1.0, this.aabb.maxY, this.aabb.maxZ)).optimize(); -+ } -+ case UP: // +Y -+ case DOWN: { // -Y -+ final double from = direction == Direction.UP ? 1.0 - CollisionUtil.COLLISION_EPSILON : CollisionUtil.COLLISION_EPSILON; -+ if (from > this.aabb.maxY || this.aabb.minY > from) { -+ return Shapes.empty(); -+ } -+ return new AABBVoxelShape(new AABB(this.aabb.minX, 0.0, this.aabb.minZ, this.aabb.maxX, 1.0, this.aabb.maxZ)).optimize(); -+ } -+ case SOUTH: // +Z -+ case NORTH: { // -Z -+ final double from = direction == Direction.SOUTH ? 1.0 - CollisionUtil.COLLISION_EPSILON : CollisionUtil.COLLISION_EPSILON; -+ if (from > this.aabb.maxZ || this.aabb.minZ > from) { -+ return Shapes.empty(); -+ } -+ return new AABBVoxelShape(new AABB(this.aabb.minX, this.aabb.minY, 0.0, this.aabb.maxX, this.aabb.maxY, 1.0)).optimize(); -+ } -+ default: { -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ } -+ -+ @Override -+ public double collide(Direction.Axis enumdirection_enumaxis, AABB axisalignedbb, double d0) { -+ if (CollisionUtil.isEmpty(this.aabb) || CollisionUtil.isEmpty(axisalignedbb)) { -+ return d0; -+ } -+ switch (enumdirection_enumaxis.ordinal()) { -+ case 0: -+ return CollisionUtil.collideX(this.aabb, axisalignedbb, d0); -+ case 1: -+ return CollisionUtil.collideY(this.aabb, axisalignedbb, d0); -+ case 2: -+ return CollisionUtil.collideZ(this.aabb, axisalignedbb, d0); -+ default: -+ throw new IllegalStateException("Unknown axis requested"); -+ } -+ } -+ -+ @Override -+ public boolean intersects(AABB axisalingedbb) { -+ return CollisionUtil.voxelShapeIntersect(this.aabb, axisalingedbb); -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/world/ChunkEntitySlices.java b/src/main/java/com/tuinity/tuinity/world/ChunkEntitySlices.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ad711b6c0628a9cd93ff0d5484769807e5e5b9c0 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/world/ChunkEntitySlices.java -@@ -0,0 +1,500 @@ -+package com.tuinity.tuinity.world; -+ -+import com.destroystokyo.paper.util.maplist.EntityList; -+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; -+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.entity.boss.EnderDragonPart; -+import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -+import net.minecraft.world.phys.AABB; -+import java.util.Arrays; -+import java.util.Iterator; -+import java.util.List; -+import java.util.function.Predicate; -+ -+public final class ChunkEntitySlices { -+ -+ protected final int minSection; -+ protected final int maxSection; -+ protected final int chunkX; -+ protected final int chunkZ; -+ protected final ServerLevel world; -+ -+ protected final EntityCollectionBySection allEntities; -+ protected final EntityCollectionBySection hardCollidingEntities; -+ protected final Reference2ObjectOpenHashMap, EntityCollectionBySection> entitiesByClass; -+ protected final EntityList entities = new EntityList(); -+ -+ public ChunkHolder.FullChunkStatus status; -+ -+ // TODO implement container search optimisations -+ -+ public ChunkEntitySlices(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkHolder.FullChunkStatus status, -+ final int minSection, final int maxSection) { // inclusive, inclusive -+ this.minSection = minSection; -+ this.maxSection = maxSection; -+ this.chunkX = chunkX; -+ this.chunkZ = chunkZ; -+ this.world = world; -+ -+ this.allEntities = new EntityCollectionBySection(this); -+ this.hardCollidingEntities = new EntityCollectionBySection(this); -+ this.entitiesByClass = new Reference2ObjectOpenHashMap<>(); -+ -+ this.status = status; -+ } -+ -+ // Tuinity start - optimise CraftChunk#getEntities -+ public org.bukkit.entity.Entity[] getChunkEntities() { -+ List ret = new java.util.ArrayList<>(); -+ final Entity[] entities = this.entities.getRawData(); -+ for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) { -+ final Entity entity = entities[i]; -+ if (entity == null) { -+ continue; -+ } -+ final org.bukkit.entity.Entity bukkit = entity.getBukkitEntity(); -+ if (bukkit != null && bukkit.isValid()) { -+ ret.add(bukkit); -+ } -+ } -+ -+ return ret.toArray(new org.bukkit.entity.Entity[0]); -+ } -+ // Tuinity end - optimise CraftChunk#getEntities -+ -+ public boolean isEmpty() { -+ return this.entities.size() == 0; -+ } -+ -+ private void updateTicketLevels() { -+ final Entity[] entities = this.entities.getRawData(); -+ for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) { -+ final Entity entity = entities[i]; -+ entity.chunkStatus = this.status; -+ } -+ } -+ -+ public synchronized void updateStatus(final ChunkHolder.FullChunkStatus status) { -+ this.status = status; -+ this.updateTicketLevels(); -+ } -+ -+ public synchronized void addEntity(final Entity entity, final int chunkSection) { -+ if (!this.entities.add(entity)) { -+ return; -+ } -+ entity.chunkStatus = this.status; -+ final int sectionIndex = chunkSection - this.minSection; -+ -+ this.allEntities.addEntity(entity, sectionIndex); -+ -+ if (entity.hardCollides()) { -+ this.hardCollidingEntities.addEntity(entity, sectionIndex); -+ } -+ -+ for (final Iterator, EntityCollectionBySection>> iterator = -+ this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) { -+ final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); -+ -+ if (entry.getKey().isInstance(entity)) { -+ entry.getValue().addEntity(entity, sectionIndex); -+ } -+ } -+ } -+ -+ public synchronized void removeEntity(final Entity entity, final int chunkSection) { -+ if (!this.entities.remove(entity)) { -+ return; -+ } -+ entity.chunkStatus = ChunkHolder.FullChunkStatus.INACCESSIBLE; -+ final int sectionIndex = chunkSection - this.minSection; -+ -+ this.allEntities.removeEntity(entity, sectionIndex); -+ -+ if (entity.hardCollides()) { -+ this.hardCollidingEntities.removeEntity(entity, sectionIndex); -+ } -+ -+ for (final Iterator, EntityCollectionBySection>> iterator = -+ this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) { -+ final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); -+ -+ if (entry.getKey().isInstance(entity)) { -+ entry.getValue().removeEntity(entity, sectionIndex); -+ } -+ } -+ } -+ -+ public void getHardCollidingEntities(final Entity except, final AABB box, final List into, final Predicate predicate) { -+ this.hardCollidingEntities.getEntities(except, box, into, predicate); -+ } -+ -+ public void getEntities(final Entity except, final AABB box, final List into, final Predicate predicate) { -+ this.allEntities.getEntitiesWithEnderDragonParts(except, box, into, predicate); -+ } -+ -+ public void getEntities(final EntityType type, final AABB box, final List into, -+ final Predicate predicate) { -+ this.allEntities.getEntities(type, box, (List)into, (Predicate)predicate); -+ } -+ -+ protected EntityCollectionBySection initClass(final Class clazz) { -+ final EntityCollectionBySection ret = new EntityCollectionBySection(this); -+ -+ for (int sectionIndex = 0; sectionIndex < this.allEntities.entitiesBySection.length; ++sectionIndex) { -+ final BasicEntityList sectionEntities = this.allEntities.entitiesBySection[sectionIndex]; -+ if (sectionEntities == null) { -+ continue; -+ } -+ -+ final Entity[] storage = sectionEntities.storage; -+ -+ for (int i = 0, len = Math.min(storage.length, sectionEntities.size()); i < len; ++i) { -+ final Entity entity = storage[i]; -+ -+ if (clazz.isInstance(entity)) { -+ ret.addEntity(entity, sectionIndex); -+ } -+ } -+ } -+ -+ return ret; -+ } -+ -+ public void getEntities(final Class clazz, final Entity except, final AABB box, final List into, -+ final Predicate predicate) { -+ EntityCollectionBySection collection = this.entitiesByClass.get(clazz); -+ if (collection != null) { -+ collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List)into, (Predicate)predicate); -+ } else { -+ synchronized (this) { -+ this.entitiesByClass.putIfAbsent(clazz, collection = this.initClass(clazz)); -+ } -+ collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List)into, (Predicate)predicate); -+ } -+ } -+ -+ public synchronized void updateEntity(final Entity entity) { -+ /*// TODO -+ if (prev aabb != entity.getBoundingBox()) { -+ this.entityMap.delete(entity, prev aabb); -+ this.entityMap.insert(entity, prev aabb = entity.getBoundingBox()); -+ }*/ -+ } -+ -+ protected static final class BasicEntityList { -+ -+ protected static final Entity[] EMPTY = new Entity[0]; -+ protected static final int DEFAULT_CAPACITY = 4; -+ -+ protected E[] storage; -+ protected int size; -+ -+ public BasicEntityList() { -+ this(0); -+ } -+ -+ public BasicEntityList(final int cap) { -+ this.storage = (E[])(cap <= 0 ? EMPTY : new Entity[cap]); -+ } -+ -+ public boolean isEmpty() { -+ return this.size == 0; -+ } -+ -+ public int size() { -+ return this.size; -+ } -+ -+ private void resize() { -+ if (this.storage == EMPTY) { -+ this.storage = (E[])new Entity[DEFAULT_CAPACITY]; -+ } else { -+ this.storage = Arrays.copyOf(this.storage, this.storage.length * 2); -+ } -+ } -+ -+ public void add(final E entity) { -+ final int idx = this.size++; -+ if (idx >= this.storage.length) { -+ this.resize(); -+ this.storage[idx] = entity; -+ } else { -+ this.storage[idx] = entity; -+ } -+ } -+ -+ public int indexOf(final E entity) { -+ final E[] storage = this.storage; -+ -+ for (int i = 0, len = Math.min(this.storage.length, this.size); i < len; ++i) { -+ if (storage[i] == entity) { -+ return i; -+ } -+ } -+ -+ return -1; -+ } -+ -+ public boolean remove(final E entity) { -+ final int idx = this.indexOf(entity); -+ if (idx == -1) { -+ return false; -+ } -+ -+ final int size = --this.size; -+ final E[] storage = this.storage; -+ if (idx != size) { -+ System.arraycopy(storage, idx + 1, storage, idx, size - idx); -+ } -+ -+ storage[size] = null; -+ -+ return true; -+ } -+ -+ public boolean has(final E entity) { -+ return this.indexOf(entity) != -1; -+ } -+ } -+ -+ protected static final class EntityCollectionBySection { -+ -+ protected final ChunkEntitySlices manager; -+ protected final long[] nonEmptyBitset; -+ protected final BasicEntityList[] entitiesBySection; -+ protected int count; -+ -+ public EntityCollectionBySection(final ChunkEntitySlices manager) { -+ this.manager = manager; -+ -+ final int sectionCount = manager.maxSection - manager.minSection + 1; -+ -+ this.nonEmptyBitset = new long[(sectionCount + (Long.SIZE - 1)) >>> 6]; // (sectionCount + (Long.SIZE - 1)) / Long.SIZE -+ this.entitiesBySection = new BasicEntityList[sectionCount]; -+ } -+ -+ public void addEntity(final Entity entity, final int sectionIndex) { -+ BasicEntityList list = this.entitiesBySection[sectionIndex]; -+ -+ if (list != null && list.has(entity)) { -+ return; -+ } -+ -+ if (list == null) { -+ this.entitiesBySection[sectionIndex] = list = new BasicEntityList<>(); -+ this.nonEmptyBitset[sectionIndex >>> 6] |= (1L << (sectionIndex & (Long.SIZE - 1))); -+ } -+ -+ list.add(entity); -+ ++this.count; -+ } -+ -+ public void removeEntity(final Entity entity, final int sectionIndex) { -+ final BasicEntityList list = this.entitiesBySection[sectionIndex]; -+ -+ if (list == null || !list.remove(entity)) { -+ return; -+ } -+ -+ --this.count; -+ -+ if (list.isEmpty()) { -+ this.entitiesBySection[sectionIndex] = null; -+ this.nonEmptyBitset[sectionIndex >>> 6] ^= (1L << (sectionIndex & (Long.SIZE - 1))); -+ } -+ } -+ -+ public void getEntities(final Entity except, final AABB box, final List into, final Predicate predicate) { -+ if (this.count == 0) { -+ return; -+ } -+ -+ final int minSection = this.manager.minSection; -+ final int maxSection = this.manager.maxSection; -+ -+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection); -+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection); -+ -+ // TODO use the bitset -+ -+ final BasicEntityList[] entitiesBySection = this.entitiesBySection; -+ -+ for (int section = min; section <= max; ++section) { -+ final BasicEntityList list = entitiesBySection[section - minSection]; -+ -+ if (list == null) { -+ continue; -+ } -+ -+ final Entity[] storage = list.storage; -+ -+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) { -+ final Entity entity = storage[i]; -+ -+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) { -+ continue; -+ } -+ -+ if (predicate != null && !predicate.test(entity)) { -+ continue; -+ } -+ -+ into.add(entity); -+ } -+ } -+ } -+ -+ public void getEntitiesWithEnderDragonParts(final Entity except, final AABB box, final List into, -+ final Predicate predicate) { -+ if (this.count == 0) { -+ return; -+ } -+ -+ final int minSection = this.manager.minSection; -+ final int maxSection = this.manager.maxSection; -+ -+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection); -+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection); -+ -+ // TODO use the bitset -+ -+ final BasicEntityList[] entitiesBySection = this.entitiesBySection; -+ -+ for (int section = min; section <= max; ++section) { -+ final BasicEntityList list = entitiesBySection[section - minSection]; -+ -+ if (list == null) { -+ continue; -+ } -+ -+ final Entity[] storage = list.storage; -+ -+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) { -+ final Entity entity = storage[i]; -+ -+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) { -+ continue; -+ } -+ -+ if (predicate == null || predicate.test(entity)) { -+ into.add(entity); -+ } // else: continue to test the ender dragon parts -+ -+ if (entity instanceof EnderDragon) { -+ for (final EnderDragonPart part : ((EnderDragon)entity).subEntities) { -+ if (part == except || !part.getBoundingBox().intersects(box)) { -+ continue; -+ } -+ -+ if (predicate != null && !predicate.test(part)) { -+ continue; -+ } -+ -+ into.add(part); -+ } -+ } -+ } -+ } -+ } -+ -+ public void getEntitiesWithEnderDragonParts(final Entity except, final Class clazz, final AABB box, final List into, -+ final Predicate predicate) { -+ if (this.count == 0) { -+ return; -+ } -+ -+ final int minSection = this.manager.minSection; -+ final int maxSection = this.manager.maxSection; -+ -+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection); -+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection); -+ -+ // TODO use the bitset -+ -+ final BasicEntityList[] entitiesBySection = this.entitiesBySection; -+ -+ for (int section = min; section <= max; ++section) { -+ final BasicEntityList list = entitiesBySection[section - minSection]; -+ -+ if (list == null) { -+ continue; -+ } -+ -+ final Entity[] storage = list.storage; -+ -+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) { -+ final Entity entity = storage[i]; -+ -+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) { -+ continue; -+ } -+ -+ if (predicate == null || predicate.test(entity)) { -+ into.add(entity); -+ } // else: continue to test the ender dragon parts -+ -+ if (entity instanceof EnderDragon) { -+ for (final EnderDragonPart part : ((EnderDragon)entity).subEntities) { -+ if (part == except || !part.getBoundingBox().intersects(box) || !clazz.isInstance(part)) { -+ continue; -+ } -+ -+ if (predicate != null && !predicate.test(part)) { -+ continue; -+ } -+ -+ into.add(part); -+ } -+ } -+ } -+ } -+ } -+ -+ public void getEntities(final EntityType type, final AABB box, final List into, -+ final Predicate predicate) { -+ if (this.count == 0) { -+ return; -+ } -+ -+ final int minSection = this.manager.minSection; -+ final int maxSection = this.manager.maxSection; -+ -+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection); -+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection); -+ -+ // TODO use the bitset -+ -+ final BasicEntityList[] entitiesBySection = this.entitiesBySection; -+ -+ for (int section = min; section <= max; ++section) { -+ final BasicEntityList list = entitiesBySection[section - minSection]; -+ -+ if (list == null) { -+ continue; -+ } -+ -+ final Entity[] storage = list.storage; -+ -+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) { -+ final Entity entity = storage[i]; -+ -+ if (entity == null || (type != null && entity.getType() != type) || !entity.getBoundingBox().intersects(box)) { -+ continue; -+ } -+ -+ if (predicate != null && !predicate.test((T)entity)) { -+ continue; -+ } -+ -+ into.add((T)entity); -+ } -+ } -+ } -+ } -+} -diff --git a/src/main/java/com/tuinity/tuinity/world/EntitySliceManager.java b/src/main/java/com/tuinity/tuinity/world/EntitySliceManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f188ff6b08abddd06a3120fb15825e0f71196893 ---- /dev/null -+++ b/src/main/java/com/tuinity/tuinity/world/EntitySliceManager.java -@@ -0,0 +1,391 @@ -+package com.tuinity.tuinity.world; -+ -+import com.tuinity.tuinity.util.CoordinateUtils; -+import com.tuinity.tuinity.util.WorldUtil; -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import net.minecraft.core.BlockPos; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.phys.AABB; -+import java.util.List; -+import java.util.concurrent.locks.StampedLock; -+import java.util.function.Predicate; -+ -+public final class EntitySliceManager { -+ -+ protected static final int REGION_SHIFT = 5; -+ protected static final int REGION_MASK = (1 << REGION_SHIFT) - 1; -+ protected static final int REGION_SIZE = 1 << REGION_SHIFT; -+ -+ public final ServerLevel world; -+ -+ private final StampedLock stateLock = new StampedLock(); -+ protected final Long2ObjectOpenHashMap regions = new Long2ObjectOpenHashMap<>(64, 0.7f); -+ -+ private final int minSection; // inclusive -+ private final int maxSection; // inclusive -+ -+ protected final Long2ObjectOpenHashMap statusMap = new Long2ObjectOpenHashMap<>(); -+ { -+ this.statusMap.defaultReturnValue(ChunkHolder.FullChunkStatus.INACCESSIBLE); -+ } -+ -+ public EntitySliceManager(final ServerLevel world) { -+ this.world = world; -+ this.minSection = WorldUtil.getMinSection(world); -+ this.maxSection = WorldUtil.getMaxSection(world); -+ } -+ -+ public void chunkStatusChange(final int x, final int z, final ChunkHolder.FullChunkStatus newStatus) { -+ if (newStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { -+ this.statusMap.remove(CoordinateUtils.getChunkKey(x, z)); -+ } else { -+ this.statusMap.put(CoordinateUtils.getChunkKey(x, z), newStatus); -+ final ChunkEntitySlices slices = this.getChunk(x, z); -+ if (slices != null) { -+ slices.updateStatus(newStatus); -+ } -+ } -+ } -+ -+ public synchronized void addEntity(final Entity entity) { -+ final BlockPos pos = entity.blockPosition(); -+ final int sectionX = pos.getX() >> 4; -+ final int sectionY = Mth.clamp(pos.getY() >> 4, this.minSection, this.maxSection); -+ final int sectionZ = pos.getZ() >> 4; -+ final ChunkEntitySlices slices = this.getOrCreateChunk(sectionX, sectionZ); -+ slices.addEntity(entity, sectionY); -+ -+ entity.sectionX = sectionX; -+ entity.sectionY = sectionY; -+ entity.sectionZ = sectionZ; -+ } -+ -+ public synchronized void removeEntity(final Entity entity) { -+ final ChunkEntitySlices slices = this.getChunk(entity.sectionX, entity.sectionZ); -+ slices.removeEntity(entity, entity.sectionY); -+ if (slices.isEmpty()) { -+ this.removeChunk(entity.sectionX, entity.sectionZ); -+ } -+ } -+ -+ public void moveEntity(final Entity entity) { -+ final BlockPos newPos = entity.blockPosition(); -+ final int newSectionX = newPos.getX() >> 4; -+ final int newSectionY = Mth.clamp(newPos.getY() >> 4, this.minSection, this.maxSection); -+ final int newSectionZ = newPos.getZ() >> 4; -+ -+ if (newSectionX == entity.sectionX && newSectionY == entity.sectionY && newSectionZ == entity.sectionZ) { -+ return; -+ } -+ -+ synchronized (this) { -+ // are we changing chunks? -+ if (newSectionX != entity.sectionX || newSectionZ != entity.sectionZ) { -+ final ChunkEntitySlices slices = this.getOrCreateChunk(newSectionX, newSectionZ); -+ final ChunkEntitySlices old = this.getChunk(entity.sectionX, entity.sectionZ); -+ synchronized (old) { -+ old.removeEntity(entity, entity.sectionY); -+ if (old.isEmpty()) { -+ this.removeChunk(entity.sectionX, entity.sectionZ); -+ } -+ } -+ -+ synchronized (slices) { -+ slices.addEntity(entity, newSectionY); -+ -+ entity.sectionX = newSectionX; -+ entity.sectionY = newSectionY; -+ entity.sectionZ = newSectionZ; -+ } -+ } else { -+ final ChunkEntitySlices slices = this.getChunk(newSectionX, newSectionZ); -+ // same chunk -+ synchronized (slices) { -+ slices.removeEntity(entity, entity.sectionY); -+ slices.addEntity(entity, newSectionY); -+ } -+ entity.sectionY = newSectionY; -+ } -+ } -+ -+ } -+ -+ public void getEntities(final Entity except, final AABB box, final List into, final Predicate predicate) { -+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4; -+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4; -+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4; -+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4; -+ -+ final int minRegionX = minChunkX >> REGION_SHIFT; -+ final int minRegionZ = minChunkZ >> REGION_SHIFT; -+ final int maxRegionX = maxChunkX >> REGION_SHIFT; -+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT; -+ -+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { -+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; -+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; -+ -+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { -+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); -+ -+ if (region == null) { -+ continue; -+ } -+ -+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; -+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; -+ -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); -+ if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { -+ continue; -+ } -+ -+ chunk.getEntities(except, box, into, predicate); -+ } -+ } -+ } -+ } -+ } -+ -+ public void getHardCollidingEntities(final Entity except, final AABB box, final List into, final Predicate predicate) { -+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4; -+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4; -+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4; -+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4; -+ -+ final int minRegionX = minChunkX >> REGION_SHIFT; -+ final int minRegionZ = minChunkZ >> REGION_SHIFT; -+ final int maxRegionX = maxChunkX >> REGION_SHIFT; -+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT; -+ -+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { -+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; -+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; -+ -+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { -+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); -+ -+ if (region == null) { -+ continue; -+ } -+ -+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; -+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; -+ -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); -+ if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { -+ continue; -+ } -+ -+ chunk.getHardCollidingEntities(except, box, into, predicate); -+ } -+ } -+ } -+ } -+ } -+ -+ public void getEntities(final EntityType type, final AABB box, final List into, -+ final Predicate predicate) { -+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4; -+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4; -+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4; -+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4; -+ -+ final int minRegionX = minChunkX >> REGION_SHIFT; -+ final int minRegionZ = minChunkZ >> REGION_SHIFT; -+ final int maxRegionX = maxChunkX >> REGION_SHIFT; -+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT; -+ -+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { -+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; -+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; -+ -+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { -+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); -+ -+ if (region == null) { -+ continue; -+ } -+ -+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; -+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; -+ -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); -+ if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { -+ continue; -+ } -+ -+ chunk.getEntities(type, box, (List)into, (Predicate)predicate); -+ } -+ } -+ } -+ } -+ } -+ -+ public void getEntities(final Class clazz, final Entity except, final AABB box, final List into, -+ final Predicate predicate) { -+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4; -+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4; -+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4; -+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4; -+ -+ final int minRegionX = minChunkX >> REGION_SHIFT; -+ final int minRegionZ = minChunkZ >> REGION_SHIFT; -+ final int maxRegionX = maxChunkX >> REGION_SHIFT; -+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT; -+ -+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { -+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; -+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; -+ -+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { -+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); -+ -+ if (region == null) { -+ continue; -+ } -+ -+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; -+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; -+ -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); -+ if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { -+ continue; -+ } -+ -+ chunk.getEntities(clazz, except, box, into, predicate); -+ } -+ } -+ } -+ } -+ } -+ -+ public ChunkEntitySlices getChunk(final int chunkX, final int chunkZ) { -+ final ChunkSlicesRegion region = this.getRegion(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); -+ if (region == null) { -+ return null; -+ } -+ -+ return region.get((chunkX & REGION_MASK) | ((chunkZ & REGION_MASK) << REGION_SHIFT)); -+ } -+ -+ public ChunkEntitySlices getOrCreateChunk(final int chunkX, final int chunkZ) { -+ final ChunkSlicesRegion region = this.getRegion(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); -+ ChunkEntitySlices ret; -+ if (region == null || (ret = region.get((chunkX & REGION_MASK) | ((chunkZ & REGION_MASK) << REGION_SHIFT))) == null) { -+ ret = new ChunkEntitySlices(this.world, chunkX, chunkZ, this.statusMap.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)), -+ WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)); -+ -+ this.addChunk(chunkX, chunkZ, ret); -+ -+ return ret; -+ } -+ -+ return ret; -+ } -+ -+ public ChunkSlicesRegion getRegion(final int regionX, final int regionZ) { -+ final long key = CoordinateUtils.getChunkKey(regionX, regionZ); -+ final long attempt = this.stateLock.tryOptimisticRead(); -+ if (attempt != 0L) { -+ try { -+ final ChunkSlicesRegion ret = this.regions.get(key); -+ -+ if (this.stateLock.validate(attempt)) { -+ return ret; -+ } -+ } catch (final Error error) { -+ throw error; -+ } catch (final Throwable thr) { -+ // ignore -+ } -+ } -+ -+ this.stateLock.readLock(); -+ try { -+ return this.regions.get(key); -+ } finally { -+ this.stateLock.tryUnlockRead(); -+ } -+ } -+ -+ public synchronized void removeChunk(final int chunkX, final int chunkZ) { -+ final long key = CoordinateUtils.getChunkKey(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); -+ final int relIndex = (chunkX & REGION_MASK) | ((chunkZ & REGION_MASK) << REGION_SHIFT); -+ -+ final ChunkSlicesRegion region = this.regions.get(key); -+ final int remaining = region.remove(relIndex); -+ -+ if (remaining == 0) { -+ this.stateLock.writeLock(); -+ try { -+ this.regions.remove(key); -+ } finally { -+ this.stateLock.tryUnlockWrite(); -+ } -+ } -+ } -+ -+ public synchronized void addChunk(final int chunkX, final int chunkZ, final ChunkEntitySlices slices) { -+ final long key = CoordinateUtils.getChunkKey(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); -+ final int relIndex = (chunkX & REGION_MASK) | ((chunkZ & REGION_MASK) << REGION_SHIFT); -+ -+ ChunkSlicesRegion region = this.regions.get(key); -+ if (region != null) { -+ region.add(relIndex, slices); -+ } else { -+ region = new ChunkSlicesRegion(); -+ region.add(relIndex, slices); -+ this.stateLock.writeLock(); -+ try { -+ this.regions.put(key, region); -+ } finally { -+ this.stateLock.tryUnlockWrite(); -+ } -+ } -+ } -+ -+ public static final class ChunkSlicesRegion { -+ -+ protected final ChunkEntitySlices[] slices = new ChunkEntitySlices[REGION_SIZE * REGION_SIZE]; -+ protected int sliceCount; -+ -+ public ChunkEntitySlices get(final int index) { -+ return this.slices[index]; -+ } -+ -+ public int remove(final int index) { -+ final ChunkEntitySlices slices = this.slices[index]; -+ if (slices == null) { -+ throw new IllegalStateException(); -+ } -+ -+ this.slices[index] = null; -+ -+ return --this.sliceCount; -+ } -+ -+ public void add(final int index, final ChunkEntitySlices slices) { -+ final ChunkEntitySlices curr = this.slices[index]; -+ if (curr != null) { -+ throw new IllegalStateException(); -+ } -+ -+ this.slices[index] = slices; -+ -+ ++this.sliceCount; -+ } -+ } -+} -diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java -index 59437f04911662f06596ef61b91017caa6427eec..82e8338c69e846ab9ff0a9b9427d968e0a67927e 100644 ---- a/src/main/java/net/minecraft/Util.java -+++ b/src/main/java/net/minecraft/Util.java -@@ -67,6 +67,22 @@ public class Util { - private static final AtomicInteger WORKER_COUNT = new AtomicInteger(1); - private static final ExecutorService BOOTSTRAP_EXECUTOR = makeExecutor("Bootstrap", -2); // Paper - add -2 priority - private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main", -1); // Paper - add -1 priority -+ // Tuinity start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread -+ public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() { -+ -+ private final AtomicInteger count = new AtomicInteger(); -+ -+ @Override -+ public Thread newThread(Runnable run) { -+ Thread ret = new Thread(run); -+ ret.setName("Profile Lookup Executor #" + this.count.getAndIncrement()); -+ ret.setUncaughtExceptionHandler((Thread thread, Throwable throwable) -> { -+ LOGGER.fatal("Uncaught exception in thread " + thread.getName(), throwable); -+ }); -+ return ret; -+ } -+ }); -+ // Tuinity end - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread - private static final ExecutorService IO_POOL = makeIoExecutor(); - public static LongSupplier timeSource = System::nanoTime; - public static final UUID NIL_UUID = new UUID(0L, 0L); -diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java -index b70aa66732fb5e957aed0901f4c76358b2c56f8e..b01d7da333bac7820e42b6f645634a15ef88ae4f 100644 ---- a/src/main/java/net/minecraft/core/BlockPos.java -+++ b/src/main/java/net/minecraft/core/BlockPos.java -@@ -478,9 +478,9 @@ public class BlockPos extends Vec3i { - } - - public BlockPos.MutableBlockPos set(int x, int y, int z) { -- this.setX(x); -- this.setY(y); -- this.setZ(z); -+ this.x = x; // Tuinity - force inline -+ this.y = y; // Tuinity - force inline -+ this.z = z; // Tuinity - force inline - return this; - } - -@@ -544,19 +544,19 @@ public class BlockPos extends Vec3i { - // Paper start - comment out useless overrides @Override - TODO figure out why this is suddenly important to keep - @Override - public BlockPos.MutableBlockPos setX(int i) { -- super.setX(i); -+ this.x = i; // Tuinity - return this; - } - - @Override - public BlockPos.MutableBlockPos setY(int i) { -- super.setY(i); -+ this.y = i; // Tuinity - return this; - } - - @Override - public BlockPos.MutableBlockPos setZ(int i) { -- super.setZ(i); -+ this.z = i; // Tuinity - return this; - } - // Paper end -diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java -index 5e09890ba2fe326503a49b2dbec09845f5c8c5eb..3ad3652f8074de10222fb01c50548b4312103cc3 100644 ---- a/src/main/java/net/minecraft/core/Vec3i.java -+++ b/src/main/java/net/minecraft/core/Vec3i.java -@@ -17,9 +17,9 @@ public class Vec3i implements Comparable { - return IntStream.of(vec3i.getX(), vec3i.getY(), vec3i.getZ()); - }); - public static final Vec3i ZERO = new Vec3i(0, 0, 0); -- private int x; -- private int y; -- private int z; -+ protected int x; // Tuinity - protected -+ protected int y; // Tuinity - protected -+ protected int z; // Tuinity - protected - - // Paper start - public boolean isValidLocation(net.minecraft.world.level.LevelHeightAccessor levelHeightAccessor) { -@@ -84,17 +84,17 @@ public class Vec3i implements Comparable { - return this.z; - } - -- public Vec3i setX(int x) { -+ protected Vec3i setX(int x) { // Tuinity - not needed here - Also revert the decision to expose set on an _immutable_ type - this.x = x; - return this; - } - -- public Vec3i setY(int y) { -+ protected Vec3i setY(int y) { // Tuinity - not needed here - Also revert the decision to expose set on an _immutable_ type - this.y = y; - return this; - } - -- public Vec3i setZ(int z) { -+ protected Vec3i setZ(int z) { // Tuinity - not needed here - Also revert the decision to expose set on an _immutable_ type - this.z = z; - return this; - } -diff --git a/src/main/java/net/minecraft/network/CipherDecoder.java b/src/main/java/net/minecraft/network/CipherDecoder.java -index 06d545bc7206dd0d56cf27c31935c0f5ed21ef08..3dfbe08b68b958a52d5f4464b22b70f3ad9a012c 100644 ---- a/src/main/java/net/minecraft/network/CipherDecoder.java -+++ b/src/main/java/net/minecraft/network/CipherDecoder.java -@@ -7,14 +7,30 @@ import java.util.List; - import javax.crypto.Cipher; - - public class CipherDecoder extends MessageToMessageDecoder { -- private final CipherBase cipher; -+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Tuinity - -- public CipherDecoder(Cipher cipher) { -- this.cipher = new CipherBase(cipher); -+ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Tuinity -+ this.cipher = cipher; // Tuinity - } - - @Override - protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception { -- list.add(this.cipher.decipher(channelHandlerContext, byteBuf)); -+ // Tuinity start -+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf); -+ try { -+ cipher.process(compatible); -+ list.add(compatible); -+ } catch (Exception e) { -+ compatible.release(); // compatible will never be used if we throw an exception -+ throw e; -+ } -+ // Tuinity end - } -+ -+ // Tuinity start -+ @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { -+ cipher.close(); -+ } -+ // Tuinity end - } -diff --git a/src/main/java/net/minecraft/network/CipherEncoder.java b/src/main/java/net/minecraft/network/CipherEncoder.java -index 50a7058b18a8ca05363b73eaefbd812ef50d53f1..34bd72ebace9a61625693d724ea0a88c0dd1f601 100644 ---- a/src/main/java/net/minecraft/network/CipherEncoder.java -+++ b/src/main/java/net/minecraft/network/CipherEncoder.java -@@ -4,16 +4,33 @@ import io.netty.buffer.ByteBuf; - import io.netty.channel.ChannelHandlerContext; - import io.netty.handler.codec.MessageToByteEncoder; - import javax.crypto.Cipher; -+import java.util.List; - --public class CipherEncoder extends MessageToByteEncoder { -- private final CipherBase cipher; -+public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder { // Tuinity - change superclass -+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Tuinity - -- public CipherEncoder(Cipher cipher) { -- this.cipher = new CipherBase(cipher); -+ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Tuinity -+ this.cipher = cipher; // Tuinity - } - - @Override -- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { -- this.cipher.encipher(byteBuf, byteBuf2); -+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception { -+ // Tuinity start -+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf); -+ try { -+ cipher.process(compatible); -+ list.add(compatible); -+ } catch (Exception e) { -+ compatible.release(); // compatible will never be used if we throw an exception -+ throw e; -+ } -+ // Tuinity end - } -+ -+ // Tuinity start -+ @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { -+ cipher.close(); -+ } -+ // Tuinity end - } -diff --git a/src/main/java/net/minecraft/network/CompressionDecoder.java b/src/main/java/net/minecraft/network/CompressionDecoder.java -index efd05c8c1114aab4c237ccbc2e4e935a08c076ee..c18e9773b707fa64d2ea0985c811174c4d82ccbd 100644 ---- a/src/main/java/net/minecraft/network/CompressionDecoder.java -+++ b/src/main/java/net/minecraft/network/CompressionDecoder.java -@@ -11,14 +11,18 @@ import java.util.zip.Inflater; - public class CompressionDecoder extends ByteToMessageDecoder { - public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152; - public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608; -- private final Inflater inflater; -+ // Tuinity start -+ // private final Inflater inflater; -+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; -+ // Tuinity end - private int threshold; - private boolean validateDecompressed; - -- public CompressionDecoder(int compressionThreshold, boolean bl) { -+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean bl) { - this.threshold = compressionThreshold; - this.validateDecompressed = bl; -- this.inflater = new Inflater(); -+ this.compressor = compressor; // Tuinity -+ // this.inflater = new Inflater(); // Tuinity - } - - @Override -@@ -39,17 +43,39 @@ public class CompressionDecoder extends ByteToMessageDecoder { - } - } - -- byte[] bs = new byte[friendlyByteBuf.readableBytes()]; -- friendlyByteBuf.readBytes(bs); -- this.inflater.setInput(bs); -- byte[] cs = new byte[i]; -- this.inflater.inflate(cs); -- list.add(Unpooled.wrappedBuffer(cs)); -- this.inflater.reset(); -+ // Tuinity start -+// byte[] bs = new byte[friendlyByteBuf.readableBytes()]; -+// friendlyByteBuf.readBytes(bs); -+// this.inflater.setInput(bs); -+// byte[] cs = new byte[i]; -+// this.inflater.inflate(cs); -+// list.add(Unpooled.wrappedBuffer(cs)); -+// this.inflater.reset(); -+ int claimedUncompressedSize = i; // OBFHELPER -+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), compressor, byteBuf); -+ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(channelHandlerContext.alloc(), compressor, claimedUncompressedSize); -+ try { -+ compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize); -+ list.add(uncompressed); -+ byteBuf.clear(); -+ } catch (Exception e) { -+ uncompressed.release(); -+ throw e; -+ } finally { -+ compatibleIn.release(); -+ } -+ // Tuinity end - } - } - } - -+ // Tuinity start -+ @Override -+ public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { -+ compressor.close(); -+ } -+ // Tuinity end -+ - public void setThreshold(int compressionThreshold, boolean bl) { - this.threshold = compressionThreshold; - this.validateDecompressed = bl; -diff --git a/src/main/java/net/minecraft/network/CompressionEncoder.java b/src/main/java/net/minecraft/network/CompressionEncoder.java -index 524c0c674f63cfcb601416a18348f37aabb4e3ff..241ee2247d6f0ead736e5e25f2bb25655d9b3d19 100644 ---- a/src/main/java/net/minecraft/network/CompressionEncoder.java -+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java -@@ -6,39 +6,71 @@ import io.netty.handler.codec.MessageToByteEncoder; - import java.util.zip.Deflater; - - public class CompressionEncoder extends MessageToByteEncoder { -- private final byte[] encodeBuf = new byte[8192]; -- private final Deflater deflater; -+ // private final byte[] encodeBuf = new byte[8192]; // Tuinity -+ // private final Deflater deflater; // Tuinity -+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Tuinity - private int threshold; - -- public CompressionEncoder(int compressionThreshold) { -+ public CompressionEncoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold) { - this.threshold = compressionThreshold; -- this.deflater = new Deflater(); -+ // this.deflater = new Deflater(); // Tuinity -+ this.compressor = compressor; // Tuinity - } - - @Override -- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) { -+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { // Tuinity - int i = byteBuf.readableBytes(); - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf2); - if (i < this.threshold) { - friendlyByteBuf.writeVarInt(0); - friendlyByteBuf.writeBytes(byteBuf); - } else { -- byte[] bs = new byte[i]; -- byteBuf.readBytes(bs); -- friendlyByteBuf.writeVarInt(bs.length); -- this.deflater.setInput(bs, 0, i); -- this.deflater.finish(); -- -- while(!this.deflater.finished()) { -- int j = this.deflater.deflate(this.encodeBuf); -- friendlyByteBuf.writeBytes(this.encodeBuf, 0, j); -+ // Tuinity start -+// byte[] bs = new byte[i]; -+// byteBuf.readBytes(bs); -+// friendlyByteBuf.writeVarInt(bs.length); -+// this.deflater.setInput(bs, 0, i); -+// this.deflater.finish(); -+// -+// while(!this.deflater.finished()) { -+// int j = this.deflater.deflate(this.encodeBuf); -+// friendlyByteBuf.writeBytes(this.encodeBuf, 0, j); -+// } -+// -+// this.deflater.reset(); -+ friendlyByteBuf.writeVarInt(i); -+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), compressor, byteBuf); -+ try { -+ compressor.deflate(compatibleIn, byteBuf2); -+ } finally { -+ compatibleIn.release(); - } -- -- this.deflater.reset(); -+ // Tuinity end - } - - } - -+ // Tuinity start -+ @Override -+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) { -+ // We allocate bytes to be compressed plus 1 byte. This covers two cases: -+ // -+ // - Compression -+ // According to https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h#L103, -+ // if the data compresses well (and we do not have some pathological case) then the maximum -+ // size the compressed size will ever be is the input size minus one. -+ // - Uncompressed -+ // This is fairly obvious - we will then have one more than the uncompressed size. -+ int initialBufferSize = msg.readableBytes() + 1; -+ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), compressor, initialBufferSize); -+ } -+ -+ @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { -+ compressor.close(); -+ } -+ // Tuinity end -+ - public int getThreshold() { - return this.threshold; - } -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 9d09ec3b127e3440bef6b248578dec109407f9ff..a8a46be5ee2173c2d1c7ad7299f05ab5ce3390b5 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -49,6 +49,8 @@ import org.apache.logging.log4j.Logger; - import org.apache.logging.log4j.Marker; - import org.apache.logging.log4j.MarkerManager; - -+ -+import io.netty.util.concurrent.AbstractEventExecutor; // Tuinity - public class Connection extends SimpleChannelInboundHandler> { - - private static final float AVERAGE_PACKETS_SMOOTHING = 0.75F; -@@ -93,6 +95,77 @@ public class Connection extends SimpleChannelInboundHandler> { - public boolean queueImmunity = false; - public ConnectionProtocol protocol; - // Paper end -+ // Tuinity start - add pending task queue -+ private final Queue pendingTasks = new java.util.concurrent.ConcurrentLinkedQueue<>(); -+ public void execute(final Runnable run) { -+ if (this.channel == null || !this.channel.isRegistered()) { -+ run.run(); -+ return; -+ } -+ final boolean queue = !this.queue.isEmpty(); -+ if (!queue) { -+ this.channel.eventLoop().execute(run); -+ } else { -+ this.pendingTasks.add(run); -+ if (this.queue.isEmpty()) { -+ // something flushed async, dump tasks now -+ Runnable r; -+ while ((r = this.pendingTasks.poll()) != null) { -+ this.channel.eventLoop().execute(r); -+ } -+ } -+ } -+ } -+ // Tuinity end - add pending task queue -+ -+ // Tuinity start - allow controlled flushing -+ volatile boolean canFlush = true; -+ private final java.util.concurrent.atomic.AtomicInteger packetWrites = new java.util.concurrent.atomic.AtomicInteger(); -+ private int flushPacketsStart; -+ private final Object flushLock = new Object(); -+ -+ public void disableAutomaticFlush() { -+ synchronized (this.flushLock) { -+ this.flushPacketsStart = this.packetWrites.get(); // must be volatile and before canFlush = false -+ this.canFlush = false; -+ } -+ } -+ -+ public void enableAutomaticFlush() { -+ synchronized (this.flushLock) { -+ this.canFlush = true; -+ if (this.packetWrites.get() != this.flushPacketsStart) { // must be after canFlush = true -+ this.flush(); // only make the flush call if we need to -+ } -+ } -+ } -+ -+ private final void flush() { -+ if (this.channel.eventLoop().inEventLoop()) { -+ this.channel.flush(); -+ } else { -+ this.channel.eventLoop().execute(() -> { -+ this.channel.flush(); -+ }); -+ } -+ } -+ // Tuinity end - allow controlled flushing -+ // Tuinity start - packet limiter -+ protected final Object PACKET_LIMIT_LOCK = new Object(); -+ protected final com.tuinity.tuinity.util.IntervalledCounter allPacketCounts = com.tuinity.tuinity.config.TuinityConfig.allPacketsLimit != null ? new com.tuinity.tuinity.util.IntervalledCounter( -+ (long)(com.tuinity.tuinity.config.TuinityConfig.allPacketsLimit.packetLimitInterval * 1.0e9) -+ ) : null; -+ protected final java.util.Map>, com.tuinity.tuinity.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>(); -+ -+ private boolean stopReadingPackets; -+ private void killForPacketSpam() { -+ this.sendPacket(new ClientboundDisconnectPacket(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(com.tuinity.tuinity.config.TuinityConfig.kickMessage, true)[0]), (future) -> { -+ this.disconnect(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(com.tuinity.tuinity.config.TuinityConfig.kickMessage, true)[0]); -+ }); -+ this.setReadOnly(); -+ this.stopReadingPackets = true; -+ } -+ // Tuinity end - packet limiter - - public Connection(PacketFlow side) { - this.receiving = side; -@@ -173,6 +246,45 @@ public class Connection extends SimpleChannelInboundHandler> { - - protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet packet) { - if (this.channel.isOpen()) { -+ // Tuinity start - packet limiter -+ if (this.stopReadingPackets) { -+ return; -+ } -+ if (this.allPacketCounts != null || -+ com.tuinity.tuinity.config.TuinityConfig.packetSpecificLimits.containsKey(packet.getClass())) { -+ long time = System.nanoTime(); -+ synchronized (PACKET_LIMIT_LOCK) { -+ if (this.allPacketCounts != null) { -+ this.allPacketCounts.updateAndAdd(1, time); -+ if (this.allPacketCounts.getRate() >= com.tuinity.tuinity.config.TuinityConfig.allPacketsLimit.maxPacketRate) { -+ this.killForPacketSpam(); -+ return; -+ } -+ } -+ -+ for (Class check = packet.getClass(); check != Object.class; check = check.getSuperclass()) { -+ com.tuinity.tuinity.config.TuinityConfig.PacketLimit packetSpecificLimit = -+ com.tuinity.tuinity.config.TuinityConfig.packetSpecificLimits.get(check); -+ if (packetSpecificLimit == null) { -+ continue; -+ } -+ com.tuinity.tuinity.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> { -+ return new com.tuinity.tuinity.util.IntervalledCounter((long)(packetSpecificLimit.packetLimitInterval * 1.0e9)); -+ }); -+ counter.updateAndAdd(1, time); -+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate) { -+ switch (packetSpecificLimit.violateAction) { -+ case DROP: -+ return; -+ case KICK: -+ this.killForPacketSpam(); -+ return; -+ } -+ } -+ } -+ } -+ } -+ // Tuinity end - packet limiter - try { - Connection.genericsFtw(packet, this.packetListener); - } catch (RunningOnDifferentThreadException cancelledpackethandleexception) { -@@ -255,7 +367,7 @@ public class Connection extends SimpleChannelInboundHandler> { - net.minecraft.server.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && - (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) - ))) { -- this.sendPacket(packet, callback); -+ this.writePacket(packet, callback, null); // Tuinity - return; - } - // write the packets to the queue, then flush - antixray hooks there already -@@ -279,6 +391,14 @@ public class Connection extends SimpleChannelInboundHandler> { - } - - private void sendPacket(Packet packet, @Nullable GenericFutureListener> callback) { -+ // Tuinity start - add flush parameter -+ this.writePacket(packet, callback, Boolean.TRUE); -+ } -+ private void writePacket(Packet packet, @Nullable GenericFutureListener> callback, Boolean flushConditional) { -+ this.packetWrites.getAndIncrement(); // must be befeore using canFlush -+ boolean effectiveFlush = flushConditional == null ? this.canFlush : flushConditional.booleanValue(); -+ final boolean flush = effectiveFlush || packet instanceof net.minecraft.network.protocol.game.ClientboundKeepAlivePacket || packet instanceof ClientboundDisconnectPacket; // no delay for certain packets -+ // Tuinity end - add flush parameter - ConnectionProtocol enumprotocol = ConnectionProtocol.getProtocolForPacket(packet); - ConnectionProtocol enumprotocol1 = this.getCurrentProtocol(); - -@@ -289,16 +409,31 @@ public class Connection extends SimpleChannelInboundHandler> { - } - - if (this.channel.eventLoop().inEventLoop()) { -- this.a(packet, callback, enumprotocol, enumprotocol1); -+ this.a(packet, callback, enumprotocol, enumprotocol1, flush); // Tuinity - add flush parameter - } else { -+ // Tuinity start - optimise packets that are not flushed -+ // note: since the type is not dynamic here, we need to actually copy the old executor code -+ // into two branches. On conflict, just re-copy - no changes were made inside the executor code. -+ if (!flush) { -+ AbstractEventExecutor.LazyRunnable run = () -> { -+ this.a(packet, callback, enumprotocol, enumprotocol1, flush); // Tuinity - add flush parameter -+ }; -+ this.channel.eventLoop().execute(run); -+ } else { // Tuinity end - optimise packets that are not flushed - this.channel.eventLoop().execute(() -> { -- this.a(packet, callback, enumprotocol, enumprotocol1); -+ this.a(packet, callback, enumprotocol, enumprotocol1, flush); // Tuinity - add flush parameter // Tuinity - diff on change - }); -+ } // Tuinity - } - - } - - private void a(Packet packet, @Nullable GenericFutureListener> genericfuturelistener, ConnectionProtocol enumprotocol, ConnectionProtocol enumprotocol1) { -+ // Tuinity start - add flush parameter -+ this.a(packet, genericfuturelistener, enumprotocol, enumprotocol1, true); -+ } -+ private void a(Packet packet, @Nullable GenericFutureListener> genericfuturelistener, ConnectionProtocol enumprotocol, ConnectionProtocol enumprotocol1, boolean flush) { -+ // Tuinity end - add flush parameter - if (enumprotocol != enumprotocol1) { - this.setProtocol(enumprotocol); - } -@@ -312,7 +447,7 @@ public class Connection extends SimpleChannelInboundHandler> { - - try { - // Paper end -- ChannelFuture channelfuture = this.channel.writeAndFlush(packet); -+ ChannelFuture channelfuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet); // Tuinity - add flush parameter - - if (genericfuturelistener != null) { - channelfuture.addListener(genericfuturelistener); -@@ -353,7 +488,12 @@ public class Connection extends SimpleChannelInboundHandler> { - return false; - } - private boolean processQueue() { -+ try { // Tuinity - add pending task queue - if (this.queue.isEmpty()) return true; -+ // Tuinity start - make only one flush call per sendPacketQueue() call -+ final boolean needsFlush = this.canFlush; -+ boolean hasWrotePacket = false; -+ // Tuinity end - make only one flush call per sendPacketQueue() call - // If we are on main, we are safe here in that nothing else should be processing queue off main anymore - // But if we are not on main due to login/status, the parent is synchronized on packetQueue - java.util.Iterator iterator = this.queue.iterator(); -@@ -361,19 +501,31 @@ public class Connection extends SimpleChannelInboundHandler> { - PacketHolder queued = iterator.next(); // poll -> peek - - // Fix NPE (Spigot bug caused by handleDisconnection()) -- if (queued == null) { -+ if (false && queued == null) { // Tuinity - diff on change, this logic is redundant: iterator guarantees ret of an element - on change, hook the flush logic here - return true; - } - - Packet packet = queued.packet; - if (!packet.isReady()) { -+ // Tuinity start - make only one flush call per sendPacketQueue() call -+ if (hasWrotePacket && (needsFlush || this.canFlush)) { -+ this.flush(); -+ } -+ // Tuinity end - make only one flush call per sendPacketQueue() call - return false; - } else { - iterator.remove(); -- this.sendPacket(packet, queued.listener); -+ this.writePacket(packet, queued.listener, (!iterator.hasNext() && (needsFlush || this.canFlush)) ? Boolean.TRUE : Boolean.FALSE); // Tuinity - make only one flush call per sendPacketQueue() call -+ hasWrotePacket = true; // Tuinity - make only one flush call per sendPacketQueue() call - } - } - return true; -+ } finally { // Tuinity start - add pending task queue -+ Runnable r; -+ while ((r = this.pendingTasks.poll()) != null) { -+ this.channel.eventLoop().execute(r); -+ } -+ } // Tuinity end - add pending task queue - } - // Paper end - -@@ -396,7 +548,14 @@ public class Connection extends SimpleChannelInboundHandler> { - } - - if (this.packetListener instanceof ServerGamePacketListenerImpl) { -+ // Tuinity start - detailed watchdog information -+ net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener); -+ try { -+ // Tuinity end - detailed watchdog information - ((ServerGamePacketListenerImpl) this.packetListener).tick(); -+ } finally { // Tuinity start - detailed watchdog information -+ net.minecraft.network.protocol.PacketUtils.packetProcessing.pop(); -+ } // Tuinity start - detailed watchdog information - } - - if (!this.isConnected() && !this.disconnectionHandled) { -@@ -498,11 +657,28 @@ public class Connection extends SimpleChannelInboundHandler> { - return networkmanager; - } - -- public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) { -- this.encrypted = true; -- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher)); -- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher)); -+ // Tuinity start -+// public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) { -+// this.encrypted = true; -+// this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher)); -+// this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher)); -+// } -+ -+ public void setupEncryption(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException { -+ if (!this.encrypted) { -+ try { -+ com.velocitypowered.natives.encryption.VelocityCipher decryption = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key); -+ com.velocitypowered.natives.encryption.VelocityCipher encryption = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key); -+ -+ this.encrypted = true; -+ this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryption)); -+ this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryption)); -+ } catch (java.security.GeneralSecurityException e) { -+ throw new net.minecraft.util.CryptException(e); -+ } -+ } - } -+ // Tuinity end - - public boolean isEncrypted() { - return this.encrypted; -@@ -531,16 +707,17 @@ public class Connection extends SimpleChannelInboundHandler> { - - public void setupCompression(int compressionThreshold, boolean flag) { - if (compressionThreshold >= 0) { -+ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(-1); // Tuinity - if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { - ((CompressionDecoder) this.channel.pipeline().get("decompress")).setThreshold(compressionThreshold, flag); - } else { -- this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressionThreshold, flag)); -+ this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressor, compressionThreshold, flag)); // Tuinity - } - - if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) { - ((CompressionEncoder) this.channel.pipeline().get("compress")).setThreshold(compressionThreshold); - } else { -- this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressionThreshold)); -+ this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressor, compressionThreshold)); // Tuinity - } - } else { - if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { -diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index bcf53ec07b8eeec7a88fb67e6fb908362e6f51b0..7265bee436d61d33645fa2d9ed4240529834dbf5 100644 ---- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java -+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -20,6 +20,24 @@ public class PacketUtils { - - private static final Logger LOGGER = LogManager.getLogger(); - -+ // Tuinity start - detailed watchdog information -+ public static final java.util.concurrent.ConcurrentLinkedDeque packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>(); -+ static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong(); -+ -+ public static long getTotalProcessedPackets() { -+ return totalMainThreadPacketsProcessed.get(); -+ } -+ -+ public static java.util.List getCurrentPacketProcessors() { -+ java.util.List ret = new java.util.ArrayList<>(4); -+ for (PacketListener listener : packetProcessing) { -+ ret.add(listener); -+ } -+ -+ return ret; -+ } -+ // Tuinity end - detailed watchdog information -+ - public PacketUtils() {} - - public static void ensureRunningOnSameThread(Packet packet, T listener, ServerLevel world) throws RunningOnDifferentThreadException { -@@ -30,6 +48,8 @@ public class PacketUtils { - if (!engine.isSameThread()) { - Timing timing = MinecraftTimings.getPacketTiming(packet); // Paper - timings - engine.execute(() -> { -+ packetProcessing.push(listener); // Tuinity - detailed watchdog information -+ try { // Tuinity - detailed watchdog information - if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerGamePacketListenerImpl && ((ServerGamePacketListenerImpl) listener).processedDisconnect)) return; // CraftBukkit, MC-142590 - if (listener.getConnection().isConnected()) { - try (Timing ignored = timing.startTiming()) { // Paper - timings -@@ -53,6 +73,12 @@ public class PacketUtils { - } else { - PacketUtils.LOGGER.debug("Ignoring packet due to disconnection: {}", packet); - } -+ // Tuinity start - detailed watchdog information -+ } finally { -+ totalMainThreadPacketsProcessed.getAndIncrement(); -+ packetProcessing.pop(); -+ } -+ // Tuinity end - detailed watchdog information - - }); - throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java -index d8be2ad889f46491e50404916fb4ae0de5f42098..5b9ea0af272c5e7a85d2a954a9214bf875bc7e9f 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java -@@ -32,25 +32,17 @@ public class ClientboundLightUpdatePacket implements Packet { -- if (remainingSends.get() == 0) { -- cleaner1.run(); -- cleaner2.run(); -- } -- }, "Light Packet Release"); -- } -+ // Tuinity - rewrite light engine - } - - @Override - public boolean hasFinishListener() { -- return true; -+ return false; // Tuinity - rewrite light engine - } - - // Paper end -@@ -63,8 +55,8 @@ public class ClientboundLightUpdatePacket implements Packet com.mojang.serialization.MapCodec fieldWithFallbacks(com.mojang.serialization.Codec codec, String name, String ...fallback) { -+ return com.mojang.serialization.MapCodec.of( -+ new com.mojang.serialization.codecs.FieldEncoder<>(name, codec), -+ new FieldFallbackDecoder<>(name, java.util.Arrays.asList(fallback), codec), -+ () -> "FieldFallback[" + name + ": " + codec.toString() + "]" -+ ); -+ } -+ -+ // This is likely a common occurrence, sadly -+ public static final class FieldFallbackDecoder extends com.mojang.serialization.MapDecoder.Implementation { -+ protected final String name; -+ protected final List fallback; -+ private final com.mojang.serialization.Decoder elementCodec; -+ -+ public FieldFallbackDecoder(final String name, final List fallback, final com.mojang.serialization.Decoder elementCodec) { -+ this.name = name; -+ this.fallback = fallback; -+ this.elementCodec = elementCodec; -+ } -+ -+ @Override -+ public com.mojang.serialization.DataResult decode(final com.mojang.serialization.DynamicOps ops, final com.mojang.serialization.MapLike input) { -+ T value = input.get(name); -+ if (value == null) { -+ for (String fall : fallback) { -+ value = input.get(fall); -+ if (value != null) { -+ break; -+ } -+ } -+ if (value == null) { -+ return com.mojang.serialization.DataResult.error("No key " + name + " in " + input); -+ } -+ } -+ return elementCodec.parse(ops, value); -+ } -+ -+ @Override -+ public java.util.stream.Stream keys(final com.mojang.serialization.DynamicOps ops) { -+ return java.util.stream.Stream.of(ops.createString(name)); -+ } -+ -+ @Override -+ public boolean equals(final Object o) { -+ if (this == o) { -+ return true; -+ } -+ if (o == null || getClass() != o.getClass()) { -+ return false; -+ } -+ final FieldFallbackDecoder that = (FieldFallbackDecoder)o; -+ return java.util.Objects.equals(name, that.name) && java.util.Objects.equals(elementCodec, that.elementCodec) -+ && java.util.Objects.equals(fallback, that.fallback); -+ } -+ -+ @Override -+ public int hashCode() { -+ return java.util.Objects.hash(name, fallback, elementCodec); -+ } -+ -+ @Override -+ public String toString() { -+ return "FieldDecoder[" + name + ": " + elementCodec + ']'; -+ } -+ } - } -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index cfd43069ee2b6f79afb12e10d223f6bf75100034..75c31ec2553c0959f1ac34b554a39a73144da8bd 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -57,7 +57,7 @@ import org.apache.logging.log4j.Logger; - // CraftBukkit start - import net.minecraft.SharedConstants; - --public class Main { -+public class Main { // - - private static final Logger LOGGER = LogManager.getLogger(); - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3dded5c491ace6b073a7bc3178976bd70f0b9393..f25bb4214cffd0050241ea229b6acb0c16b2b0a5 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -293,6 +293,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); - public int autosavePeriod; - public boolean serverAutoSave = false; // Paper -@@ -327,6 +328,76 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= MAX_CHUNK_EXEC_TIME) { -+ if (!moreTasks) { -+ lastMidTickExecuteFailure = currTime; -+ } -+ -+ // note: negative values reduce the time -+ long overuse = diff - MAX_CHUNK_EXEC_TIME; -+ if (overuse >= (10L * 1000L * 1000L)) { // 10ms -+ // make sure something like a GC or dumb plugin doesn't screw us over... -+ overuse = 10L * 1000L * 1000L; // 10ms -+ } -+ -+ double overuseCount = (double)overuse/(double)MAX_CHUNK_EXEC_TIME; -+ long extraSleep = (long)Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME); -+ -+ lastMidTickExecute = currTime + extraSleep; -+ return; -+ } -+ } -+ } finally { -+ co.aikar.timings.MinecraftTimings.midTickChunkTasks.stopTiming(); -+ } -+ } -+ // Tuinity end - execute chunk tasks mid tick -+ - public MinecraftServer(OptionSet options, DataPackConfig datapackconfiguration, Thread thread, RegistryAccess.RegistryHolder iregistrycustom_dimension, LevelStorageSource.LevelStorageAccess convertable_conversionsession, WorldData savedata, PackRepository resourcepackrepository, Proxy proxy, DataFixer datafixer, ServerResources datapackresources, @Nullable MinecraftSessionService minecraftsessionservice, @Nullable GameProfileRepository gameprofilerepository, @Nullable GameProfileCache usercache, ChunkProgressListenerFactory worldloadlistenerfactory) { - super("Server"); - SERVER = this; // Paper - better singleton -@@ -1141,6 +1212,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -- midTickLoadChunks(); // will only do loads since we are still considered !canSleepForTick -+ // Tuinity - replace logic - return !this.canOversleep(); - }); - isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); -@@ -1459,6 +1518,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Spigot - Spigot > // CraftBukkit - cb > vanilla! -+ return "Tuinity"; // Tuinity - Tuinity > //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! - } - - public SystemReport fillSystemReport(SystemReport details) { -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 7b6c547e71230fbb3733f99a4597b3f5b51547b8..1b324839e37d510552f5f5497de009add69ecda5 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -223,6 +223,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider - io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc. - // Paper end -+ com.tuinity.tuinity.config.TuinityConfig.init((java.io.File) options.valueOf("tuinity-settings")); // Tuinity - Server Config - - this.setPvpAllowed(dedicatedserverproperties.pvp); - this.setFlightAllowed(dedicatedserverproperties.allowFlight); -diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 574434760cb91234b994f101a5ddef595337b42e..fd24a282d28254182cdb88cb500b3f3c32ce958e 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkHolder.java -+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -41,6 +41,8 @@ import net.minecraft.world.level.lighting.LevelLightEngine; - import net.minecraft.server.MinecraftServer; - // CraftBukkit end - -+import it.unimi.dsi.fastutil.shorts.ShortOpenHashSet; // Tuinity -+ - public class ChunkHolder { - - public static final Either UNLOADED_CHUNK = Either.right(ChunkHolder.ChunkLoadingFailure.UNLOADED); -@@ -55,7 +57,7 @@ public class ChunkHolder { - private volatile CompletableFuture> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage - private volatile CompletableFuture> tickingChunkFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage - private volatile CompletableFuture> entityTickingChunkFuture; private volatile boolean isEntityTickingReady; // Paper - cache chunk ticking stage -- private CompletableFuture chunkToSave; -+ public CompletableFuture chunkToSave; // Tuinity - public - @Nullable - private final DebugBuffer chunkToSaveHistory; - public int oldTicketLevel; -@@ -238,6 +240,12 @@ public class ChunkHolder { - long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); - this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); - this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); -+ // Tuinity start - optimise checkDespawn -+ LevelChunk chunk = this.getFullChunkUnchecked(); -+ if (chunk != null) { -+ chunk.updateGeneralAreaCache(); -+ } -+ // Tuinity end - optimise checkDespawn - } - // Paper end - optimise isOutsideOfRange - long lastAutoSaveTime; // Paper - incremental autosave -@@ -388,7 +396,7 @@ public class ChunkHolder { - if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296 - if (this.changedBlocksPerSection[i] == null) { - this.hasChangedSections = true; -- this.changedBlocksPerSection[i] = new ShortArraySet(); -+ this.changedBlocksPerSection[i] = new ShortOpenHashSet(); // Tuinity - use a set to make setting constant-time - } - - this.changedBlocksPerSection[i].add(SectionPos.sectionRelativePos(pos)); -@@ -489,7 +497,7 @@ public class ChunkHolder { - // Paper start - per player view distance - // there can be potential desync with player's last mapped section and the view distance map, so use the - // view distance map here. -- com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerViewDistanceBroadcastMap; -+ com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerChunkManager.broadcastMap; // Tuinity - replace old player chunk manager - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = viewDistanceMap.getObjectsInRange(this.pos); - if (players == null) { - return; -@@ -506,6 +514,7 @@ public class ChunkHolder { - - int viewDistance = viewDistanceMap.getLastViewDistance(player); - long lastPosition = viewDistanceMap.getLastCoordinate(player); -+ if (!this.chunkMap.playerChunkManager.isChunkSent(player, this.pos.x, this.pos.z)) continue; // Tuinity - replace player chunk management - - int distX = Math.abs(net.minecraft.server.MCUtil.getCoordinateX(lastPosition) - this.pos.x); - int distZ = Math.abs(net.minecraft.server.MCUtil.getCoordinateZ(lastPosition) - this.pos.z); -@@ -522,6 +531,7 @@ public class ChunkHolder { - continue; - } - ServerPlayer player = (ServerPlayer)temp; -+ if (!this.chunkMap.playerChunkManager.isChunkSent(player, this.pos.x, this.pos.z)) continue; // Tuinity - replace player chunk management - player.connection.send(packet); - } - } -@@ -597,7 +607,13 @@ public class ChunkHolder { - CompletableFuture completablefuture1 = new CompletableFuture(); - - completablefuture1.thenRunAsync(() -> { -+ // Tuinity start - do not allow ticket level changes -+ boolean unloadingBefore = this.chunkMap.unloadingPlayerChunk; -+ this.chunkMap.unloadingPlayerChunk = true; -+ try { -+ // Tuinity end - do not allow ticket level changes - playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state); -+ } finally { this.chunkMap.unloadingPlayerChunk = unloadingBefore; } // Tuinity - do not allow ticket level changes - }, executor); - this.pendingFullStateConfirmation = completablefuture1; - completablefuture.thenAccept((either) -> { -@@ -607,12 +623,23 @@ public class ChunkHolder { - }); - } - -+ private boolean loadCallbackScheduled = false; -+ private boolean unloadCallbackScheduled = false; -+ - private void demoteFullChunk(ChunkMap playerchunkmap, ChunkHolder.FullChunkStatus playerchunk_state) { - this.pendingFullStateConfirmation.cancel(false); -+ // Tuinity start - do not allow ticket level changes -+ boolean unloadingBefore = this.chunkMap.unloadingPlayerChunk; -+ this.chunkMap.unloadingPlayerChunk = true; -+ try { // Tuinity end - do not allow ticket level changes - playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state); -+ } finally { this.chunkMap.unloadingPlayerChunk = unloadingBefore; } // Tuinity - do not allow ticket level changes - } - -- protected void updateFutures(ChunkMap chunkStorage, Executor executor) { -+ protected long updateCount; // Tuinity - correctly handle recursion -+ public void updateFutures(ChunkMap chunkStorage, Executor executor) { // Tuinity -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Async ticket level update"); // Tuinity -+ long updateCount = ++this.updateCount; // Tuinity - correctly handle recursion - ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel); - ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel); - boolean flag = this.oldTicketLevel <= ChunkMap.MAX_CHUNK_DISTANCE; -@@ -622,10 +649,23 @@ public class ChunkHolder { - // CraftBukkit start - // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins. - if (playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { -- this.getStatusFutureUncheckedMain(ChunkStatus.FULL).thenAccept((either) -> { // Paper - ensure main -+ this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> { // Paper - ensure main // Tuinity - is always on main -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Async full status chunk future completion"); // Tuinity - LevelChunk chunk = (LevelChunk)either.left().orElse(null); -- if (chunk != null) { -+ if (chunk != null && chunk.wasLoadCallbackInvoked() && ChunkHolder.this.ticketLevel > 33) { // Tuinity - only invoke unload if load was called -+ // Tuinity start - only schedule once, now the future is no longer completed as RIGHT if unloaded... -+ if (ChunkHolder.this.unloadCallbackScheduled) { -+ return; -+ } -+ ChunkHolder.this.unloadCallbackScheduled = true; -+ // Tuinity end - only schedule once, now the future is no longer completed as RIGHT if unloaded... - chunkStorage.callbackExecutor.execute(() -> { -+ // Tuinity start - only schedule once, now the future is no longer completed as RIGHT if unloaded... -+ ChunkHolder.this.unloadCallbackScheduled = false; -+ if (ChunkHolder.this.ticketLevel <= 33) { -+ return; -+ } -+ // Tuinity end - only schedule once, now the future is no longer completed as RIGHT if unloaded... - // Minecraft will apply the chunks tick lists to the world once the chunk got loaded, and then store the tick - // lists again inside the chunk once the chunk becomes inaccessible and set the chunk's needsSaving flag. - // These actions may however happen deferred, so we manually set the needsSaving flag already here. -@@ -641,6 +681,12 @@ public class ChunkHolder { - - // Run callback right away if the future was already done - chunkStorage.callbackExecutor.run(); -+ // Tuinity start - correctly handle recursion -+ if (this.updateCount != updateCount) { -+ // something else updated ticket level for us. -+ return; -+ } -+ // Tuinity end - correctly handle recursion - } - // CraftBukkit end - CompletableFuture completablefuture; -@@ -681,7 +727,8 @@ public class ChunkHolder { - this.fullChunkFuture = chunkStorage.prepareAccessibleChunk(this); - this.scheduleFullChunkPromotion(chunkStorage, this.fullChunkFuture, executor, ChunkHolder.FullChunkStatus.BORDER); - // Paper start - cache ticking ready status -- ensureMain(this.fullChunkFuture).thenAccept(either -> { // Paper - ensure main -+ this.fullChunkFuture.thenAccept(either -> { // Paper - ensure main // Tuinity - always fired on main -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Async full chunk future completion"); // Tuinity - final Optional left = either.left(); - if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { - // note: Here is a very good place to add callbacks to logic waiting on this. -@@ -712,7 +759,8 @@ public class ChunkHolder { - this.tickingChunkFuture = chunkStorage.prepareTickingChunk(this); - this.scheduleFullChunkPromotion(chunkStorage, this.tickingChunkFuture, executor, ChunkHolder.FullChunkStatus.TICKING); - // Paper start - cache ticking ready status -- ensureMain(this.tickingChunkFuture).thenAccept(either -> { // Paper - ensure main -+ this.tickingChunkFuture.thenAccept(either -> { // Paper - ensure main // Tuinity - always completed on main -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Async ticking chunk future completion"); // Tuinity - either.ifLeft(chunk -> { - // note: Here is a very good place to add callbacks to logic waiting on this. - ChunkHolder.this.isTickingReady = true; -@@ -722,6 +770,9 @@ public class ChunkHolder { - ChunkHolder.this.chunkMap.level.onChunkSetTicking(ChunkHolder.this.pos.x, ChunkHolder.this.pos.z); - } - // Paper end - rewrite ticklistserver -+ // Tuinity start - ticking chunk set -+ ChunkHolder.this.chunkMap.level.getChunkSource().tickingChunks.add(chunk); -+ // Tuinity end - ticking chunk set - }); - }); - // Paper end -@@ -731,6 +782,12 @@ public class ChunkHolder { - if (flag4 && !flag5) { - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage - this.tickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -+ // Tuinity start - ticking chunk set -+ LevelChunk chunkIfCached = this.getFullChunkUnchecked(); -+ if (chunkIfCached != null) { -+ this.chunkMap.level.getChunkSource().tickingChunks.remove(chunkIfCached); -+ } -+ // Tuinity end - ticking chunk set - } - - boolean flag6 = playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.ENTITY_TICKING); -@@ -744,9 +801,13 @@ public class ChunkHolder { - this.entityTickingChunkFuture = chunkStorage.prepareEntityTickingChunk(this.pos); - this.scheduleFullChunkPromotion(chunkStorage, this.entityTickingChunkFuture, executor, ChunkHolder.FullChunkStatus.ENTITY_TICKING); - // Paper start - cache ticking ready status -- ensureMain(this.entityTickingChunkFuture).thenAccept(either -> { // Paper ensureMain -+ this.entityTickingChunkFuture.thenAccept(either -> { // Paper ensureMain // Tuinity - always completed on main -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Async entity ticking chunk future completion"); // Tuinity - either.ifLeft(chunk -> { - ChunkHolder.this.isEntityTickingReady = true; -+ // Tuinity start - entity ticking chunk set -+ ChunkHolder.this.chunkMap.level.getChunkSource().entityTickingChunks.add(chunk); -+ // Tuinity end - entity ticking chunk set - }); - }); - // Paper end -@@ -756,6 +817,12 @@ public class ChunkHolder { - if (flag6 && !flag7) { - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage - this.entityTickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -+ // Tuinity start - entity ticking chunk set -+ LevelChunk chunkIfCached = this.getFullChunkUnchecked(); -+ if (chunkIfCached != null) { -+ this.chunkMap.level.getChunkSource().entityTickingChunks.remove(chunkIfCached); -+ } -+ // Tuinity end - entity ticking chunk set - } - - if (!playerchunk_state1.isOrAfter(playerchunk_state)) { -@@ -786,11 +853,19 @@ public class ChunkHolder { - // CraftBukkit start - // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins. - if (!playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { -- this.getStatusFutureUncheckedMain(ChunkStatus.FULL).thenAccept((either) -> { // Paper - ensure main -+ this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> { // Paper - ensure main // Tuinity - is always on main -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Async full status chunk future completion"); // Tuinity - LevelChunk chunk = (LevelChunk)either.left().orElse(null); -- if (chunk != null) { -+ if (chunk != null && ChunkHolder.this.oldTicketLevel <= 33 && !chunk.wasLoadCallbackInvoked()) { // Tuinity - ensure ticket level is set to loaded before calling, as now this can complete with ticket level > 33 -+ // Tuinity start - only schedule once, now the future is no longer completed as RIGHT if unloaded... -+ if (ChunkHolder.this.loadCallbackScheduled) { -+ return; -+ } -+ ChunkHolder.this.loadCallbackScheduled = true; -+ // Tuinity end - only schedule once, now the future is no longer completed as RIGHT if unloaded... - chunkStorage.callbackExecutor.execute(() -> { -- chunk.loadCallback(); -+ ChunkHolder.this.loadCallbackScheduled = false; // Tuinity - only schedule once, now the future is no longer completed as RIGHT if unloaded... -+ if (ChunkHolder.this.oldTicketLevel <= 33) chunk.loadCallback(); // Tuinity " - }); - } - }).exceptionally((throwable) -> { -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 42fd259f4492e539112b5bcb310aaaadab58a443..b9b985268f5627a238c302f81400a05bfd7c592d 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -104,6 +104,7 @@ import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - - import org.bukkit.entity.Player; // CraftBukkit -+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Tuinity - - public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider { - -@@ -116,8 +117,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public static final int MAX_VIEW_DISTANCE = 33; - public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance(); - // Paper start - faster copying -- public final Long2ObjectLinkedOpenHashMap updatingChunkMap = new com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<>(); // Paper - faster copying -- public final Long2ObjectLinkedOpenHashMap visibleChunkMap = new ProtectedVisibleChunksMap(); // Paper - faster copying -+ // Tuinity start - Don't copy -+ public final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object updatingChunks = new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(); -+ // Tuinity end - Don't copy - - private class ProtectedVisibleChunksMap extends com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy { - @Override -@@ -140,8 +142,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - } - // Paper end -- public final com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy pendingVisibleChunks = new com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy(); // Paper - this is used if the visible chunks is updated while iterating only -- public transient com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy visibleChunksClone; // Paper - used for async access of visible chunks, clone and cache only when needed -+ // Tuinity - Don't copy - public static final int FORCED_TICKET_LEVEL = 31; - // public final Long2ObjectLinkedOpenHashMap updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); // Paper - moved up - // public volatile Long2ObjectLinkedOpenHashMap visibleChunkMap; // Paper - moved up -@@ -149,7 +150,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final LongSet entitiesInLevel; - public final ServerLevel level; - private final ThreadedLevelLightEngine lightEngine; -- private final BlockableEventLoop mainThreadExecutor; -+ public final BlockableEventLoop mainThreadExecutor; // Tuinity - public - final java.util.concurrent.Executor mainInvokingExecutor; // Paper - public final ChunkGenerator generator; - public final Supplier overworldDataStorage; -@@ -182,32 +183,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final CallbackExecutor callbackExecutor = new CallbackExecutor(); - public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable { - -- // Paper start - replace impl with recursive safe multi entry queue -- // it's possible to schedule multiple tasks currently, so it's vital we change this impl -- // If we recurse into the executor again, we will append to another queue, ensuring task order consistency -- private java.util.Queue queue = new java.util.ArrayDeque<>(); // Paper - remove final -+ // Tuinity start - revert paper's change -+ private Runnable queued; - - @Override - public void execute(Runnable runnable) { - org.spigotmc.AsyncCatcher.catchOp("Callback Executor execute"); -- if (this.queue == null) { -- this.queue = new java.util.ArrayDeque<>(); -+ if (queued != null) { -+ MinecraftServer.LOGGER.fatal("Failed to schedule runnable", new IllegalStateException("Already queued")); // Paper - make sure this is printed -+ throw new IllegalStateException("Already queued"); - } -- this.queue.add(runnable); -+ queued = runnable; - } -+ // Tuinity end - revert paper's change - - @Override - public void run() { - org.spigotmc.AsyncCatcher.catchOp("Callback Executor run"); -- if (this.queue == null) { -- return; -- } -- java.util.Queue queue = this.queue; -- this.queue = null; -- // Paper end -- Runnable task; -- while ((task = queue.poll()) != null) { // Paper -+ // Tuinity start - revert paper's change -+ Runnable task = queued; -+ queued = null; -+ if (task != null) { - task.run(); -+ // Tuinity end - revert paper's change - } - } - }; -@@ -216,22 +214,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper - // Paper start - distance maps - private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); -- // Paper start - no-tick view distance -- int noTickViewDistance; -- public final int getRawNoTickViewDistance() { -- return this.noTickViewDistance; -- } -- public final int getEffectiveNoTickViewDistance() { -- return this.noTickViewDistance == -1 ? this.getEffectiveViewDistance() : this.noTickViewDistance; -- } -- public final int getLoadViewDistance() { -- return Math.max(this.getEffectiveViewDistance(), this.getEffectiveNoTickViewDistance()); -- } -- -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceBroadcastMap; -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceTickMap; -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceNoTickMap; -- // Paper end - no-tick view distance -+ public final com.tuinity.tuinity.chunk.PlayerChunkLoader playerChunkManager = new com.tuinity.tuinity.chunk.PlayerChunkLoader(this, this.pooledLinkedPlayerHashSets); // Tuinity - replace chunk loader - // Paper start - use distance map to optimise tracker - public static boolean isLegacyTrackingEntity(Entity entity) { - return entity.isLegacyTrackingEntity; -@@ -240,7 +223,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // inlined EnumMap, TrackingRange.TrackingRangeType - static final org.spigotmc.TrackingRange.TrackingRangeType[] TRACKING_RANGE_TYPES = org.spigotmc.TrackingRange.TrackingRangeType.values(); - public final com.destroystokyo.paper.util.misc.PlayerAreaMap[] playerEntityTrackerTrackMaps; -- final int[] entityTrackerTrackRanges; -+ final int[] entityTrackerTrackRanges; public int getEntityTrackerRange(final int ordinal) { return this.entityTrackerTrackRanges[ordinal]; } // Tuinity - public read - - private int convertSpigotRangeToVanilla(final int vanilla) { - return MinecraftServer.getServer().getScaledTrackingDistance(vanilla); -@@ -257,6 +240,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick - public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap; - // Paper end - optimise PlayerChunkMap#isOutsideRange -+ // Tuinity start - optimise checkDespawn -+ public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40; -+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1); -+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE; -+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap; -+ // Tuinity end - optimise checkDespawn - - void addPlayerToDistanceMaps(ServerPlayer player) { - int chunkX = MCUtil.getChunkCoordinate(player.getX()); -@@ -267,7 +256,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; - int trackRange = this.entityTrackerTrackRanges[i]; - -- trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance())); -+ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, player.getBukkitEntity().getViewDistance())); // Tuinity - per player view distances - } - // Paper end - use distance map to optimise entity tracker - // Paper start - optimise PlayerChunkMap#isOutsideRange -@@ -276,19 +265,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper start - optimise PlayerChunkMap#isOutsideRange - this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); - // Paper end - optimise PlayerChunkMap#isOutsideRange -- // Paper start - no-tick view distance -- int effectiveTickViewDistance = this.getEffectiveViewDistance(); -- int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance); -- -- if (!this.skipPlayer(player)) { -- this.playerViewDistanceTickMap.add(player, chunkX, chunkZ, effectiveTickViewDistance); -- this.playerViewDistanceNoTickMap.add(player, chunkX, chunkZ, effectiveNoTickViewDistance + 2); // clients need chunk 1 neighbour, and we need another 1 for sending those extra neighbours (as we require neighbours to send) -- } -- -- player.needsChunkCenterUpdate = true; -- this.playerViewDistanceBroadcastMap.add(player, chunkX, chunkZ, effectiveNoTickViewDistance + 1); // clients need an extra neighbour to render the full view distance configured -- player.needsChunkCenterUpdate = false; -- // Paper end - no-tick view distance -+ this.playerChunkManager.addPlayer(player); // Tuinity - replace chunk loader -+ // Tuinity start - optimise checkDespawn -+ this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); -+ // Tuinity end - optimise checkDespawn - } - - void removePlayerFromDistanceMaps(ServerPlayer player) { -@@ -301,11 +281,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerMobSpawnMap.remove(player); - this.playerChunkTickRangeMap.remove(player); - // Paper end - optimise PlayerChunkMap#isOutsideRange -- // Paper start - no-tick view distance -- this.playerViewDistanceBroadcastMap.remove(player); -- this.playerViewDistanceTickMap.remove(player); -- this.playerViewDistanceNoTickMap.remove(player); -- // Paper end - no-tick view distance -+ this.playerChunkManager.removePlayer(player); // Tuinity - replace chunk loader -+ // Tuinity start - optimise checkDespawn -+ this.playerGeneralAreaMap.remove(player); -+ // Tuinity end - optimise checkDespawn - } - - void updateMaps(ServerPlayer player) { -@@ -317,28 +296,125 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; - int trackRange = this.entityTrackerTrackRanges[i]; - -- trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance())); -+ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, player.getBukkitEntity().getViewDistance())); // Tuinity - per player view distances - } - // Paper end - use distance map to optimise entity tracker - // Paper start - optimise PlayerChunkMap#isOutsideRange - this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); - // Paper end - optimise PlayerChunkMap#isOutsideRange -- // Paper start - no-tick view distance -- int effectiveTickViewDistance = this.getEffectiveViewDistance(); -- int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance); -+ this.playerChunkManager.updatePlayer(player); // Tuinity - replace chunk loader -+ // Tuinity start - optimise checkDespawn -+ this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); -+ // Tuinity end - optimise checkDespawn -+ } -+ // Paper end -+ // Tuinity start -+ public final List regionManagers = new java.util.ArrayList<>(); -+ public final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager dataRegionManager; - -- if (!this.skipPlayer(player)) { -- this.playerViewDistanceTickMap.update(player, chunkX, chunkZ, effectiveTickViewDistance); -- this.playerViewDistanceNoTickMap.update(player, chunkX, chunkZ, effectiveNoTickViewDistance + 2); // clients need chunk 1 neighbour, and we need another 1 for sending those extra neighbours (as we require neighbours to send) -+ public static final class DataRegionData implements com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionData { -+ // Tuinity start - optimise notify() -+ private com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet navigators; -+ -+ public com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet getNavigators() { -+ return this.navigators; -+ } -+ -+ public boolean addToNavigators(final Mob navigator) { -+ if (this.navigators == null) { -+ this.navigators = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(); -+ } -+ return this.navigators.add(navigator); - } - -- player.needsChunkCenterUpdate = true; -- this.playerViewDistanceBroadcastMap.update(player, chunkX, chunkZ, effectiveNoTickViewDistance + 1); // clients need an extra neighbour to render the full view distance configured -- player.needsChunkCenterUpdate = false; -- // Paper end - no-tick view distance -+ public boolean removeFromNavigators(final Mob navigator) { -+ if (this.navigators == null) { -+ return false; -+ } -+ return this.navigators.remove(navigator); -+ } -+ // Tuinity end - optimise notify() - } -- // Paper end - -+ public static final class DataRegionSectionData implements com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSectionData { -+ -+ // Tuinity start - optimise notify() -+ private com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet navigators; -+ -+ public com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet getNavigators() { -+ return this.navigators; -+ } -+ -+ public boolean addToNavigators(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section, final Mob navigator) { -+ if (this.navigators == null) { -+ this.navigators = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(); -+ } -+ final boolean ret = this.navigators.add(navigator); -+ if (ret) { -+ final DataRegionData data = (DataRegionData)section.getRegion().regionData; -+ if (!data.addToNavigators(navigator)) { -+ throw new IllegalStateException(); -+ } -+ } -+ return ret; -+ } -+ -+ public boolean removeFromNavigators(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section, final Mob navigator) { -+ if (this.navigators == null) { -+ return false; -+ } -+ final boolean ret = this.navigators.remove(navigator); -+ if (ret) { -+ final DataRegionData data = (DataRegionData)section.getRegion().regionData; -+ if (!data.removeFromNavigators(navigator)) { -+ throw new IllegalStateException(); -+ } -+ } -+ return ret; -+ } -+ // Tuinity end - optimise notify() -+ -+ @Override -+ public void removeFromRegion(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section, -+ final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.Region from) { -+ final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData; -+ final DataRegionData fromData = (DataRegionData)from.regionData; -+ // Tuinity start - optimise notify() -+ if (sectionData.navigators != null) { -+ for (final Iterator iterator = sectionData.navigators.unsafeIterator(com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ if (!fromData.removeFromNavigators(iterator.next())) { -+ throw new IllegalStateException(); -+ } -+ } -+ } -+ // Tuinity end - optimise notify() -+ } -+ -+ @Override -+ public void addToRegion(final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section, -+ final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.Region oldRegion, -+ final com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.Region newRegion) { -+ final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData; -+ final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData; -+ final DataRegionData newRegionData = (DataRegionData)newRegion.regionData; -+ // Tuinity start - optimise notify() -+ if (sectionData.navigators != null) { -+ for (final Iterator iterator = sectionData.navigators.unsafeIterator(com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ if (!newRegionData.addToNavigators(iterator.next())) { -+ throw new IllegalStateException(); -+ } -+ } -+ } -+ // Tuinity end - optimise notify() -+ } -+ } -+ -+ public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { -+ return this.pendingUnloads.get(com.tuinity.tuinity.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ } -+ // Tuiniy end -+ -+ boolean unloadingPlayerChunk = false; // Tuinity - do not allow ticket level changes while unloading chunks - private final java.util.concurrent.ExecutorService lightThread; // Paper - public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { - super(new File(session.getDimensionPath(world.dimension()), "region"), dataFixer, dsync); -@@ -465,53 +541,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - }); - // Paper end - optimise PlayerChunkMap#isOutsideRange -- // Paper start - no-tick view distance -- this.setNoTickViewDistance(this.level.paperConfig.noTickViewDistance); -- this.playerViewDistanceTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- checkHighPriorityChunks(player); -- if (newState.size() != 1) { -- return; -- } -- LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfLoadedMainThreadNoCache(rangeX, rangeZ); -- if (chunk == null || !chunk.areNeighboursLoaded(2)) { -- return; -- } -- -- ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ); -- ChunkMap.this.level.getChunkSource().addTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update -- }, -+ this.setNoTickViewDistance(this.level.paperConfig.noTickViewDistance); // Tuinity - replace chunk loading system -+ // Tuinity start -+ this.dataRegionManager = new com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); -+ this.regionManagers.add(this.dataRegionManager); -+ // Tuinity end -+ // Tuinity start - optimise checkDespawn -+ this.playerGeneralAreaMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, - (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- if (newState != null) { -- return; -+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ); -+ if (chunk != null) { -+ chunk.updateGeneralAreaCache(newState); - } -- ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ); -- ChunkMap.this.level.getChunkSource().removeTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update -- // Paper start -- ChunkMap.this.level.getChunkSource().clearPriorityTickets(chunkPos); - }, -- (player, prevPos, newPos) -> { -- player.lastHighPriorityChecked = -1; // reset and recheck -- checkHighPriorityChunks(player); -- }); -- // Paper end -- this.playerViewDistanceNoTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); -- this.playerViewDistanceBroadcastMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, - (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- if (player.needsChunkCenterUpdate) { -- player.needsChunkCenterUpdate = false; -- player.connection.send(new ClientboundSetChunkCacheCenterPacket(currPosX, currPosZ)); -+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ); -+ if (chunk != null) { -+ chunk.updateGeneralAreaCache(newState); - } -- ChunkMap.this.updateChunkTracking(player, new ChunkPos(rangeX, rangeZ), new Packet[2], false, true); // unloaded, loaded -- }, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- ChunkMap.this.updateChunkTracking(player, new ChunkPos(rangeX, rangeZ), null, true, false); // unloaded, loaded - }); -- // Paper end - no-tick view distance -+ // Tuinity end - optimise checkDespawn - } - - // Paper start - Chunk Prioritization -@@ -545,6 +596,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void checkHighPriorityChunks(ServerPlayer player) { -+ if (true) return; // Tuinity - replace player chunk loader - int currentTick = MinecraftServer.currentTick; - if (currentTick - player.lastHighPriorityChecked < 20 || !player.isRealPlayer) { // weed out fake players - return; -@@ -552,7 +604,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - player.lastHighPriorityChecked = currentTick; - it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap priorities = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); - -- int viewDistance = getEffectiveNoTickViewDistance(); -+ int viewDistance = 10;//int viewDistance = getEffectiveNoTickViewDistance(); // Tuinity - replace player chunk loader - net.minecraft.core.BlockPos.MutableBlockPos pos = new net.minecraft.core.BlockPos.MutableBlockPos(); - - // Prioritize circular near -@@ -618,7 +670,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - private boolean shouldSkipPrioritization(ChunkPos coord) { -- if (playerViewDistanceNoTickMap.getObjectsInRange(coord.toLong()) == null) return true; -+ if (true) return true; // Tuinity - replace player chunk loader - unused outside paper player loader logic - ChunkHolder chunk = getUpdatingChunkIfPresent(coord.toLong()); - return chunk != null && (chunk.isFullChunkReady()); - } -@@ -686,7 +738,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - @Nullable - public ChunkHolder getUpdatingChunkIfPresent(long pos) { -- return (ChunkHolder) this.updatingChunkMap.get(pos); -+ return this.updatingChunks.getUpdating(pos); // Tuinity - Don't copy - } - - // Paper start - remove cloning of visible chunks unless accessed as a collection async -@@ -694,47 +746,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - private boolean isIterating = false; - private boolean hasPendingVisibleUpdate = false; - public void forEachVisibleChunk(java.util.function.Consumer consumer) { -- org.spigotmc.AsyncCatcher.catchOp("forEachVisibleChunk"); -- boolean prev = isIterating; -- isIterating = true; -- try { -- for (ChunkHolder value : this.visibleChunkMap.values()) { -- consumer.accept(value); -- } -- } finally { -- this.isIterating = prev; -- if (!this.isIterating && this.hasPendingVisibleUpdate) { -- ((ProtectedVisibleChunksMap)this.visibleChunkMap).copyFrom(this.pendingVisibleChunks); -- this.pendingVisibleChunks.clear(); -- this.hasPendingVisibleUpdate = false; -- } -- } -+ throw new UnsupportedOperationException(); // Tuinity - Don't copy - } - public Long2ObjectLinkedOpenHashMap getVisibleChunks() { -- if (Thread.currentThread() == this.level.thread) { -- return this.visibleChunkMap; -- } else { -- synchronized (this.visibleChunkMap) { -- if (DEBUG_ASYNC_VISIBLE_CHUNKS) new Throwable("Async getVisibleChunks").printStackTrace(); -- if (this.visibleChunksClone == null) { -- this.visibleChunksClone = this.hasPendingVisibleUpdate ? this.pendingVisibleChunks.clone() : ((ProtectedVisibleChunksMap)this.visibleChunkMap).clone(); -- } -- return this.visibleChunksClone; -- } -+ // Tuinity start - Don't copy (except in rare cases) -+ synchronized (this.updatingChunks) { -+ return this.updatingChunks.getVisibleMap().clone(); - } -+ // Tuinity end - Don't copy (except in rare cases) - } - // Paper end - - @Nullable - public ChunkHolder getVisibleChunkIfPresent(long pos) { -- // Paper start - mt safe get -- if (Thread.currentThread() != this.level.thread) { -- synchronized (this.visibleChunkMap) { -- return (ChunkHolder) (this.hasPendingVisibleUpdate ? this.pendingVisibleChunks.get(pos) : ((ProtectedVisibleChunksMap)this.visibleChunkMap).safeGet(pos)); -- } -+ // Tuinity start - Don't copy -+ if (Thread.currentThread() == this.level.thread) { -+ return this.updatingChunks.getVisible(pos); - } -- return (ChunkHolder) (this.hasPendingVisibleUpdate ? this.pendingVisibleChunks.get(pos) : ((ProtectedVisibleChunksMap)this.visibleChunkMap).safeGet(pos)); -- // Paper end -+ return this.updatingChunks.getVisibleAsync(pos); -+ // Tuinity end - Don't copy - } - - protected IntSupplier getChunkQueueLevel(long pos) { -@@ -856,12 +886,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - @Nullable - ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k) { -+ if (this.unloadingPlayerChunk) { LOGGER.fatal("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Tuinity - if (k > ChunkMap.MAX_CHUNK_DISTANCE && level > ChunkMap.MAX_CHUNK_DISTANCE) { - return holder; - } else { - if (holder != null) { - holder.setTicketLevel(level); -- holder.updateRanges(); // Paper - optimise isOutsideOfRange -+ // Tuinity - move to correct place - } - - if (holder != null) { -@@ -876,11 +907,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - holder = (ChunkHolder) this.pendingUnloads.remove(pos); - if (holder != null) { - holder.setTicketLevel(level); -+ holder.updateRanges(); // Paper - optimise isOutsideOfRange // Tuinity - move to correct place - } else { - holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); -+ // Tuinity start -+ for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { -+ this.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); -+ } -+ // Tuinity end - } - -- this.updatingChunkMap.put(pos, holder); -+ this.updatingChunks.queueUpdate(pos, holder); // Tuinity - Don't copy - this.modified = true; - } - -@@ -1035,7 +1072,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - while (longiterator.hasNext()) { // Spigot - long j = longiterator.nextLong(); - longiterator.remove(); // Spigot -- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); -+ ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Tuinity - Don't copy - - if (playerchunk != null) { - this.pendingUnloads.put(j, playerchunk); -@@ -1072,7 +1109,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.level, chunkPos.x, chunkPos.z, -- poiData, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.LOW_PRIORITY); -+ poiData, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); // Tuinity - use normal priority - - if (!chunk.isUnsaved()) { - return; -@@ -1093,7 +1130,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - asyncSaveData = ChunkSerializer.getAsyncSaveData(this.level, chunk); - } - -- this.level.asyncChunkTaskManager.scheduleChunkSave(chunkPos.x, chunkPos.z, com.destroystokyo.paper.io.PrioritizedTaskQueue.LOW_PRIORITY, -+ this.level.asyncChunkTaskManager.scheduleChunkSave(chunkPos.x, chunkPos.z, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY, // Tuinity - use normal priority - asyncSaveData, chunk); - - chunk.setUnsaved(false); -@@ -1109,7 +1146,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - if (completablefuture1 != completablefuture) { - this.scheduleUnload(pos, holder); - } else { -- if (this.pendingUnloads.remove(pos, holder) && ichunkaccess != null) { -+ // Tuinity start - do not allow ticket level changes while unloading chunks -+ org.spigotmc.AsyncCatcher.catchOp("playerchunk unload"); -+ boolean unloadingBefore = this.unloadingPlayerChunk; -+ this.unloadingPlayerChunk = true; -+ try { -+ // Tuinity end - do not allow ticket level changes while unloading chunks -+ // Tuinity start -+ boolean removed; -+ if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -+ for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { -+ this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); -+ } -+ // Tuinity end - if (ichunkaccess instanceof LevelChunk) { - ((LevelChunk) ichunkaccess).setLoaded(false); - } -@@ -1134,7 +1183,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.lightEngine.updateChunkStatus(ichunkaccess.getPos()); - this.lightEngine.tryScheduleUpdate(); - this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); -+ } else if (removed) { // Tuinity start -+ for (int index = 0, len = this.regionManagers.size(); index < len; ++index) { -+ this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); -+ } - } -+ // Tuinity end -+ } finally { this.unloadingPlayerChunk = unloadingBefore; } // Tuinity - do not allow ticket level changes while unloading chunks - - } - }; -@@ -1153,19 +1208,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - if (!this.modified) { - return false; - } else { -- // Paper start - stop cloning visibleChunks -- synchronized (this.visibleChunkMap) { -- if (isIterating) { -- hasPendingVisibleUpdate = true; -- this.pendingVisibleChunks.copyFrom((com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy)this.updatingChunkMap); -- } else { -- hasPendingVisibleUpdate = false; -- this.pendingVisibleChunks.clear(); -- ((ProtectedVisibleChunksMap)this.visibleChunkMap).copyFrom((com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy)this.updatingChunkMap); -- this.visibleChunksClone = null; -- } -+ // Tuinity start - Don't copy -+ synchronized (this.updatingChunks) { -+ this.updatingChunks.performUpdates(); - } -- // Paper end -+ // Tuinity end - Don't copy - - this.modified = false; - return true; -@@ -1178,11 +1225,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - if (requiredStatus == ChunkStatus.EMPTY) { - return this.scheduleChunkLoad(chunkcoordintpair); - } else { -+ // Tuinity start - revert 1.17 chunk system changes -+ CompletableFuture> future = holder.getOrScheduleFuture(requiredStatus.getParent(), this); -+ return future.thenComposeAsync((either) -> { -+ Optional optional = either.left(); -+ if (!optional.isPresent()) { -+ return CompletableFuture.completedFuture(either); -+ } -+ // Tuinity end - revert 1.17 chunk system changes -+ -+ // Tuinity start - revert 1.17 chunk system changes - if (requiredStatus == ChunkStatus.LIGHT) { - this.distanceManager.addTicket(TicketType.LIGHT, chunkcoordintpair, 33 + ChunkStatus.getDistance(ChunkStatus.LIGHT), chunkcoordintpair); - } -- -- Optional optional = ((Either) holder.getOrScheduleFuture(requiredStatus.getParent(), this).getNow(ChunkHolder.UNLOADED_CHUNK)).left(); -+ // Tuinity end - revert 1.17 chunk system changes - - if (optional.isPresent() && ((ChunkAccess) optional.get()).getStatus().isOrAfter(requiredStatus)) { - CompletableFuture> completablefuture = requiredStatus.load(this.level, this.structureManager, this.lightEngine, (ichunkaccess) -> { -@@ -1194,6 +1250,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } else { - return this.scheduleChunkGeneration(holder, requiredStatus); - } -+ }, this.mainThreadExecutor).thenComposeAsync(CompletableFuture::completedFuture, this.mainThreadExecutor); // Tuinity - revert 1.17 chunk system changes - } - } - -@@ -1294,7 +1351,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }); - Executor executor = (runnable) -> { - // Paper start - optimize chunk status progression without jumping through thread pool -- if (holder.canAdvanceStatus()) { -+ if (false && holder.canAdvanceStatus()) { // Tuinity - these optimisations will be revisited later - this.mainInvokingExecutor.execute(runnable); - return; - } -@@ -1325,7 +1382,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.releaseLightTicket(chunkcoordintpair); - return CompletableFuture.completedFuture(Either.right(playerchunk_failure)); - }); -- }, executor); -+ }, executor).thenComposeAsync((either) -> { // Tuinity start - force competion on the main thread -+ return CompletableFuture.completedFuture(either); -+ }, this.mainThreadExecutor); // use the main executor, we want to ensure only one chunk callback can be completed per runnable execute -+ // Tuinity end - force competion on the main thread - } - - protected void releaseLightTicket(ChunkPos pos) { -@@ -1484,9 +1544,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - chunk.unpackTicks(); - return chunk; - }); -- }, (runnable) -> { -- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(playerchunk, runnable)); -- }); -+ }, this.mainThreadExecutor); // Tuinity - queue to execute immediately so this doesn't delay chunk unloading - } - - public int getTickingGenerated() { -@@ -1571,7 +1629,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int k = this.viewDistance; - - this.viewDistance = j; -- this.setNoTickViewDistance(this.getRawNoTickViewDistance()); //Paper - no-tick view distance - propagate changes to no-tick, which does the actual chunk loading/sending -+ this.playerChunkManager.setTickDistance(Mth.clamp(viewDistance, 2, 32)); // Tuinity - replace player loader system - } - - } -@@ -1579,26 +1637,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper start - no-tick view distance - public final void setNoTickViewDistance(int viewDistance) { - viewDistance = viewDistance == -1 ? -1 : Mth.clamp(viewDistance, 2, 32); -- -- this.noTickViewDistance = viewDistance; -- int loadViewDistance = this.getLoadViewDistance(); -- this.distanceManager.setNoTickViewDistance(loadViewDistance + 2 + 2); // add 2 to account for the change to 31 -> 33 tickets // see notes in the distance map updating for the other + 2 -- -- if (this.level != null && this.level.players != null) { // this can be called from constructor, where these aren't set -- for (ServerPlayer player : this.level.players) { -- net.minecraft.server.network.ServerGamePacketListenerImpl connection = player.connection; -- if (connection != null) { -- // moved in from PlayerList -- connection.send(new net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket(loadViewDistance)); -- } -- this.updateMaps(player); -- // Paper end - no-tick view distance -- } -- } -+ this.playerChunkManager.setLoadDistance(viewDistance == -1 ? -1 : viewDistance + 1); // Tuinity - replace player loader system - add 1 here, we need an extra one to send to clients for chunks in this viewDistance to render - - } - -- protected void updateChunkTracking(ServerPlayer player, ChunkPos pos, Packet[] packets, boolean withinMaxWatchDistance, boolean withinViewDistance) { -+ public void updateChunkTracking(ServerPlayer player, ChunkPos pos, Packet[] packets, boolean withinMaxWatchDistance, boolean withinViewDistance) { // Tuinity - public - if (player.level == this.level) { - if (withinViewDistance && !withinMaxWatchDistance) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); -@@ -1622,7 +1665,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public int size() { -- return this.visibleChunkMap.size(); -+ return this.updatingChunks.getVisibleMap().size(); // Tuinity - Don't copy - } - - protected DistanceManager getDistanceManager() { -@@ -1927,6 +1970,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - */ // Paper end - replaced by distance map - - this.updateMaps(player); // Paper - distance maps -+ this.playerChunkManager.updatePlayer(player); // Tuinity - respond to movement immediately - - } - -@@ -1935,7 +1979,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper start - per player view distance - // there can be potential desync with player's last mapped section and the view distance map, so use the - // view distance map here. -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = this.playerViewDistanceBroadcastMap.getObjectsInRange(chunkPos); -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = this.playerChunkManager.broadcastMap.getObjectsInRange(chunkPos); // Tuinity - replace player chunk loader system - - if (inRange == null) { - return Stream.empty(); -@@ -1951,8 +1995,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - continue; - } - ServerPlayer player = (ServerPlayer)temp; -- int viewDistance = this.playerViewDistanceBroadcastMap.getLastViewDistance(player); -- long lastPosition = this.playerViewDistanceBroadcastMap.getLastCoordinate(player); -+ if (!this.playerChunkManager.isChunkSent(player, chunkPos.x, chunkPos.z)) continue; // Tuinity - replace player chunk management -+ int viewDistance = this.playerChunkManager.broadcastMap.getLastViewDistance(player); // Tuinity - replace player chunk loader system -+ long lastPosition = this.playerChunkManager.broadcastMap.getLastCoordinate(player); // Tuinity - replace player chunk loader system - - int distX = Math.abs(MCUtil.getCoordinateX(lastPosition) - chunkPos.x); - int distZ = Math.abs(MCUtil.getCoordinateZ(lastPosition) - chunkPos.z); -@@ -1967,6 +2012,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - continue; - } - ServerPlayer player = (ServerPlayer)temp; -+ if (!this.playerChunkManager.isChunkSent(player, chunkPos.x, chunkPos.z)) continue; // Tuinity - replace player chunk management - players.add(player); - } - } -@@ -2281,7 +2327,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially - final Entity entity; - private final int range; - SectionPos lastSectionPos; -- public final Set seenBy = Sets.newIdentityHashSet(); -+ public final Set seenBy = new ReferenceOpenHashSet<>(); // Tuinity - optimise map impl - - public TrackedEntity(Entity entity, int i, int j, boolean flag) { - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit -@@ -2381,7 +2427,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially - double vec3d_dy = player.getY() - this.entity.getY(); - double vec3d_dz = player.getZ() - this.entity.getZ(); - // Paper end - remove allocation of Vec3D here -- int i = Math.min(this.getEffectiveRange(), (ChunkMap.this.viewDistance - 1) * 16); -+ int i = Math.min(this.getEffectiveRange(), player.getBukkitEntity().getViewDistance() * 16); // Tuinity - per player view distance - boolean flag = vec3d_dx >= (double) (-i) && vec3d_dx <= (double) i && vec3d_dz >= (double) (-i) && vec3d_dz <= (double) i && this.entity.broadcastToPlayer(player); // Paper - remove allocation of Vec3D here - - // CraftBukkit start - respect vanish API -@@ -2416,7 +2462,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially - int j = entity.getType().clientTrackingRange() * 16; - j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper - -- if (j < i) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic -+ if (j > i) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic // Tuinity - not anymore! - i = j; - } - } -diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 1cc4e0a1f3d8235ef88b48e01ca8b78a263d2676..428d94c60b826ddf3797d6713661dff1ca835ac2 100644 ---- a/src/main/java/net/minecraft/server/level/DistanceManager.java -+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -36,6 +36,7 @@ import net.minecraft.world.level.chunk.LevelChunk; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - -+import it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap; // Tuinity - public abstract class DistanceManager { - - static final Logger LOGGER = LogManager.getLogger(); -@@ -44,9 +45,9 @@ public abstract class DistanceManager { - private static final int INITIAL_TICKET_LIST_CAPACITY = 4; - final Long2ObjectMap> playersPerChunk = new Long2ObjectOpenHashMap(); - public final Long2ObjectOpenHashMap>> tickets = new Long2ObjectOpenHashMap(); -- private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker(); -+ //private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker(); // Tuinity - replace ticket level propagator - public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used -- private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); -+ //private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); // Tuinity - no longer used - // Paper start use a queue, but still keep unique requirement - public final java.util.Queue pendingChunkUpdates = new java.util.ArrayDeque() { - @Override -@@ -77,6 +78,46 @@ public abstract class DistanceManager { - this.mainThreadExecutor = mainThreadExecutor; - } - -+ // Tuinity start - replace ticket level propagator -+ protected final Long2IntLinkedOpenHashMap ticketLevelUpdates = new Long2IntLinkedOpenHashMap() { -+ @Override -+ protected void rehash(int newN) { -+ // no downsizing allowed -+ if (newN < this.n) { -+ return; -+ } -+ super.rehash(newN); -+ } -+ }; -+ protected final com.tuinity.tuinity.util.misc.Delayed8WayDistancePropagator2D ticketLevelPropagator = new com.tuinity.tuinity.util.misc.Delayed8WayDistancePropagator2D( -+ (long coordinate, byte oldLevel, byte newLevel) -> { -+ DistanceManager.this.ticketLevelUpdates.putAndMoveToLast(coordinate, convertBetweenTicketLevels(newLevel)); -+ } -+ ); -+ // function for converting between ticket levels and propagator levels and vice versa -+ // the problem is the ticket level propagator will propagate from a set source down to zero, whereas mojang expects -+ // levels to propagate from a set value up to a maximum value. so we need to convert the levels we put into the propagator -+ // and the levels we get out of the propagator -+ -+ // this maps so that GOLDEN_TICKET + 1 will be 0 in the propagator, GOLDEN_TICKET will be 1, and so on -+ // we need GOLDEN_TICKET+1 as 0 because anything >= GOLDEN_TICKET+1 should be unloaded -+ public static int convertBetweenTicketLevels(final int level) { -+ return ChunkMap.MAX_CHUNK_DISTANCE - level + 1; -+ } -+ -+ protected final int getPropagatedTicketLevel(final long coordinate) { -+ return convertBetweenTicketLevels(this.ticketLevelPropagator.getLevel(coordinate)); -+ } -+ -+ protected final void updateTicketLevel(final long coordinate, final int ticketLevel) { -+ if (ticketLevel > ChunkMap.MAX_CHUNK_DISTANCE) { -+ this.ticketLevelPropagator.removeSource(coordinate); -+ } else { -+ this.ticketLevelPropagator.setSource(coordinate, convertBetweenTicketLevels(ticketLevel)); -+ } -+ } -+ // Tuinity end - replace ticket level propagator -+ - protected void purgeStaleTickets() { - ++this.ticketTickCounter; - ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); -@@ -87,7 +128,7 @@ public abstract class DistanceManager { - if ((entry.getValue()).removeIf((ticket) -> { // CraftBukkit - decompile error - return ticket.timedOut(this.ticketTickCounter); - })) { -- this.ticketTracker.update(entry.getLongKey(), DistanceManager.getTicketLevelAt((SortedArraySet) entry.getValue()), false); -+ this.updateTicketLevel(entry.getLongKey(), getTicketLevelAt(entry.getValue())); // Tuinity - replace ticket level propagator - } - - if (((SortedArraySet) entry.getValue()).isEmpty()) { -@@ -110,60 +151,93 @@ public abstract class DistanceManager { - @Nullable - protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k); - -+ protected long ticketLevelUpdateCount; // Tuinity - replace ticket level propagator - public boolean runAllUpdates(ChunkMap playerchunkmap) { - //this.f.a(); // Paper - no longer used - org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper -- this.playerTicketManager.runAllUpdates(); -- int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE); -- boolean flag = i != 0; -+ //this.playerTicketManager.runAllUpdates(); // Tuinity - no longer used -+ boolean flag = this.ticketLevelPropagator.propagateUpdates(); // Tuinity - replace ticket level propagator - - if (flag) { - ; - } - -- // Paper start -- if (!this.pendingChunkUpdates.isEmpty()) { -- this.pollingPendingChunkUpdates = true; try { // Paper - Chunk priority -- while(!this.pendingChunkUpdates.isEmpty()) { -- ChunkHolder remove = this.pendingChunkUpdates.remove(); -- remove.isUpdateQueued = false; -- remove.updateFutures(playerchunkmap, this.mainThreadExecutor); -- } -- } finally { this.pollingPendingChunkUpdates = false; } // Paper - Chunk priority -- // Paper end -- return true; -- } else { -- if (!this.ticketsToRelease.isEmpty()) { -- LongIterator longiterator = this.ticketsToRelease.iterator(); -+ // Tuinity start - replace level propagator -+ ticket_update_loop: -+ while (!this.ticketLevelUpdates.isEmpty()) { -+ flag = true; - -- while (longiterator.hasNext()) { -- long j = longiterator.nextLong(); -+ boolean oldPolling = this.pollingPendingChunkUpdates; -+ this.pollingPendingChunkUpdates = true; -+ try { -+ for (java.util.Iterator iterator = this.ticketLevelUpdates.long2IntEntrySet().fastIterator(); iterator.hasNext();) { -+ Long2IntMap.Entry entry = iterator.next(); -+ long key = entry.getLongKey(); -+ int newLevel = entry.getIntValue(); -+ ChunkHolder chunk = this.getChunk(key); -+ -+ if (chunk == null && newLevel > ChunkMap.MAX_CHUNK_DISTANCE) { -+ // not loaded and it shouldn't be loaded! -+ continue; -+ } -+ -+ int currentLevel = chunk == null ? ChunkMap.MAX_CHUNK_DISTANCE + 1 : chunk.getTicketLevel(); -+ -+ if (currentLevel == newLevel) { -+ // nothing to do -+ continue; -+ } - -- if (this.getTickets(j).stream().anyMatch((ticket) -> { -- return ticket.getType() == TicketType.PLAYER; -- })) { -- ChunkHolder playerchunk = playerchunkmap.getUpdatingChunkIfPresent(j); -+ this.updateChunkScheduling(key, newLevel, chunk, currentLevel); -+ } - -- if (playerchunk == null) { -- throw new IllegalStateException(); -+ long recursiveCheck = ++this.ticketLevelUpdateCount; -+ while (!this.ticketLevelUpdates.isEmpty()) { -+ long key = this.ticketLevelUpdates.firstLongKey(); -+ int newLevel = this.ticketLevelUpdates.removeFirstInt(); -+ ChunkHolder chunk = this.getChunk(key); -+ -+ if (chunk == null) { -+ if (newLevel <= ChunkMap.MAX_CHUNK_DISTANCE) { -+ throw new IllegalStateException("Expected chunk holder to be created"); - } -+ // not loaded and it shouldn't be loaded! -+ continue; -+ } - -- CompletableFuture> completablefuture = playerchunk.getEntityTickingChunkFuture(); -+ int currentLevel = chunk.oldTicketLevel; - -- completablefuture.thenAccept((either) -> { -- this.mainThreadExecutor.execute(() -> { -- this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> { -- }, j, false)); -- }); -- }); -+ if (currentLevel == newLevel) { -+ // nothing to do -+ continue; -+ } -+ -+ chunk.updateFutures(playerchunkmap, this.mainThreadExecutor); -+ if (recursiveCheck != this.ticketLevelUpdateCount) { -+ // back to the start, we must create player chunks and update the ticket level fields before -+ // processing the actual level updates -+ continue ticket_update_loop; - } - } - -- this.ticketsToRelease.clear(); -- } -+ for (;;) { -+ if (recursiveCheck != this.ticketLevelUpdateCount) { -+ continue ticket_update_loop; -+ } -+ ChunkHolder pendingUpdate = this.pendingChunkUpdates.poll(); -+ if (pendingUpdate == null) { -+ break; -+ } - -- return flag; -+ pendingUpdate.updateFutures(playerchunkmap, this.mainThreadExecutor); -+ } -+ } finally { -+ this.pollingPendingChunkUpdates = oldPolling; -+ } - } -+ -+ return flag; -+ // Tuinity end - replace level propagator - } - boolean pollingPendingChunkUpdates = false; // Paper - Chunk priority - -@@ -175,7 +249,7 @@ public abstract class DistanceManager { - - ticket1.setCreatedTick(this.ticketTickCounter); - if (ticket.getTicketLevel() < j) { -- this.ticketTracker.update(i, ticket.getTicketLevel(), true); -+ this.updateTicketLevel(i, ticket.getTicketLevel()); // Tuinity - replace ticket level propagator - } - - return ticket == ticket1; // CraftBukkit -@@ -219,7 +293,7 @@ public abstract class DistanceManager { - // Paper start - Chunk priority - int newLevel = getTicketLevelAt(arraysetsorted); - if (newLevel > oldLevel) { -- this.ticketTracker.update(i, newLevel, false); -+ this.updateTicketLevel(i, newLevel); // Paper // Tuinity - replace ticket level propagator - } - // Paper end - return removed; // CraftBukkit -@@ -313,7 +387,7 @@ public abstract class DistanceManager { - org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket"); - long pair = coords.toLong(); - ChunkHolder chunk = chunkMap.getUpdatingChunkIfPresent(pair); -- boolean needsTicket = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null && !hasPlayerTicket(coords, 33); -+ boolean needsTicket = false; // Tuinity - replace old loader system - - if (needsTicket) { - Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, coords); -@@ -411,7 +485,7 @@ public abstract class DistanceManager { - return new ObjectOpenHashSet(); - })).add(player); - //this.f.update(i, 0, true); // Paper - no longer used -- this.playerTicketManager.update(i, 0, true); -+ //this.playerTicketManager.update(i, 0, true); // Tuinity - no longer used - } - - public void removePlayer(SectionPos pos, ServerPlayer player) { -@@ -423,7 +497,7 @@ public abstract class DistanceManager { - if (objectset == null || objectset.isEmpty()) { // Paper - this.playersPerChunk.remove(i); - //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used -- this.playerTicketManager.update(i, Integer.MAX_VALUE, false); -+ //this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Tuinity - no longer used - } - - } -@@ -442,7 +516,7 @@ public abstract class DistanceManager { - } - - protected void setNoTickViewDistance(int i) { // Paper - force abi breakage on usage change -- this.playerTicketManager.updateViewDistance(i); -+ throw new UnsupportedOperationException("use world api"); // Tuinity - no longer relevant - } - - public int getNaturalSpawnChunkCount() { -@@ -507,7 +581,7 @@ public abstract class DistanceManager { - SortedArraySet> tickets = entry.getValue(); - if (tickets.remove(target)) { - // copied from removeTicket -- this.ticketTracker.update(entry.getLongKey(), DistanceManager.getTicketLevelAt(tickets), false); -+ this.updateTicketLevel(entry.getLongKey(), getTicketLevelAt(tickets)); // Tuinity - replace ticket level propagator - - // can't use entry after it's removed - if (tickets.isEmpty()) { -@@ -563,6 +637,7 @@ public abstract class DistanceManager { - } - } - -+ /* Tuinity - replace old loader system - private class FixedPlayerDistanceChunkTracker extends ChunkTracker { - - protected final Long2ByteMap chunks = new Long2ByteOpenHashMap(); -@@ -858,4 +933,5 @@ public abstract class DistanceManager { - } - // Paper end - } -+ */ // Tuinity - replace old loader system - } -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 0d143d073fa7cdfa14f12e9c795350dca8ac5e80..8b84befc6840d25dc3d6e2d42a4024a3c979a097 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -47,6 +47,7 @@ import net.minecraft.world.level.storage.LevelStorageSource; - import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; // Paper - - public class ServerChunkCache extends ChunkSource { -+ public static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(); // Tuinity - - public static final List CHUNK_STATUSES = ChunkStatus.getStatusList(); - private final DistanceManager distanceManager; -@@ -138,7 +139,7 @@ public class ServerChunkCache extends ChunkSource { - return (LevelChunk)this.getChunk(x, z, ChunkStatus.FULL, true); - } - -- private long chunkFutureAwaitCounter; -+ long chunkFutureAwaitCounter; // Tuinity - private -> package private - - public void getEntityTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { - if (Thread.currentThread() != this.mainThread) { -@@ -200,9 +201,9 @@ public class ServerChunkCache extends ChunkSource { - - try { - if (onLoad != null) { -- chunkMap.callbackExecutor.execute(() -> { -+ // Tuinity - revert incorrect use of callback executor - onLoad.accept(either == null ? null : either.left().orElse(null)); // indicate failure to the callback. -- }); -+ // Tuinity - revert incorrect use of callback executor - } - } catch (Throwable thr) { - if (thr instanceof ThreadDeath) { -@@ -232,6 +233,166 @@ public class ServerChunkCache extends ChunkSource { - } - // Paper end - rewrite ticklistserver - -+ // Tuinity start -+ // this will try to avoid chunk neighbours for lighting -+ public final ChunkAccess getFullStatusChunkAt(int chunkX, int chunkZ) { -+ LevelChunk ifLoaded = this.getChunkAtIfLoadedImmediately(chunkX, chunkZ); -+ if (ifLoaded != null) { -+ return ifLoaded; -+ } -+ -+ ChunkAccess empty = this.getChunk(chunkX, chunkZ, ChunkStatus.EMPTY, true); -+ if (empty != null && empty.getStatus().isOrAfter(ChunkStatus.FULL)) { -+ return empty; -+ } -+ return this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); -+ } -+ -+ public final ChunkAccess getFullStatusChunkAtIfLoaded(int chunkX, int chunkZ) { -+ LevelChunk ifLoaded = this.getChunkAtIfLoadedImmediately(chunkX, chunkZ); -+ if (ifLoaded != null) { -+ return ifLoaded; -+ } -+ -+ ChunkAccess ret = this.getChunkAtImmediately(chunkX, chunkZ); -+ if (ret != null && ret.getStatus().isOrAfter(ChunkStatus.FULL)) { -+ return ret; -+ } else { -+ return null; -+ } -+ } -+ -+ void getChunkAtAsynchronously(int chunkX, int chunkZ, int ticketLevel, -+ java.util.function.Consumer consumer) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, ticketLevel, (ChunkHolder chunkHolder) -> { -+ if (ticketLevel <= 33) { -+ return (CompletableFuture)chunkHolder.getFullChunkFuture(); -+ } else { -+ return chunkHolder.getOrScheduleFuture(ChunkHolder.getStatus(ticketLevel), ServerChunkCache.this.chunkMap); -+ } -+ }, consumer); -+ } -+ -+ void getChunkAtAsynchronously(int chunkX, int chunkZ, int ticketLevel, -+ java.util.function.Function>> function, -+ java.util.function.Consumer consumer) { -+ if (Thread.currentThread() != this.mainThread) { -+ throw new IllegalStateException(); -+ } -+ -+ ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ Long identifier = Long.valueOf(this.chunkFutureAwaitCounter++); -+ this.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, identifier); -+ this.runDistanceManagerUpdates(); -+ -+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()); -+ -+ if (chunk == null) { -+ throw new IllegalStateException("Expected playerchunk " + chunkPos + " in world '" + this.level.getWorld().getName() + "'"); -+ } -+ -+ CompletableFuture> future = function.apply(chunk); -+ -+ future.whenCompleteAsync((either, throwable) -> { -+ try { -+ if (throwable != null) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ LOGGER.fatal("Failed to complete future await for chunk " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "'", throwable); -+ } else if (either.right().isPresent()) { -+ LOGGER.fatal("Failed to complete future await for chunk " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "': " + either.right().get().toString()); -+ } -+ -+ try { -+ if (consumer != null) { -+ consumer.accept(either == null ? null : either.left().orElse(null)); // indicate failure to the callback. -+ } -+ } catch (Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ LOGGER.fatal("Load callback for future await failed " + chunkPos.toString() + " in world '" + ServerChunkCache.this.level.getWorld().getName() + "'", thr); -+ return; -+ } -+ } finally { -+ // due to odd behaviour with CB unload implementation we need to have these AFTER the load callback. -+ ServerChunkCache.this.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); -+ ServerChunkCache.this.removeTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, identifier); -+ } -+ }, this.mainThreadProcessor); -+ } -+ -+ void chunkLoadAccept(int chunkX, int chunkZ, ChunkAccess chunk, java.util.function.Consumer consumer) { -+ try { -+ consumer.accept(chunk); -+ } catch (Throwable throwable) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ LOGGER.error("Load callback for chunk " + chunkX + "," + chunkZ + " in world '" + this.level.getWorld().getName() + "' threw an exception", throwable); -+ } -+ } -+ -+ public final void getChunkAtAsynchronously(int chunkX, int chunkZ, ChunkStatus status, boolean gen, boolean allowSubTicketLevel, java.util.function.Consumer onLoad) { -+ // try to fire sync -+ int chunkStatusTicketLevel = 33 + ChunkStatus.getDistance(status); -+ ChunkHolder playerChunk = this.chunkMap.getUpdatingChunkIfPresent(com.tuinity.tuinity.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ if (playerChunk != null) { -+ ChunkStatus holderStatus = playerChunk.getChunkHolderStatus(); -+ ChunkAccess immediate = playerChunk.getAvailableChunkNow(); -+ if (immediate != null) { -+ if (allowSubTicketLevel ? immediate.getStatus().isOrAfter(status) : (playerChunk.getTicketLevel() <= chunkStatusTicketLevel && holderStatus != null && holderStatus.isOrAfter(status))) { -+ this.chunkLoadAccept(chunkX, chunkZ, immediate, onLoad); -+ return; -+ } else { -+ if (gen || (!allowSubTicketLevel && immediate.getStatus().isOrAfter(status))) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } else { -+ this.chunkLoadAccept(chunkX, chunkZ, null, onLoad); -+ return; -+ } -+ } -+ } -+ } -+ -+ // need to fire async -+ -+ if (gen && !allowSubTicketLevel) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } -+ -+ this.getChunkAtAsynchronously(chunkX, chunkZ, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.EMPTY), (ChunkAccess chunk) -> { -+ if (chunk == null) { -+ throw new IllegalStateException("Chunk cannot be null"); -+ } -+ -+ if (!chunk.getStatus().isOrAfter(status)) { -+ if (gen) { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } else { -+ ServerChunkCache.this.chunkLoadAccept(chunkX, chunkZ, null, onLoad); -+ return; -+ } -+ } else { -+ if (allowSubTicketLevel) { -+ ServerChunkCache.this.chunkLoadAccept(chunkX, chunkZ, chunk, onLoad); -+ return; -+ } else { -+ this.getChunkAtAsynchronously(chunkX, chunkZ, chunkStatusTicketLevel, onLoad); -+ return; -+ } -+ } -+ }); -+ } -+ -+ final com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet tickingChunks = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); -+ final com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet entityTickingChunks = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); -+ // Tuinity end -+ - public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, boolean flag, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkstatusupdatelistener, Supplier supplier) { - this.level = world; - this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(world); -@@ -575,6 +736,8 @@ public class ServerChunkCache extends ChunkSource { - return completablefuture; - } - -+ private long syncLoadCounter; // Tuinity - prevent plugin unloads from removing our ticket -+ - private CompletableFuture> getChunkFutureMainThread(int i, int j, ChunkStatus chunkstatus, boolean flag) { - // Paper start - add isUrgent - old sig left in place for dirty nms plugins - return getChunkFutureMainThread(i, j, chunkstatus, flag, false); -@@ -593,9 +756,12 @@ public class ServerChunkCache extends ChunkSource { - ChunkHolder.FullChunkStatus currentChunkState = ChunkHolder.getFullChunkStatus(playerchunk.getTicketLevel()); - currentlyUnloading = (oldChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !currentChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)); - } -+ final Long identifier; // Tuinity - prevent plugin unloads from removing our ticket - if (flag && !currentlyUnloading) { - // CraftBukkit end - this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); -+ identifier = Long.valueOf(this.syncLoadCounter++); // Tuinity - prevent plugin unloads from removing our ticket -+ this.distanceManager.addTicketAtLevel(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Tuinity - prevent plugin unloads from removing our ticket - if (isUrgent) this.distanceManager.markUrgent(chunkcoordintpair); // Paper - Chunk priority - if (this.chunkAbsent(playerchunk, l)) { - ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -@@ -606,12 +772,20 @@ public class ServerChunkCache extends ChunkSource { - playerchunk = this.getVisibleChunkIfPresent(k); - gameprofilerfiller.pop(); - if (this.chunkAbsent(playerchunk, l)) { -+ this.distanceManager.removeTicketAtLevel(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Tuinity - throw (IllegalStateException) Util.pauseInIde((Throwable) (new IllegalStateException("No chunk holder after ticket has been added"))); - } - } -- } -+ } else { identifier = null; } // Tuinity - prevent plugin unloads from removing our ticket - // Paper start - Chunk priority - CompletableFuture> future = this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(chunkstatus, this.chunkMap); -+ // Tuinity start - prevent plugin unloads from removing our ticket -+ if (flag && !currentlyUnloading) { -+ future.thenAcceptAsync((either) -> { -+ ServerChunkCache.this.distanceManager.removeTicketAtLevel(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); -+ }, ServerChunkCache.this.mainThreadProcessor); -+ } -+ // Tuinity end - prevent plugin unloads from removing our ticket - if (isUrgent) { - future.thenAccept(either -> this.distanceManager.clearUrgent(chunkcoordintpair)); - } -@@ -669,6 +843,8 @@ public class ServerChunkCache extends ChunkSource { - - public boolean runDistanceManagerUpdates() { - if (distanceManager.delayDistanceManagerTick) return false; // Paper - Chunk priority -+ if (this.chunkMap.unloadingPlayerChunk) { LOGGER.fatal("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Tuinity -+ co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Tuinity - add timings for distance manager - boolean flag = this.distanceManager.runAllUpdates(this.chunkMap); - boolean flag1 = this.chunkMap.promoteChunkMap(); - -@@ -678,6 +854,7 @@ public class ServerChunkCache extends ChunkSource { - this.clearCache(); - return true; - } -+ } finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Tuinity - add timings for distance manager - } - - // Paper start - helper -@@ -735,6 +912,7 @@ public class ServerChunkCache extends ChunkSource { - - // CraftBukkit start - modelled on below - public void purgeUnload() { -+ if (true) return; // Tuinity - tickets will be removed later, this behavior isn't really well accounted for by the chunk system - this.level.getProfiler().push("purge"); - this.distanceManager.purgeStaleTickets(); - this.runDistanceManagerUpdates(); -@@ -750,17 +928,18 @@ public class ServerChunkCache extends ChunkSource { - this.level.getProfiler().push("purge"); - this.level.timings.doChunkMap.startTiming(); // Spigot - this.distanceManager.purgeStaleTickets(); -- this.level.getServer().midTickLoadChunks(); // Paper -+ // Tuinity - replace logic - this.runDistanceManagerUpdates(); - this.level.timings.doChunkMap.stopTiming(); // Spigot - this.level.getProfiler().popPush("chunks"); - this.level.timings.chunks.startTiming(); // Paper - timings -+ this.chunkMap.playerChunkManager.tick(); // Tuinity - this is mostly is to account for view distance changes - this.tickChunks(); - this.level.timings.chunks.stopTiming(); // Paper - timings - this.level.timings.doChunkUnload.startTiming(); // Spigot - this.level.getProfiler().popPush("unload"); - this.chunkMap.tick(booleansupplier); -- this.level.getServer().midTickLoadChunks(); // Paper -+ // Tuinity - replace logic - this.level.timings.doChunkUnload.stopTiming(); // Spigot - this.level.getProfiler().pop(); - this.clearCache(); -@@ -834,24 +1013,31 @@ public class ServerChunkCache extends ChunkSource { - - this.lastSpawnState = spawnercreature_d; - this.level.getProfiler().pop(); -- List list = Lists.newArrayList(this.chunkMap.visibleChunkMap.values()); // Paper -+ //List list = Lists.newArrayList(this.chunkMap.visibleChunkMap.values()); // Paper - -- Collections.shuffle(list); -+ //Collections.shuffle(list); - // Paper - moved natural spawn event up - this.level.timings.chunkTicks.startTiming(); // Paper -- final int[] chunksTicked = {0}; // Paper -- list.forEach((playerchunk) -> { -- Optional optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); -- -- if (optional.isPresent()) { -- LevelChunk chunk = (LevelChunk) optional.get(); -+ // Tuinity start -+ int chunksTicked = 0; -+ com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.Iterator iterator = this.entityTickingChunks.iterator(); -+ try { while (iterator.hasNext()) { -+ LevelChunk chunk = iterator.next(); -+ ChunkHolder playerchunk = chunk.playerChunk; -+ if (playerchunk != null) { -+ this.level.getProfiler().push("broadcast"); -+ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timings -+ playerchunk.broadcastChanges(chunk); -+ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timings -+ this.level.getProfiler().pop(); -+ // Tuinity end - ChunkPos chunkcoordintpair = chunk.getPos(); - -- if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange -+ if ((true || this.level.isPositionEntityTicking(chunkcoordintpair)) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange // Tuinity - we only iterate entity ticking chunks - chunk.setInhabitedTime(chunk.getInhabitedTime() + j); - if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, true)) { // Spigot // Paper - optimise isOutsideOfRange - NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2); -- if (chunksTicked[0]++ % 10 == 0) this.level.getServer().midTickLoadChunks(); // Paper -+ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper // Tuinity - } - - // this.level.timings.doTickTiles.startTiming(); // Spigot // Paper -@@ -859,7 +1045,11 @@ public class ServerChunkCache extends ChunkSource { - // this.level.timings.doTickTiles.stopTiming(); // Spigot // Paper - } - } -- }); -+ } // Tuinity start - optimise chunk tick iteration -+ } finally { -+ iterator.finishedIterating(); -+ } -+ // Tuinity end - optimise chunk tick iteration - this.level.timings.chunkTicks.stopTiming(); // Paper - this.level.getProfiler().push("customSpawners"); - if (flag1) { -@@ -868,25 +1058,28 @@ public class ServerChunkCache extends ChunkSource { - } // Paper - timings - } - -- this.level.getProfiler().popPush("broadcast"); -- this.chunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping -- Optional optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); // CraftBukkit - decompile error -- -- Objects.requireNonNull(playerchunk); -- -- // Paper start - timings -- optional.ifPresent(chunk -> { -- this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timings -- playerchunk.broadcastChanges(chunk); -- this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timings -- }); -- // Paper end -- }); -- this.level.getProfiler().pop(); -+ // Tuinity - no, iterating just ONCE is expensive enough! Don't do it TWICE! Code moved up - this.level.getProfiler().pop(); - } - -+ // Tuinity start - controlled flush for entity tracker packets -+ List disabledFlushes = new java.util.ArrayList<>(this.level.players.size()); -+ for (ServerPlayer player : this.level.players) { -+ net.minecraft.server.network.ServerGamePacketListenerImpl connection = player.connection; -+ if (connection != null) { -+ connection.connection.disableAutomaticFlush(); -+ disabledFlushes.add(connection.connection); -+ } -+ } -+ try { // Tuinity end - controlled flush for entity tracker packets - this.chunkMap.tick(); -+ // Tuinity start - controlled flush for entity tracker packets -+ } finally { -+ for (net.minecraft.network.Connection networkManager : disabledFlushes) { -+ networkManager.enableAutomaticFlush(); -+ } -+ } -+ // Tuinity end - controlled flush for entity tracker packets - } - - private void getFullChunk(long pos, Consumer chunkConsumer) { -@@ -1033,46 +1226,14 @@ public class ServerChunkCache extends ChunkSource { - super.doRunTask(task); - } - -- // Paper start -- private long lastMidTickChunkTask = 0; -- public boolean pollChunkLoadTasks() { -- if (com.destroystokyo.paper.io.chunk.ChunkTaskManager.pollChunkWaitQueue() || ServerChunkCache.this.level.asyncChunkTaskManager.pollNextChunkTask()) { -- try { -- ServerChunkCache.this.runDistanceManagerUpdates(); -- } finally { -- // from below: process pending Chunk loadCallback() and unloadCallback() after each run task -- chunkMap.callbackExecutor.run(); -- } -- return true; -- } -- return false; -- } -- public void midTickLoadChunks() { -- net.minecraft.server.MinecraftServer server = ServerChunkCache.this.level.getServer(); -- // always try to load chunks, restrain generation/other updates only. don't count these towards tick count -- //noinspection StatementWithEmptyBody -- while (pollChunkLoadTasks()) {} -- -- if (System.nanoTime() - lastMidTickChunkTask < 200000) { -- return; -- } -- -- for (;server.midTickChunksTasksRan < com.destroystokyo.paper.PaperConfig.midTickChunkTasks && server.haveTime();) { -- if (this.pollTask()) { -- server.midTickChunksTasksRan++; -- lastMidTickChunkTask = System.nanoTime(); -- } else { -- break; -- } -- } -- } -- // Paper end -+ // Tuinity - replace logic - - @Override - // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task - public boolean pollTask() { - try { - boolean execChunkTask = com.destroystokyo.paper.io.chunk.ChunkTaskManager.pollChunkWaitQueue() || ServerChunkCache.this.level.asyncChunkTaskManager.pollNextChunkTask(); // Paper -+ ServerChunkCache.this.chunkMap.playerChunkManager.tickMidTick(); // Tuinity - if (ServerChunkCache.this.runDistanceManagerUpdates()) { - return true; - } else { -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index fe62ec1a888a93d90f40d86908f83faaed907ba6..d73aa6032bf56448f518cff9f019b3f7a1c5eddb 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -173,7 +173,7 @@ public class ServerEntity { - // Paper end - remove allocation of Vec3D here - boolean flag4 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; - -- if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround()) { -+ if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(com.tuinity.tuinity.config.TuinityConfig.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Tuinity - send full pos for hard colliding entities to prevent collision problems due to desync - if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { - if (flag2) { - packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.isOnGround()); -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index baa25df9f446c8edea9666983425df31c32a13ff..f9ed48f5bbde84fd1804e482f2777b516cc3a1ef 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -114,6 +114,7 @@ import net.minecraft.world.level.block.Block; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.entity.TickingBlockEntity; - import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.chunk.ChunkAccess; - import net.minecraft.world.level.chunk.ChunkGenerator; - import net.minecraft.world.level.chunk.LevelChunk; - import net.minecraft.world.level.chunk.LevelChunkSection; -@@ -161,6 +162,7 @@ import org.bukkit.event.server.MapInitializeEvent; - import org.bukkit.event.weather.LightningStrikeEvent; - import org.bukkit.event.world.TimeSkipEvent; - // CraftBukkit end -+import it.unimi.dsi.fastutil.ints.IntArrayList; // Tuinity - - public class ServerLevel extends Level implements WorldGenLevel { - -@@ -189,7 +191,9 @@ public class ServerLevel extends Level implements WorldGenLevel { - final Int2ObjectMap dragonParts; - private final StructureFeatureManager structureFeatureManager; - private final boolean tickTime; -- -+ // Tuinity start - execute chunk tasks mid tick -+ public long lastMidTickExecuteFailure; -+ // Tuinity end - execute chunk tasks mid tick - - // CraftBukkit start - private int tickPosition; -@@ -300,6 +304,172 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - } - // Paper end - rewrite ticklistserver -+ // Tuinity start -+ public final boolean areChunksLoadedForMove(AABB axisalignedbb) { -+ // copied code from collision methods, so that we can guarantee that they wont load chunks (we don't override -+ // ICollisionAccess methods for VoxelShapes) -+ // be more strict too, add a block (dumb plugins in move events?) -+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3; -+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3; -+ -+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3; -+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3; -+ -+ int minChunkX = minBlockX >> 4; -+ int maxChunkX = maxBlockX >> 4; -+ -+ int minChunkZ = minBlockZ >> 4; -+ int maxChunkZ = maxBlockZ >> 4; -+ -+ ServerChunkCache chunkProvider = this.getChunkSource(); -+ -+ for (int cx = minChunkX; cx <= maxChunkX; ++cx) { -+ for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { -+ if (chunkProvider.getChunkAtIfLoadedImmediately(cx, cz) == null) { -+ return false; -+ } -+ } -+ } -+ -+ return true; -+ } -+ -+ public final void loadChunksForMoveAsync(AABB axisalignedbb, double toX, double toZ, -+ java.util.function.Consumer> onLoad) { -+ if (Thread.currentThread() != this.thread) { -+ this.getChunkSource().mainThreadProcessor.execute(() -> { -+ this.loadChunksForMoveAsync(axisalignedbb, toX, toZ, onLoad); -+ }); -+ return; -+ } -+ List ret = new java.util.ArrayList<>(); -+ IntArrayList ticketLevels = new IntArrayList(); -+ -+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3; -+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3; -+ -+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3; -+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3; -+ -+ int minChunkX = minBlockX >> 4; -+ int maxChunkX = maxBlockX >> 4; -+ -+ int minChunkZ = minBlockZ >> 4; -+ int maxChunkZ = maxBlockZ >> 4; -+ -+ ServerChunkCache chunkProvider = this.getChunkSource(); -+ -+ int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1); -+ int[] loadedChunks = new int[1]; -+ -+ Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter++); -+ -+ java.util.function.Consumer consumer = (ChunkAccess chunk) -> { -+ if (chunk != null) { -+ int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().toLong()).getTicketLevel()); -+ ret.add(chunk); -+ ticketLevels.add(ticketLevel); -+ chunkProvider.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunk.getPos(), ticketLevel, holderIdentifier); -+ } -+ if (++loadedChunks[0] == requiredChunks) { -+ try { -+ onLoad.accept(java.util.Collections.unmodifiableList(ret)); -+ } finally { -+ for (int i = 0, len = ret.size(); i < len; ++i) { -+ ChunkPos chunkPos = ret.get(i).getPos(); -+ int ticketLevel = ticketLevels.getInt(i); -+ -+ chunkProvider.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); -+ chunkProvider.removeTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, holderIdentifier); -+ } -+ } -+ } -+ }; -+ -+ for (int cx = minChunkX; cx <= maxChunkX; ++cx) { -+ for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { -+ chunkProvider.getChunkAtAsynchronously(cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, false, consumer); -+ } -+ } -+ } -+ // Tuinity end -+ // Tuinity start - optimise checkDespawn -+ public final List playersAffectingSpawning = new java.util.ArrayList<>(); -+ // Tuinity end - optimise checkDespawn -+ // Tuinity start - optimise get nearest players for entity AI -+ @Override -+ public final ServerPlayer getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, @Nullable LivingEntity source, -+ double centerX, double centerY, double centerZ) { -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby; -+ nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4); -+ -+ if (nearby == null) { -+ return null; -+ } -+ -+ Object[] backingSet = nearby.getBackingSet(); -+ -+ double closestDistanceSquared = Double.MAX_VALUE; -+ ServerPlayer closest = null; -+ -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object _player = backingSet[i]; -+ if (!(_player instanceof ServerPlayer)) { -+ continue; -+ } -+ ServerPlayer player = (ServerPlayer)_player; -+ -+ double distanceSquared = player.distanceToSqr(centerX, centerY, centerZ); -+ if (distanceSquared < closestDistanceSquared && condition.test(source, player)) { -+ closest = player; -+ closestDistanceSquared = distanceSquared; -+ } -+ } -+ -+ return closest; -+ } -+ -+ @Override -+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition, LivingEntity entityliving) { -+ return this.getNearestPlayer(pathfindertargetcondition, entityliving, entityliving.getX(), entityliving.getY(), entityliving.getZ()); -+ } -+ -+ @Override -+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition, -+ double d0, double d1, double d2) { -+ return this.getNearestPlayer(pathfindertargetcondition, null, d0, d1, d2); -+ } -+ -+ @Override -+ public List getNearbyPlayers(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, LivingEntity source, AABB axisalignedbb) { -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby; -+ double centerX = (axisalignedbb.maxX + axisalignedbb.minX) * 0.5; -+ double centerZ = (axisalignedbb.maxZ + axisalignedbb.minZ) * 0.5; -+ nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4); -+ -+ List ret = new java.util.ArrayList<>(); -+ -+ if (nearby == null) { -+ return ret; -+ } -+ -+ Object[] backingSet = nearby.getBackingSet(); -+ -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object _player = backingSet[i]; -+ if (!(_player instanceof ServerPlayer)) { -+ continue; -+ } -+ ServerPlayer player = (ServerPlayer)_player; -+ -+ if (axisalignedbb.contains(player.getX(), player.getY(), player.getZ()) && condition.test(source, player)) { -+ ret.add(player); -+ } -+ } -+ -+ return ret; -+ } -+ // Tuinity end - optimise get nearest players for entity AI - - // Add env and gen to constructor, WorldData -> WorldDataServer - public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, ServerLevelData iworlddataserver, ResourceKey resourcekey, DimensionType dimensionmanager, ChunkProgressListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { -@@ -347,7 +517,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - DataFixer datafixer = minecraftserver.getFixerUpper(); - EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, new File(convertable_conversionsession.getDimensionPath(resourcekey), "entities"), datafixer, flag2, minecraftserver); - -- this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage); -+ this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Tuinity - StructureManager definedstructuremanager = minecraftserver.getStructureManager(); - int j = this.spigotConfig.viewDistance; // Spigot - PersistentEntitySectionManager persistententitysectionmanager = this.entityManager; -@@ -400,6 +570,14 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - public void tick(BooleanSupplier shouldKeepTicking) { -+ // Tuinity start - optimise checkDespawn -+ this.playersAffectingSpawning.clear(); -+ for (ServerPlayer player : this.players) { -+ if (net.minecraft.world.entity.EntitySelector.affectsSpawning.test(player)) { -+ this.playersAffectingSpawning.add(player); -+ } -+ } -+ // Tuinity end - optimise checkDespawn - ProfilerFiller gameprofilerfiller = this.getProfiler(); - - this.handlingTick = true; -@@ -545,7 +723,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - timings.scheduledBlocks.stopTiming(); // Paper - -- this.getServer().midTickLoadChunks(); // Paper -+ // Tuinity - replace logic - gameprofilerfiller.popPush("raid"); - this.timings.raids.startTiming(); // Paper - timings - this.raids.tick(); -@@ -558,7 +736,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - timings.doSounds.startTiming(); // Spigot - this.runBlockEvents(); - timings.doSounds.stopTiming(); // Spigot -- this.getServer().midTickLoadChunks(); // Paper -+ // Tuinity - replace logic - this.handlingTick = false; - gameprofilerfiller.pop(); - boolean flag3 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players -@@ -605,12 +783,12 @@ public class ServerLevel extends Level implements WorldGenLevel { - timings.entityTick.stopTiming(); // Spigot - timings.tickEntities.stopTiming(); // Spigot - gameprofilerfiller.pop(); -- this.getServer().midTickLoadChunks(); // Paper -+ // Tuinity - replace logic - this.tickBlockEntities(); - } - - gameprofilerfiller.push("entityManagement"); -- this.getServer().midTickLoadChunks(); // Paper -+ // Tuinity - replace logic - this.entityManager.tick(); - gameprofilerfiller.pop(); - } -@@ -655,6 +833,10 @@ public class ServerLevel extends Level implements WorldGenLevel { - entityplayer.stopSleepInBed(false, false); - }); - } -+ // Paper start - optimise random block ticking -+ private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); -+ private final com.tuinity.tuinity.util.math.ThreadUnsafeRandom randomTickRandom = new com.tuinity.tuinity.util.math.ThreadUnsafeRandom(); -+ // Paper end - - public void tickChunk(LevelChunk chunk, int randomTickSpeed) { - ChunkPos chunkcoordintpair = chunk.getPos(); -@@ -664,10 +846,10 @@ public class ServerLevel extends Level implements WorldGenLevel { - ProfilerFiller gameprofilerfiller = this.getProfiler(); - - gameprofilerfiller.push("thunder"); -- BlockPos blockposition; -+ final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change - - if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder -- blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); -+ blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper - if (this.isRainingAt(blockposition)) { - DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); - boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper -@@ -690,64 +872,78 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - gameprofilerfiller.popPush("iceandsnow"); -- if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow -- blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15)); -- BlockPos blockposition1 = blockposition.below(); -+ if (!this.paperConfig.disableIceAndSnow && this.randomTickRandom.nextInt(16) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking -+ // Paper start - optimise chunk ticking -+ this.getRandomBlockPosition(j, 0, k, 15, blockposition); -+ int normalY = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15) + 1; -+ int downY = normalY - 1; -+ blockposition.setY(normalY); -+ // Paper end - Biome biomebase = this.getBiome(blockposition); - -- if (biomebase.shouldFreeze((LevelReader) this, blockposition1)) { -- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.defaultBlockState(), null); // CraftBukkit -+ // Paper start - optimise chunk ticking -+ blockposition.setY(downY); -+ if (biomebase.shouldFreeze(this, blockposition)) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.ICE.defaultBlockState(), null); // CraftBukkit -+ // Paper end - } - - if (flag) { -+ blockposition.setY(normalY); // Paper - if (biomebase.shouldSnow(this, blockposition)) { - org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit - } - -- BlockState iblockdata = this.getBlockState(blockposition1); -+ blockposition.setY(downY); // Paper -+ BlockState iblockdata = this.getBlockState(blockposition); // Paper -+ blockposition.setY(normalY); // Paper - Biome.Precipitation biomebase_precipitation = this.getBiome(blockposition).getPrecipitation(); - -- if (biomebase_precipitation == Biome.Precipitation.RAIN && biomebase.isColdEnoughToSnow(blockposition1)) { -+ blockposition.setY(downY); // Paper -+ if (biomebase_precipitation == Biome.Precipitation.RAIN && biomebase.isColdEnoughToSnow(blockposition)) { // Paper - biomebase_precipitation = Biome.Precipitation.SNOW; - } - -- iblockdata.getBlock().handlePrecipitation(iblockdata, (Level) this, blockposition1, biomebase_precipitation); -+ iblockdata.getBlock().handlePrecipitation(iblockdata, (Level) this, blockposition, biomebase_precipitation); // Paper - } - } - -- gameprofilerfiller.popPush("tickBlocks"); -+ // Paper start - optimise random block ticking -+ gameprofilerfiller.popPush("randomTick"); - timings.chunkTicksBlocks.startTiming(); // Paper - if (randomTickSpeed > 0) { -- LevelChunkSection[] achunksection = chunk.getSections(); -- int l = achunksection.length; -- -- for (int i1 = 0; i1 < l; ++i1) { -- LevelChunkSection chunksection = achunksection[i1]; -- -- if (chunksection != LevelChunk.EMPTY_SECTION && chunksection.isRandomlyTicking()) { -- int j1 = chunksection.bottomBlockY(); -- -- for (int k1 = 0; k1 < randomTickSpeed; ++k1) { -- BlockPos blockposition2 = this.getBlockRandomPos(j, j1, k, 15); -- -- gameprofilerfiller.push("randomTick"); -- BlockState iblockdata1 = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); -+ LevelChunkSection[] sections = chunk.getSections(); -+ int minSection = com.tuinity.tuinity.util.WorldUtil.getMinSection(this); -+ for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { -+ LevelChunkSection section = sections[sectionIndex]; -+ if (section == null || section.tickingList.size() == 0) { -+ continue; -+ } - -- if (iblockdata1.isRandomlyTicking()) { -- iblockdata1.randomTick(this, blockposition2, this.random); -- } -+ int yPos = (sectionIndex + minSection) << 4; -+ for (int a = 0; a < randomTickSpeed; ++a) { -+ int tickingBlocks = section.tickingList.size(); -+ int index = this.randomTickRandom.nextInt(16 * 16 * 16); -+ if (index >= tickingBlocks) { -+ continue; -+ } - -- FluidState fluid = iblockdata1.getFluidState(); -+ long raw = section.tickingList.getRaw(index); -+ int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); -+ int randomX = location & 15; -+ int randomY = ((location >>> (4 + 4)) & 255) | yPos; -+ int randomZ = (location >>> 4) & 15; - -- if (fluid.isRandomlyTicking()) { -- fluid.randomTick(this, blockposition2, this.random); -- } -+ BlockPos blockposition2 = blockposition.set(j + randomX, randomY, k + randomZ); -+ BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - -- gameprofilerfiller.pop(); -- } -+ iblockdata.randomTick(this, blockposition2, this.randomTickRandom); -+ // We drop the fluid tick since LAVA is ALREADY TICKED by the above method (See LiquidBlock). -+ // TODO CHECK ON UPDATE - } - } - } -+ // Paper end - optimise random block ticking - timings.chunkTicksBlocks.stopTiming(); // Paper - gameprofilerfiller.pop(); - } -@@ -873,7 +1069,27 @@ public class ServerLevel extends Level implements WorldGenLevel { - - } - -+ // Tuinity start - log detailed entity tick information -+ // TODO replace with varhandle -+ static final java.util.concurrent.atomic.AtomicReference currentlyTickingEntity = new java.util.concurrent.atomic.AtomicReference<>(); -+ -+ public static List getCurrentlyTickingEntities() { -+ Entity ticking = currentlyTickingEntity.get(); -+ List ret = java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking }); -+ -+ return ret; -+ } -+ // Tuinity end - log detailed entity tick information -+ - public void tickNonPassenger(Entity entity) { -+ // Tuinity start - log detailed entity tick information -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); -+ this.entityManager.updateNavigatorsInRegion(entity); // Tuinity - optimise notify -+ try { -+ if (currentlyTickingEntity.get() == null) { -+ currentlyTickingEntity.lazySet(entity); -+ } -+ // Tuinity end - log detailed entity tick information - ++TimingHistory.entityTicks; // Paper - timings - // Spigot start - co.aikar.timings.Timing timer; // Paper -@@ -914,7 +1130,13 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - // } finally { timer.stopTiming(); } // Paper - timings - move up -- -+ // Tuinity start - log detailed entity tick information -+ } finally { -+ if (currentlyTickingEntity.get() == entity) { -+ currentlyTickingEntity.lazySet(null); -+ } -+ } -+ // Tuinity end - log detailed entity tick information - } - - private void tickPassenger(Entity vehicle, Entity passenger) { -@@ -1206,9 +1428,13 @@ public class ServerLevel extends Level implements WorldGenLevel { - // Spigot Start - for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) { - if (tileentity instanceof net.minecraft.world.Container) { -+ // Tuinity start - this area looks like it can load chunks, change the behavior -+ // chests for example can apply physics to the world -+ // so instead we just change the active container and call the event - for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) { -- h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper -+ ((org.bukkit.craftbukkit.entity.CraftHumanEntity)h).getHandle().closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - } -+ // Tuiniy end - } - } - // Spigot End -@@ -1305,9 +1531,19 @@ public class ServerLevel extends Level implements WorldGenLevel { - VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); - - if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) { -- Iterator iterator = this.navigatingMobs.iterator(); -+ // Tuinity start - optimise notify() -+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.Region region = this.getChunkSource().chunkMap.dataRegionManager.getRegion(pos.getX() >> 4, pos.getZ() >> 4); -+ if (region == null) { -+ return; -+ } -+ com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet navigatorsFromRegion = ((ChunkMap.DataRegionData)region.regionData).getNavigators(); -+ if (navigatorsFromRegion == null) { -+ return; -+ } -+ com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.Iterator iterator = navigatorsFromRegion.iterator(); - -- while (iterator.hasNext()) { -+ -+ try { while (iterator.hasNext()) { // Tuinity end - optimise notify() - // CraftBukkit start - fix SPIGOT-6362 - Mob entityinsentient; - try { -@@ -1326,6 +1562,11 @@ public class ServerLevel extends Level implements WorldGenLevel { - navigationabstract.recomputePath(pos); - } - } -+ // Tuinity start - optimise notify() -+ } finally { -+ iterator.finishedIterating(); -+ } -+ // Tuinity end - optimise notify() - - } - } // Paper -@@ -2107,10 +2348,12 @@ public class ServerLevel extends Level implements WorldGenLevel { - - public void onTickingStart(Entity entity) { - ServerLevel.this.entityTickList.add(entity); -+ ServerLevel.this.entityManager.addNavigatorsIfPathingToRegion(entity); // Tuinity - optimise notify - } - - public void onTickingEnd(Entity entity) { - ServerLevel.this.entityTickList.remove(entity); -+ ServerLevel.this.entityManager.removeNavigatorsFromData(entity); // Tuinity - optimise notify - } - - public void onTrackingStart(Entity entity) { -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index bc05cc34f6cd526a1d13261f1ac779d5397cbbac..53ef5ecc750f9d0e2634267a33042f24c969f305 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -261,7 +261,7 @@ public class ServerPlayer extends Player { - - public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks - public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper -- boolean needsChunkCenterUpdate; // Paper - no-tick view distance -+ public boolean needsChunkCenterUpdate; // Paper - no-tick view distance // Tuinity - public - public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event - - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) { -@@ -419,7 +419,7 @@ public class ServerPlayer extends Player { - - if (blockposition1 != null) { - this.moveTo(blockposition1, 0.0F, 0.0F); -- if (world.noCollision(this)) { -+ if (world.noCollision(this, this.getBoundingBox(), null, true)) { // Tuinity - make sure this loads chunks, we default to NOT loading now - break; - } - } -@@ -427,7 +427,7 @@ public class ServerPlayer extends Player { - } else { - this.moveTo(blockposition, 0.0F, 0.0F); - -- while (!world.noCollision(this) && this.getY() < (double) (world.getMaxBuildHeight() - 1)) { -+ while (!world.noCollision(this, this.getBoundingBox(), null, true) && this.getY() < (double) (world.getMaxBuildHeight() - 1)) { // Tuinity - make sure this loads chunks, we default to NOT loading now - this.setPos(this.getX(), this.getY() + 1.0D, this.getZ()); - } - } -@@ -1564,6 +1564,18 @@ public class ServerPlayer extends Player { - this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); - this.doCloseContainer(); - } -+ // Tuinity start - special close for unloaded inventory -+ @Override -+ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { -+ // copied from above -+ CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit -+ // Paper end -+ // copied from below -+ this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); -+ this.containerMenu = this.inventoryMenu; -+ // do not run close logic -+ } -+ // Tuinity end - special close for unloaded inventory - - public void doCloseContainer() { - this.containerMenu.removed((Player) this); -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 1c83fbc96a074c85a3e349e936ff1f3198596709..e97e3b4de132a452d560c19a1dcecd28f8010c62 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -56,14 +56,28 @@ public class ServerPlayerGameMode { - @Nullable - private GameType previousGameModeForPlayer; - private boolean isDestroyingBlock; -- private int destroyProgressStart; -+ private int destroyProgressStart; private long lastDigTime; // Tuinity - lag compensate block breaking - private BlockPos destroyPos; - private int gameTicks; - private boolean hasDelayedDestroy; - private BlockPos delayedDestroyPos; -- private int delayedTickStart; -+ private int delayedTickStart; private long hasDestroyedTooFastStartTime; // Tuinity - lag compensate block breaking - private int lastSentState; - -+ // Tuinity start - lag compensate block breaking -+ private int getTimeDiggingLagCompensate() { -+ int lagCompensated = (int)((System.nanoTime() - this.lastDigTime) / (50L * 1000L * 1000L)); -+ int tickDiff = this.gameTicks - this.destroyProgressStart; -+ return (com.tuinity.tuinity.config.TuinityConfig.lagCompensateBlockBreaking && lagCompensated > (tickDiff + 1)) ? lagCompensated : tickDiff; // add one to ensure we don't lag compensate unless we need to -+ } -+ -+ private int getTimeDiggingTooFastLagCompensate() { -+ int lagCompensated = (int)((System.nanoTime() - this.hasDestroyedTooFastStartTime) / (50L * 1000L * 1000L)); -+ int tickDiff = this.gameTicks - this.delayedTickStart; -+ return (com.tuinity.tuinity.config.TuinityConfig.lagCompensateBlockBreaking && lagCompensated > (tickDiff + 1)) ? lagCompensated : tickDiff; // add one to ensure we don't lag compensate unless we need to -+ } -+ // Tuinity end -+ - public ServerPlayerGameMode(ServerPlayer player) { - this.gameModeForPlayer = GameType.DEFAULT_MODE; - this.destroyPos = BlockPos.ZERO; -@@ -130,7 +144,7 @@ public class ServerPlayerGameMode { - if (iblockdata == null || iblockdata.isAir()) { // Paper - this.hasDelayedDestroy = false; - } else { -- float f = this.incrementDestroyProgress(iblockdata, this.delayedDestroyPos, this.delayedTickStart); -+ float f = this.updateBlockBreakAnimation(iblockdata, this.delayedDestroyPos, this.getTimeDiggingTooFastLagCompensate()); // Tuinity - lag compensate destroying blocks - - if (f >= 1.0F) { - this.hasDelayedDestroy = false; -@@ -150,7 +164,7 @@ public class ServerPlayerGameMode { - this.lastSentState = -1; - this.isDestroyingBlock = false; - } else { -- this.incrementDestroyProgress(iblockdata, this.destroyPos, this.destroyProgressStart); -+ this.updateBlockBreakAnimation(iblockdata, this.destroyPos, this.getTimeDiggingLagCompensate()); // Tuinity - lag compensate destroying - } - } - -@@ -158,6 +172,12 @@ public class ServerPlayerGameMode { - - private float incrementDestroyProgress(BlockState state, BlockPos pos, int i) { - int j = this.gameTicks - i; -+ // Tuinity start - change i (startTime) to totalTime -+ return this.updateBlockBreakAnimation(state, pos, j); -+ } -+ private float updateBlockBreakAnimation(BlockState state, BlockPos pos, int totalTime) { -+ int j = totalTime; -+ // Tuinity end - float f = state.getDestroyProgress(this.player, this.player.level, pos) * (float) (j + 1); - int k = (int) (f * 10.0F); - -@@ -226,7 +246,7 @@ public class ServerPlayerGameMode { - return; - } - -- this.destroyProgressStart = this.gameTicks; -+ this.destroyProgressStart = this.gameTicks; this.lastDigTime = System.nanoTime(); // Tuinity - lag compensate block breaking - float f = 1.0F; - - iblockdata = this.level.getBlockState(pos); -@@ -279,12 +299,12 @@ public class ServerPlayerGameMode { - int j = (int) (f * 10.0F); - - this.level.destroyBlockProgress(this.player.getId(), pos, j); -- this.player.connection.send(new ClientboundBlockBreakAckPacket(pos, this.level.getBlockState(pos), action, true, "actual start of destroying")); -+ if (!com.tuinity.tuinity.config.TuinityConfig.lagCompensateBlockBreaking) this.player.connection.send(new ClientboundBlockBreakAckPacket(pos, this.level.getBlockState(pos), action, true, "actual start of destroying")); - this.lastSentState = j; - } - } else if (action == ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK) { - if (pos.equals(this.destroyPos)) { -- int k = this.gameTicks - this.destroyProgressStart; -+ int k = this.getTimeDiggingLagCompensate(); // Tuinity - lag compensate block breaking - - iblockdata = this.level.getBlockState(pos); - if (!iblockdata.isAir()) { -@@ -301,12 +321,18 @@ public class ServerPlayerGameMode { - this.isDestroyingBlock = false; - this.hasDelayedDestroy = true; - this.delayedDestroyPos = pos; -- this.delayedTickStart = this.destroyProgressStart; -+ this.delayedTickStart = this.destroyProgressStart; this.hasDestroyedTooFastStartTime = this.lastDigTime; // Tuinity - lag compensate block breaking - } - } - } - -+ // Tuinity start - this can cause clients on a lagging server to think they're not currently destroying a block -+ if (com.tuinity.tuinity.config.TuinityConfig.lagCompensateBlockBreaking) { -+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ } else { - this.player.connection.send(new ClientboundBlockBreakAckPacket(pos, this.level.getBlockState(pos), action, true, "stopped destroying")); -+ } -+ // Tuinity end - this can cause clients on a lagging server to think they're not currently destroying a block - } else if (action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) { - this.isDestroyingBlock = false; - if (!Objects.equals(this.destroyPos, pos) && !BlockPos.ZERO.equals(this.destroyPos)) { -@@ -318,7 +344,7 @@ public class ServerPlayerGameMode { - } - - this.level.destroyBlockProgress(this.player.getId(), pos, -1); -- this.player.connection.send(new ClientboundBlockBreakAckPacket(pos, this.level.getBlockState(pos), action, true, "aborted destroying")); -+ if (!com.tuinity.tuinity.config.TuinityConfig.lagCompensateBlockBreaking) this.player.connection.send(new ClientboundBlockBreakAckPacket(pos, this.level.getBlockState(pos), action, true, "aborted destroying")); // Tuinity - this can cause clients on a lagging server to think they stopped destroying a block they're currently destroying - } - - } -@@ -328,7 +354,13 @@ public class ServerPlayerGameMode { - - public void destroyAndAck(BlockPos pos, ServerboundPlayerActionPacket.Action action, String reason) { - if (this.destroyBlock(pos)) { -+ // Tuinity start - this can cause clients on a lagging server to think they're not currently destroying a block -+ if (com.tuinity.tuinity.config.TuinityConfig.lagCompensateBlockBreaking) { -+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ } else { - this.player.connection.send(new ClientboundBlockBreakAckPacket(pos, this.level.getBlockState(pos), action, true, reason)); -+ } -+ // Tuinity end - this can cause clients on a lagging server to think they're not currently destroying a block - } else { - this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // CraftBukkit - SPIGOT-5196 - } -diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index f0df7b2bd618c7be18c4c86f735b303dc73d98ad..73e1efe5bcec0522384118f0ca5e4d4f3e8bce82 100644 ---- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -+++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -@@ -25,6 +25,17 @@ import net.minecraft.world.level.lighting.LevelLightEngine; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - -+// Tuinity start -+import ca.spottedleaf.starlight.light.StarLightEngine; -+import com.tuinity.tuinity.util.CoordinateUtils; -+import java.util.function.Supplier; -+import net.minecraft.world.level.lighting.LayerLightEventListener; -+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongArrayList; -+import it.unimi.dsi.fastutil.longs.LongIterator; -+import net.minecraft.world.level.chunk.ChunkStatus; -+// Tuinity end -+ - public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable { - private static final Logger LOGGER = LogManager.getLogger(); - private final ProcessorMailbox taskMailbox; -@@ -168,13 +179,166 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - private volatile int taskPerBatch = 5; - private final AtomicBoolean scheduled = new AtomicBoolean(); - -+ // Tuinity start - replace light engine impl -+ protected final ca.spottedleaf.starlight.light.StarLightInterface theLightEngine; -+ public final boolean hasBlockLight; -+ public final boolean hasSkyLight; -+ // Tuinity end - replace light engine impl -+ - public ThreadedLevelLightEngine(LightChunkGetter chunkProvider, ChunkMap chunkStorage, boolean hasBlockLight, ProcessorMailbox processor, ProcessorHandle> executor) { -- super(chunkProvider, true, hasBlockLight); -+ super(chunkProvider, false, false); // Tuinity - destroy vanilla light engine state - this.chunkMap = chunkStorage; this.playerChunkMap = chunkMap; // Paper - this.sorterMailbox = executor; - this.taskMailbox = processor; -+ // Tuinity start - replace light engine impl -+ this.hasBlockLight = true; -+ this.hasSkyLight = hasBlockLight; // Nice variable name. -+ this.theLightEngine = new ca.spottedleaf.starlight.light.StarLightInterface(chunkProvider, this.hasSkyLight, this.hasBlockLight, this); -+ // Tuinity end - replace light engine impl -+ } -+ -+ // Tuinity start - replace light engine impl -+ protected final ChunkAccess getChunk(final int chunkX, final int chunkZ) { -+ return ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().getChunkAtImmediately(chunkX, chunkZ); -+ } -+ -+ protected long relightCounter; -+ -+ public int relight(java.util.Set chunks_param, -+ java.util.function.Consumer chunkLightCallback, -+ java.util.function.IntConsumer onComplete) { -+ if (!org.bukkit.Bukkit.isPrimaryThread()) { -+ throw new IllegalStateException("Must only be called on the main thread"); -+ } -+ -+ java.util.Set chunks = new java.util.LinkedHashSet<>(chunks_param); -+ // add tickets -+ java.util.Map ticketIds = new java.util.HashMap<>(); -+ int totalChunks = 0; -+ for (java.util.Iterator iterator = chunks.iterator(); iterator.hasNext();) { -+ final ChunkPos chunkPos = iterator.next(); -+ -+ final ChunkAccess chunk = ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().getChunkAtImmediately(chunkPos.x, chunkPos.z); -+ if (chunk == null || !chunk.isLightCorrect() || !chunk.getStatus().isOrAfter(ChunkStatus.LIGHT)) { -+ // cannot relight this chunk -+ iterator.remove(); -+ continue; -+ } -+ -+ final Long id = Long.valueOf(this.relightCounter++); -+ -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().addTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), id); -+ ticketIds.put(chunkPos, id); -+ -+ ++totalChunks; -+ } -+ -+ this.taskMailbox.tell(() -> { -+ this.theLightEngine.relightChunks(chunks, (ChunkPos chunkPos) -> { -+ chunkLightCallback.accept(chunkPos); -+ ((java.util.concurrent.Executor)((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().mainThreadProcessor).execute(() -> { -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()).broadcast(new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(chunkPos, ThreadedLevelLightEngine.this, null, null, true), false); -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().removeTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), ticketIds.get(chunkPos)); -+ }); -+ }, onComplete); -+ }); -+ this.tryScheduleUpdate(); -+ -+ return totalChunks; -+ } -+ -+ private final Long2IntOpenHashMap chunksBeingWorkedOn = new Long2IntOpenHashMap(); -+ -+ private void queueTaskForSection(final int chunkX, final int chunkY, final int chunkZ, final Supplier> runnable) { -+ final ServerLevel world = (ServerLevel)this.theLightEngine.getWorld(); -+ -+ final ChunkAccess center = this.theLightEngine.getAnyChunkNow(chunkX, chunkZ); -+ if (center == null || !center.getStatus().isOrAfter(ChunkStatus.LIGHT)) { -+ // do not accept updates in unlit chunks, unless we might be generating a chunk. thanks to the amazing -+ // chunk scheduling, we could be lighting and generating a chunk at the same time -+ return; -+ } -+ -+ if (center.getStatus() != ChunkStatus.FULL) { -+ // do not keep chunk loaded, we are probably in a gen thread -+ // if we proceed to add a ticket the chunk will be loaded, which is not what we want (avoid cascading gen) -+ runnable.get(); -+ return; -+ } -+ -+ if (!world.getChunkSource().chunkMap.mainThreadExecutor.isSameThread()) { -+ // ticket logic is not safe to run off-main, re-schedule -+ world.getChunkSource().chunkMap.mainThreadExecutor.execute(() -> { -+ this.queueTaskForSection(chunkX, chunkY, chunkZ, runnable); -+ }); -+ return; -+ } -+ -+ final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ -+ final CompletableFuture updateFuture = runnable.get(); -+ -+ if (updateFuture == null) { -+ // not scheduled -+ return; -+ } -+ -+ final int references = this.chunksBeingWorkedOn.addTo(key, 1); -+ if (references == 0) { -+ final ChunkPos pos = new ChunkPos(chunkX, chunkZ); -+ world.getChunkSource().addRegionTicket(ca.spottedleaf.starlight.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos); -+ } -+ -+ // append future to this chunk and 1 radius neighbours chunk save futures -+ // this prevents us from saving the world without first waiting for the light engine -+ -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ ChunkHolder neighbour = world.getChunkSource().chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(dx + chunkX, dz + chunkZ)); -+ if (neighbour != null) { -+ neighbour.chunkToSave = neighbour.chunkToSave.thenCombine(updateFuture, (final ChunkAccess curr, final Void ignore) -> { -+ return curr; -+ }); -+ } -+ } -+ } -+ -+ updateFuture.thenAcceptAsync((final Void ignore) -> { -+ final int newReferences = this.chunksBeingWorkedOn.get(key); -+ if (newReferences == 1) { -+ this.chunksBeingWorkedOn.remove(key); -+ final ChunkPos pos = new ChunkPos(chunkX, chunkZ); -+ world.getChunkSource().removeRegionTicket(ca.spottedleaf.starlight.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos); -+ } else { -+ this.chunksBeingWorkedOn.put(key, newReferences - 1); -+ } -+ }, world.getChunkSource().chunkMap.mainThreadExecutor).whenComplete((final Void ignore, final Throwable thr) -> { -+ if (thr != null) { -+ LOGGER.fatal("Failed to remove ticket level for post chunk task " + new ChunkPos(chunkX, chunkZ), thr); -+ } -+ }); -+ } -+ -+ @Override -+ public boolean hasLightWork() { -+ // route to new light engine -+ return this.theLightEngine.hasUpdates() || !this.queue.isEmpty(); - } - -+ @Override -+ public LayerLightEventListener getLayerListener(final LightLayer lightType) { -+ return lightType == LightLayer.BLOCK ? this.theLightEngine.getBlockReader() : this.theLightEngine.getSkyReader(); -+ } -+ -+ @Override -+ public int getRawBrightness(final BlockPos pos, final int ambientDarkness) { -+ // need to use new light hooks for this -+ final int sky = this.theLightEngine.getSkyReader().getLightValue(pos) - ambientDarkness; -+ final int block = this.theLightEngine.getBlockReader().getLightValue(pos); -+ return Math.max(sky, block); -+ } -+ // Tuinity end - replace light engine impl -+ - @Override - public void close() { - } -@@ -191,15 +355,16 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - - @Override - public void checkBlock(BlockPos pos) { -- BlockPos blockPos = pos.immutable(); -- this.addTask(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ThreadedLevelLightEngine.TaskType.POST_UPDATE, Util.name(() -> { -- super.checkBlock(blockPos); -- }, () -> { -- return "checkBlock " + blockPos; -- })); -+ // Tuinity start - replace light engine impl -+ final BlockPos posCopy = pos.immutable(); -+ this.queueTaskForSection(posCopy.getX() >> 4, posCopy.getY() >> 4, posCopy.getZ() >> 4, () -> { -+ return this.theLightEngine.blockChange(posCopy); -+ }); -+ // Tuinity end - replace light engine impl - } - - protected void updateChunkStatus(ChunkPos pos) { -+ if (true) return; // Tuinity - replace light engine impl - this.addTask(pos.x, pos.z, () -> { - return 0; - }, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -@@ -222,17 +387,16 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - - @Override - public void updateSectionStatus(SectionPos pos, boolean notReady) { -- this.addTask(pos.x(), pos.z(), () -> { -- return 0; -- }, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -- super.updateSectionStatus(pos, notReady); -- }, () -> { -- return "updateSectionStatus " + pos + " " + notReady; -- })); -+ // Tuinity start - replace light engine impl -+ this.queueTaskForSection(pos.getX(), pos.getY(), pos.getZ(), () -> { -+ return this.theLightEngine.sectionChange(pos, notReady); -+ }); -+ // Tuinity end - replace light engine impl - } - - @Override - public void enableLightSources(ChunkPos chunkPos, boolean bl) { -+ if (true) return; // Tuinity - replace light engine impl - this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { - super.enableLightSources(chunkPos, bl); - }, () -> { -@@ -242,6 +406,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - - @Override - public void queueSectionData(LightLayer lightType, SectionPos pos, @Nullable DataLayer nibbles, boolean bl) { -+ if (true) return; // Tuinity - replace light engine impl - this.addTask(pos.x(), pos.z(), () -> { - return 0; - }, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -@@ -263,6 +428,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - - @Override - public void retainData(ChunkPos pos, boolean retainData) { -+ if (true) return; // Tuinity - replace light engine impl - this.addTask(pos.x, pos.z, () -> { - return 0; - }, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -@@ -273,6 +439,37 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - } - - public CompletableFuture lightChunk(ChunkAccess chunk, boolean excludeBlocks) { -+ // Tuinity start - replace light engine impl -+ if (true) { -+ boolean lit = excludeBlocks; -+ final ChunkPos chunkPos = chunk.getPos(); -+ -+ return CompletableFuture.supplyAsync(() -> { -+ final Boolean[] emptySections = StarLightEngine.getEmptySectionsForChunk(chunk); -+ if (!lit) { -+ chunk.setLightCorrect(false); -+ this.theLightEngine.lightChunk(chunk, emptySections); -+ chunk.setLightCorrect(true); -+ } else { -+ this.theLightEngine.forceLoadInChunk(chunk, emptySections); -+ // can't really force the chunk to be edged checked, as we need neighbouring chunks - but we don't have -+ // them, so if it's not loaded then i guess we can't do edge checks. later loads of the chunk should -+ // catch what we miss here. -+ this.theLightEngine.checkChunkEdges(chunkPos.x, chunkPos.z); -+ } -+ -+ this.chunkMap.releaseLightTicket(chunkPos); -+ return chunk; -+ }, (runnable) -> { -+ this.theLightEngine.scheduleChunkLight(chunkPos, runnable); -+ this.tryScheduleUpdate(); -+ }).whenComplete((final ChunkAccess c, final Throwable throwable) -> { -+ if (throwable != null) { -+ LOGGER.fatal("Failed to light chunk " + chunkPos, throwable); -+ } -+ }); -+ } -+ // Tuinity end - replace light engine impl - ChunkPos chunkPos = chunk.getPos(); - // Paper start - //ichunkaccess.b(false); // Don't need to disable this -@@ -320,7 +517,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - } - - public void tryScheduleUpdate() { -- if ((!this.queue.isEmpty() || super.hasLightWork()) && this.scheduled.compareAndSet(false, true)) { // Paper -+ if (this.hasLightWork() && this.scheduled.compareAndSet(false, true)) { // Paper // Tuinity - rewrite light engine - this.taskMailbox.tell(() -> { - this.runUpdate(); - this.scheduled.set(false); -@@ -337,12 +534,12 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - if (queue.poll(pre, post)) { - pre.forEach(Runnable::run); - pre.clear(); -- super.runUpdates(Integer.MAX_VALUE, true, true); -+ this.theLightEngine.propagateChanges(); // Tuinity - rewrite light engine - post.forEach(Runnable::run); - post.clear(); - } else { - // might have level updates to go still -- super.runUpdates(Integer.MAX_VALUE, true, true); -+ this.theLightEngine.propagateChanges(); // Tuinity - rewrite light engine - } - // Paper end - } -diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index 3c1698ba0d3bc412ab957777d9b5211dbc555208..c438cbfa1f964a5bea98bca85e688d8019e1c4fb 100644 ---- a/src/main/java/net/minecraft/server/level/TicketType.java -+++ b/src/main/java/net/minecraft/server/level/TicketType.java -@@ -31,6 +31,8 @@ public class TicketType { - public static final TicketType PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit - public static final TicketType PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit - public static final TicketType DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper -+ public static final TicketType CHUNK_RELIGHT = create("light_update", Long::compareTo); // Tuinity - ensure chunks stay loaded for lighting -+ public static final TicketType REQUIRED_LOAD = create("required_load", Long::compareTo); // Tuinity - make sure getChunkAt does not fail - - public static TicketType create(String name, Comparator argumentComparator) { - return new TicketType<>(name, argumentComparator, 0L); -diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index 0f6b534a4c789a2f09f6c4624e5d58b99c7ed0e6..fea852674098fe411841d8e5ebeace7d11d94e4f 100644 ---- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java -+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -77,6 +77,23 @@ public class WorldGenRegion implements WorldGenLevel { - @Nullable - private Supplier currentlyGenerating; - -+ // Tuinity start -+ // No-op, this class doesn't provide entity access -+ @Override -+ public List getHardCollidingEntities(Entity except, AABB box, Predicate predicate) { -+ return Collections.emptyList(); -+ } -+ -+ @Override -+ public void getEntities(Entity except, AABB box, Predicate predicate, List into) {} -+ -+ @Override -+ public void getHardCollidingEntities(Entity except, AABB box, Predicate predicate, List into) {} -+ -+ @Override -+ public void getEntitiesByClass(Class clazz, Entity except, AABB box, List into, Predicate predicate) {} -+ // Tuinity end -+ - public WorldGenRegion(ServerLevel world, List list, ChunkStatus chunkstatus, int i) { - this.generatingStatus = chunkstatus; - this.writeRadiusCutoff = i; -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index 961660f6f9e00b93252519e38b74c66c53388ed2..c80280150897064dc9d814edfbbcc1ce6eb9cf52 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -104,6 +104,11 @@ public class ServerConnectionListener { - ServerConnectionListener.LOGGER.info("Using default channel type"); - } - -+ // Tuinity start - indicate Velocity natives in use -+ ServerConnectionListener.LOGGER.info("Tuinity: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity."); -+ ServerConnectionListener.LOGGER.info("Tuinity: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity."); -+ // Tuinity end -+ - this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer() { - protected void initChannel(Channel channel) { - try { -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index ad1a9c6c354d40d5fa589666b1b00792d9cd6161..162a4b3b3312867a64425caa0d6ec6af157b20e1 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -536,6 +536,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - double d10 = Math.max(d6 * d6 + d7 * d7 + d8 * d8, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); - // Paper end - fix large move vectors killing the server - -+ // Tuinity start - fix large move vectors killing the server -+ double otherFieldX = d3 - this.vehicleLastGoodX; -+ double otherFieldY = d4 - this.vehicleLastGoodY - 1.0E-6D; -+ double otherFieldZ = d5 - this.vehicleLastGoodZ; -+ d10 = Math.max(d10, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); -+ // Tuinity end - fix large move vectors killing the server - - // CraftBukkit start - handle custom speeds and skipped ticks - this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; -@@ -576,12 +582,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - return; - } - -- boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D)); -+ AABB oldBox = entity.getBoundingBox(); // Tuinity - copy from player movement packet - -- d6 = d3 - this.vehicleLastGoodX; -- d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; -- d8 = d5 - this.vehicleLastGoodZ; -+ d6 = d3 - this.vehicleLastGoodX; // Tuinity - diff on change, used for checking large move vectors above -+ d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; // Tuinity - diff on change, used for checking large move vectors above -+ d8 = d5 - this.vehicleLastGoodZ; // Tuinity - diff on change, used for checking large move vectors above - entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8)); -+ boolean didCollide = toX != entity.getX() || toY != entity.getY() || toZ != entity.getZ(); // Tuinity - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be... - double d11 = d7; - - d6 = d3 - entity.getX(); -@@ -595,16 +602,23 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - boolean flag1 = false; - - if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot -- flag1 = true; -+ flag1 = true; // Tuinity - diff on change, this should be moved wrongly - ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)); - } - Location curPos = this.getCraftPlayer().getLocation(); // Spigot - - entity.absMoveTo(d3, d4, d5, f, f1); - this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit -- boolean flag2 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D)); -- -- if (flag && (flag1 || !flag2)) { -+ // Tuinity start - optimise out extra getCubes -+ boolean teleportBack = flag1; // violating this is always a fail -+ if (!teleportBack) { -+ // note: only call after setLocation, or else getBoundingBox is wrong -+ AABB newBox = entity.getBoundingBox(); -+ if (didCollide || !oldBox.equals(newBox)) { -+ teleportBack = this.hasNewCollision(worldserver, entity, oldBox, newBox); -+ } // else: no collision at all detected, why do we care? -+ } -+ if (teleportBack) { // Tuinity end - optimise out extra getCubes - entity.absMoveTo(d0, d1, d2, f, f1); - this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit - this.connection.send(new ClientboundMoveVehiclePacket(entity)); -@@ -690,7 +704,32 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - } - - private boolean noBlocksAround(Entity entity) { -- return entity.level.getBlockStates(entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D)).allMatch(BlockBehaviour.BlockStateBase::isAir); -+ // Tuinity start - stop using streams, this is already a known fixed problem in Entity#move -+ AABB box = entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D); -+ int minX = Mth.floor(box.minX); -+ int minY = Mth.floor(box.minY); -+ int minZ = Mth.floor(box.minZ); -+ int maxX = Mth.floor(box.maxX); -+ int maxY = Mth.floor(box.maxY); -+ int maxZ = Mth.floor(box.maxZ); -+ -+ Level world = entity.level; -+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); -+ -+ for (int y = minY; y <= maxY; ++y) { -+ for (int z = minZ; z <= maxZ; ++z) { -+ for (int x = minX; x <= maxX; ++x) { -+ pos.set(x, y, z); -+ BlockState type = world.getTypeIfLoaded(pos); -+ if (type != null && !type.isAir()) { -+ return false; -+ } -+ } -+ } -+ } -+ -+ return true; -+ // Tuinity end - stop using streams, this is already a known fixed problem in Entity#move - } - - @Override -@@ -1227,7 +1266,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - } - - if (this.awaitingPositionFromClient != null) { -- if (this.tickCount - this.awaitingTeleportTime > 20) { -+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Tuinity - this will greatly screw with clients with > 1000ms RTT - this.awaitingTeleportTime = this.tickCount; - this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); - } -@@ -1266,6 +1305,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - double currDeltaZ = toZ - prevZ; - double d11 = Math.max(d7 * d7 + d8 * d8 + d9 * d9, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); - // Paper end - fix large move vectors killing the server -+ // Tuinity start - fix large move vectors killing the server -+ double otherFieldX = d0 - this.lastGoodX; -+ double otherFieldY = d1 - this.lastGoodY; -+ double otherFieldZ = d2 - this.lastGoodZ; -+ d11 = Math.max(d11, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); -+ // Tuinity end - fix large move vectors killing the server - - if (this.player.isSleeping()) { - if (d11 > 1.0D) { -@@ -1315,11 +1360,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - } - } - -- AABB axisalignedbb = this.player.getBoundingBox(); -+ AABB axisalignedbb = this.player.getBoundingBox(); // Tuinity - diff on change, should be old AABB - -- d7 = d0 - this.lastGoodX; -- d8 = d1 - this.lastGoodY; -- d9 = d2 - this.lastGoodZ; -+ d7 = d0 - this.lastGoodX; // Tuinity - diff on change, used for checking large move vectors above -+ d8 = d1 - this.lastGoodY; // Tuinity - diff on change, used for checking large move vectors above -+ d9 = d2 - this.lastGoodZ; // Tuinity - diff on change, used for checking large move vectors above - boolean flag = d8 > 0.0D; - - if (this.player.isOnGround() && !packet.isOnGround() && flag) { -@@ -1354,6 +1399,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - } - - this.player.move(MoverType.PLAYER, new Vec3(d7, d8, d9)); -+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Tuinity - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be... - this.player.setOnGround(packet.isOnGround()); // CraftBukkit - SPIGOT-5810, SPIGOT-5835: reset by this.player.move - // Paper start - prevent position desync - if (this.awaitingPositionFromClient != null) { -@@ -1373,12 +1419,23 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - boolean flag1 = false; - - if (!this.player.isChangingDimension() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot -- flag1 = true; -+ flag1 = true; // Tuinity - diff on change, this should be moved wrongly - ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); - } - - this.player.absMoveTo(d0, d1, d2, f, f1); -- if (!this.player.noPhysics && !this.player.isSleeping() && (flag1 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew((LevelReader) worldserver, axisalignedbb))) { -+ // Tuinity start - optimise out extra getCubes -+ // Original for reference: -+ // boolean teleportBack = flag1 && worldserver.getCubes(this.player, axisalignedbb) || (didCollide && this.a((IWorldReader) worldserver, axisalignedbb)); -+ boolean teleportBack = flag1; // violating this is always a fail -+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) { -+ AABB newBox = this.player.getBoundingBox(); -+ if (didCollide || !axisalignedbb.equals(newBox)) { -+ // note: only call after setLocation, or else getBoundingBox is wrong -+ teleportBack = this.hasNewCollision(worldserver, this.player, axisalignedbb, newBox); -+ } // else: no collision at all detected, why do we care? -+ } -+ if (!this.player.noPhysics && !this.player.isSleeping() && teleportBack) { // Tuinity end - optimise out extra getCubes - this.teleport(d3, d4, d5, f, f1); - } else { - // CraftBukkit start - fire PlayerMoveEvent -@@ -1465,6 +1522,27 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - } - } - -+ // Tuinity start - optimise out extra getCubes -+ private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) { -+ final List collisions = com.tuinity.tuinity.util.CachedLists.getTempCollisionList(); -+ try { -+ com.tuinity.tuinity.util.CollisionUtil.getCollisions(world, entity, newBox, collisions, false, true, -+ true, false, null, null); -+ -+ for (int i = 0, len = collisions.size(); i < len; ++i) { -+ final AABB box = collisions.get(i); -+ if (!com.tuinity.tuinity.util.CollisionUtil.voxelShapeIntersect(box, oldBox)) { -+ return true; -+ } -+ } -+ -+ return false; -+ } finally { -+ com.tuinity.tuinity.util.CachedLists.returnTempCollisionList(collisions); -+ } -+ } -+ // Tuinity end - optimise out extra getCubes -+ - private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box) { - Stream stream = world.getCollisions(this.player, this.player.getBoundingBox().deflate(9.999999747378752E-6D), (entity) -> { - return true; -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 45e77d96f673ce68cf15ce3d45fd1eeffed4d8d8..9ab220ef0d20151d4e205f3edc213fd9353601ad 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -275,12 +275,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener - } - - SecretKey secretkey = packet.getSecretKey(privatekey); -- Cipher cipher = Crypt.getCipher(2, secretkey); -- Cipher cipher1 = Crypt.getCipher(1, secretkey); -+ // Tuinity start -+// Cipher cipher = Crypt.getCipher(2, secretkey); -+// Cipher cipher1 = Crypt.getCipher(1, secretkey); -+ // Tuinity end - - s = (new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretkey))).toString(16); - this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING; -- this.connection.setEncryptionKey(cipher, cipher1); -+ this.connection.setupEncryption(secretkey); // Tuinity - } catch (CryptException cryptographyexception) { - throw new IllegalStateException("Protocol error", cryptographyexception); - } -diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java -index 61405c2b53e03a4b83e2c70c6e4d3739ca9676cb..357efb989362e0be8cb08533ad677634f0b390f7 100644 ---- a/src/main/java/net/minecraft/server/players/GameProfileCache.java -+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java -@@ -62,6 +62,11 @@ public class GameProfileCache { - @Nullable - private Executor executor; - -+ // Tuinity start -+ protected final java.util.concurrent.locks.ReentrantLock stateLock = new java.util.concurrent.locks.ReentrantLock(); -+ protected final java.util.concurrent.locks.ReentrantLock lookupLock = new java.util.concurrent.locks.ReentrantLock(); -+ // Tuinity end -+ - public GameProfileCache(GameProfileRepository profileRepository, File cacheFile) { - this.profileRepository = profileRepository; - this.file = cacheFile; -@@ -69,6 +74,7 @@ public class GameProfileCache { - } - - private void safeAdd(GameProfileCache.GameProfileInfo entry) { -+ try { this.stateLock.lock(); // Tuinity - allow better concurrency - GameProfile gameprofile = entry.getProfile(); - - entry.setLastAccess(this.getNextOperation()); -@@ -83,6 +89,7 @@ public class GameProfileCache { - if (uuid != null) { - this.profilesByUUID.put(uuid, entry); - } -+ } finally { this.stateLock.unlock(); } // Tuinity - allow better concurrency - - } - -@@ -119,7 +126,7 @@ public class GameProfileCache { - return com.destroystokyo.paper.PaperConfig.isProxyOnlineMode(); // Paper - } - -- public synchronized void add(GameProfile profile) { // Paper - synchronize -+ public void add(GameProfile profile) { // Paper - synchronize // Tuinity - allow better concurrency - Calendar calendar = Calendar.getInstance(); - - calendar.setTime(new Date()); -@@ -142,8 +149,9 @@ public class GameProfileCache { - } - // Paper end - -- public synchronized Optional get(String name) { // Paper - synchronize -+ public Optional get(String name) { // Paper - synchronize // Tuinity start - allow better concurrency - String s1 = name.toLowerCase(Locale.ROOT); -+ boolean stateLocked = true; try { this.stateLock.lock(); // Tuinity - allow better concurrency - GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1); - boolean flag = false; - -@@ -157,10 +165,14 @@ public class GameProfileCache { - Optional optional; - - if (usercache_usercacheentry != null) { -+ stateLocked = false; this.stateLock.unlock(); // Tuinity - allow better concurrency - usercache_usercacheentry.setLastAccess(this.getNextOperation()); - optional = Optional.of(usercache_usercacheentry.getProfile()); - } else { -+ stateLocked = false; this.stateLock.unlock(); // Tuinity - allow better concurrency -+ try { this.lookupLock.lock(); // Tuinity - allow better concurrency - optional = GameProfileCache.lookupGameProfile(this.profileRepository, name); // Spigot - use correct case for offline players -+ } finally { this.lookupLock.unlock(); } // Tuinity - allow better concurrency - if (optional.isPresent()) { - this.add((GameProfile) optional.get()); - flag = false; -@@ -172,6 +184,7 @@ public class GameProfileCache { - } - - return optional; -+ } finally { if (stateLocked) { this.stateLock.unlock(); } } // Tuinity - allow better concurrency - } - - public void getAsync(String username, Consumer> consumer) { -@@ -187,7 +200,7 @@ public class GameProfileCache { - } else { - this.requests.put(username, CompletableFuture.supplyAsync(() -> { - return this.get(username); -- }, Util.backgroundExecutor()).whenCompleteAsync((optional, throwable) -> { -+ }, Util.PROFILE_EXECUTOR).whenCompleteAsync((optional, throwable) -> { // Tuinity - not a good idea to use BLOCKING OPERATIONS on the worldgen executor - this.requests.remove(username); - }, this.executor).whenCompleteAsync((optional, throwable) -> { - consumer.accept(optional); -@@ -322,7 +335,9 @@ public class GameProfileCache { - } - - private Stream getTopMRUProfiles(int limit) { -+ try { this.stateLock.lock(); // Tuinity - allow better concurrency - return ImmutableList.copyOf(this.profilesByUUID.values()).stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit((long) limit); -+ } finally { this.stateLock.unlock(); } // Tuinity - allow better concurrency - } - - private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo entry, DateFormat dateFormat) { -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 9966d0bb4f85866a46f5e4098416ab9af81f8d9f..ea8956b2c4cbe7059512ebfa9fd7a865e5fae0ac 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -177,6 +177,7 @@ public abstract class PlayerList { - abstract public void loadAndSaveFiles(); // Paper - moved from DedicatedPlayerList constructor - - public void placeNewPlayer(Connection connection, ServerPlayer player) { -+ player.isRealPlayer = true; // Paper // Tuinity - this is a better place to write this that works and isn't overriden by plugins - ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);// Paper - if (prev != null) { - disconnectPendingPlayer(prev); -@@ -266,7 +267,7 @@ public abstract class PlayerList { - boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); - - // Spigot - view distance -- playerconnection.send(new ClientboundLoginPacket(player.getId(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), worlddata.isHardcore(), this.server.levelKeys(), this.registryHolder, worldserver1.dimensionType(), worldserver1.dimension(), this.getMaxPlayers(), worldserver1.getChunkSource().chunkMap.getLoadViewDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat())); // Paper - no-tick view distance -+ playerconnection.send(new ClientboundLoginPacket(player.getId(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), worlddata.isHardcore(), this.server.levelKeys(), this.registryHolder, worldserver1.dimensionType(), worldserver1.dimension(), this.getMaxPlayers(), worldserver1.getChunkSource().chunkMap.playerChunkManager.getLoadDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat())); // Paper - no-tick view distance // Tuinity - replace old player chunk management - player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit - playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName()))); - playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); -@@ -730,7 +731,7 @@ public abstract class PlayerList { - SocketAddress socketaddress = loginlistener.connection.getRemoteAddress(); - - ServerPlayer entity = new ServerPlayer(this.server, this.server.getLevel(Level.OVERWORLD), gameprofile); -- entity.isRealPlayer = true; // Paper - Chunk priority -+ // Tuinity - some plugins (namely protocolsupport) bypass this logic completely! So this needs to be moved. - Player player = entity.getBukkitEntity(); - PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.getRawAddress()).getAddress()); - -@@ -934,13 +935,13 @@ public abstract class PlayerList { - - worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper - entityplayer1.forceCheckHighPriority(); // Player - Chunk priority -- while (avoidSuffocation && !worldserver1.noCollision(entityplayer1) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) { -+ while (avoidSuffocation && !worldserver1.noCollision(entityplayer1, entityplayer1.getBoundingBox(), null, true) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) { // Tuinity - make sure this loads chunks, we default to NOT loading now - entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ()); - } - // CraftBukkit start - LevelData worlddata = worldserver1.getLevelData(); - entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionType(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), flag)); -- entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getChunkSource().chunkMap.getLoadViewDistance())); // Spigot // Paper - no-tick view distance -+ entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getChunkSource().chunkMap.playerChunkManager.getLoadDistance())); // Spigot // Paper - no-tick view distance// Tuinity - replace old player chunk management - entityplayer1.setLevel(worldserver1); - entityplayer1.unsetRemoved(); - entityplayer1.connection.teleport(new Location(worldserver1.getWorld(), entityplayer1.getX(), entityplayer1.getY(), entityplayer1.getZ(), entityplayer1.getYRot(), entityplayer1.getXRot())); -@@ -1215,7 +1216,7 @@ public abstract class PlayerList { - // Really shouldn't happen... - backingSet = world != null ? world.players.toArray() : players.toArray(); - } else { -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearbyPlayers = chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(MCUtil.fastFloor(x) >> 4, MCUtil.fastFloor(z) >> 4); -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearbyPlayers = chunkMap.playerChunkManager.broadcastMap.getObjectsInRange(MCUtil.fastFloor(x) >> 4, MCUtil.fastFloor(z) >> 4); // Tuinity - replace old player chunk management - if (nearbyPlayers == null) { - return; - } -diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java -index 07e1374ac3430662edd9f585e59b785e329f0820..9f9c0b56f0891e9c423d79f8ae4c3643a2b91048 100644 ---- a/src/main/java/net/minecraft/util/BitStorage.java -+++ b/src/main/java/net/minecraft/util/BitStorage.java -@@ -104,4 +104,32 @@ public class BitStorage { - } - - } -+ -+ // Paper start -+ public final void forEach(DataBitConsumer consumer) { -+ int i = 0; -+ long[] along = this.data; -+ int j = along.length; -+ -+ for (int k = 0; k < j; ++k) { -+ long l = along[k]; -+ -+ for (int i1 = 0; i1 < this.valuesPerLong; ++i1) { -+ consumer.accept(i, (int) (l & this.mask)); -+ l >>= this.bits; -+ ++i; -+ if (i >= this.size) { -+ return; -+ } -+ } -+ } -+ } -+ -+ @FunctionalInterface -+ public static interface DataBitConsumer { -+ -+ void accept(int location, int data); -+ -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/util/valueproviders/IntProvider.java b/src/main/java/net/minecraft/util/valueproviders/IntProvider.java -index 020a19cd683dd3779c5116d12b3cdcd3b3ca69b4..17d209c347b07acef451180c97835f41b8bf8433 100644 ---- a/src/main/java/net/minecraft/util/valueproviders/IntProvider.java -+++ b/src/main/java/net/minecraft/util/valueproviders/IntProvider.java -@@ -9,13 +9,44 @@ import net.minecraft.core.Registry; - - public abstract class IntProvider { - private static final Codec> CONSTANT_OR_DISPATCH_CODEC = Codec.either(Codec.INT, Registry.INT_PROVIDER_TYPES.dispatch(IntProvider::getType, IntProviderType::codec)); -- public static final Codec CODEC = CONSTANT_OR_DISPATCH_CODEC.xmap((either) -> { -+ public static final Codec CODEC_REAL = CONSTANT_OR_DISPATCH_CODEC.xmap((either) -> { // Paper - used by CODEC below - return either.map(ConstantInt::of, (intProvider) -> { - return intProvider; - }); - }, (intProvider) -> { - return intProvider.getType() == IntProviderType.CONSTANT ? Either.left(((ConstantInt)intProvider).getValue()) : Either.right(intProvider); - }); -+ // Tuinity start -+ public static final Codec CODEC = new Codec<>() { -+ @Override -+ public DataResult> decode(com.mojang.serialization.DynamicOps ops, T input) { -+ /* -+ UniformInt: -+ count -> { (old format) -+ base, spread -+ } -> {UniformInt} { (new format & type) -+ base, base + spread -+ } */ -+ -+ -+ if (ops.get(input, "base").result().isPresent() && ops.get(input, "spread").result().isPresent()) { -+ // detected old format -+ int base = ops.getNumberValue(ops.get(input, "base").result().get()).result().get().intValue(); -+ int spread = ops.getNumberValue(ops.get(input, "spread").result().get()).result().get().intValue(); -+ return DataResult.success(new com.mojang.datafixers.util.Pair<>(UniformInt.of(base, base + spread), input)); -+ } -+ -+ // not old format, forward to real codec -+ return CODEC_REAL.decode(ops, input); -+ } -+ -+ @Override -+ public DataResult encode(IntProvider input, com.mojang.serialization.DynamicOps ops, T prefix) { -+ // forward to real codec -+ return CODEC_REAL.encode(input, ops, prefix); -+ } -+ }; -+ // Tuinity end - public static final Codec NON_NEGATIVE_CODEC = codec(0, Integer.MAX_VALUE); - public static final Codec POSITIVE_CODEC = codec(1, Integer.MAX_VALUE); - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index b8f8f4b369ed5f77a644b6bc8aea5068a0f03582..b4c15376da0ba9c33efe7e7da648690e7a931981 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -356,8 +356,27 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - } - - public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getPlayersInTrackRange() { -- return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()] -- .getObjectsInRange(MCUtil.getCoordinateKey(this)); -+ // Tuinity start - determine highest range of passengers -+ if (this.passengers.isEmpty()) { -+ return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()] -+ .getObjectsInRange(MCUtil.getCoordinateKey(this)); -+ } -+ Iterable passengers = this.getIndirectPassengers(); -+ net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap; -+ org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType; -+ int range = chunkMap.getEntityTrackerRange(type.ordinal()); -+ -+ for (Entity passenger : passengers) { -+ org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType; -+ int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal()); -+ if (passengerRange > range) { -+ type = passengerType; -+ range = passengerRange; -+ } -+ } -+ -+ return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this)); -+ // Tuinity end - determine highest range of passengers - } - // Paper end - optimise entity tracking - -@@ -392,6 +411,56 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - } - // Paper end - make end portalling safe - -+ // Tuinity start -+ public final AABB getBoundingBoxAt(double x, double y, double z) { -+ return this.dimensions.makeBoundingBox(x, y, z); -+ } -+ // Tuinity end -+ -+ // Tuinity start -+ /** -+ * Overriding this field will cause memory leaks. -+ */ -+ private final boolean hardCollides; -+ -+ private static final java.util.Map, Boolean> cachedOverrides = java.util.Collections.synchronizedMap(new java.util.WeakHashMap<>()); -+ { -+ /* // Goodbye, broken on reobf... -+ Boolean hardCollides = cachedOverrides.get(this.getClass()); -+ if (hardCollides == null) { -+ try { -+ java.lang.reflect.Method getHardCollisionBoxEntityMethod = Entity.class.getMethod("canCollideWith", Entity.class); -+ java.lang.reflect.Method hasHardCollisionBoxMethod = Entity.class.getMethod("canBeCollidedWith"); -+ if (!this.getClass().getMethod(hasHardCollisionBoxMethod.getName(), hasHardCollisionBoxMethod.getParameterTypes()).equals(hasHardCollisionBoxMethod) -+ || !this.getClass().getMethod(getHardCollisionBoxEntityMethod.getName(), getHardCollisionBoxEntityMethod.getParameterTypes()).equals(getHardCollisionBoxEntityMethod)) { -+ hardCollides = Boolean.TRUE; -+ } else { -+ hardCollides = Boolean.FALSE; -+ } -+ cachedOverrides.put(this.getClass(), hardCollides); -+ } -+ catch (ThreadDeath thr) { throw thr; } -+ catch (Throwable thr) { -+ // shouldn't happen, just explode -+ throw new RuntimeException(thr); -+ } -+ } */ -+ this.hardCollides = this instanceof Boat -+ || this instanceof net.minecraft.world.entity.monster.Shulker -+ || this instanceof net.minecraft.world.entity.vehicle.AbstractMinecart; -+ } -+ -+ public final boolean hardCollides() { -+ return this.hardCollides; -+ } -+ -+ public net.minecraft.server.level.ChunkHolder.FullChunkStatus chunkStatus; -+ -+ public int sectionX = Integer.MIN_VALUE; -+ public int sectionY = Integer.MIN_VALUE; -+ public int sectionZ = Integer.MIN_VALUE; -+ // Tuinity end -+ - public Entity(EntityType type, Level world) { - this.id = Entity.ENTITY_COUNTER.incrementAndGet(); - this.passengers = ImmutableList.of(); -@@ -813,7 +882,42 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - return this.onGround; - } - -+ // Tuinity start - detailed watchdog information -+ public final Object posLock = new Object(); // Tuinity - log detailed entity tick information -+ -+ private Vec3 moveVector; -+ private double moveStartX; -+ private double moveStartY; -+ private double moveStartZ; -+ -+ public final Vec3 getMoveVector() { -+ return this.moveVector; -+ } -+ -+ public final double getMoveStartX() { -+ return this.moveStartX; -+ } -+ -+ public final double getMoveStartY() { -+ return this.moveStartY; -+ } -+ -+ public final double getMoveStartZ() { -+ return this.moveStartZ; -+ } -+ // Tuinity end - detailed watchdog information -+ - public void move(MoverType movementType, Vec3 movement) { -+ // Tuinity start - detailed watchdog information -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -+ synchronized (this.posLock) { -+ this.moveStartX = this.getX(); -+ this.moveStartY = this.getY(); -+ this.moveStartZ = this.getZ(); -+ this.moveVector = movement; -+ } -+ try { -+ // Tuinity end - detailed watchdog information - if (this.noPhysics) { - this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); - } else { -@@ -949,9 +1053,44 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - float f2 = this.getBlockSpeedFactor(); - - this.setDeltaMovement(this.getDeltaMovement().multiply((double) f2, 1.0D, (double) f2)); -- if (this.level.getBlockStatesIfLoaded(this.getBoundingBox().deflate(1.0E-6D)).noneMatch((iblockdata1) -> { -- return iblockdata1.is((Tag) BlockTags.FIRE) || iblockdata1.is(Blocks.LAVA); -- })) { -+ // Tuinity start - remove expensive streams from here -+ boolean noneMatch = true; -+ AABB fireSearchBox = this.getBoundingBox().deflate(1.0E-6D); -+ { -+ int minX = Mth.floor(fireSearchBox.minX); -+ int minY = Mth.floor(fireSearchBox.minY); -+ int minZ = Mth.floor(fireSearchBox.minZ); -+ int maxX = Mth.floor(fireSearchBox.maxX); -+ int maxY = Mth.floor(fireSearchBox.maxY); -+ int maxZ = Mth.floor(fireSearchBox.maxZ); -+ fire_search_loop: -+ for (int fz = minZ; fz <= maxZ; ++fz) { -+ for (int fx = minX; fx <= maxX; ++fx) { -+ for (int fy = minY; fy <= maxY; ++fy) { -+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)this.level.getChunkIfLoadedImmediately(fx >> 4, fz >> 4); -+ if (chunk == null) { -+ // Vanilla rets an empty stream if all the chunks are not loaded, so noneMatch will be true -+ // even if we're in lava/fire -+ noneMatch = true; -+ break fire_search_loop; -+ } -+ if (!noneMatch) { -+ // don't do get type, we already know we're in fire - we just need to check the chunks -+ // loaded state -+ continue; -+ } -+ -+ BlockState type = chunk.getType(fx, fy, fz); -+ if (type.is((Tag) BlockTags.FIRE) || type.is(Blocks.LAVA)) { -+ noneMatch = false; -+ // can't break, we need to retain vanilla behavior by ensuring ALL chunks are loaded -+ } -+ } -+ } -+ } -+ } -+ if (noneMatch) { -+ // Tuinity end - remove expensive streams from here - if (this.remainingFireTicks <= 0) { - this.setRemainingFireTicks(-this.getFireImmuneTicks()); - } -@@ -968,6 +1107,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - this.level.getProfiler().pop(); - } - } -+ // Tuinity start - detailed watchdog information -+ } finally { -+ synchronized (this.posLock) { // Tuinity -+ this.moveVector = null; -+ } // Tuinity -+ } -+ // Tuinity end - detailed watchdog information - } - - protected void tryCheckInsideBlocks() { -@@ -1073,39 +1219,79 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - return offsetFactor; - } - -- private Vec3 collide(Vec3 movement) { -- AABB axisalignedbb = this.getBoundingBox(); -- CollisionContext voxelshapecollision = CollisionContext.of(this); -- VoxelShape voxelshape = this.level.getWorldBorder().getCollisionShape(); -- Stream stream = !this.level.getWorldBorder().isWithinBounds(axisalignedbb) ? Stream.empty() : Stream.of(voxelshape); // Paper -- Stream stream1 = this.level.getEntityCollisions(this, axisalignedbb.expandTowards(movement), (entity) -> { -- return true; -- }); -- RewindableStream streamaccumulator = new RewindableStream<>(Stream.concat(stream1, stream)); -- Vec3 vec3d1 = movement.lengthSqr() == 0.0D ? movement : Entity.collideBoundingBoxHeuristically(this, movement, axisalignedbb, this.level, voxelshapecollision, streamaccumulator); -- boolean flag = movement.x != vec3d1.x; -- boolean flag1 = movement.y != vec3d1.y; -- boolean flag2 = movement.z != vec3d1.z; -- boolean flag3 = this.onGround || flag1 && movement.y < 0.0D; -- -- if (this.maxUpStep > 0.0F && flag3 && (flag || flag2)) { -- Vec3 vec3d2 = Entity.collideBoundingBoxHeuristically(this, new Vec3(movement.x, (double) this.maxUpStep, movement.z), axisalignedbb, this.level, voxelshapecollision, streamaccumulator); -- Vec3 vec3d3 = Entity.collideBoundingBoxHeuristically(this, new Vec3(0.0D, (double) this.maxUpStep, 0.0D), axisalignedbb.expandTowards(movement.x, 0.0D, movement.z), this.level, voxelshapecollision, streamaccumulator); -- -- if (vec3d3.y < (double) this.maxUpStep) { -- Vec3 vec3d4 = Entity.collideBoundingBoxHeuristically(this, new Vec3(movement.x, 0.0D, movement.z), axisalignedbb.move(vec3d3), this.level, voxelshapecollision, streamaccumulator).add(vec3d3); -- -- if (vec3d4.horizontalDistanceSqr() > vec3d2.horizontalDistanceSqr()) { -- vec3d2 = vec3d4; -+ private Vec3 collide(Vec3 moveVector) { -+ // Tuinity start - optimise collisions -+ // This is a copy of vanilla's except that it uses strictly AABB math -+ if (moveVector.x == 0.0 && moveVector.y == 0.0 && moveVector.z == 0.0) { -+ return moveVector; -+ } -+ -+ final Level world = this.level; -+ final AABB currBoundingBox = this.getBoundingBox(); -+ -+ if (com.tuinity.tuinity.util.CollisionUtil.isEmpty(currBoundingBox)) { -+ return moveVector; -+ } -+ -+ final List potentialCollisions = com.tuinity.tuinity.util.CachedLists.getTempCollisionList(); -+ try { -+ final double stepHeight = (double)this.maxUpStep; -+ final AABB collisionBox; -+ -+ if (moveVector.x == 0.0 && moveVector.z == 0.0 && moveVector.y != 0.0) { -+ if (moveVector.y > 0.0) { -+ collisionBox = com.tuinity.tuinity.util.CollisionUtil.cutUpwards(currBoundingBox, moveVector.y); -+ } else { -+ collisionBox = com.tuinity.tuinity.util.CollisionUtil.cutDownwards(currBoundingBox, moveVector.y); -+ } -+ } else { -+ if (stepHeight > 0.0 && (this.onGround || (moveVector.y < 0.0)) && (moveVector.x != 0.0 || moveVector.z != 0.0)) { -+ // don't bother getting the collisions if we don't need them. -+ if (moveVector.y <= 0.0) { -+ collisionBox = com.tuinity.tuinity.util.CollisionUtil.expandUpwards(currBoundingBox.expandTowards(moveVector.x, moveVector.y, moveVector.z), stepHeight); -+ } else { -+ collisionBox = currBoundingBox.expandTowards(moveVector.x, Math.max(stepHeight, moveVector.y), moveVector.z); -+ } -+ } else { -+ collisionBox = currBoundingBox.expandTowards(moveVector.x, moveVector.y, moveVector.z); - } - } - -- if (vec3d2.horizontalDistanceSqr() > vec3d1.horizontalDistanceSqr()) { -- return vec3d2.add(Entity.collideBoundingBoxHeuristically(this, new Vec3(0.0D, -vec3d2.y + movement.y, 0.0D), axisalignedbb.move(vec3d2), this.level, voxelshapecollision, streamaccumulator)); -+ com.tuinity.tuinity.util.CollisionUtil.getCollisions(world, this, collisionBox, potentialCollisions, false, true, -+ false, false, null, null); -+ -+ if (com.tuinity.tuinity.util.CollisionUtil.isCollidingWithBorderEdge(world.getWorldBorder(), collisionBox)) { -+ com.tuinity.tuinity.util.CollisionUtil.addBoxesToIfIntersects(world.getWorldBorder().getCollisionShape(), collisionBox, potentialCollisions); - } -- } - -- return vec3d1; -+ final Vec3 limitedMoveVector = com.tuinity.tuinity.util.CollisionUtil.performCollisions(moveVector, currBoundingBox, potentialCollisions); -+ -+ if (stepHeight > 0.0 -+ && (this.onGround || (limitedMoveVector.y != moveVector.y && moveVector.y < 0.0)) -+ && (limitedMoveVector.x != moveVector.x || limitedMoveVector.z != moveVector.z)) { -+ Vec3 vec3d2 = com.tuinity.tuinity.util.CollisionUtil.performCollisions(new Vec3(moveVector.x, stepHeight, moveVector.z), currBoundingBox, potentialCollisions); -+ final Vec3 vec3d3 = com.tuinity.tuinity.util.CollisionUtil.performCollisions(new Vec3(0.0, stepHeight, 0.0), currBoundingBox.expandTowards(moveVector.x, 0.0, moveVector.z), potentialCollisions); -+ -+ if (vec3d3.y < stepHeight) { -+ final Vec3 vec3d4 = com.tuinity.tuinity.util.CollisionUtil.performCollisions(new Vec3(moveVector.x, 0.0D, moveVector.z), currBoundingBox.move(vec3d3), potentialCollisions).add(vec3d3); -+ -+ if (vec3d4.horizontalDistanceSqr() > vec3d2.horizontalDistanceSqr()) { -+ vec3d2 = vec3d4; -+ } -+ } -+ -+ if (vec3d2.horizontalDistanceSqr() > limitedMoveVector.horizontalDistanceSqr()) { -+ return vec3d2.add(com.tuinity.tuinity.util.CollisionUtil.performCollisions(new Vec3(0.0D, -vec3d2.y + moveVector.y, 0.0D), currBoundingBox.move(vec3d2), potentialCollisions)); -+ } -+ -+ return limitedMoveVector; -+ } else { -+ return limitedMoveVector; -+ } -+ } finally { -+ com.tuinity.tuinity.util.CachedLists.returnTempCollisionList(potentialCollisions); -+ } -+ // Tuinity end - optimise collisions - } - - public static Vec3 collideBoundingBoxHeuristically(@Nullable Entity entity, Vec3 movement, AABB entityBoundingBox, Level world, CollisionContext context, RewindableStream collisions) { -@@ -2244,9 +2430,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - float f = this.dimensions.width * 0.8F; - AABB axisalignedbb = AABB.ofSize(this.getEyePosition(), (double) f, 1.0E-6D, (double) f); - -- return this.level.getBlockCollisions(this, axisalignedbb, (iblockdata, blockposition) -> { -- return iblockdata.isSuffocating(this.level, blockposition); -- }).findAny().isPresent(); -+ // Tuinity start -+ return com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this.level, this, axisalignedbb, null, -+ false, false, false, true, (iblockdata, blockposition) -> { -+ return iblockdata.isSuffocating(this.level, blockposition); -+ }); -+ // Tuinity end - } - } - -@@ -2254,11 +2443,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - return InteractionResult.PASS; - } - -- public boolean canCollideWith(Entity other) { -+ public boolean canCollideWith(Entity other) { // Tuinity - diff on change, hard colliding entities override this - TODO CHECK ON UPDATE - AbstractMinecart/Boat override - return other.canBeCollidedWith() && !this.isPassengerOfSameVehicle(other); - } - -- public boolean canBeCollidedWith() { -+ public boolean canBeCollidedWith() { // Tuinity - diff on change, hard colliding entities override this TODO CHECK ON UPDATE - Boat/Shulker override - return false; - } - -@@ -3742,7 +3931,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - } - - public void setDeltaMovement(Vec3 velocity) { -+ synchronized (this.posLock) { // Tuinity - this.deltaMovement = velocity; -+ } // Tuinity - } - - public void setDeltaMovement(double x, double y, double z) { -@@ -3809,7 +4000,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - // Paper end - // Paper start - fix MC-4 - if (this instanceof ItemEntity) { -- if (com.destroystokyo.paper.PaperConfig.fixEntityPositionDesync) { -+ if (false && com.destroystokyo.paper.PaperConfig.fixEntityPositionDesync) { // Tuinity - revert - // encode/decode from PacketPlayOutEntity - x = Mth.lfloor(x * 4096.0D) * (1 / 4096.0D); - y = Mth.lfloor(y * 4096.0D) * (1 / 4096.0D); -@@ -3818,7 +4009,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - } - // Paper end - fix MC-4 - if (this.position.x != x || this.position.y != y || this.position.z != z) { -+ synchronized (this.posLock) { // Tuinity - this.position = new Vec3(x, y, z); -+ } // Tuinity - int i = Mth.floor(x); - int j = Mth.floor(y); - int k = Mth.floor(z); -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index bada11542390b7575466f0e7062470665b8266c4..c73f3aa6dd75fe03c7e18180487d7bd6374b6339 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -789,7 +789,12 @@ public abstract class Mob extends LivingEntity { - if (this.level.getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { - this.discard(); - } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { -- Player entityhuman = this.level.findNearbyPlayer(this, -1.0D, EntitySelector.affectsSpawning); // Paper -+ // Tuinity start - optimise checkDespawn -+ Player entityhuman = this.level.findNearbyPlayer(this, level.paperConfig.hardDespawnDistance + 1, EntitySelector.affectsSpawning); // Paper -+ if (entityhuman == null) { -+ entityhuman = ((ServerLevel)this.level).playersAffectingSpawning.isEmpty() ? null : ((ServerLevel)this.level).playersAffectingSpawning.get(0); -+ } -+ // Tuinity end - optimise checkDespawn - - if (entityhuman != null) { - double d0 = entityhuman.distanceToSqr((Entity) this); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index 84a0ee595bebcc1947c602c4c06e7437706ce37c..efe66264ad5717bf3aac0fbda07275fb5571acc1 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -83,7 +83,11 @@ public class AcquirePoi extends Behavior { - return true; - } - }; -- Set set = poiManager.findAllClosestFirst(this.poiType.getPredicate(), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.HAS_SPACE).limit(5L).collect(Collectors.toSet()); -+ // Tuinity start - optimise POI access -+ java.util.List poiposes = new java.util.ArrayList<>(); -+ com.tuinity.tuinity.util.PoiAccess.findNearestPoiPositions(poiManager, this.poiType.getPredicate(), predicate, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); -+ Set set = new java.util.HashSet<>(poiposes); -+ // Tuinity end - optimise POI access - Path path = entity.getNavigation().createPath(set, this.poiType.getValidRange()); - if (path != null && path.canReach()) { - BlockPos blockPos = path.getTarget(); -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -index 09998d160a6d79fdb5a5041a5d572649a1532e6a..3fe1f9bd4bb670d9a1ddabf2475f4d8f44d7e6fe 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -@@ -30,11 +30,19 @@ public class GateBehavior extends Behavior { - - @Override - protected boolean canStillUse(ServerLevel world, E entity, long time) { -- return this.behaviors.stream().filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.RUNNING; -- }).anyMatch((behavior) -> { -- return behavior.canStillUse(world, entity, time); -- }); -+ // Tuinity start - remove streams -+ List>> entries = this.behaviors.entries; -+ for (int i = 0; i < entries.size(); i++) { -+ ShufflingList.WeightedEntry> entry = entries.get(i); -+ Behavior behavior = entry.getData(); -+ if (behavior.getStatus() == Status.RUNNING) { -+ if (behavior.canStillUse(world, entity, time)) { -+ return true; -+ } -+ } -+ } -+ return false; -+ // Tuinity end - remove streams - } - - @Override -@@ -45,25 +53,35 @@ public class GateBehavior extends Behavior { - @Override - protected void start(ServerLevel world, E entity, long time) { - this.orderPolicy.apply(this.behaviors); -- this.runningPolicy.apply(this.behaviors.stream(), world, entity, time); -+ this.runningPolicy.apply(this.behaviors.entries, world, entity, time); // Tuinity - remove streams - } - - @Override - protected void tick(ServerLevel world, E entity, long time) { -- this.behaviors.stream().filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.RUNNING; -- }).forEach((behavior) -> { -- behavior.tickOrStop(world, entity, time); -- }); -+ // Tuinity start - remove streams -+ List>> entries = this.behaviors.entries; -+ for (int i = 0; i < entries.size(); i++) { -+ ShufflingList.WeightedEntry> entry = entries.get(i); -+ Behavior behavior = entry.getData(); -+ if (behavior.getStatus() == Status.RUNNING) { -+ behavior.tickOrStop(world, entity, time); -+ } -+ } -+ // Tuinity end - remove streams - } - - @Override - protected void stop(ServerLevel world, E entity, long time) { -- this.behaviors.stream().filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.RUNNING; -- }).forEach((behavior) -> { -- behavior.doStop(world, entity, time); -- }); -+ // Tuinity start - remove streams -+ List>> entries = this.behaviors.entries; -+ for (int i = 0; i < entries.size(); i++) { -+ ShufflingList.WeightedEntry> entry = entries.get(i); -+ Behavior behavior = entry.getData(); -+ if (behavior.getStatus() == Status.RUNNING) { -+ behavior.doStop(world, entity, time); -+ } -+ } -+ // Tuinity end - remove streams - this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory); - } - -@@ -94,25 +112,33 @@ public class GateBehavior extends Behavior { - public static enum RunningPolicy { - RUN_ONE { - @Override -- public void apply(Stream> tasks, ServerLevel world, E entity, long time) { -- tasks.filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.STOPPED; -- }).filter((behavior) -> { -- return behavior.tryStart(world, entity, time); -- }).findFirst(); -+ // Tuinity start - remove streams -+ public void apply(List>> tasks, ServerLevel world, E entity, long time) { -+ for (int i = 0; i < tasks.size(); i++) { -+ ShufflingList.WeightedEntry> task = tasks.get(i); -+ Behavior behavior = task.getData(); -+ if (behavior.getStatus() == Status.STOPPED && behavior.tryStart(world, entity, time)) { -+ break; -+ } -+ } -+ // Tuinity end - remove streams - } - }, - TRY_ALL { - @Override -- public void apply(Stream> tasks, ServerLevel world, E entity, long time) { -- tasks.filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.STOPPED; -- }).forEach((behavior) -> { -- behavior.tryStart(world, entity, time); -- }); -+ // Tuinity start - remove streams -+ public void apply(List>> tasks, ServerLevel world, E entity, long time) { -+ for (int i = 0; i < tasks.size(); i++) { -+ ShufflingList.WeightedEntry> task = tasks.get(i); -+ Behavior behavior = task.getData(); -+ if (behavior.getStatus() == Status.STOPPED) { -+ behavior.tryStart(world, entity, time); -+ } -+ } -+ // Tuinity end - remove streams - } - }; - -- public abstract void apply(Stream> tasks, ServerLevel world, E entity, long time); -+ public abstract void apply(List>> tasks, ServerLevel world, E entity, long time); // Tuinity - remove streams - } - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java b/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -index 1f59e790d62f0be8e505e339a6699ca3964aea0d..bb43e47d4b3989610a52c1941598865aee93ac04 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -@@ -34,21 +34,42 @@ public class SetLookAndInteract extends Behavior { - - @Override - public boolean checkExtraStartConditions(ServerLevel world, LivingEntity entity) { -- return this.selfFilter.test(entity) && this.getVisibleEntities(entity).stream().anyMatch(this::isMatchingTarget); -+ // Tuinity start - remove streams -+ if (!this.selfFilter.test(entity)) { -+ return false; -+ } -+ -+ List visibleEntities = this.getVisibleEntities(entity); -+ for (int i = 0; i < visibleEntities.size(); i++) { -+ LivingEntity livingEntity = visibleEntities.get(i); -+ if (this.isMatchingTarget(livingEntity)) { -+ return true; -+ } -+ } -+ return false; -+ // Tuinity end - remove streams - } - - @Override - public void start(ServerLevel world, LivingEntity entity, long time) { - super.start(world, entity, time); - Brain brain = entity.getBrain(); -- brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).ifPresent((list) -> { -- list.stream().filter((livingEntity2) -> { -- return livingEntity2.distanceToSqr(entity) <= (double)this.interactionRangeSqr; -- }).filter(this::isMatchingTarget).findFirst().ifPresent((livingEntity) -> { -- brain.setMemory(MemoryModuleType.INTERACTION_TARGET, livingEntity); -- brain.setMemory(MemoryModuleType.LOOK_TARGET, new EntityTracker(livingEntity, true)); -- }); -- }); -+ // Tuinity start - remove streams -+ List list = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).orElse(null); -+ if (list != null) { -+ double maxRangeSquared = (double)this.interactionRangeSqr; -+ for (int i = 0; i < list.size(); i++) { -+ LivingEntity livingEntity2 = list.get(i); -+ if (livingEntity2.distanceToSqr(entity) <= maxRangeSquared) { -+ if (this.isMatchingTarget(livingEntity2)) { -+ brain.setMemory(MemoryModuleType.INTERACTION_TARGET, livingEntity2); -+ brain.setMemory(MemoryModuleType.LOOK_TARGET, new EntityTracker(livingEntity2, true)); -+ break; -+ } -+ } -+ } -+ } -+ // Tuinity end - remove streams - } - - private boolean isMatchingTarget(LivingEntity entity) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -index 4fa64b1e2004810906bb0b174436c8e687a75ada..d5a3c6d239abbb31c52ec2dfb9b18b1b705cbc88 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -@@ -12,7 +12,7 @@ import java.util.Random; - import java.util.stream.Stream; - - public class ShufflingList { -- protected final List> entries; -+ public final List> entries; // Tuinity - public - private final Random random = new Random(); - private final boolean isUnsafe; // Paper - -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index e605daac0c90f5d0b9315d1499938feb0e478d0e..570316cf7831de70086fae35676006ee052851e0 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -@@ -27,7 +27,7 @@ import net.minecraft.world.phys.Vec3; - - public abstract class PathNavigation { - private static final int MAX_TIME_RECOMPUTE = 20; -- protected final Mob mob; -+ protected final Mob mob; public final Mob getEntity() { return this.mob; } // Tuinity - public accessor - protected final Level level; - @Nullable - protected Path path; -@@ -40,7 +40,7 @@ public abstract class PathNavigation { - protected long lastTimeoutCheck; - protected double timeoutLimit; - protected float maxDistanceToWaypoint = 0.5F; -- protected boolean hasDelayedRecomputation; -+ protected boolean hasDelayedRecomputation; protected final boolean needsPathRecalculation() { return this.hasDelayedRecomputation; } // Tuinity - public accessor - protected long timeLastRecompute; - protected NodeEvaluator nodeEvaluator; - private BlockPos targetPos; -@@ -49,6 +49,13 @@ public abstract class PathNavigation { - public final PathFinder pathFinder; - private boolean isStuck; - -+ // Tuinity start -+ public boolean isViableForPathRecalculationChecking() { -+ return !this.needsPathRecalculation() && -+ (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0); -+ } -+ // Tuinity end -+ - public PathNavigation(Mob mob, Level world) { - this.mob = mob; - this.level = world; -@@ -404,7 +411,7 @@ public abstract class PathNavigation { - } - - public void recomputePath(BlockPos pos) { -- if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) { -+ if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) { // Tuinity - diff on change - needed for isViableForPathRecalculationChecking() - Node node = this.path.getEndNode(); - Vec3 vec3 = new Vec3(((double)node.x + this.mob.getX()) / 2.0D, ((double)node.y + this.mob.getY()) / 2.0D, ((double)node.z + this.mob.getZ()) / 2.0D); - if (pos.closerThan(vec3, (double)(this.path.getNodeCount() - this.path.getNextNodeIndex()))) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -index e41b2fa1db6fb77a26cdb498904021b430e35be0..f0ba454eea673bf02d1f6d7fe30c4f672643fe0c 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -@@ -49,8 +49,12 @@ public class NearestBedSensor extends Sensor { - return true; - } - }; -- Stream stream = poiManager.findAll(PoiType.HOME.getPredicate(), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY); -- Path path = entity.getNavigation().createPath(stream, PoiType.HOME.getValidRange()); -+ // Tuinity start - optimise POI access -+ java.util.List poiposes = new java.util.ArrayList<>(); -+ // don't ask me why it's unbounded. ask mojang. -+ com.tuinity.tuinity.util.PoiAccess.findAnyPoiPositions(poiManager, PoiType.HOME.getPredicate(), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); -+ Path path = entity.getNavigation().createPath(new java.util.HashSet<>(poiposes), PoiType.HOME.getValidRange()); -+ // Tuinity end - optimise POI access - if (path != null && path.canReach()) { - BlockPos blockPos = path.getTarget(); - Optional optional = poiManager.getType(blockPos); -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java -index 49f3b25d28072b61f5cc97260df61df892a58714..de6b591eb865c6f5c23aaa4b9374bb9bbaaa85f6 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java -@@ -25,17 +25,20 @@ public class NearestItemSensor extends Sensor { - protected void doTick(ServerLevel world, Mob entity) { - Brain brain = entity.getBrain(); - List list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(8.0D, 4.0D, 8.0D), (itemEntity) -> { -- return true; -+ return itemEntity.closerThan(entity, 9.0D) && entity.wantsToPickUp(itemEntity.getItem()); // Tuinity - move predicate into getEntities - }); -- list.sort(Comparator.comparingDouble(entity::distanceToSqr)); -+ list.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); // better to take the sort perf hit than using line of sight more than we need to. -+ // Tuinity start - remove streams - // Paper start - remove streams in favour of lists - ItemEntity nearest = null; -- for (ItemEntity entityItem : list) { -- if (entity.wantsToPickUp(entityItem.getItem()) && entityItem.closerThan(entity, 9.0D) && entity.hasLineOfSight(entityItem)) { -+ for (int i = 0; i < list.size(); i++) { -+ ItemEntity entityItem = list.get(i); -+ if (entity.hasLineOfSight(entityItem)) { - nearest = entityItem; - break; - } - } -+ // Tuinity end - remove streams - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest)); - // Paper end - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -index ffd83db0a419ab589e89feeddd3fb038d6ed5839..31ef567cf4f331d3329dd176392686db56aead66 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -@@ -18,12 +18,19 @@ public class NearestLivingEntitySensor extends Sensor { - List list = world.getEntitiesOfClass(LivingEntity.class, aABB, (livingEntity2) -> { - return livingEntity2 != entity && livingEntity2.isAlive(); - }); -- list.sort(Comparator.comparingDouble(entity::distanceToSqr)); -+ // Tuinity start - remove streams -+ list.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); - Brain brain = entity.getBrain(); - brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, list); - // Paper start - remove streams in favour of lists -- List visibleMobs = new java.util.ArrayList<>(list); -- visibleMobs.removeIf(otherEntityLiving -> !Sensor.isEntityTargetable(entity, otherEntityLiving)); -+ List visibleMobs = new java.util.ArrayList<>(); -+ for (int i = 0, len = list.size(); i < len; i++) { -+ LivingEntity nearby = list.get(i); -+ if (Sensor.isEntityTargetable(entity, nearby)) { -+ visibleMobs.add(nearby); -+ } -+ } -+ // Tuinity end - remove streams - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, visibleMobs); - // Paper end - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -index 457ea75137b8b02dc32bf1769ae8d57c470da470..3392a8d425d9f5e1417a665fb1514d013bf89337 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -@@ -21,25 +21,31 @@ public class PlayerSensor extends Sensor { - - @Override - protected void doTick(ServerLevel world, LivingEntity entity) { -- // Paper start - remove streams in favour of lists -- List players = new java.util.ArrayList<>(world.players()); -- players.removeIf(player -> !EntitySelector.NO_SPECTATORS.test(player) || !entity.closerThan(player, 16.0D)); // Paper - removeIf only re-allocates once compared to iterator -+ // Tuinity start - remove streams -+ List players = (List)world.getNearbyPlayers(entity, entity.getX(), entity.getY(), entity.getZ(), 16.0D, EntitySelector.NO_SPECTATORS); -+ players.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); - Brain brain = entity.getBrain(); - - brain.setMemory(MemoryModuleType.NEAREST_PLAYERS, players); - -- Player nearest = null, nearestTargetable = null; -- for (Player player : players) { -- if (Sensor.isEntityTargetable(entity, player)) { -- if (nearest == null) nearest = player; -- if (Sensor.isEntityAttackable(entity, player)) { -- nearestTargetable = player; -- break; // Both variables are assigned, no reason to loop further -- } -+ Player firstTargetable = null; -+ Player firstAttackable = null; -+ for (int index = 0, len = players.size(); index < len; ++index) { -+ Player player = players.get(index); -+ if (firstTargetable == null && isEntityTargetable(entity, player)) { -+ firstTargetable = player; -+ } -+ if (firstAttackable == null && isEntityAttackable(entity, player)) { -+ firstAttackable = player; -+ } -+ -+ if (firstAttackable != null && firstTargetable != null) { -+ break; - } - } -- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, nearest); -- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, nearestTargetable); -- // Paper end -+ -+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, firstTargetable); -+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, Optional.ofNullable(firstAttackable)); -+ // Tuinity end - remove streams - } - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java -index 478010bc291fa3276aab0f66ce6283403af710ec..a198538fe4ae560adc66fad5a2f6b80bbd894e4b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java -@@ -22,7 +22,17 @@ public class VillagerBabiesSensor extends Sensor { - } - - private List getNearestVillagerBabies(LivingEntity entities) { -- return this.getVisibleEntities(entities).stream().filter(this::isVillagerBaby).collect(Collectors.toList()); -+ // Tuinity start - remove streams -+ List list = new java.util.ArrayList<>(); -+ List visibleEntities = this.getVisibleEntities(entities); -+ for (int i = 0; i < visibleEntities.size(); i++) { -+ LivingEntity livingEntity = visibleEntities.get(i); -+ if (this.isVillagerBaby(livingEntity)) { -+ list.add(livingEntity); -+ } -+ } -+ return list; -+ // Tuinity end - remove streams - } - - private boolean isVillagerBaby(LivingEntity entity) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index 6c3455823f996e0421975b7f4a00f4e333e9f514..3ba30a2e6f1e3eb82b2b6e8968fd2babbf220ded 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -37,7 +37,7 @@ public class PoiManager extends SectionStorage { - public static final int VILLAGE_SECTION_SIZE = 1; - private final PoiManager.DistanceTracker distanceTracker; - private final LongSet loadedChunks = new LongOpenHashSet(); -- private final net.minecraft.server.level.ServerLevel world; // Paper -+ public final net.minecraft.server.level.ServerLevel world; // Paper // Tuinity public - - public PoiManager(File directory, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) { - super(directory, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world); -@@ -100,36 +100,55 @@ public class PoiManager extends SectionStorage { - } - - public Optional find(Predicate typePredicate, Predicate posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) { -- return this.findAll(typePredicate, posPredicate, pos, radius, occupationStatus).findFirst(); -+ // Tuinity start - re-route to faster logic -+ BlockPos ret = com.tuinity.tuinity.util.PoiAccess.findAnyPoiPosition(this, typePredicate, posPredicate, pos, radius, occupationStatus, false); -+ return Optional.ofNullable(ret); -+ // Tuinity end - re-route to faster logic - } - - public Optional findClosest(Predicate typePredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) { -- return this.getInRange(typePredicate, pos, radius, occupationStatus).map(PoiRecord::getPos).min(Comparator.comparingDouble((blockPos2) -> { -- return blockPos2.distSqr(pos); -- })); -+ // Tuinity start - re-route to faster logic -+ BlockPos ret = com.tuinity.tuinity.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, radius, radius*radius, occupationStatus, false); -+ return Optional.ofNullable(ret); -+ // Tuinity end - re-route to faster logic - } - - public Optional findClosest(Predicate predicate, Predicate predicate2, BlockPos blockPos, int i, PoiManager.Occupancy occupancy) { -- return this.getInRange(predicate, blockPos, i, occupancy).map(PoiRecord::getPos).filter(predicate2).min(Comparator.comparingDouble((blockPos2) -> { -- return blockPos2.distSqr(blockPos); -- })); -+ // Tuinity start - re-route to faster logic -+ BlockPos ret = com.tuinity.tuinity.util.PoiAccess.findClosestPoiDataPosition(this, predicate, predicate2, blockPos, i, i*i, occupancy, false); -+ return Optional.ofNullable(ret); -+ // Tuinity end - re-route to faster logic - } - - public Optional take(Predicate typePredicate, Predicate positionPredicate, BlockPos pos, int radius) { -- return this.getInRange(typePredicate, pos, radius, PoiManager.Occupancy.HAS_SPACE).filter((poi) -> { -- return positionPredicate.test(poi.getPos()); -- }).findFirst().map((poi) -> { -- poi.acquireTicket(); -- return poi.getPos(); -- }); -+ // Tuinity start - re-route to faster logic -+ PoiRecord ret = com.tuinity.tuinity.util.PoiAccess.findAnyPoiRecord( -+ this, typePredicate, positionPredicate, pos, radius, PoiManager.Occupancy.HAS_SPACE, false -+ ); -+ if (ret == null) { -+ return Optional.empty(); -+ } -+ ret.acquireTicket(); -+ return Optional.of(ret.getPos()); -+ // Tuinity end - re-route to faster logic - } - - public Optional getRandom(Predicate typePredicate, Predicate positionPredicate, PoiManager.Occupancy occupationStatus, BlockPos pos, int radius, Random random) { -- List list = this.getInRange(typePredicate, pos, radius, occupationStatus).collect(Collectors.toList()); -- Collections.shuffle(list, random); -- return list.stream().filter((poiRecord) -> { -- return positionPredicate.test(poiRecord.getPos()); -- }).findFirst().map(PoiRecord::getPos); -+ // Tuinity start - re-route to faster logic -+ List list = new java.util.ArrayList<>(); -+ com.tuinity.tuinity.util.PoiAccess.findAnyPoiRecords( -+ this, typePredicate, positionPredicate, pos, radius, occupationStatus, false, Integer.MAX_VALUE, list -+ ); -+ -+ // the old method shuffled the list and then tried to find the first element in it that -+ // matched positionPredicate, however we moved positionPredicate into the poi search. This means we can avoid a -+ // shuffle entirely, and just pick a random element from list -+ if (list.isEmpty()) { -+ return Optional.empty(); -+ } -+ -+ return Optional.of(list.get(random.nextInt(list.size())).getPos()); -+ // Tuinity end - re-route to faster logic - } - - public boolean release(BlockPos pos) { -@@ -183,7 +202,7 @@ public class PoiManager extends SectionStorage { - data = this.getData(chunkcoordintpair); - } - com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.world, -- chunkcoordintpair.x, chunkcoordintpair.z, data, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.LOW_PRIORITY); -+ chunkcoordintpair.x, chunkcoordintpair.z, data, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); // Tuinity - use normal priority - } - // Paper end - this.distanceTracker.runAllUpdates(); -diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java -index 75c1c4671fedb425dea20dc4fb0c6cb2304dee83..fc7b364adc2d0e5db22aa25e029c2e13c84d6096 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java -+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java -@@ -25,12 +25,12 @@ import org.apache.logging.log4j.Logger; - public class PoiSection { - private static final Logger LOGGER = LogManager.getLogger(); - private final Short2ObjectMap records = new Short2ObjectOpenHashMap<>(); -- private final Map> byType = Maps.newHashMap(); -+ private final Map> byType = Maps.newHashMap(); public final Map> getData() { return this.byType; } // Tuinity - public accessor - private final Runnable setDirty; - private boolean isValid; - - public static Codec codec(Runnable updateListener) { -- return RecordCodecBuilder.create((instance) -> { -+ return RecordCodecBuilder.create((instance) -> { // Tuinity - decompile fix - return instance.group(RecordCodecBuilder.point(updateListener), Codec.BOOL.optionalFieldOf("Valid", Boolean.valueOf(false)).forGetter((poiSet) -> { - return poiSet.isValid; - }), PoiRecord.codec(updateListener).listOf().fieldOf("Records").forGetter((poiSet) -> { -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index 925f16d5eb092518ef774f69a8d99689feb0f5d7..01d8af06f19427354cac95d691e65d31253fef94 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -91,7 +91,7 @@ public class Turtle extends Animal { - } - - public void setHomePos(BlockPos pos) { -- this.entityData.set(Turtle.HOME_POS, pos); -+ this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... - } - - public BlockPos getHomePos() { // Paper - public -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index d8780f06efc261a42389e466573a0bcf10c333f6..9e0eec259fdae57e235bfe00ece4df9957edc642 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -498,6 +498,11 @@ public abstract class Player extends LivingEntity { - this.containerMenu = this.inventoryMenu; - } - // Paper end -+ // Tuinity start - special close for unloaded inventory -+ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { -+ this.containerMenu = this.inventoryMenu; -+ } -+ // Tuinity end - special close for unloaded inventory - - public void closeContainer() { - this.containerMenu = this.inventoryMenu; -diff --git a/src/main/java/net/minecraft/world/item/EnderEyeItem.java b/src/main/java/net/minecraft/world/item/EnderEyeItem.java -index 7ccfe737fdf7f07b731ea0ff82e897564350705c..abcc3dac7c7369a3f37e85ddeecbe272833298c9 100644 ---- a/src/main/java/net/minecraft/world/item/EnderEyeItem.java -+++ b/src/main/java/net/minecraft/world/item/EnderEyeItem.java -@@ -60,9 +60,10 @@ public class EnderEyeItem extends Item { - - // CraftBukkit start - Use relative location for far away sounds - // world.b(1038, blockposition1.c(1, 0, 1), 0); -- int viewDistance = world.getCraftServer().getViewDistance() * 16; -+ //int viewDistance = world.getCraftServer().getViewDistance() * 16; // Tuinity - apply view distance patch - BlockPos soundPos = blockposition1.offset(1, 0, 1); - for (ServerPlayer player : world.getServer().getPlayerList().players) { -+ final int viewDistance = player.getBukkitEntity().getViewDistance(); // Tuinity - apply view distance patch - double deltaX = soundPos.getX() - player.getX(); - double deltaZ = soundPos.getZ() - player.getZ(); - double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; -diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java -index fe4dba491b586757a16aa36e62682f364daa2602..ec781ab232d12cedb5f0236860377c4917c576d7 100644 ---- a/src/main/java/net/minecraft/world/level/BlockGetter.java -+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java -@@ -84,7 +84,8 @@ public interface BlockGetter extends LevelHeightAccessor { - return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), new BlockPos(raytrace1.getTo())); - } - // Paper end -- FluidState fluid = this.getFluidState(blockposition); -+ if (iblockdata.isAir()) return null; // Tuinity - optimise air cases -+ FluidState fluid = iblockdata.getFluidState(); // Tuinity - don't need to go to world state again - Vec3 vec3d = raytrace1.getFrom(); - Vec3 vec3d1 = raytrace1.getTo(); - VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition); -diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java -index 2a784a8342e708e0813c7076a2ca8e429446ffd3..b909bd7bf10adc9165df49a210df0d73912cd626 100644 ---- a/src/main/java/net/minecraft/world/level/CollisionGetter.java -+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java -@@ -36,28 +36,40 @@ public interface CollisionGetter extends BlockGetter { - return this.isUnobstructed(entity, Shapes.create(entity.getBoundingBox())); - } - -+ // Tuinity start - optimise collisions -+ default boolean noCollision(Entity entity, AABB box, Predicate filter, boolean loadChunks) { -+ return !com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this, entity, box, null, loadChunks, false, entity != null, true, null) -+ && !com.tuinity.tuinity.util.CollisionUtil.getEntityHardCollisions(this, entity, box, null, true, filter); -+ } -+ // Tuinity end - optimise collisions -+ - default boolean noCollision(AABB box) { -- return this.noCollision((Entity)null, box, (e) -> { -- return true; -- }); -+ // Tuinity start - optimise collisions -+ return !com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this, null, box, null, false, false, false, true, null) -+ && !com.tuinity.tuinity.util.CollisionUtil.getEntityHardCollisions(this, null, box, null, true, null); -+ // Tuinity end - optimise collisions - } - - default boolean noCollision(Entity entity) { -- return this.noCollision(entity, entity.getBoundingBox(), (e) -> { -- return true; -- }); -+ // Tuinity start - optimise collisions -+ AABB box = entity.getBoundingBox(); -+ return !com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this, entity, box, null, false, false, entity != null, true, null) -+ && !com.tuinity.tuinity.util.CollisionUtil.getEntityHardCollisions(this, entity, box, null, true, null); -+ // Tuinity end - optimise collisions - } - - default boolean noCollision(Entity entity, AABB box) { -- return this.noCollision(entity, box, (e) -> { -- return true; -- }); -+ // Tuinity start - optimise collisions -+ return !com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this, entity, box, null, false, false, entity != null, true, null) -+ && !com.tuinity.tuinity.util.CollisionUtil.getEntityHardCollisions(this, entity, box, null, true, null); -+ // Tuinity end - optimise collisions - } - - default boolean noCollision(@Nullable Entity entity, AABB box, Predicate filter) { -- try { if (entity != null) entity.collisionLoadChunks = true; // Paper -- return this.getCollisions(entity, box, filter).allMatch(VoxelShape::isEmpty); -- } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper -+ // Tuinity start - optimise collisions -+ return !com.tuinity.tuinity.util.CollisionUtil.getCollisionsForBlocksOrWorldBorder(this, entity, box, null, false, false, entity != null, true, null) -+ && !com.tuinity.tuinity.util.CollisionUtil.getEntityHardCollisions(this, entity, box, null, true, filter); -+ // Tuinity end - optimise collisions - } - - Stream getEntityCollisions(@Nullable Entity entity, AABB box, Predicate predicate); -diff --git a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java -index 6124e3a32325e8c74bf839010a79d7c82c49aaff..56053b158127150fcd1fba4b6970a52e9bb38db6 100644 ---- a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java -+++ b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java -@@ -106,7 +106,7 @@ public class CollisionSpliterator extends AbstractSpliterator { - - VoxelShape voxelShape = blockState.getCollisionShape(this.collisionGetter, this.pos, this.context); - if (voxelShape == Shapes.block()) { -- if (!this.box.intersects((double)i, (double)j, (double)k, (double)i + 1.0D, (double)j + 1.0D, (double)k + 1.0D)) { -+ if (!com.tuinity.tuinity.util.CollisionUtil.voxelShapeIntersect(this.box, (double)i, (double)j, (double)k, (double)i + 1.0D, (double)j + 1.0D, (double)k + 1.0D)) { // Tuinity - keep vanilla behavior for voxelshape intersection - See comment in CollisionUtil - continue; - } - -diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java -index 325e244c46ec208a2e7e18d71ccbbfcc25fc1bce..6a4e44dd8935018d1b5283761dfb8e855be62987 100644 ---- a/src/main/java/net/minecraft/world/level/EntityGetter.java -+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java -@@ -18,6 +18,18 @@ import net.minecraft.world.phys.shapes.Shapes; - import net.minecraft.world.phys.shapes.VoxelShape; - - public interface EntityGetter { -+ -+ // Tuinity start -+ List getHardCollidingEntities(Entity except, AABB box, Predicate predicate); -+ -+ void getEntities(Entity except, AABB box, Predicate predicate, List into); -+ -+ void getHardCollidingEntities(Entity except, AABB box, Predicate predicate, List into); -+ -+ void getEntitiesByClass(Class clazz, Entity except, final AABB box, List into, -+ Predicate predicate); -+ // Tuinity end -+ - List getEntities(@Nullable Entity except, AABB box, Predicate predicate); - - List getEntities(EntityTypeTest filter, AABB box, Predicate predicate); -@@ -37,7 +49,7 @@ public interface EntityGetter { - return true; - } else { - for(Entity entity2 : this.getEntities(entity, shape.bounds())) { -- if (!entity2.isRemoved() && entity2.blocksBuilding && (entity == null || !entity2.isPassengerOfSameVehicle(entity)) && Shapes.joinIsNotEmpty(shape, Shapes.create(entity2.getBoundingBox()), BooleanOp.AND)) { -+ if (!entity2.isRemoved() && entity2.blocksBuilding && (entity == null || !entity2.isPassengerOfSameVehicle(entity)) && shape.intersects(entity2.getBoundingBox())) { // Tuinity - return false; - } - } -@@ -54,9 +66,9 @@ public interface EntityGetter { - if (box.getSize() < 1.0E-7D) { - return Stream.empty(); - } else { -- AABB aABB = box.inflate(1.0E-7D); -- return this.getEntities(entity, aABB, predicate.and((entityx) -> { -- if (entityx.getBoundingBox().intersects(aABB)) { -+ AABB aABB = box.inflate(-1.0E-7D); // Tuinity - needs to be negated, or else we get things we don't collide with -+ Predicate hardCollides = (entityx) -> { // Tuinity - optimise entity hard collisions -+ if (true || entityx.getBoundingBox().intersects(aABB)) { // Tuinity - always true - if (entity == null) { - if (entityx.canBeCollidedWith()) { - return true; -@@ -67,7 +79,11 @@ public interface EntityGetter { - } - - return false; -- })).stream().map(Entity::getBoundingBox).map(Shapes::create); -+ }; // Tuinity start - optimise entity hard collisions -+ predicate = predicate == null ? hardCollides : hardCollides.and(predicate); -+ return (entity != null && entity.hardCollides() ? this.getEntities(entity, aABB, predicate) : this.getHardCollidingEntities(entity, aABB, predicate)) -+ .stream().map(Entity::getBoundingBox).map(Shapes::create); -+ // Tuinity end - optimise entity hard collisions - } - } - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 474078b68f1bf22037495f42bae59b790fd8cb46..61a4dea715689b0ce9247040db5dd2080ee2e167 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -167,6 +167,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper - public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray - -+ public final com.tuinity.tuinity.config.TuinityConfig.WorldConfig tuinityConfig; // Tuinity - Server Config -+ - public final co.aikar.timings.WorldTimingsHandler timings; // Paper - public static BlockPos lastPhysicsProblem; // Spigot - private org.spigotmc.TickLimiter entityLimiter; -@@ -203,9 +205,117 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - return this.typeKey; - } - -+ // Tuinity start -+ protected final com.tuinity.tuinity.world.EntitySliceManager entitySliceManager; -+ -+ // Tuinity start - optimise CraftChunk#getEntities -+ public org.bukkit.entity.Entity[] getChunkEntities(int chunkX, int chunkZ) { -+ com.tuinity.tuinity.world.ChunkEntitySlices slices = this.entitySliceManager.getChunk(chunkX, chunkZ); -+ if (slices == null) { -+ return new org.bukkit.entity.Entity[0]; -+ } -+ return slices.getChunkEntities(); -+ } -+ // Tuinity end - optimise CraftChunk#getEntities -+ -+ @Override -+ public List getHardCollidingEntities(Entity except, AABB box, Predicate predicate) { -+ List ret = new java.util.ArrayList<>(); -+ this.entitySliceManager.getEntities(except, box, ret, predicate); -+ return ret; -+ } -+ -+ @Override -+ public void getEntities(Entity except, AABB box, Predicate predicate, List into) { -+ this.entitySliceManager.getEntities(except, box, into, predicate); -+ } -+ -+ @Override -+ public void getHardCollidingEntities(Entity except, AABB box, Predicate predicate, List into) { -+ this.entitySliceManager.getHardCollidingEntities(except, box, into, predicate); -+ } -+ -+ @Override -+ public void getEntitiesByClass(Class clazz, Entity except, final AABB box, List into, -+ Predicate predicate) { -+ this.entitySliceManager.getEntities((Class)clazz, except, box, (List)into, (Predicate)predicate); -+ } -+ -+ @Override -+ public List getEntitiesOfClass(Class entityClass, AABB box, Predicate predicate) { -+ List ret = new java.util.ArrayList<>(); -+ this.entitySliceManager.getEntities(entityClass, null, box, ret, predicate); -+ return ret; -+ } -+ // Tuinity end -+ // Tuinity start - optimise checkDespawn -+ public final List getNearbyPlayers(@Nullable Entity source, double sourceX, double sourceY, -+ double sourceZ, double maxRange, @Nullable Predicate predicate) { -+ LevelChunk chunk; -+ if (maxRange < 0.0 || maxRange >= net.minecraft.server.level.ChunkMap.GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE || -+ (chunk = (LevelChunk)this.getChunkIfLoadedImmediately(Mth.floor(sourceX) >> 4, Mth.floor(sourceZ) >> 4)) == null) { -+ return this.getNearbyPlayersSlow(source, sourceX, sourceY, sourceZ, maxRange, predicate); -+ } -+ -+ List ret = new java.util.ArrayList<>(); -+ chunk.getNearestPlayers(sourceX, sourceY, sourceZ, predicate, maxRange, ret); -+ return ret; -+ } -+ -+ private List getNearbyPlayersSlow(@Nullable Entity source, double sourceX, double sourceY, -+ double sourceZ, double maxRange, @Nullable Predicate predicate) { -+ List ret = new java.util.ArrayList<>(); -+ double maxRangeSquared = maxRange * maxRange; -+ -+ for (net.minecraft.server.level.ServerPlayer player : (List)this.players()) { -+ if ((maxRange < 0.0 || player.distanceToSqr(sourceX, sourceY, sourceZ) < maxRangeSquared)) { -+ if (predicate == null || predicate.test(player)) { -+ ret.add(player); -+ } -+ } -+ } -+ -+ return ret; -+ } -+ -+ private net.minecraft.server.level.ServerPlayer getNearestPlayerSlow(@Nullable Entity source, double sourceX, double sourceY, -+ double sourceZ, double maxRange, @Nullable Predicate predicate) { -+ net.minecraft.server.level.ServerPlayer closest = null; -+ double closestRangeSquared = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange; -+ -+ for (net.minecraft.server.level.ServerPlayer player : (List)this.players()) { -+ double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ); -+ if (distanceSquared < closestRangeSquared && (predicate == null || predicate.test(player))) { -+ closest = player; -+ closestRangeSquared = distanceSquared; -+ } -+ } -+ -+ return closest; -+ } -+ -+ -+ public final net.minecraft.server.level.ServerPlayer getNearestPlayer(@Nullable Entity source, double sourceX, double sourceY, -+ double sourceZ, double maxRange, @Nullable Predicate predicate) { -+ LevelChunk chunk; -+ if (maxRange < 0.0 || maxRange >= net.minecraft.server.level.ChunkMap.GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE || -+ (chunk = (LevelChunk)this.getChunkIfLoadedImmediately(Mth.floor(sourceX) >> 4, Mth.floor(sourceZ) >> 4)) == null) { -+ return this.getNearestPlayerSlow(source, sourceX, sourceY, sourceZ, maxRange, predicate); -+ } -+ -+ return chunk.findNearestPlayer(sourceX, sourceY, sourceZ, maxRange, predicate); -+ } -+ -+ @Override -+ public @Nullable Player getNearestPlayer(double d0, double d1, double d2, double d3, @Nullable Predicate predicate) { -+ return this.getNearestPlayer(null, d0, d1, d2, d3, predicate); -+ } -+ // Tuinity end - optimise checkDespawn -+ - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, final DimensionType dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot - this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper -+ this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData)worlddatamutable).getLevelName()); // Tuinity - Server Config - this.generator = gen; - this.world = new CraftWorld((ServerLevel) this, gen, env); - this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit -@@ -279,6 +389,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.chunkPacketBlockController = this.paperConfig.antiXray ? - new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) - : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray -+ this.entitySliceManager = new com.tuinity.tuinity.world.EntitySliceManager((ServerLevel)this); // Tuinity - } - - // Paper start -@@ -364,6 +475,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - @Override - public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline -+ // Tuinity start - make sure loaded chunks get the inlined variant of this function -+ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource(); -+ if (cps.mainThread == Thread.currentThread()) { -+ LevelChunk ifLoaded = cps.getChunkAtIfLoadedMainThread(chunkX, chunkZ); -+ if (ifLoaded != null) { -+ return ifLoaded; -+ } -+ } -+ // Tuinity end - make sure loaded chunks get the inlined variant of this function - return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump - } - -@@ -552,7 +672,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); - // Paper start - per player view distance - allow block updates for non-ticking chunks in player view distance - // if copied from above -- } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || ((ServerLevel)this).getChunkSource().chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(MCUtil.getCoordinateKey(blockposition)) != null)) { -+ } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || ((ServerLevel)this).getChunkSource().chunkMap.playerChunkManager.broadcastMap.getObjectsInRange(MCUtil.getCoordinateKey(blockposition)) != null)) { // Tuinity - replace old player chunk management - ((ServerLevel)this).getChunkSource().blockChanged(blockposition); - // Paper end - per player view distance - } -@@ -867,6 +987,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public void guardEntityTick(Consumer tickConsumer, T entity) { - try { - tickConsumer.accept(entity); -+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick - } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) throw throwable; // Paper - // Paper start - Prevent tile entity and entity crashes -@@ -996,26 +1117,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { - this.getProfiler().incrementCounter("getEntities"); - List list = Lists.newArrayList(); -- -- this.getEntities().get(box, (entity1) -> { -- if (entity1 != except && predicate.test(entity1)) { -- list.add(entity1); -- } -- -- if (entity1 instanceof EnderDragon) { -- EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity1).getSubEntities(); -- int i = aentitycomplexpart.length; -- -- for (int j = 0; j < i; ++j) { -- EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; -- -- if (entity1 != except && predicate.test(entitycomplexpart)) { -- list.add(entitycomplexpart); -- } -- } -- } -- -- }, predicate == net.minecraft.world.entity.EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper -+ this.entitySliceManager.getEntities(except, box, list, predicate); // Tuinity - optimise this call - return list; - } - -@@ -1024,26 +1126,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.getProfiler().incrementCounter("getEntities"); - List list = Lists.newArrayList(); - -- this.getEntities().get(filter, box, (entity) -> { -- if (predicate.test(entity)) { -- list.add(entity); -- } -- -- if (entity instanceof EnderDragon) { -- EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity).getSubEntities(); -- int i = aentitycomplexpart.length; -- -- for (int j = 0; j < i; ++j) { -- EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; -- T t0 = filter.tryCast(entitycomplexpart); -- -- if (t0 != null && predicate.test(t0)) { -- list.add(t0); -- } -- } -+ // Tuinity start - optimise this call -+ if (filter instanceof net.minecraft.world.entity.EntityType) { -+ this.entitySliceManager.getEntities((net.minecraft.world.entity.EntityType)filter, box, list, predicate); -+ } else { -+ Predicate test = (obj) -> { -+ return filter.tryCast(obj) != null; -+ }; -+ predicate = predicate == null ? test : test.and((Predicate)predicate); -+ Class base; -+ if (filter == null || (base = filter.getBaseClass()) == null || base == Entity.class) { -+ this.entitySliceManager.getEntities((Entity) null, box, (List)list, (Predicate)predicate); -+ } else { -+ this.entitySliceManager.getEntities(base, null, box, (List)list, (Predicate)predicate); // Tuinity - optimise this call - } -- -- }); -+ } -+ // Tuinity end - optimise this call - return list; - } - -@@ -1331,10 +1429,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public abstract TagContainer getTagManager(); - - public BlockPos getBlockRandomPos(int x, int y, int z, int l) { -+ // Paper start - allow use of mutable pos -+ BlockPos.MutableBlockPos ret = new BlockPos.MutableBlockPos(); -+ this.getRandomBlockPosition(x, y, z, l, ret); -+ return ret.immutable(); -+ } -+ public final BlockPos.MutableBlockPos getRandomBlockPosition(int x, int y, int z, int l, BlockPos.MutableBlockPos out) { -+ // Paper end - this.randValue = this.randValue * 3 + 1013904223; - int i1 = this.randValue >> 2; - -- return new BlockPos(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15)); -+ out.set(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15)); // Paper - change to setValues call -+ return out; // Paper - } - - public boolean noSave() { -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 88145f04989c71a686aae1b486087ecdf55e268c..c6821bfb28b582733cd977864c28ca5cf0c69872 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -262,7 +262,7 @@ public final class NaturalSpawner { - blockposition_mutableblockposition.set(l, i, i1); - double d0 = (double) l + 0.5D; - double d1 = (double) i1 + 0.5D; -- Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, false); -+ Player entityhuman = (chunk instanceof LevelChunk) ? ((LevelChunk)chunk).findNearestPlayer(d0, i, d1, 576.0D, net.minecraft.world.entity.EntitySelector.NO_SPECTATORS) : world.getNearestPlayer(d0, (double) i, d1, -1.0D, false); // Tuinity - use chunk's player cache to optimize search in range - - if (entityhuman != null) { - double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); -@@ -335,7 +335,7 @@ public final class NaturalSpawner { - } - - private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) { -- return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerThan((Position) (new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isPositionEntityTicking((BlockPos) pos)); -+ return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerThan((Position) (new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isPositionEntityTicking((BlockPos) pos)); // Tuinity - diff on change, copy into caller - } - - private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index aa1ba8b74ab70b6cede99e4853ac0203f388ab06..a242a80b16c7d074d52a52728646224b1a0091d4 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -139,19 +139,28 @@ public class FarmBlock extends Block { - } - - private static boolean isNearWater(LevelReader world, BlockPos pos) { -- Iterator iterator = BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4)).iterator(); -- -- BlockPos blockposition1; -- -- do { -- if (!iterator.hasNext()) { -- return false; -+ // Tuinity start - remove abstract block iteration -+ int xOff = pos.getX(); -+ int yOff = pos.getY(); -+ int zOff = pos.getZ(); -+ -+ for (int dz = -4; dz <= 4; ++dz) { -+ int z = dz + zOff; -+ for (int dx = -4; dx <= 4; ++dx) { -+ int x = xOff + dx; -+ for (int dy = 0; dy <= 1; ++dy) { -+ int y = dy + yOff; -+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)world.getChunk(x >> 4, z >> 4); -+ net.minecraft.world.level.material.FluidState fluid = chunk.getBlockData(x, y, z).getFluidState(); -+ if (fluid.is(FluidTags.WATER)) { -+ return true; -+ } -+ } - } -+ } - -- blockposition1 = (BlockPos) iterator.next(); -- } while (!world.getFluidState(blockposition1).is((Tag) FluidTags.WATER)); -- -- return true; -+ return false; -+ // Tuinity end - remove abstract block iteration - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java -index 6381544b0038de9a09c01238638e4e127e4eddc6..5bdec9531f2f2b1f50ed3b71ab79f2b058647a07 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java -@@ -150,7 +150,7 @@ public class SkullBlockEntity extends BlockEntity { - public static void updateGameprofile(@Nullable GameProfile owner, Consumer callback) { - if (owner != null && !StringUtil.isNullOrEmpty(owner.getName()) && (!owner.isComplete() || !owner.getProperties().containsKey("textures")) && profileCache != null && sessionService != null) { - profileCache.getAsync(owner.getName(), (profile) -> { -- Util.backgroundExecutor().execute(() -> { -+ Util.PROFILE_EXECUTOR.execute(() -> { // Tuinity - not a good idea to use BLOCKING OPERATIONS on the worldgen executor - Util.ifElse(profile, (profilex) -> { - Property property = Iterables.getFirst(profilex.getProperties().get("textures"), (Property)null); - if (property == null) { -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 1179c62695da4dcf02590c97d8da3c6fcdbee9ef..04d5ef90cd4171f9360017ac0c01ce48ae6ec983 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -610,14 +610,14 @@ public abstract class BlockBehaviour { - - public abstract static class BlockStateBase extends StateHolder { - -- private final int lightEmission; -- private final boolean useShapeForLightOcclusion; -+ private final int lightEmission; public final int getEmittedLight() { return this.lightEmission; } // Tuinity - OBFHELPER -+ private final boolean useShapeForLightOcclusion; public final boolean isTransparentOnSomeFaces() { return this.useShapeForLightOcclusion; } // Tuinity - OBFHELPER - private final boolean isAir; - private final Material material; - private final MaterialColor materialColor; - public final float destroySpeed; - private final boolean requiresCorrectToolForDrops; -- private final boolean canOcclude; -+ private final boolean canOcclude; public final boolean isOpaque() { return this.canOcclude; } // Tuinity - OBFHELPER - private final BlockBehaviour.StatePredicate isRedstoneConductor; - private final BlockBehaviour.StatePredicate isSuffocating; - private final BlockBehaviour.StatePredicate isViewBlocking; -@@ -643,6 +643,7 @@ public abstract class BlockBehaviour { - this.isViewBlocking = blockbase_info.isViewBlocking; - this.hasPostProcess = blockbase_info.hasPostProcess; - this.emissiveRendering = blockbase_info.emissiveRendering; -+ this.conditionallyFullOpaque = this.isOpaque() & this.isTransparentOnSomeFaces(); // Tuinity - } - // Paper start - impl cached craft block data, lazy load to fix issue with loading at the wrong time - private org.bukkit.craftbukkit.block.data.CraftBlockData cachedCraftBlockData; -@@ -658,13 +659,34 @@ public abstract class BlockBehaviour { - protected FluidState fluid; - // Paper end - -+ // Tuinity start -+ protected boolean shapeExceedsCube = true; -+ public final boolean shapeExceedsCube() { -+ return this.shapeExceedsCube; -+ } -+ // Tuinity end -+ // Tuinity start -+ protected int opacityIfCached = -1; -+ // ret -1 if opacity is dynamic, or -1 if the block is conditionally full opaque, else return opacity in [0, 15] -+ public final int getOpacityIfCached() { -+ return this.opacityIfCached; -+ } -+ -+ protected final boolean conditionallyFullOpaque; -+ public final boolean isConditionallyFullOpaque() { -+ return this.conditionallyFullOpaque; -+ } -+ // Tuinity end -+ - public void initCache() { - this.fluid = this.getBlock().getFluidState(this.asState()); // Paper - moved from getFluid() - this.isTicking = this.getBlock().isRandomlyTicking(this.asState()); // Paper - moved from isTicking() - if (!this.getBlock().hasDynamicShape()) { - this.cache = new BlockBehaviour.BlockStateBase.Cache(this.asState()); - } -- -+ this.shapeExceedsCube = this.cache == null || this.cache.largeCollisionShape; // Tuinity - moved from actual method to here -+ this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque() ? -1 : this.cache.lightBlock; // Tuinity - cache opacity for light -+ // TODO optimise light - } - - public Block getBlock() { -@@ -700,7 +722,7 @@ public abstract class BlockBehaviour { - } - - public final boolean hasLargeCollisionShape() { // Paper -- return this.cache == null || this.cache.largeCollisionShape; -+ return this.shapeExceedsCube; // Tuinity - moved into shape cache init - } - - public final boolean useShapeForLightOcclusion() { // Paper -diff --git a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -index baf1cb77eb170a44d821eae572d059f18ea46d7e..5d25223cb2f31e78b1608bd2846effba5b4301a4 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -+++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -@@ -40,11 +40,13 @@ public abstract class StateHolder { - private final ImmutableMap, Comparable> values; - private Table, Comparable, S> neighbours; - protected final MapCodec propertiesCodec; -+ protected final com.tuinity.tuinity.util.table.ZeroCollidingReferenceStateTable optimisedTable; // Tuinity - optimise state lookup - - protected StateHolder(O owner, ImmutableMap, Comparable> entries, MapCodec codec) { - this.owner = owner; - this.values = entries; - this.propertiesCodec = codec; -+ this.optimisedTable = new com.tuinity.tuinity.util.table.ZeroCollidingReferenceStateTable(this, entries); // Tuinity - optimise state lookup - } - - public > S cycle(Property property) { -@@ -85,11 +87,11 @@ public abstract class StateHolder { - } - - public > boolean hasProperty(Property property) { -- return this.values.containsKey(property); -+ return this.optimisedTable.get(property) != null; // Tuinity - optimise state lookup - } - - public > T getValue(Property property) { -- Comparable comparable = this.values.get(property); -+ Comparable comparable = this.optimisedTable.get(property); // Tuinity - optimise state lookup - if (comparable == null) { - throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); - } else { -@@ -98,24 +100,18 @@ public abstract class StateHolder { - } - - public > Optional getOptionalValue(Property property) { -- Comparable comparable = this.values.get(property); -+ Comparable comparable = this.optimisedTable.get(property); // Tuinity - optimise state lookup - return comparable == null ? Optional.empty() : Optional.of(property.getValueClass().cast(comparable)); - } - - public , V extends T> S setValue(Property property, V value) { -- Comparable comparable = this.values.get(property); -- if (comparable == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.owner); -- } else if (comparable == value) { -- return (S)this; -- } else { -- S object = this.neighbours.get(property, value); -- if (object == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); -- } else { -- return object; -- } -+ // Tuinity start - optimise state lookup -+ final S ret = (S)this.optimisedTable.get(property, value); -+ if (ret == null) { -+ throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); - } -+ return ret; -+ // Tuinity end - optimise state lookup - } - - public void populateNeighbours(Map, Comparable>, S> states) { -@@ -134,7 +130,7 @@ public abstract class StateHolder { - } - } - -- this.neighbours = (Table, Comparable, S>)(table.isEmpty() ? table : ArrayTable.create(table)); -+ this.neighbours = (Table, Comparable, S>)(table.isEmpty() ? table : ArrayTable.create(table)); this.optimisedTable.loadInTable((Table)this.neighbours, this.values); // Tuinity - optimise state lookup - } - } - -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -index ff1a0d125edd2ea10c870cbb62ae9aa23644b6dc..90c5d20d92dd0dba3503c0f8bc16ed533ca59869 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -@@ -7,6 +7,13 @@ import java.util.Optional; - public class BooleanProperty extends Property { - private final ImmutableSet values = ImmutableSet.of(true, false); - -+ // Tuinity start - optimise iblockdata state lookup -+ @Override -+ public final int getIdFor(final Boolean value) { -+ return value.booleanValue() ? 1 : 0; -+ } -+ // Tuinity end - optimise iblockdata state lookup -+ - protected BooleanProperty(String name) { - super(name, Boolean.class); - } -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -index bcf8b24e9f9e9870c1a1d27c721a6a433305d55a..32aa07141682ebdd99c2fce9b64c9f283a5d5707 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -@@ -17,6 +17,15 @@ public class EnumProperty & StringRepresentable> extends Prope - private final ImmutableSet values; - private final Map names = Maps.newHashMap(); - -+ // Tuinity start - optimise iblockdata state lookup -+ private int[] idLookupTable; -+ -+ @Override -+ public final int getIdFor(final T value) { -+ return this.idLookupTable[value.ordinal()]; -+ } -+ // Tuinity end - optimise iblockdata state lookup -+ - protected EnumProperty(String name, Class type, Collection values) { - super(name, type); - this.values = ImmutableSet.copyOf(values); -@@ -31,6 +40,14 @@ public class EnumProperty & StringRepresentable> extends Prope - this.names.put(string, enum_); - } - -+ // Tuinity start - optimise iblockdata state lookup -+ int id = 0; -+ this.idLookupTable = new int[type.getEnumConstants().length]; -+ java.util.Arrays.fill(this.idLookupTable, -1); -+ for (final T value : this.getPossibleValues()) { -+ this.idLookupTable[value.ordinal()] = id++; -+ } -+ // Tuinity end - optimise iblockdata state lookup - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -index 72f508321ebffcca31240fbdd068b4d185454cbc..346ae8ff58afd1c1f439c150c3d21143b41c3295 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -@@ -13,6 +13,16 @@ public class IntegerProperty extends Property { - public final int min; - public final int max; - -+ // Tuinity start - optimise iblockdata state lookup -+ @Override -+ public final int getIdFor(final Integer value) { -+ final int val = value.intValue(); -+ final int ret = val - this.min; -+ -+ return ret | ((this.max - ret) >> 31); -+ } -+ // Tuinity end - optimise iblockdata state lookup -+ - protected IntegerProperty(String name, int min, int max) { - super(name, Integer.class); - this.min = min; -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -index 81b43e0b0146729a8a1c6ade82634c86cde67857..9d5e76877bc06b3318c817c40821a453ac4c4a97 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -@@ -20,6 +20,17 @@ public abstract class Property> { - }, this::getName); - private final Codec> valueCodec = this.codec.xmap(this::value, Property.Value::value); - -+ // Tuinity start - optimise iblockdata state lookup -+ private static final java.util.concurrent.atomic.AtomicInteger ID_GENERATOR = new java.util.concurrent.atomic.AtomicInteger(); -+ private final int id = ID_GENERATOR.getAndIncrement(); -+ -+ public final int getId() { -+ return this.id; -+ } -+ -+ public abstract int getIdFor(final T value); -+ // Tuinity end - optimise state lookup -+ - protected Property(String name, Class type) { - this.clazz = type; - this.name = name; -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java -index 8393950a0b38ec7897d7643803d5accdb1f983f3..c8d88bbf7e765ce69101c0b04b919c9cfb99a4e2 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java -@@ -1,5 +1,6 @@ - package net.minecraft.world.level.chunk; - -+import ca.spottedleaf.starlight.light.SWMRNibbleArray; - import it.unimi.dsi.fastutil.shorts.ShortArrayList; - import it.unimi.dsi.fastutil.shorts.ShortList; - import java.util.Collection; -@@ -41,6 +42,36 @@ public interface ChunkAccess extends BlockGetter, FeatureAccess { - net.minecraft.world.level.Level getLevel(); - // Paper end - -+ // Tuinity start -+ default SWMRNibbleArray[] getBlockNibbles() { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ default void setBlockNibbles(SWMRNibbleArray[] nibbles) { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ -+ default SWMRNibbleArray[] getSkyNibbles() { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ default void setSkyNibbles(SWMRNibbleArray[] nibbles) { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ public default boolean[] getSkyEmptinessMap() { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ public default void setSkyEmptinessMap(final boolean[] emptinessMap) { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ -+ public default boolean[] getBlockEmptinessMap() { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ -+ public default void setBlockEmptinessMap(final boolean[] emptinessMap) { -+ throw new UnsupportedOperationException(this.getClass().getName()); -+ } -+ // Tuinity end -+ - BlockState getType(final int x, final int y, final int z); // Paper - @Nullable - BlockState setBlockState(BlockPos pos, BlockState state, boolean moved); -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index 4a40fa5f7c71481ef0b275955bbd81a737889781..a5d7fdd9ec0342e000e467a002846873a10d75fc 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -196,7 +196,7 @@ public abstract class ChunkGenerator { - // Get origin location (re)defined by event call. - center = new BlockPos(event.getOrigin().getBlockX(), event.getOrigin().getBlockY(), event.getOrigin().getBlockZ()); - // Get world (re)defined by event call. -- world = ((org.bukkit.craftbukkit.CraftWorld) event.getOrigin().getWorld()).getHandle(); -+ //world = ((org.bukkit.craftbukkit.CraftWorld) event.getOrigin().getWorld()).getHandle(); // Tuinity - callers and this function don't expect this to change - // Get radius and whether to find unexplored structures (re)defined by event call. - radius = event.getRadius(); - skipExistingChunks = event.shouldFindUnexplored(); -diff --git a/src/main/java/net/minecraft/world/level/chunk/DataLayer.java b/src/main/java/net/minecraft/world/level/chunk/DataLayer.java -index c4acc7e0035d37167cf5a56f8d90ba17f85cbbe3..2beae8a39987dd9c514e9d369056e65943d7b130 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/DataLayer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/DataLayer.java -@@ -12,7 +12,7 @@ public class DataLayer { - public static final int SIZE = 2048; - private static final int NIBBLE_SIZE = 4; - @Nullable -- protected byte[] data; -+ protected byte[] data; public final byte[] getDataRaw() { return this.data; } // Tuinity - provide accessor - // Paper start - public static final DataLayer EMPTY_NIBBLE_ARRAY = new DataLayer() { - @Override -@@ -62,6 +62,7 @@ public class DataLayer { - boolean poolSafe = false; - public java.lang.Runnable cleaner; - private void registerCleaner() { -+ if (true) return; // Tuinity - purge cleaner usage - if (!poolSafe) { - cleaner = net.minecraft.server.MCUtil.registerCleaner(this, this.data, DataLayer::releaseBytes); - } else { -@@ -76,7 +77,7 @@ public class DataLayer { - } - public DataLayer(byte[] bytes, boolean isSafe) { - this.data = bytes; -- if (!isSafe) this.data = getCloneIfSet(); // Paper - clone for safety -+ // Tuinity - purge cleaner usage - registerCleaner(); - // Paper end - if (bytes.length != 2048) { -@@ -162,7 +163,7 @@ public class DataLayer { - } - // Paper end - public DataLayer copy() { -- return this.data == null ? new DataLayer() : new DataLayer(this.data); // Paper - clone in ctor -+ return this.data == null ? new DataLayer() : new DataLayer(this.data.clone()); // Paper - clone in ctor // Tuinity - no longer clone in constructor - } - - public String toString() { -diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java -index 8245c5834ec69beb8e3b95fb3900601009a9273f..88f30cd8e57ccb69da633daac49f8bc9e44111da 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java -@@ -1,5 +1,6 @@ - package net.minecraft.world.level.chunk; - -+import ca.spottedleaf.starlight.light.SWMRNibbleArray; - import it.unimi.dsi.fastutil.longs.LongSet; - import java.util.BitSet; - import java.util.Map; -@@ -29,6 +30,48 @@ public class ImposterProtoChunk extends ProtoChunk { - this.wrapped = wrapped; - } - -+ // Tuinity start - rewrite light engine -+ @Override -+ public SWMRNibbleArray[] getBlockNibbles() { -+ return this.getWrapped().getBlockNibbles(); -+ } -+ -+ @Override -+ public void setBlockNibbles(SWMRNibbleArray[] nibbles) { -+ this.getWrapped().setBlockNibbles(nibbles); -+ } -+ -+ @Override -+ public SWMRNibbleArray[] getSkyNibbles() { -+ return this.getWrapped().getSkyNibbles(); -+ } -+ -+ @Override -+ public void setSkyNibbles(SWMRNibbleArray[] nibbles) { -+ this.getWrapped().setSkyNibbles(nibbles); -+ } -+ -+ @Override -+ public boolean[] getSkyEmptinessMap() { -+ return this.getWrapped().getSkyEmptinessMap(); -+ } -+ -+ @Override -+ public void setSkyEmptinessMap(boolean[] emptinessMap) { -+ this.getWrapped().setSkyEmptinessMap(emptinessMap); -+ } -+ -+ @Override -+ public boolean[] getBlockEmptinessMap() { -+ return this.getWrapped().getBlockEmptinessMap(); -+ } -+ -+ @Override -+ public void setBlockEmptinessMap(boolean[] emptinessMap) { -+ this.getWrapped().setBlockEmptinessMap(emptinessMap); -+ } -+ // Tuinity end - rewrite light engine -+ - @Nullable - @Override - public BlockEntity getBlockEntity(BlockPos pos) { -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index a84b75a53a0324fab9aeb9b80bf74eb0a84ecd2e..4f6a356e3a27915f1d95132a0a5fddb163735cf6 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -1,5 +1,7 @@ - package net.minecraft.world.level.chunk; - -+import ca.spottedleaf.starlight.light.SWMRNibbleArray; -+import ca.spottedleaf.starlight.light.StarLightEngine; - import com.google.common.collect.ImmutableList; - import com.destroystokyo.paper.exception.ServerInternalException; - import com.google.common.collect.Maps; -@@ -17,7 +19,6 @@ import java.util.Collections; - import java.util.Iterator; - import java.util.Map; - import java.util.Map.Entry; --import java.util.Objects; - import java.util.Set; - import java.util.function.Consumer; - import java.util.function.Supplier; -@@ -28,7 +29,6 @@ import net.minecraft.CrashReport; - import net.minecraft.CrashReportCategory; - import net.minecraft.ReportedException; - import net.minecraft.core.BlockPos; --import net.minecraft.core.DefaultedRegistry; - import net.minecraft.core.Registry; - import net.minecraft.core.SectionPos; - import net.minecraft.nbt.CompoundTag; -@@ -125,11 +125,62 @@ public class LevelChunk implements ChunkAccess { - private volatile boolean isLightCorrect; - private final Int2ObjectMap gameEventDispatcherSections; - -+ // Tuinity start - rewrite light engine -+ protected volatile SWMRNibbleArray[] blockNibbles; -+ protected volatile SWMRNibbleArray[] skyNibbles; -+ protected volatile boolean[] skyEmptinessMap; -+ protected volatile boolean[] blockEmptinessMap; -+ -+ @Override -+ public SWMRNibbleArray[] getBlockNibbles() { -+ return this.blockNibbles; -+ } -+ -+ @Override -+ public void setBlockNibbles(SWMRNibbleArray[] nibbles) { -+ this.blockNibbles = nibbles; -+ } -+ -+ @Override -+ public SWMRNibbleArray[] getSkyNibbles() { -+ return this.skyNibbles; -+ } -+ -+ @Override -+ public void setSkyNibbles(SWMRNibbleArray[] nibbles) { -+ this.skyNibbles = nibbles; -+ } -+ -+ @Override -+ public boolean[] getSkyEmptinessMap() { -+ return this.skyEmptinessMap; -+ } -+ -+ @Override -+ public void setSkyEmptinessMap(boolean[] emptinessMap) { -+ this.skyEmptinessMap = emptinessMap; -+ } -+ -+ @Override -+ public boolean[] getBlockEmptinessMap() { -+ return this.blockEmptinessMap; -+ } -+ -+ @Override -+ public void setBlockEmptinessMap(boolean[] emptinessMap) { -+ this.blockEmptinessMap = emptinessMap; -+ } -+ // Tuinity end - rewrite light engine -+ - public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes) { - this(world, pos, biomes, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, (LevelChunkSection[]) null, (Consumer) null); - } - - public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes, UpgradeData upgradeData, TickList blockTickScheduler, TickList fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer loadToWorldConsumer) { -+ // Tuinity start -+ this.blockNibbles = StarLightEngine.getFilledEmptyLight(world); -+ this.skyNibbles = StarLightEngine.getFilledEmptyLight(world); -+ // Tuinity end - this.pendingBlockEntities = Maps.newHashMap(); - this.tickersInLevel = Maps.newHashMap(); - this.heightmaps = Maps.newEnumMap(Heightmap.Types.class); -@@ -192,7 +243,7 @@ public class LevelChunk implements ChunkAccess { - return NEIGHBOUR_CACHE_RADIUS; - } - -- boolean loadedTicketLevel; -+ boolean loadedTicketLevel; public final boolean wasLoadCallbackInvoked() { return this.loadedTicketLevel; } // Tuinity - public accessor - private long neighbourChunksLoadedBitset; - private final LevelChunk[] loadedNeighbourChunks = new LevelChunk[(NEIGHBOUR_CACHE_RADIUS * 2 + 1) * (NEIGHBOUR_CACHE_RADIUS * 2 + 1)]; - -@@ -242,11 +293,12 @@ public class LevelChunk implements ChunkAccess { - ChunkMap chunkMap = chunkProviderServer.chunkMap; - // this code handles the addition of ticking tickets - the distance map handles the removal - if (!areNeighboursLoaded(bitsetBefore, 2) && areNeighboursLoaded(bitsetAfter, 2)) { -- if (chunkMap.playerViewDistanceTickMap.getObjectsInRange(this.coordinateKey) != null) { -+ if (chunkMap.playerChunkManager.tickMap.getObjectsInRange(this.coordinateKey) != null) { // Tuinity - replace old player chunk loading system - // now we're ready for entity ticking - chunkProviderServer.mainThreadProcessor.execute(() -> { - // double check that this condition still holds. -- if (LevelChunk.this.areNeighboursLoaded(2) && chunkMap.playerViewDistanceTickMap.getObjectsInRange(LevelChunk.this.coordinateKey) != null) { -+ if (LevelChunk.this.areNeighboursLoaded(2) && chunkMap.playerChunkManager.tickMap.getObjectsInRange(LevelChunk.this.coordinateKey) != null) { // Tuinity - replace old player chunk loading system -+ chunkMap.playerChunkManager.onChunkPlayerTickReady(this.chunkPos.x, this.chunkPos.z); // Tuinity - replace old player chunk - chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.PLAYER, LevelChunk.this.chunkPos, 31, LevelChunk.this.chunkPos); // 31 -> entity ticking, TODO check on update - } - }); -@@ -255,31 +307,18 @@ public class LevelChunk implements ChunkAccess { - - // this code handles the chunk sending - if (!areNeighboursLoaded(bitsetBefore, 1) && areNeighboursLoaded(bitsetAfter, 1)) { -- if (chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(this.coordinateKey) != null) { -- // now we're ready to send -- chunkMap.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkMap.getUpdatingChunkIfPresent(this.coordinateKey), (() -> { // Copied frm PlayerChunkMap -- // double check that this condition still holds. -- if (!LevelChunk.this.areNeighboursLoaded(1)) { -- return; -- } -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(LevelChunk.this.coordinateKey); -- if (inRange == null) { -- return; -- } -- -- // broadcast -- Object[] backingSet = inRange.getBackingSet(); -- Packet[] chunkPackets = new Packet[2]; -- for (int index = 0, len = backingSet.length; index < len; ++index) { -- Object temp = backingSet[index]; -- if (!(temp instanceof net.minecraft.server.level.ServerPlayer)) { -- continue; -- } -- net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)temp; -- chunkMap.playerLoadedChunk(player, chunkPackets, LevelChunk.this); -- } -- }))); -- } -+ // Tuinity start - replace old player chunk loading system -+ chunkProviderServer.mainThreadProcessor.execute(() -> { -+ if (!LevelChunk.this.areNeighboursLoaded(1)) { -+ return; -+ } -+ LevelChunk.this.postProcessGeneration(); -+ if (!LevelChunk.this.areNeighboursLoaded(1)) { -+ return; -+ } -+ chunkMap.playerChunkManager.onChunkSendReady(this.chunkPos.x, this.chunkPos.z); -+ }); -+ // Tuinity end - replace old player chunk loading system - } - // Paper end - no-tick view distance - } -@@ -330,9 +369,102 @@ public class LevelChunk implements ChunkAccess { - } - } - // Paper end -+ // Tuinity start - optimise checkDespawn -+ private boolean playerGeneralAreaCacheSet; -+ private com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playerGeneralAreaCache; -+ -+ public com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getPlayerGeneralAreaCache() { -+ if (!this.playerGeneralAreaCacheSet) { -+ this.updateGeneralAreaCache(); -+ } -+ return this.playerGeneralAreaCache; -+ } -+ -+ public void updateGeneralAreaCache() { -+ this.updateGeneralAreaCache(((ServerLevel)this.level).getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(this.coordinateKey)); -+ } -+ -+ public void updateGeneralAreaCache(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet value) { -+ this.playerGeneralAreaCacheSet = true; -+ this.playerGeneralAreaCache = value; -+ } -+ -+ public net.minecraft.server.level.ServerPlayer findNearestPlayer(double sourceX, double sourceY, double sourceZ, -+ double maxRange, java.util.function.Predicate predicate) { -+ if (!this.playerGeneralAreaCacheSet) { -+ this.updateGeneralAreaCache(); -+ } -+ -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby = this.playerGeneralAreaCache; -+ -+ if (nearby == null) { -+ return null; -+ } -+ -+ Object[] backingSet = nearby.getBackingSet(); -+ double closestDistance = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange; -+ net.minecraft.server.level.ServerPlayer closest = null; -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object _player = backingSet[i]; -+ if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) { -+ continue; -+ } -+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player; -+ -+ double distance = player.distanceToSqr(sourceX, sourceY, sourceZ); -+ if (distance < closestDistance && predicate.test(player)) { -+ closest = player; -+ closestDistance = distance; -+ } -+ } -+ -+ return closest; -+ } -+ -+ public void getNearestPlayers(double sourceX, double sourceY, double sourceZ, java.util.function.Predicate predicate, -+ double range, java.util.List ret) { -+ if (!this.playerGeneralAreaCacheSet) { -+ this.updateGeneralAreaCache(); -+ } -+ -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby = this.playerGeneralAreaCache; -+ -+ if (nearby == null) { -+ return; -+ } -+ -+ double rangeSquared = range * range; -+ -+ Object[] backingSet = nearby.getBackingSet(); -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object _player = backingSet[i]; -+ if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) { -+ continue; -+ } -+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player; -+ -+ if (range >= 0.0) { -+ double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ); -+ if (distanceSquared > rangeSquared) { -+ continue; -+ } -+ } -+ -+ if (predicate == null || predicate.test(player)) { -+ ret.add(player); -+ } -+ } -+ } -+ // Tuinity end - optimise checkDespawn - - public LevelChunk(ServerLevel worldserver, ProtoChunk protoChunk, @Nullable Consumer consumer) { - this(worldserver, protoChunk.getPos(), protoChunk.getBiomes(), protoChunk.getUpgradeData(), protoChunk.getBlockTicks(), protoChunk.getLiquidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), consumer); -+ // Tuinity start - copy over protochunk light -+ this.setBlockNibbles(protoChunk.getBlockNibbles()); -+ this.setSkyNibbles(protoChunk.getSkyNibbles()); -+ this.setSkyEmptinessMap(protoChunk.getSkyEmptinessMap()); -+ this.setBlockEmptinessMap(protoChunk.getBlockEmptinessMap()); -+ // Tuinity end - copy over protochunk light - Iterator iterator = protoChunk.getBlockEntities().values().iterator(); - - while (iterator.hasNext()) { -@@ -794,6 +926,7 @@ public class LevelChunk implements ChunkAccess { - - // CraftBukkit start - public void loadCallback() { -+ if (this.loadedTicketLevel) { LOGGER.error("Double calling chunk load!", new Throwable()); } // Tuinity - // Paper start - neighbour cache - int chunkX = this.chunkPos.x; - int chunkZ = this.chunkPos.z; -@@ -813,6 +946,7 @@ public class LevelChunk implements ChunkAccess { - // Paper end - neighbour cache - org.bukkit.Server server = this.level.getCraftServer(); - this.level.getChunkSource().addLoadedChunk(this); // Paper -+ ((ServerLevel)this.level).getChunkSource().chunkMap.playerChunkManager.onChunkLoad(this.chunkPos.x, this.chunkPos.z); // Tuinity - rewrite player chunk management - if (server != null) { - /* - * If it's a new world, the first few chunks are generated inside -@@ -848,6 +982,7 @@ public class LevelChunk implements ChunkAccess { - } - - public void unloadCallback() { -+ if (!this.loadedTicketLevel) { LOGGER.error("Double calling chunk unload!", new Throwable()); } // Tuinity - org.bukkit.Server server = this.level.getCraftServer(); - org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(this.bukkitChunk, this.isUnsaved()); - server.getPluginManager().callEvent(unloadEvent); -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -index cdac1f7b30e4c043dcb12ac9e29af926df8170bd..5d2f76eeb4aef0a5ee8c202c1c682171d4d5b2ea 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -18,7 +18,8 @@ public class LevelChunkSection { - short nonEmptyBlockCount; // Paper - package-private - private short tickingBlockCount; - private short tickingFluidCount; -- final PalettedContainer states; // Paper - package-private -+ public final PalettedContainer states; // Paper - package-private // Tuinity - public -+ public final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper - - // Paper start - Anti-Xray - Add parameters - @Deprecated public LevelChunkSection(int yOffset) { this(yOffset, null, null, true); } // Notice for updates: Please make sure this constructor isn't used anywhere -@@ -79,6 +80,9 @@ public class LevelChunkSection { - --this.nonEmptyBlockCount; - if (blockState.isRandomlyTicking()) { - --this.tickingBlockCount; -+ // Paper start -+ this.tickingList.remove(x, y, z); -+ // Paper end - } - } - -@@ -90,6 +94,9 @@ public class LevelChunkSection { - ++this.nonEmptyBlockCount; - if (state.isRandomlyTicking()) { - ++this.tickingBlockCount; -+ // Paper start -+ this.tickingList.add(x, y, z, state); -+ // Paper end - } - } - -@@ -125,22 +132,28 @@ public class LevelChunkSection { - } - - public void recalcBlockCounts() { -+ // Paper start -+ this.tickingList.clear(); -+ // Paper end - this.nonEmptyBlockCount = 0; - this.tickingBlockCount = 0; - this.tickingFluidCount = 0; -- this.states.count((state, count) -> { -+ this.states.forEachLocation((state, location) -> { // Paper - FluidState fluidState = state.getFluidState(); - if (!state.isAir()) { -- this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + count); -+ this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + 1); // Paper - if (state.isRandomlyTicking()) { -- this.tickingBlockCount = (short)(this.tickingBlockCount + count); -+ // Paper start -+ this.tickingBlockCount = (short)(this.tickingBlockCount + 1); -+ this.tickingList.add(location, state); -+ // Paper end - } - } - - if (!fluidState.isEmpty()) { -- this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + count); -+ this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + 1); // Paper - if (fluidState.isRandomlyTicking()) { -- this.tickingFluidCount = (short)(this.tickingFluidCount + count); -+ this.tickingFluidCount = (short)(this.tickingFluidCount + 1); // Paper - } - } - -diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -index 554474d4b2e57d8a005b3c3b9b23f32a62243058..ebeb3e3b0619b034a9681da999e9ac33cc241718 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -@@ -174,7 +174,7 @@ public class PalettedContainer implements PaletteResize { - return this.get(y << 8 | z << 4 | x); // Paper - inline - } - -- protected T get(int index) { -+ public T get(int index) { // Tuinity - public - T object = this.palette.valueFor(this.storage.get(index)); - return (T)(object == null ? this.defaultValue : object); - } -@@ -320,4 +320,12 @@ public class PalettedContainer implements PaletteResize { - public interface CountConsumer { - void accept(T object, int count); - } -+ -+ // Paper start -+ public void forEachLocation(PalettedContainer.CountConsumer datapaletteblock_a) { -+ this.storage.forEach((int location, int data) -> { -+ datapaletteblock_a.accept(this.palette.valueFor(data), location); -+ }); -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java -index 7dc3d806a680150c6a2fffa1436fd63bbdc31eb3..f6d05372f592a3b7619ad6989630c140ffd4f03b 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java -@@ -1,5 +1,7 @@ - package net.minecraft.world.level.chunk; - -+import ca.spottedleaf.starlight.light.SWMRNibbleArray; -+import ca.spottedleaf.starlight.light.StarLightEngine; - import com.google.common.collect.Lists; - import com.google.common.collect.Maps; - import com.google.common.collect.Sets; -@@ -72,6 +74,53 @@ public class ProtoChunk implements ChunkAccess { - // Paper end - private static boolean PRINTED_OUTDATED_CTOR_MSG = false; // Paper - Add level - -+ // Tuinity start - rewrite light engine -+ protected volatile SWMRNibbleArray[] blockNibbles; -+ protected volatile SWMRNibbleArray[] skyNibbles; -+ protected volatile boolean[] skyEmptinessMap; -+ protected volatile boolean[] blockEmptinessMap; -+ -+ @Override -+ public SWMRNibbleArray[] getBlockNibbles() { -+ return this.blockNibbles; -+ } -+ -+ @Override -+ public void setBlockNibbles(SWMRNibbleArray[] nibbles) { -+ this.blockNibbles = nibbles; -+ } -+ -+ @Override -+ public SWMRNibbleArray[] getSkyNibbles() { -+ return this.skyNibbles; -+ } -+ -+ @Override -+ public void setSkyNibbles(SWMRNibbleArray[] nibbles) { -+ this.skyNibbles = nibbles; -+ } -+ -+ @Override -+ public boolean[] getSkyEmptinessMap() { -+ return this.skyEmptinessMap; -+ } -+ -+ @Override -+ public void setSkyEmptinessMap(boolean[] emptinessMap) { -+ this.skyEmptinessMap = emptinessMap; -+ } -+ -+ @Override -+ public boolean[] getBlockEmptinessMap() { -+ return this.blockEmptinessMap; -+ } -+ -+ @Override -+ public void setBlockEmptinessMap(boolean[] emptinessMap) { -+ this.blockEmptinessMap = emptinessMap; -+ } -+ // Tuinity end - rewrite light engine -+ - @Deprecated // Paper start - add level - public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world) { - // Paper start -@@ -100,6 +149,10 @@ public class ProtoChunk implements ChunkAccess { - } - } - public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, @Nullable LevelChunkSection[] levelChunkSections, ProtoTickList blockTickScheduler, ProtoTickList fluidTickScheduler, LevelHeightAccessor world, net.minecraft.server.level.ServerLevel level) { -+ // Tuinity start -+ this.blockNibbles = StarLightEngine.getFilledEmptyLight(world); -+ this.skyNibbles = StarLightEngine.getFilledEmptyLight(world); -+ // Tuinity end - this.level = level; - // Paper end - this.chunkPos = pos; -@@ -197,7 +250,7 @@ public class ProtoChunk implements ChunkAccess { - - LevelChunkSection levelChunkSection = this.getOrCreateSection(l); - BlockState blockState = levelChunkSection.setBlockState(i & 15, j & 15, k & 15, state); -- if (this.status.isOrAfter(ChunkStatus.FEATURES) && state != blockState && (state.getLightBlock(this, pos) != blockState.getLightBlock(this, pos) || state.getLightEmission() != blockState.getLightEmission() || state.useShapeForLightOcclusion() || blockState.useShapeForLightOcclusion())) { -+ if (this.status.isOrAfter(ChunkStatus.LIGHT) && state != blockState && (state.getLightBlock(this, pos) != blockState.getLightBlock(this, pos) || state.getLightEmission() != blockState.getLightEmission() || state.useShapeForLightOcclusion() || blockState.useShapeForLightOcclusion())) { // Tuinity - move block updates to only happen after lighting occurs (or during, thanks chunk system) - this.lightEngine.checkBlock(pos); - } - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 9ee2321150d3de7bf1a11c212951bc69872f4dd8..9815a91040e7cbcbcd171e68b0a935ea26ff8a2a 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -65,6 +65,21 @@ import org.apache.logging.log4j.Logger; - - public class ChunkSerializer { - -+ // Tuinity start - replace light engine impl -+ private static final int STARLIGHT_LIGHT_VERSION = 5; -+ -+ private static final String BLOCKLIGHT_STATE_TAG = "starlight.blocklight_state"; -+ private static final String SKYLIGHT_STATE_TAG = "starlight.skylight_state"; -+ private static final String STARLIGHT_VERSION_TAG = "starlight.light_version"; -+ // Tuinity end - replace light engine impl -+ // Tuinity start -+ // TODO: Check on update -+ public static long getLastWorldSaveTime(CompoundTag chunkData) { -+ CompoundTag levelData = chunkData.getCompound("Level"); -+ return levelData.getLong("LastUpdate"); -+ } -+ // Tuinity end -+ - private static final Logger LOGGER = LogManager.getLogger(); - public static final String TAG_UPGRADE_DATA = "UpgradeData"; - -@@ -118,7 +133,7 @@ public class ChunkSerializer { - } - // Paper end - BiomeSource worldchunkmanager = chunkgenerator.getBiomeSource(); -- CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate -+ CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate // Tuinity - diff on change - ChunkPos chunkcoordintpair1 = new ChunkPos(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate - - if (!Objects.equals(pos, chunkcoordintpair1)) { -@@ -133,13 +148,20 @@ public class ChunkSerializer { - ProtoTickList protochunkticklist1 = new ProtoTickList<>((fluidtype) -> { - return fluidtype == null || fluidtype == Fluids.EMPTY; - }, pos, nbttagcompound1.getList("LiquidsToBeTicked", 9), world); -- boolean flag = nbttagcompound1.getBoolean("isLightOn"); -+ boolean flag = getStatus(nbt).isOrAfter(ChunkStatus.LIGHT) && nbttagcompound1.get("isLightOn") != null && nbttagcompound1.getInt(STARLIGHT_VERSION_TAG) == STARLIGHT_LIGHT_VERSION; // Tuinity - ListTag nbttaglist = nbttagcompound1.getList("Sections", 10); - int i = world.getSectionsCount(); - LevelChunkSection[] achunksection = new LevelChunkSection[i]; - boolean flag1 = world.dimensionType().hasSkyLight(); - ServerChunkCache chunkproviderserver = world.getChunkSource(); - LevelLightEngine lightengine = chunkproviderserver.getLightEngine(); -+ // Tuinity start -+ ca.spottedleaf.starlight.light.SWMRNibbleArray[] blockNibbles = ca.spottedleaf.starlight.light.StarLightEngine.getFilledEmptyLight(world); // Tuinity - replace light impl -+ ca.spottedleaf.starlight.light.SWMRNibbleArray[] skyNibbles = ca.spottedleaf.starlight.light.StarLightEngine.getFilledEmptyLight(world); // Tuinity - replace light impl -+ final int minSection = com.tuinity.tuinity.util.WorldUtil.getMinLightSection(world); -+ final int maxSection = com.tuinity.tuinity.util.WorldUtil.getMaxLightSection(world); -+ boolean canReadSky = world.dimensionType().hasSkyLight(); -+ // Tuinity end - - if (flag) { - tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main -@@ -148,7 +170,7 @@ public class ChunkSerializer { - } - - for (int j = 0; j < nbttaglist.size(); ++j) { -- CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); -+ CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); CompoundTag sectionData = nbttagcompound2; // Tuinity - byte b0 = nbttagcompound2.getByte("Y"); - - if (nbttagcompound2.contains("Palette", 9) && nbttagcompound2.contains("BlockStates", 12)) { -@@ -166,23 +188,29 @@ public class ChunkSerializer { - } - - if (flag) { -- if (nbttagcompound2.contains("BlockLight", 7)) { -- // Paper start - delay this task since we're executing off-main -- DataLayer blockLight = new DataLayer(nbttagcompound2.getByteArray("BlockLight")); -- tasksToExecuteOnMain.add(() -> { -- lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkcoordintpair1, b0), blockLight, true); -- }); -- // Paper end - delay this task since we're executing off-main -+ // Tuinity start - rewrite light engine -+ int y = sectionData.getByte("Y"); -+ -+ if (sectionData.contains("BlockLight", 7)) { -+ // this is where our diff is -+ blockNibbles[y - minSection] = new ca.spottedleaf.starlight.light.SWMRNibbleArray(sectionData.getByteArray("BlockLight").clone(), sectionData.getInt(BLOCKLIGHT_STATE_TAG)); // clone for data safety -+ } else { -+ blockNibbles[y - minSection] = new ca.spottedleaf.starlight.light.SWMRNibbleArray(null, sectionData.getInt(BLOCKLIGHT_STATE_TAG)); - } - -- if (flag1 && nbttagcompound2.contains("SkyLight", 7)) { -- // Paper start - delay this task since we're executing off-main -- DataLayer skyLight = new DataLayer(nbttagcompound2.getByteArray("SkyLight")); -- tasksToExecuteOnMain.add(() -> { -- lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkcoordintpair1, b0), skyLight, true); -- }); -- // Paper end - delay this task since we're executing off-main -+ if (canReadSky) { -+ if (sectionData.contains("SkyLight", 7)) { -+ // we store under the same key so mod programs editing nbt -+ // can still read the data, hopefully. -+ // however, for compatibility we store chunks as unlit so vanilla -+ // is forced to re-light them if it encounters our data. It's too much of a burden -+ // to try and maintain compatibility with a broken and inferior skylight management system. -+ skyNibbles[y - minSection] = new ca.spottedleaf.starlight.light.SWMRNibbleArray(sectionData.getByteArray("SkyLight").clone(), sectionData.getInt(SKYLIGHT_STATE_TAG)); // clone for data safety -+ } else { -+ skyNibbles[y - minSection] = new ca.spottedleaf.starlight.light.SWMRNibbleArray(null, sectionData.getInt(SKYLIGHT_STATE_TAG)); -+ } - } -+ // Tuinity end - rewrite light engine - } - } - -@@ -226,8 +254,12 @@ public class ChunkSerializer { - object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, // Paper start - fix massive nbt memory leak due to lambda. move lambda into a container method to not leak scope. Only clone needed NBT keys. - createLoadEntitiesConsumer(new SafeNBTCopy(nbttagcompound1, "TileEntities", "Entities", "ChunkBukkitValues")) // Paper - move CB Chunk PDC into here - );// Paper end -+ ((LevelChunk)object).setBlockNibbles(blockNibbles); // Tuinity - replace light impl -+ ((LevelChunk)object).setSkyNibbles(skyNibbles); // Tuinity - replace light impl - } else { - ProtoChunk protochunk = new ProtoChunk(pos, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, world, world); // Paper - add level -+ protochunk.setBlockNibbles(blockNibbles); // Tuinity - replace light impl -+ protochunk.setSkyNibbles(skyNibbles); // Tuinity - replace light impl - - protochunk.setBiomes(biomestorage); - object = protochunk; -@@ -408,7 +440,7 @@ public class ChunkSerializer { - DataLayer[] blockLight = new DataLayer[lightenginethreaded.getMaxLightSection() - lightenginethreaded.getMinLightSection()]; - DataLayer[] skyLight = new DataLayer[lightenginethreaded.getMaxLightSection() - lightenginethreaded.getMinLightSection()]; - -- for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { -+ for (int i = lightenginethreaded.getMinLightSection(); false && i < lightenginethreaded.getMaxLightSection(); ++i) { // Tuinity - don't run loop, we don't need to - light data is per chunk now - DataLayer blockArray = lightenginethreaded.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(chunkPos, i)); - DataLayer skyArray = lightenginethreaded.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(chunkPos, i)); - -@@ -457,6 +489,12 @@ public class ChunkSerializer { - return saveChunk(world, chunk, null); - } - public static CompoundTag saveChunk(ServerLevel world, ChunkAccess chunk, AsyncSaveData asyncsavedata) { -+ // Tuinity start - rewrite light impl -+ final int minSection = com.tuinity.tuinity.util.WorldUtil.getMinLightSection(world); -+ final int maxSection = com.tuinity.tuinity.util.WorldUtil.getMaxLightSection(world); -+ ca.spottedleaf.starlight.light.SWMRNibbleArray[] blockNibbles = chunk.getBlockNibbles(); -+ ca.spottedleaf.starlight.light.SWMRNibbleArray[] skyNibbles = chunk.getSkyNibbles(); -+ // Tuinity end - rewrite light impl - // Paper end - ChunkPos chunkcoordintpair = chunk.getPos(); - CompoundTag nbttagcompound = new CompoundTag(); -@@ -466,7 +504,7 @@ public class ChunkSerializer { - nbttagcompound.put("Level", nbttagcompound1); - nbttagcompound1.putInt("xPos", chunkcoordintpair.x); - nbttagcompound1.putInt("zPos", chunkcoordintpair.z); -- nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading -+ nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading // Tuinity - diff on change - nbttagcompound1.putLong("InhabitedTime", chunk.getInhabitedTime()); - nbttagcompound1.putString("Status", chunk.getStatus().getName()); - UpgradeData chunkconverter = chunk.getUpgradeData(); -@@ -485,32 +523,33 @@ public class ChunkSerializer { - LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> { - return chunksection1 != null && SectionPos.blockToSectionCoord(chunksection1.bottomBlockY()) == finalI; // CraftBukkit - decompile errors - }).findFirst().orElse(LevelChunk.EMPTY_SECTION); -- // Paper start - async chunk save for unload -- DataLayer nibblearray; // block light -- DataLayer nibblearray1; // sky light -- if (asyncsavedata == null) { -- nibblearray = lightenginethreaded.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(chunkcoordintpair, i)); /// Paper - diff on method change (see getAsyncSaveData) -- nibblearray1 = lightenginethreaded.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(chunkcoordintpair, i)); // Paper - diff on method change (see getAsyncSaveData) -- } else { -- nibblearray = asyncsavedata.blockLight[i - lightenginethreaded.getMinLightSection()]; -- nibblearray1 = asyncsavedata.skyLight[i - lightenginethreaded.getMinLightSection()]; -- } -- // Paper end -- if (chunksection != LevelChunk.EMPTY_SECTION || nibblearray != null || nibblearray1 != null) { -- CompoundTag nbttagcompound2 = new CompoundTag(); -+ // Tuinity start - replace light engine -+ ca.spottedleaf.starlight.light.SWMRNibbleArray.SaveState blockNibble = blockNibbles[i - minSection].getSaveState(); -+ ca.spottedleaf.starlight.light.SWMRNibbleArray.SaveState skyNibble = skyNibbles[i - minSection].getSaveState(); -+ if (chunksection != LevelChunk.EMPTY_SECTION || blockNibble != null || skyNibble != null) { -+ // Tuinity end - replace light engine -+ CompoundTag nbttagcompound2 = new CompoundTag(); CompoundTag section = nbttagcompound2; // Tuinity - - nbttagcompound2.putByte("Y", (byte) (i & 255)); - if (chunksection != LevelChunk.EMPTY_SECTION) { - chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates"); - } - -- if (nibblearray != null && !nibblearray.isEmpty()) { -- nbttagcompound2.putByteArray("BlockLight", nibblearray.asBytesPoolSafe().clone()); // Paper -+ // Tuinity start - replace light engine -+ if (blockNibble != null) { -+ if (blockNibble.data != null) { -+ section.putByteArray("BlockLight", blockNibble.data); -+ } -+ section.putInt(BLOCKLIGHT_STATE_TAG, blockNibble.state); - } - -- if (nibblearray1 != null && !nibblearray1.isEmpty()) { -- nbttagcompound2.putByteArray("SkyLight", nibblearray1.asBytesPoolSafe().clone()); // Paper -+ if (skyNibble != null) { -+ if (skyNibble.data != null) { -+ section.putByteArray("SkyLight", skyNibble.data); -+ } -+ section.putInt(SKYLIGHT_STATE_TAG, skyNibble.state); - } -+ // Tuinity end - replace light engine - - nbttaglist.add(nbttagcompound2); - } -@@ -518,7 +557,8 @@ public class ChunkSerializer { - - nbttagcompound1.put("Sections", nbttaglist); - if (flag) { -- nbttagcompound1.putBoolean("isLightOn", true); -+ nbttagcompound1.putInt(STARLIGHT_VERSION_TAG, STARLIGHT_LIGHT_VERSION); // Tuinity -+ nbttagcompound1.putBoolean("isLightOn", false); // Tuinity - set to false but still store, this allows us to detect --eraseCache (as eraseCache _removes_) - } - - ChunkBiomeContainer biomestorage = chunk.getBiomes(); -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -index 176610b31f66b890afe61f4de46c412382bb8d22..776f4b5335621e5237ab9339604a097e9e4d0935 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -@@ -34,12 +34,13 @@ public class ChunkStorage implements AutoCloseable { - this.fixerUpper = dataFixer; - // Paper start - async chunk io - // remove IO worker -- this.regionFileCache = new RegionFileStorage(directory, dsync); // Paper - nuke IOWorker -+ this.regionFileCache = new RegionFileStorage(directory, dsync, true); // Paper - nuke IOWorker // Tuinity - // Paper end - async chunk io - } - - // CraftBukkit start - private boolean check(ServerChunkCache cps, int x, int z) throws IOException { -+ if (true) return true; // Tuinity - this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full" - ChunkPos pos = new ChunkPos(x, z); - if (cps != null) { - //com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); // Paper - this function is now MT-Safe -@@ -74,7 +75,7 @@ public class ChunkStorage implements AutoCloseable { - boolean flag = true; - - // CraftBukkit start -- if (i < 1466) { -+ if (false && i < 1466) { // Tuinity - no longer needed, data converter system handles it now - CompoundTag level = nbttagcompound.getCompound("Level"); - if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) { - ServerChunkCache cps = (generatoraccess == null) ? null : ((ServerLevel) generatoraccess).getChunkSource(); -@@ -86,7 +87,7 @@ public class ChunkStorage implements AutoCloseable { - // CraftBukkit end - - if (i < 1493) { -- nbttagcompound = NbtUtils.update(this.fixerUpper, DataFixTypes.CHUNK, nbttagcompound, i, 1493); -+ ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbttagcompound, i, 1493); // Tuinity - replace chunk converter - if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { - synchronized (this.persistentDataLock) { // Paper - Async chunk loading - if (this.legacyStructureHandler == null) { -@@ -98,7 +99,7 @@ public class ChunkStorage implements AutoCloseable { - } - } - -- nbttagcompound = NbtUtils.update(this.fixerUpper, DataFixTypes.CHUNK, nbttagcompound, Math.max(1493, i)); -+ nbttagcompound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbttagcompound, Math.max(1493, i), SharedConstants.getCurrentVersion().getWorldVersion()); // Tuinity - replace chunk converter - if (i < SharedConstants.getCurrentVersion().getWorldVersion()) { - nbttagcompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion()); - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -index 396c34c0866bf395b4d86361d96fe103c5d9ae7e..91d692e9337c2ec6824829259ea6ea1ad343d21a 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -@@ -128,7 +128,7 @@ public class EntityStorage implements EntityPersistentStorage { - - private CompoundTag upgradeChunkTag(CompoundTag chunkTag) { - int i = getVersion(chunkTag); -- return NbtUtils.update(this.fixerUpper, DataFixTypes.ENTITY_CHUNK, chunkTag, i); -+ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, chunkTag, i, SharedConstants.getCurrentVersion().getWorldVersion()); // Tuinity - route to new converter system - } - - public static int getVersion(CompoundTag chunkTag) { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java -index c8298a597818227de33a4afce4698ec0666cf758..b49b0c4cac8aec09ffe970c92e5a75047c0e1f1d 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java -@@ -9,6 +9,27 @@ import java.util.BitSet; - public class RegionBitmap { - private final BitSet used = new BitSet(); - -+ // Tuinity start -+ public final void copyFrom(RegionBitmap other) { -+ BitSet thisBitset = this.used; -+ BitSet otherBitset = other.used; -+ -+ for (int i = 0; i < Math.max(thisBitset.size(), otherBitset.size()); ++i) { -+ thisBitset.set(i, otherBitset.get(i)); -+ } -+ } -+ -+ public final boolean tryAllocate(int from, int length) { -+ BitSet bitset = this.used; -+ int firstSet = bitset.nextSetBit(from); -+ if (firstSet > 0 && firstSet < (from + length)) { -+ return false; -+ } -+ bitset.set(from, from + length); -+ return true; -+ } -+ // Tuinity end -+ - public void force(int start, int size) { - this.used.set(start, start + size); - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index c22391a0d4b7db49bd3994b0887939a7d8019391..118adb6fbdc56ca03652f114c1b7ced0ef26a628 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -55,6 +55,341 @@ public class RegionFile implements AutoCloseable { - public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper - public final File regionFile; // Paper - -+ // Tuinity start - try to recover from RegionFile header corruption -+ private static long roundToSectors(long bytes) { -+ long sectors = bytes >>> 12; // 4096 = 2^12 -+ long remainingBytes = bytes & 4095; -+ long sign = -remainingBytes; // sign is 1 if nonzero -+ return sectors + (sign >>> 63); -+ } -+ -+ private static final CompoundTag OVERSIZED_COMPOUND = new CompoundTag(); -+ -+ private CompoundTag attemptRead(long sector, int chunkDataLength, long fileLength) throws IOException { -+ try { -+ if (chunkDataLength < 0) { -+ return null; -+ } -+ -+ long offset = sector * 4096L + 4L; // offset for chunk data -+ -+ if ((offset + chunkDataLength) > fileLength) { -+ return null; -+ } -+ -+ ByteBuffer chunkData = ByteBuffer.allocate(chunkDataLength); -+ if (chunkDataLength != this.file.read(chunkData, offset)) { -+ return null; -+ } -+ -+ ((java.nio.Buffer)chunkData).flip(); -+ -+ byte compressionType = chunkData.get(); -+ if (compressionType < 0) { // compressionType & 128 != 0 -+ // oversized chunk -+ return OVERSIZED_COMPOUND; -+ } -+ -+ RegionFileVersion compression = RegionFileVersion.fromId(compressionType); -+ if (compression == null) { -+ return null; -+ } -+ -+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position())); -+ -+ return NbtIo.read((java.io.DataInput)new DataInputStream(new BufferedInputStream(input))); -+ } catch (Exception ex) { -+ return null; -+ } -+ } -+ -+ private int getLength(long sector) throws IOException { -+ ByteBuffer length = ByteBuffer.allocate(4); -+ if (4 != this.file.read(length, sector * 4096L)) { -+ return -1; -+ } -+ -+ return length.getInt(0); -+ } -+ -+ private void backupRegionFile() { -+ File backup = new File(this.regionFile.getParent(), this.regionFile.getName() + "." + new java.util.Random().nextLong() + ".backup"); -+ this.backupRegionFile(backup); -+ } -+ -+ private void backupRegionFile(File to) { -+ try { -+ this.file.force(true); -+ LOGGER.warn("Backing up regionfile \"" + this.regionFile.getAbsolutePath() + "\" to " + to.getAbsolutePath()); -+ java.nio.file.Files.copy(this.regionFile.toPath(), to.toPath()); -+ LOGGER.warn("Backed up the regionfile to " + to.getAbsolutePath()); -+ } catch (IOException ex) { -+ LOGGER.error("Failed to backup to " + to.getAbsolutePath(), ex); -+ } -+ } -+ -+ // note: only call for CHUNK regionfiles -+ void recalculateHeader() throws IOException { -+ if (!this.canRecalcHeader) { -+ return; -+ } -+ synchronized (this) { -+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.regionFile.getAbsolutePath(), new Throwable()); -+ -+ // try to backup file so maybe it could be sent to us for further investigation -+ -+ this.backupRegionFile(); -+ CompoundTag[] compounds = new CompoundTag[32 * 32]; // only in the regionfile (i.e exclude mojang/aikar oversized data) -+ int[] rawLengths = new int[32 * 32]; // length of chunk data including 4 byte length field, bytes -+ int[] sectorOffsets = new int[32 * 32]; // in sectors -+ boolean[] hasAikarOversized = new boolean[32 * 32]; -+ -+ long fileLength = this.file.size(); -+ long totalSectors = roundToSectors(fileLength); -+ -+ // search the regionfile from start to finish for the most up-to-date chunk data -+ -+ for (long i = 2, maxSector = Math.min((long)(Integer.MAX_VALUE >>> 8), totalSectors); i < maxSector; ++i) { // first two sectors are header, skip -+ int chunkDataLength = this.getLength(i); -+ CompoundTag compound = this.attemptRead(i, chunkDataLength, fileLength); -+ if (compound == null || compound == OVERSIZED_COMPOUND) { -+ continue; -+ } -+ -+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(compound); -+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5); -+ -+ CompoundTag otherCompound = compounds[location]; -+ -+ if (otherCompound != null && ChunkSerializer.getLastWorldSaveTime(otherCompound) > ChunkSerializer.getLastWorldSaveTime(compound)) { -+ continue; // don't overwrite newer data. -+ } -+ -+ // aikar oversized? -+ File aikarOversizedFile = this.getOversizedFile(chunkPos.x, chunkPos.z); -+ boolean isAikarOversized = false; -+ if (aikarOversizedFile.exists()) { -+ try { -+ CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z); -+ if (ChunkSerializer.getLastWorldSaveTime(compound) == ChunkSerializer.getLastWorldSaveTime(aikarOversizedCompound)) { -+ // best we got for an id. hope it's good enough -+ isAikarOversized = true; -+ } -+ } catch (Exception ex) { -+ LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x + "," + chunkPos.z + ") in regionfile " + this.regionFile.getAbsolutePath() + ", oversized data for this chunk will be lost", ex); -+ // fall through, if we can't read aikar oversized we can't risk corrupting chunk data -+ } -+ } -+ -+ hasAikarOversized[location] = isAikarOversized; -+ compounds[location] = compound; -+ rawLengths[location] = chunkDataLength + 4; -+ sectorOffsets[location] = (int)i; -+ -+ int chunkSectorLength = (int)roundToSectors(rawLengths[location]); -+ i += chunkSectorLength; -+ --i; // gets incremented next iteration -+ } -+ -+ // forge style oversized data is already handled by the local search, and aikar data we just hope -+ // we get it right as aikar data has no identifiers we could use to try and find its corresponding -+ // local data compound -+ -+ java.nio.file.Path containingFolder = this.externalFileDir; -+ File[] regionFiles = containingFolder.toFile().listFiles(); -+ boolean[] oversized = new boolean[32 * 32]; -+ RegionFileVersion[] oversizedCompressionTypes = new RegionFileVersion[32 * 32]; -+ -+ if (regionFiles != null) { -+ ChunkPos ourLowerLeftPosition = RegionFileStorage.getRegionFileCoordinates(this.regionFile); -+ -+ if (ourLowerLeftPosition == null) { -+ LOGGER.fatal("Unable to get chunk location of regionfile " + this.regionFile.getAbsolutePath() + ", cannot recover oversized chunks"); -+ } else { -+ int lowerXBound = ourLowerLeftPosition.x; // inclusive -+ int lowerZBound = ourLowerLeftPosition.z; // inclusive -+ int upperXBound = lowerXBound + 32 - 1; // inclusive -+ int upperZBound = lowerZBound + 32 - 1; // inclusive -+ -+ // read mojang oversized data -+ for (File regionFile : regionFiles) { -+ ChunkPos oversizedCoords = getOversizedChunkPair(regionFile); -+ if (oversizedCoords == null) { -+ continue; -+ } -+ -+ if ((oversizedCoords.x < lowerXBound || oversizedCoords.x > upperXBound) || (oversizedCoords.z < lowerZBound || oversizedCoords.z > upperZBound)) { -+ continue; // not in our regionfile -+ } -+ -+ // ensure oversized data is valid & is newer than data in the regionfile -+ -+ int location = (oversizedCoords.x & 31) | ((oversizedCoords.z & 31) << 5); -+ -+ byte[] chunkData; -+ try { -+ chunkData = Files.readAllBytes(regionFile.toPath()); -+ } catch (Exception ex) { -+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.getAbsolutePath() + ", data will be lost", ex); -+ continue; -+ } -+ -+ CompoundTag compound = null; -+ -+ // We do not know the compression type, as it's stored in the regionfile. So we need to try all of them -+ RegionFileVersion compression = null; -+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) { -+ try { -+ DataInputStream in = new DataInputStream(new BufferedInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData)))); // typical java -+ compound = NbtIo.read((java.io.DataInput)in); -+ compression = compressionType; -+ break; // reaches here iff readNBT does not throw -+ } catch (Exception ex) { -+ continue; -+ } -+ } -+ -+ if (compound == null) { -+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.getAbsolutePath() + ", it's corrupt. Its data will be lost"); -+ continue; -+ } -+ -+ if (compounds[location] == null || ChunkSerializer.getLastWorldSaveTime(compound) > ChunkSerializer.getLastWorldSaveTime(compounds[location])) { -+ oversized[location] = true; -+ oversizedCompressionTypes[location] = compression; -+ } -+ } -+ } -+ } -+ -+ // now we need to calculate a new offset header -+ -+ int[] calculatedOffsets = new int[32 * 32]; -+ RegionBitmap newSectorAllocations = new RegionBitmap(); -+ newSectorAllocations.force(0, 2); // make space for header -+ -+ // allocate sectors for normal chunks -+ -+ for (int chunkX = 0; chunkX < 32; ++chunkX) { -+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) { -+ int location = chunkX | (chunkZ << 5); -+ -+ if (oversized[location]) { -+ continue; -+ } -+ -+ int rawLength = rawLengths[location]; // bytes -+ int sectorOffset = sectorOffsets[location]; // sectors -+ int sectorLength = (int)roundToSectors(rawLength); -+ -+ if (newSectorAllocations.tryAllocate(sectorOffset, sectorLength)) { -+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized -+ } else { -+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath() + ", chunk will be regenerated"); -+ } -+ } -+ } -+ -+ // allocate sectors for oversized chunks -+ -+ for (int chunkX = 0; chunkX < 32; ++chunkX) { -+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) { -+ int location = chunkX | (chunkZ << 5); -+ -+ if (!oversized[location]) { -+ continue; -+ } -+ -+ int sectorOffset = newSectorAllocations.allocate(1); -+ int sectorLength = 1; -+ -+ try { -+ this.file.write(this.createExternalStub(oversizedCompressionTypes[location]), sectorOffset * 4096); -+ // only allocate in the new offsets if the write succeeds -+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized -+ } catch (IOException ex) { -+ newSectorAllocations.free(sectorOffset, sectorLength); -+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath() + " will be regenerated"); -+ } -+ } -+ } -+ -+ // rewrite aikar oversized data -+ -+ this.oversizedCount = 0; -+ for (int chunkX = 0; chunkX < 32; ++chunkX) { -+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) { -+ int location = chunkX | (chunkZ << 5); -+ int isAikarOversized = hasAikarOversized[location] ? 1 : 0; -+ -+ this.oversizedCount += isAikarOversized; -+ this.oversized[location] = (byte)isAikarOversized; -+ } -+ } -+ -+ if (this.oversizedCount > 0) { -+ try { -+ this.writeOversizedMeta(); -+ } catch (Exception ex) { -+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.regionFile.getAbsolutePath(), ex); -+ this.getOversizedMetaFile().delete(); -+ } -+ } else { -+ this.getOversizedMetaFile().delete(); -+ } -+ -+ this.usedSectors.copyFrom(newSectorAllocations); -+ -+ // before we overwrite the old sectors, print a summary of the chunks that got changed. -+ -+ LOGGER.info("Starting summary of changes for regionfile " + this.regionFile.getAbsolutePath()); -+ -+ for (int chunkX = 0; chunkX < 32; ++chunkX) { -+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) { -+ int location = chunkX | (chunkZ << 5); -+ -+ int oldOffset = this.offsets.get(location); -+ int newOffset = calculatedOffsets[location]; -+ -+ if (oldOffset == newOffset) { -+ continue; -+ } -+ -+ this.offsets.put(location, newOffset); // overwrite incorrect offset -+ -+ if (oldOffset == 0) { -+ // found lost data -+ LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath()); -+ } else if (newOffset == 0) { -+ LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.regionFile.getAbsolutePath() + ", it will be regenerated"); -+ } else { -+ LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.regionFile.getAbsolutePath()); -+ } -+ } -+ } -+ -+ LOGGER.info("End of change summary for regionfile " + this.regionFile.getAbsolutePath()); -+ -+ // simply destroy the timestamp header, it's not used -+ -+ for (int i = 0; i < 32 * 32; ++i) { -+ this.timestamps.put(i, calculatedOffsets[i] != 0 ? (int)System.currentTimeMillis() : 0); // write a valid timestamp for valid chunks, I do not want to find out whatever dumb program actually checks this -+ } -+ -+ // write new header -+ try { -+ this.flush(); -+ this.file.force(true); // try to ensure it goes through... -+ LOGGER.info("Successfully wrote new header to disk for regionfile " + this.regionFile.getAbsolutePath()); -+ } catch (IOException ex) { -+ LOGGER.fatal("Failed to write new header to disk for regionfile " + this.regionFile.getAbsolutePath(), ex); -+ } -+ } -+ } -+ -+ final boolean canRecalcHeader; // final forces compile fail on new constructor -+ // Tuinity end -+ - // Paper start - Cache chunk status - private final ChunkStatus[] statuses = new ChunkStatus[32 * 32]; - -@@ -82,8 +417,19 @@ public class RegionFile implements AutoCloseable { - public RegionFile(File file, File directory, boolean dsync) throws IOException { - this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); - } -+ // Tuinity start - add can recalc flag -+ public RegionFile(File file, File directory, boolean dsync, boolean canRecalcHeader) throws IOException { -+ this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader); -+ } -+ // Tuinity end - add can recalc flag - - public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException { -+ // Tuinity start - add can recalc flag -+ this(file, directory, outputChunkStreamVersion, dsync, false); -+ } -+ public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException { -+ this.canRecalcHeader = canRecalcHeader; -+ // Tuinity end - add can recalc flag - this.header = ByteBuffer.allocateDirect(8192); - this.regionFile = file.toFile(); // Paper - initOversizedState(); // Paper -@@ -112,14 +458,16 @@ public class RegionFile implements AutoCloseable { - RegionFile.LOGGER.warn("Region file {} has truncated header: {}", file, i); - } - -- long j = Files.size(file); -+ final long j = Files.size(file); final long regionFileSize = j; // Tuinity - recalculate header on header corruption - -+ boolean needsHeaderRecalc = false; // Tuinity - recalculate header on header corruption -+ boolean hasBackedUp = false; // Tuinity - recalculate header on header corruption - for (int k = 0; k < 1024; ++k) { -- int l = this.offsets.get(k); -+ final int l = this.offsets.get(k); final int headerLocation = l; // Tuinity - we expect this to be the header location - - if (l != 0) { -- int i1 = RegionFile.getSectorNumber(l); -- int j1 = RegionFile.getNumSectors(l); -+ final int i1 = RegionFile.getSectorNumber(l); final int offset = i1; // Tuinity - we expect this to be offset in file in sectors -+ int j1 = RegionFile.getNumSectors(l); final int sectorLength; // Tuinity - diff on change, we expect this to be sector length of region - watch out for reassignments - // Spigot start - if (j1 == 255) { - // We're maxed out, so we need to read the proper length from the section -@@ -128,32 +476,102 @@ public class RegionFile implements AutoCloseable { - j1 = (realLen.getInt(0) + 4) / 4096 + 1; - } - // Spigot end -+ sectorLength = j1; // Tuinity - diff on change, we expect this to be sector length of region - - if (i1 < 2) { - RegionFile.LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", file, k, i1); -- this.offsets.put(k, 0); -+ //this.offsets.put(k, 0); // Tuinity - we catch this, but need it in the header for the summary change - } else if (j1 == 0) { - RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", file, k); -- this.offsets.put(k, 0); -+ //this.offsets.put(k, 0); // Tuinity - we catch this, but need it in the header for the summary change - } else if ((long) i1 * 4096L > j) { - RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", file, k, i1); -- this.offsets.put(k, 0); -+ //this.offsets.put(k, 0); // Tuinity - we catch this, but need it in the header for the summary change - } else { -- this.usedSectors.force(i1, j1); -+ //this.usedSectors.force(i1, j1); // Tuinity - move this down so we can check if it fails to allocate -+ } -+ // Tuinity start - recalculate header on header corruption -+ if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) { -+ if (canRecalcHeader) { -+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + "! Recalculating header..."); -+ needsHeaderRecalc = true; -+ break; -+ } else { -+ // location = chunkX | (chunkZ << 5); -+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + -+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); -+ if (!hasBackedUp) { -+ hasBackedUp = true; -+ this.backupRegionFile(); -+ } -+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too -+ this.offsets.put(headerLocation, 0); // delete the entry from header -+ continue; -+ } - } -+ boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength); -+ if (failedToAllocate) { -+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.getAbsolutePath()); -+ } -+ if (failedToAllocate & !canRecalcHeader) { -+ // location = chunkX | (chunkZ << 5); -+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + -+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); -+ if (!hasBackedUp) { -+ hasBackedUp = true; -+ this.backupRegionFile(); -+ } -+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too -+ this.offsets.put(headerLocation, 0); // delete the entry from header -+ continue; -+ } -+ needsHeaderRecalc |= failedToAllocate; -+ // Tuinity end - recalculate header on header corruption - } - } -+ // Tuinity start - recalculate header on header corruption -+ // we move the recalc here so comparison to old header is correct when logging to console -+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues -+ LOGGER.error("Recalculating regionfile " + this.regionFile.getAbsolutePath() + ", header gave erroneous offsets & locations"); -+ this.recalculateHeader(); -+ } -+ // Tuinity end - } - - } - } - - private Path getExternalChunkPath(ChunkPos chunkPos) { -- String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; -+ String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; // Tuinity - diff on change - - return this.externalFileDir.resolve(s); - } - -+ // Tuinity start -+ private static ChunkPos getOversizedChunkPair(File file) { -+ String fileName = file.getName(); -+ -+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) { -+ return null; -+ } -+ -+ String[] split = fileName.split("\\."); -+ -+ if (split.length != 4) { -+ return null; -+ } -+ -+ try { -+ int x = Integer.parseInt(split[1]); -+ int z = Integer.parseInt(split[2]); -+ -+ return new ChunkPos(x, z); -+ } catch (NumberFormatException ex) { -+ return null; -+ } -+ } -+ // Tuinity end -+ - @Nullable - public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException { - int i = this.getOffset(pos); -@@ -177,6 +595,12 @@ public class RegionFile implements AutoCloseable { - ((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error - if (bytebuffer.remaining() < 5) { - RegionFile.LOGGER.error("Chunk {} header is truncated: expected {} but read {}", pos, l, bytebuffer.remaining()); -+ // Tuinity start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ // Tuinity end - recalculate header on regionfile corruption - return null; - } else { - int i1 = bytebuffer.getInt(); -@@ -184,6 +608,12 @@ public class RegionFile implements AutoCloseable { - - if (i1 == 0) { - RegionFile.LOGGER.warn("Chunk {} is allocated, but stream is missing", pos); -+ // Tuinity start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ // Tuinity end - recalculate header on regionfile corruption - return null; - } else { - int j1 = i1 - 1; -@@ -191,17 +621,49 @@ public class RegionFile implements AutoCloseable { - if (RegionFile.isExternalStreamChunk(b0)) { - if (j1 != 0) { - RegionFile.LOGGER.warn("Chunk has both internal and external streams"); -+ // Tuinity start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ // Tuinity end - recalculate header on regionfile corruption - } - -- return this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0)); -+ // Tuinity start - recalculate header on regionfile corruption -+ final DataInputStream ret = this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0)); -+ if (ret == null && this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ return ret; -+ // Tuinity end - recalculate header on regionfile corruption - } else if (j1 > bytebuffer.remaining()) { - RegionFile.LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", pos, j1, bytebuffer.remaining()); -+ // Tuinity start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ // Tuinity end - recalculate header on regionfile corruption - return null; - } else if (j1 < 0) { - RegionFile.LOGGER.error("Declared size {} of chunk {} is negative", i1, pos); -+ // Tuinity start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ // Tuinity end - recalculate header on regionfile corruption - return null; - } else { -- return this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1)); -+ // Tuinity start - recalculate header on regionfile corruption -+ final DataInputStream ret = this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1)); -+ if (ret == null && this.canRecalcHeader) { -+ this.recalculateHeader(); -+ return this.getChunkDataInputStream(pos); -+ } -+ return ret; -+ // Tuinity end - recalculate header on regionfile corruption - } - } - } -@@ -376,10 +838,15 @@ public class RegionFile implements AutoCloseable { - } - - private ByteBuffer createExternalStub() { -+ // Tuinity start - add version param -+ return this.createExternalStub(this.version); -+ } -+ private ByteBuffer createExternalStub(RegionFileVersion version) { -+ // Tuinity end - add version param - ByteBuffer bytebuffer = ByteBuffer.allocate(5); - - bytebuffer.putInt(1); -- bytebuffer.put((byte) (this.version.getId() | 128)); -+ bytebuffer.put((byte) (version.getId() | 128)); // Tuinity - replace with version param - ((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error - return bytebuffer; - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 6496108953effae82391b5c1ea6fdec8482731cd..a6f831fea2245e2d1f44ffa60f96b6f1243b888b 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -25,7 +25,15 @@ public class RegionFileStorage implements AutoCloseable { - private final File folder; - private final boolean sync; - -+ private final boolean isChunkData; // Tuinity -+ - RegionFileStorage(File directory, boolean dsync) { -+ // Tuinity start - add isChunkData param -+ this(directory, dsync, false); -+ } -+ RegionFileStorage(File directory, boolean dsync, boolean isChunkData) { -+ this.isChunkData = isChunkData; -+ // Tuinity end - add isChunkData param - this.folder = directory; - this.sync = dsync; - } -@@ -90,9 +98,9 @@ public class RegionFileStorage implements AutoCloseable { - - File file = this.folder; - int j = chunkcoordintpair.getRegionX(); -- File file1 = new File(file, "r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); -+ File file1 = new File(file, "r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Tuinity - diff on change - if (existingOnly && !file1.exists()) return null; // CraftBukkit -- RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync); -+ RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync, this.isChunkData); // Tuinity - allow for chunk regionfiles to regen header - - this.regionCache.putAndMoveToFirst(i, regionfile1); - // Paper start -@@ -180,6 +188,13 @@ public class RegionFileStorage implements AutoCloseable { - if (regionfile == null) { - return null; - } -+ // Tuinity start - Add regionfile parameter -+ return this.read(pos, regionfile); -+ } -+ public CompoundTag read(ChunkPos pos, RegionFile regionfile) throws IOException { -+ // We add the regionfile parameter to avoid the potential deadlock (on fileLock) if we went back to obtain a regionfile -+ // if we decide to re-read -+ // Tuinity end - // CraftBukkit end - try { // Paper - DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos); -@@ -196,6 +211,17 @@ public class RegionFileStorage implements AutoCloseable { - try { - if (datainputstream != null) { - nbttagcompound = NbtIo.read((DataInput) datainputstream); -+ // Tuinity start - recover from corrupt regionfile header -+ if (this.isChunkData) { -+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound); -+ if (!chunkPos.equals(pos)) { -+ MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos.toString() + " but got chunk data for " + chunkPos.toString() + " instead! Attempting regionfile recalculation for regionfile " + regionfile.regionFile.getAbsolutePath()); -+ regionfile.recalculateHeader(); -+ regionfile.fileLock.lock(); // otherwise we will unlock twice and only lock once. -+ return this.read(pos, regionfile); -+ } -+ } -+ // Tuinity end - recover from corrupt regionfile header - break label43; - } - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -index b7835b9b904e7d4bff64f7189049e334f5ab4d6f..ae638ac0a0557de204471fef4b03bdb0ad310b2b 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -@@ -12,7 +12,7 @@ import java.util.zip.InflaterInputStream; - import javax.annotation.Nullable; - - public class RegionFileVersion { -- private static final Int2ObjectMap VERSIONS = new Int2ObjectOpenHashMap<>(); -+ public static final Int2ObjectMap VERSIONS = new Int2ObjectOpenHashMap<>(); // Tuinity - public - public static final RegionFileVersion VERSION_GZIP = register(new RegionFileVersion(1, GZIPInputStream::new, GZIPOutputStream::new)); - public static final RegionFileVersion VERSION_DEFLATE = register(new RegionFileVersion(2, InflaterInputStream::new, DeflaterOutputStream::new)); - public static final RegionFileVersion VERSION_NONE = register(new RegionFileVersion(3, (inputStream) -> { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -index 90f7b06bd2c558be35c4577044fa033e1fb5cc22..15399f1f89aac68e64afc1e4e7942487a04fd7e0 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -@@ -61,11 +61,11 @@ public class SectionStorage extends RegionFileStorage implements AutoCloseabl - } - - @Nullable -- protected Optional get(long pos) { -+ public Optional get(long pos) { // Tuinity - public - return this.storage.get(pos); - } - -- protected Optional getOrLoad(long pos) { -+ public Optional getOrLoad(long pos) { // Tuinity - public - if (this.outsideStoredRange(pos)) { - return Optional.empty(); - } else { -@@ -135,7 +135,15 @@ public class SectionStorage extends RegionFileStorage implements AutoCloseabl - int j = getVersion(dynamic); - int k = SharedConstants.getCurrentVersion().getWorldVersion(); - boolean bl = j != k; -- Dynamic dynamic2 = this.fixerUpper.update(this.type.getType(), dynamic, j, k); -+ // Tuinity start - route to new converter system -+ Dynamic dynamic2; -+ -+ if (this.type.getType() == net.minecraft.util.datafix.fixes.References.POI_CHUNK) { -+ dynamic2 = new Dynamic<>(dynamic.getOps(), (T)ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.POI_CHUNK, (CompoundTag)dynamic.getValue(), j, k)); -+ } else { -+ dynamic2 = this.fixerUpper.update(this.type.getType(), dynamic, j, k); -+ } -+ // Tuinity end - route to new converter system - OptionalDynamic optionalDynamic = dynamic2.get("Sections"); - - for(int l = this.levelHeightAccessor.getMinSection(); l < this.levelHeightAccessor.getMaxSection(); ++l) { -diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -index f01182a0ac8a14bcd5b1deb778306e7bf1bf70ed..6ba8b50b59d3f81ec4c974defc319b1bab27c04b 100644 ---- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -@@ -9,54 +9,42 @@ import javax.annotation.Nullable; - import net.minecraft.world.entity.Entity; - - public class EntityTickList { -- private Int2ObjectMap active = new Int2ObjectLinkedOpenHashMap<>(); -- private Int2ObjectMap passive = new Int2ObjectLinkedOpenHashMap<>(); -- @Nullable -- private Int2ObjectMap iterated; -+ private final com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet entities = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Tuinity - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? - - private void ensureActiveIsNotIterated() { -- if (this.iterated == this.active) { -- this.passive.clear(); -- -- for(Entry entry : Int2ObjectMaps.fastIterable(this.active)) { -- this.passive.put(entry.getIntKey(), entry.getValue()); -- } -- -- Int2ObjectMap int2ObjectMap = this.active; -- this.active = this.passive; -- this.passive = int2ObjectMap; -- } -+ // Tuinity - replace with better logic, do not delay removals - - } - - public void add(Entity entity) { -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Tuinity - this.ensureActiveIsNotIterated(); -- this.active.put(entity.getId(), entity); -+ this.entities.add(entity); // Tuinity - replace with better logic, do not delay removals/additions - } - - public void remove(Entity entity) { -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Asynchronous entity ticklist removal"); // Tuinity - this.ensureActiveIsNotIterated(); -- this.active.remove(entity.getId()); -+ this.entities.remove(entity); // Tuinity - replace with better logic, do not delay removals/additions - } - - public boolean contains(Entity entity) { -- return this.active.containsKey(entity.getId()); -+ return this.entities.contains(entity); // Tuinity - replace with better logic, do not delay removals/additions - } - - public void forEach(Consumer action) { -- if (this.iterated != null) { -- throw new UnsupportedOperationException("Only one concurrent iteration supported"); -- } else { -- this.iterated = this.active; -- -- try { -- for(Entity entity : this.active.values()) { -- action.accept(entity); -- } -- } finally { -- this.iterated = null; -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Asynchronous entity ticklist iteration"); // Tuinity -+ // Tuinity start - replace with better logic, do not delay removals/additions -+ // To ensure nothing weird happens with dimension travelling, do not iterate over new entries... -+ // (by dfl iterator() is configured to not iterate over new entries) -+ com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.Iterator iterator = this.entities.iterator(); -+ try { -+ while (iterator.hasNext()) { -+ action.accept(iterator.next()); - } -- -+ } finally { -+ iterator.finishedIterating(); - } -+ // Tuinity end - replace with better logic, do not delay removals/additions - } - } -diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -index d1428fe87ec3be070d9a125a1774ea758d4cd74b..a7079aa957646410b43ebce5f0b55dfb05c792b1 100644 ---- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -41,8 +41,10 @@ public class PersistentEntitySectionManager implements A - private final Long2ObjectMap chunkLoadStatuses = new Long2ObjectOpenHashMap<>(); - private final LongSet chunksToUnload = new LongOpenHashSet(); - private final Queue> loadingInbox = Queues.newConcurrentLinkedQueue(); -+ public final com.tuinity.tuinity.world.EntitySliceManager entitySliceManager; // Tuinity - -- public PersistentEntitySectionManager(Class entityClass, LevelCallback handler, EntityPersistentStorage dataAccess) { -+ public PersistentEntitySectionManager(Class entityClass, LevelCallback handler, EntityPersistentStorage dataAccess, com.tuinity.tuinity.world.EntitySliceManager entitySliceManager) { // Tuinity -+ this.entitySliceManager = entitySliceManager; // Tuinity - this.visibleEntityStorage = new EntityLookup<>(); - this.sectionStorage = new EntitySectionStorage<>(entityClass, this.chunkVisibility); - this.chunkVisibility.defaultReturnValue(Visibility.HIDDEN); -@@ -52,6 +54,65 @@ public class PersistentEntitySectionManager implements A - this.entityGetter = new LevelEntityGetterAdapter<>(this.visibleEntityStorage, this.sectionStorage); - } - -+ // Tuinity start - optimise notify() -+ public final void removeNavigatorsFromData(Entity entity, final int chunkX, final int chunkZ) { -+ if (!(entity instanceof net.minecraft.world.entity.Mob)) { -+ return; -+ } -+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section = -+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(chunkX, chunkZ); -+ if (section != null) { -+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData; -+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity)); -+ } -+ } -+ -+ public final void removeNavigatorsFromData(Entity entity) { -+ if (!(entity instanceof net.minecraft.world.entity.Mob)) { -+ return; -+ } -+ BlockPos entityPos = entity.blockPosition(); -+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section = -+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4); -+ if (section != null) { -+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData; -+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity)); -+ } -+ } -+ -+ public final void addNavigatorsIfPathingToRegion(Entity entity) { -+ if (!(entity instanceof net.minecraft.world.entity.Mob)) { -+ return; -+ } -+ BlockPos entityPos = entity.blockPosition(); -+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section = -+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4); -+ if (section != null) { -+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData; -+ if (((net.minecraft.world.entity.Mob)entity).getNavigation().isViableForPathRecalculationChecking()) { -+ sectionData.addToNavigators(section, ((net.minecraft.world.entity.Mob)entity)); -+ } -+ } -+ } -+ -+ public final void updateNavigatorsInRegion(Entity entity) { -+ if (!(entity instanceof net.minecraft.world.entity.Mob)) { -+ return; -+ } -+ BlockPos entityPos = entity.blockPosition(); -+ com.tuinity.tuinity.chunk.SingleThreadChunkRegionManager.RegionSection section = -+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4); -+ if (section != null) { -+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData; -+ if (((net.minecraft.world.entity.Mob)entity).getNavigation().isViableForPathRecalculationChecking()) { -+ sectionData.addToNavigators(section, ((net.minecraft.world.entity.Mob)entity)); -+ } else { -+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity)); -+ } -+ } -+ } -+ // Tuinity end - optimise notify() -+ - void removeSectionIfEmpty(long sectionPos, EntitySection section) { - if (section.isEmpty()) { - this.sectionStorage.remove(sectionPos); -@@ -93,6 +154,7 @@ public class PersistentEntitySectionManager implements A - long l = SectionPos.asLong(entity.blockPosition()); - EntitySection entitySection = this.sectionStorage.getOrCreateSection(l); - entitySection.add(entity); -+ this.entitySliceManager.addEntity((Entity)entity); // Tuinity - entity.setLevelCallback(new PersistentEntitySectionManager.Callback(entity, l, entitySection)); - if (!existing) { - this.callbacks.onCreated(entity); -@@ -146,7 +208,9 @@ public class PersistentEntitySectionManager implements A - } - - public void updateChunkStatus(ChunkPos chunkPos, ChunkHolder.FullChunkStatus levelType) { -+ com.tuinity.tuinity.util.TickThread.ensureTickThread("Asynchronous chunk ticking status update"); // Tuinity - Visibility visibility = Visibility.fromFullChunkStatus(levelType); -+ this.entitySliceManager.chunkStatusChange(chunkPos.x, chunkPos.z, levelType); // Tuinity - this.updateChunkStatus(chunkPos, visibility); - } - -@@ -388,18 +452,38 @@ public class PersistentEntitySectionManager implements A - @Override - public void onMove() { - BlockPos blockPos = this.entity.blockPosition(); -- long l = SectionPos.asLong(blockPos); -+ long l = SectionPos.asLong(blockPos); // Tuinity - diff on change, new position section - if (l != this.currentSectionKey) { -- Visibility visibility = this.currentSection.getStatus(); -+ PersistentEntitySectionManager.this.entitySliceManager.moveEntity((Entity)this.entity); // Tuinity -+ // Tuinity start -+ int shift = PersistentEntitySectionManager.this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.regionChunkShift; -+ int oldChunkX = com.tuinity.tuinity.util.CoordinateUtils.getChunkSectionX(this.currentSectionKey); -+ int oldChunkZ = com.tuinity.tuinity.util.CoordinateUtils.getChunkSectionZ(this.currentSectionKey); -+ int oldRegionX = oldChunkX >> shift; -+ int oldRegionZ = oldChunkZ >> shift; -+ -+ int newRegionX = com.tuinity.tuinity.util.CoordinateUtils.getChunkSectionX(l) >> shift; -+ int newRegionZ = com.tuinity.tuinity.util.CoordinateUtils.getChunkSectionZ(l) >> shift; -+ -+ if (oldRegionX != newRegionX || oldRegionZ != newRegionZ) { -+ PersistentEntitySectionManager.this.removeNavigatorsFromData((Entity)this.entity, oldChunkX, oldChunkZ); -+ } -+ // Tuinity end -+ Visibility visibility = this.currentSection.getStatus(); // Tuinity - diff on change - this should be OLD section visibility - if (!this.currentSection.remove(this.entity)) { - PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (moving to {})", this.entity, SectionPos.of(this.currentSectionKey), l); - } - - PersistentEntitySectionManager.this.removeSectionIfEmpty(this.currentSectionKey, this.currentSection); -- EntitySection entitySection = PersistentEntitySectionManager.this.sectionStorage.getOrCreateSection(l); -+ EntitySection entitySection = PersistentEntitySectionManager.this.sectionStorage.getOrCreateSection(l); // Tuinity - diff on change, this should be NEW section - entitySection.add(this.entity); - this.currentSection = entitySection; - this.currentSectionKey = l; -+ // Tuinity start -+ if ((oldRegionX != newRegionX || oldRegionZ != newRegionZ) && visibility.isTicking() && entitySection.getStatus().isTicking()) { -+ PersistentEntitySectionManager.this.addNavigatorsIfPathingToRegion((Entity)this.entity); -+ } -+ // Tuinity end - this.updateStatus(visibility, entitySection.getStatus()); - } - -@@ -433,6 +517,7 @@ public class PersistentEntitySectionManager implements A - if (!this.currentSection.remove(this.entity)) { - PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", this.entity, SectionPos.of(this.currentSectionKey), reason); - } -+ PersistentEntitySectionManager.this.entitySliceManager.removeEntity((Entity)this.entity); // Tuinity - - Visibility visibility = PersistentEntitySectionManager.getEffectiveStatus(this.entity, this.currentSection.getStatus()); - if (visibility.isTicking()) { -diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java b/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java -index 05bba5410fbd9f8e333584ccbd65a909f3040322..de3122f450edacaf2eed6f60b0680ebe64f7d214 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java -@@ -10,11 +10,28 @@ import net.minecraft.world.level.LevelAccessor; - import net.minecraft.world.level.block.state.BlockState; - - public class ColumnPlacer extends BlockPlacer { -+ // Tuinity start - public static final Codec CODEC = RecordCodecBuilder.create((instance) -> { -- return instance.group(IntProvider.NON_NEGATIVE_CODEC.fieldOf("size").forGetter((columnPlacer) -> { -- return columnPlacer.size; -- })).apply(instance, ColumnPlacer::new); -+ return instance.group( -+ IntProvider.NON_NEGATIVE_CODEC.optionalFieldOf("size").forGetter((columnPlacer) -> { -+ return java.util.Optional.of(columnPlacer.size); -+ }), -+ Codec.INT.optionalFieldOf("min_size").forGetter((columnPlacer) -> { -+ return java.util.Optional.empty(); -+ }), -+ Codec.INT.optionalFieldOf("extra_size").forGetter((columnPlacer) -> { -+ return java.util.Optional.empty(); -+ }) -+ ).apply(instance, ColumnPlacer::new); - }); -+ public ColumnPlacer(java.util.Optional size, java.util.Optional minSize, java.util.Optional extraSize) { -+ if (size.isPresent()) { -+ this.size = size.get(); -+ } else { -+ this.size = net.minecraft.util.valueproviders.BiasedToBottomInt.of(minSize.get().intValue(), minSize.get().intValue() + extraSize.get().intValue()); -+ } -+ } -+ // Tuinity end - private final IntProvider size; - - public ColumnPlacer(IntProvider size) { -diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java b/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java -index 5da68897148192905c2747676c1ee2ee649f923f..b990099cf274f8cb0d96c139345cf0bf328affd6 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java -@@ -18,13 +18,13 @@ public class TreeConfiguration implements FeatureConfiguration { - return treeConfiguration.trunkProvider; - }), TrunkPlacer.CODEC.fieldOf("trunk_placer").forGetter((treeConfiguration) -> { - return treeConfiguration.trunkPlacer; -- }), BlockStateProvider.CODEC.fieldOf("foliage_provider").forGetter((treeConfiguration) -> { -+ }), net.minecraft.server.MCUtil.fieldWithFallbacks(BlockStateProvider.CODEC, "foliage_provider", "leaves_provider").forGetter((treeConfiguration) -> { // Paper - provide fallback for rename - return treeConfiguration.foliageProvider; -- }), BlockStateProvider.CODEC.fieldOf("sapling_provider").forGetter((treeConfiguration) -> { -+ }), BlockStateProvider.CODEC.optionalFieldOf("sapling_provider", new SimpleStateProvider(Blocks.OAK_SAPLING.defaultBlockState())).forGetter((treeConfiguration) -> { // Paper - provide default - it looks like for now this is OK because it's just used to check canSurvive. Same check happens in 1.16.5 for the default we provide - so it should retain behavior... - return treeConfiguration.saplingProvider; - }), FoliagePlacer.CODEC.fieldOf("foliage_placer").forGetter((treeConfiguration) -> { - return treeConfiguration.foliagePlacer; -- }), BlockStateProvider.CODEC.fieldOf("dirt_provider").forGetter((treeConfiguration) -> { -+ }), BlockStateProvider.CODEC.optionalFieldOf("dirt_provider", new SimpleStateProvider(Blocks.DIRT.defaultBlockState())).forGetter((treeConfiguration) -> { // Paper - provide defaults, old data DOES NOT have this key (thankfully ALL OLD DATA used DIRT) - return treeConfiguration.dirtProvider; - }), FeatureSize.CODEC.fieldOf("minimum_size").forGetter((treeConfiguration) -> { - return treeConfiguration.minimumSize; -diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java -index d5ba2e679ed1858ea18e18feffce50544ae036c2..78da12a3feb05a5504daf8379be3d568c389a458 100644 ---- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java -+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java -@@ -52,16 +52,37 @@ public class PortalForcer { - // int i = flag ? 16 : 128; - // CraftBukkit end - -- villageplace.ensureLoadedAndValid(this.level, blockposition, i); -- Optional optional = villageplace.getInSquare((villageplacetype) -> { -- return villageplacetype == PoiType.NETHER_PORTAL; -- }, blockposition, i, PoiManager.Occupancy.ANY).sorted(Comparator.comparingDouble((PoiRecord villageplacerecord) -> { // CraftBukkit - decompile error -- return villageplacerecord.getPos().distSqr(blockposition); -- }).thenComparingInt((villageplacerecord) -> { -- return villageplacerecord.getPos().getY(); -- })).filter((villageplacerecord) -> { -- return this.level.getBlockState(villageplacerecord.getPos()).hasProperty(BlockStateProperties.HORIZONTAL_AXIS); -- }).findFirst(); -+ // Tuinity start - optimise portals -+ Optional optional; -+ java.util.List records = new java.util.ArrayList<>(); -+ com.tuinity.tuinity.util.PoiAccess.findClosestPoiDataRecords( -+ villageplace, -+ (PoiType type) -> { -+ return type == PoiType.NETHER_PORTAL; -+ }, -+ (BlockPos pos) -> { -+ net.minecraft.world.level.chunk.ChunkAccess lowest = this.level.getChunk(pos.getX() >> 4, pos.getZ() >> 4, net.minecraft.world.level.chunk.ChunkStatus.EMPTY); -+ if (!lowest.getStatus().isOrAfter(net.minecraft.world.level.chunk.ChunkStatus.FULL)) { -+ // why would we generate the chunk? -+ return false; -+ } -+ return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS); -+ }, -+ blockposition, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records -+ ); -+ -+ // this gets us most of the way there, but we bias towards lower y values. -+ PoiRecord lowestYRecord = null; -+ for (PoiRecord record : records) { -+ if (lowestYRecord == null) { -+ lowestYRecord = record; -+ } else if (lowestYRecord.getPos().getY() > record.getPos().getY()) { -+ lowestYRecord = record; -+ } -+ } -+ // now we're done -+ optional = Optional.ofNullable(lowestYRecord); -+ // Tuinity end - optimise portals - - return optional.map((villageplacerecord) -> { - BlockPos blockposition1 = villageplacerecord.getPos(); -diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java -index 6727468946ea5f60bd80549f827a7c2b9a42b98b..97b97f69085a332fd4ca6d7500315b125f3c332b 100644 ---- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java -+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java -@@ -93,7 +93,7 @@ public class PlayerDataStorage { - // CraftBukkit end - int i = nbttagcompound.contains("DataVersion", 3) ? nbttagcompound.getInt("DataVersion") : -1; - -- player.load(NbtUtils.update(this.fixerUpper, DataFixTypes.PLAYER, nbttagcompound, i)); -+ player.load(ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.PLAYER, nbttagcompound, i, net.minecraft.SharedConstants.getCurrentVersion().getWorldVersion())); // Tuinity - replace player converter - } - - return nbttagcompound; -diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java -index 120498a39b7ca7aee9763084507508d4a1c425aa..6f7e6429c35eea346517cbf08cf223fc6d838a8c 100644 ---- a/src/main/java/net/minecraft/world/phys/AABB.java -+++ b/src/main/java/net/minecraft/world/phys/AABB.java -@@ -25,6 +25,17 @@ public class AABB { - this.maxZ = Math.max(z1, z2); - } - -+ // Tuinity start -+ public AABB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, boolean dummy) { -+ this.minX = minX; -+ this.minY = minY; -+ this.minZ = minZ; -+ this.maxX = maxX; -+ this.maxY = maxY; -+ this.maxZ = maxZ; -+ } -+ // Tuinity end -+ - public AABB(BlockPos pos) { - this((double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)(pos.getX() + 1), (double)(pos.getY() + 1), (double)(pos.getZ() + 1)); - } -diff --git a/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java -index 99427b6130895ddecee8bcf77db72d809c24c375..af1ef430e81cb9bdd749aa235577c63fa381f4c5 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java -@@ -6,6 +6,9 @@ import java.util.Arrays; - import net.minecraft.Util; - import net.minecraft.core.Direction; - -+// Tuinity start -+import it.unimi.dsi.fastutil.doubles.AbstractDoubleList; -+// Tuinity end - public class ArrayVoxelShape extends VoxelShape { - private final DoubleList xs; - private final DoubleList ys; -@@ -16,6 +19,11 @@ public class ArrayVoxelShape extends VoxelShape { - } - - ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xPoints, DoubleList yPoints, DoubleList zPoints) { -+ // Tuinity start - optimise multi-aabb shapes -+ this(shape, xPoints, yPoints, zPoints, null, 0.0, 0.0, 0.0); -+ } -+ ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xPoints, DoubleList yPoints, DoubleList zPoints, net.minecraft.world.phys.AABB[] boundingBoxesRepresentation, double offsetX, double offsetY, double offsetZ) { -+ // Tuinity end - optimise multi-aabb shapes - super(shape); - int i = shape.getXSize() + 1; - int j = shape.getYSize() + 1; -@@ -27,6 +35,12 @@ public class ArrayVoxelShape extends VoxelShape { - } else { - throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException("Lengths of point arrays must be consistent with the size of the VoxelShape.")); - } -+ // Tuinity start - optimise multi-aabb shapes -+ this.boundingBoxesRepresentation = boundingBoxesRepresentation == null ? this.toAabbs().toArray(EMPTY) : boundingBoxesRepresentation; -+ this.offsetX = offsetX; -+ this.offsetY = offsetY; -+ this.offsetZ = offsetZ; -+ // Tuinity end - optimise multi-aabb shapes - } - - @Override -@@ -42,4 +56,152 @@ public class ArrayVoxelShape extends VoxelShape { - throw new IllegalArgumentException(); - } - } -+ -+ // Tuinity start -+ public static final class DoubleListOffsetExposed extends AbstractDoubleList { -+ -+ public final DoubleArrayList list; -+ public final double offset; -+ -+ public DoubleListOffsetExposed(final DoubleArrayList list, final double offset) { -+ this.list = list; -+ this.offset = offset; -+ } -+ -+ @Override -+ public double getDouble(final int index) { -+ return this.list.getDouble(index) + this.offset; -+ } -+ -+ @Override -+ public int size() { -+ return this.list.size(); -+ } -+ } -+ -+ static final net.minecraft.world.phys.AABB[] EMPTY = new net.minecraft.world.phys.AABB[0]; -+ final net.minecraft.world.phys.AABB[] boundingBoxesRepresentation; -+ -+ final double offsetX; -+ final double offsetY; -+ final double offsetZ; -+ -+ public final net.minecraft.world.phys.AABB[] getBoundingBoxesRepresentation() { -+ return this.boundingBoxesRepresentation; -+ } -+ -+ public final double getOffsetX() { -+ return this.offsetX; -+ } -+ -+ public final double getOffsetY() { -+ return this.offsetY; -+ } -+ -+ public final double getOffsetZ() { -+ return this.offsetZ; -+ } -+ -+ @Override -+ public java.util.List toAabbs() { -+ if (this.boundingBoxesRepresentation == null) { -+ return super.toAabbs(); -+ } -+ java.util.List ret = new java.util.ArrayList<>(this.boundingBoxesRepresentation.length); -+ -+ double offX = this.offsetX; -+ double offY = this.offsetY; -+ double offZ = this.offsetZ; -+ -+ for (net.minecraft.world.phys.AABB boundingBox : this.boundingBoxesRepresentation) { -+ ret.add(boundingBox.move(offX, offY, offZ)); -+ } -+ -+ return ret; -+ } -+ -+ protected static DoubleArrayList getList(DoubleList from) { -+ if (from instanceof DoubleArrayList) { -+ return (DoubleArrayList)from; -+ } else { -+ return DoubleArrayList.wrap(from.toDoubleArray()); -+ } -+ } -+ -+ @Override -+ public VoxelShape move(double x, double y, double z) { -+ if (x == 0.0 && y == 0.0 && z == 0.0) { -+ return this; -+ } -+ DoubleListOffsetExposed xPoints, yPoints, zPoints; -+ double offsetX, offsetY, offsetZ; -+ -+ if (this.xs instanceof DoubleListOffsetExposed) { -+ xPoints = new DoubleListOffsetExposed(((DoubleListOffsetExposed)this.xs).list, offsetX = this.offsetX + x); -+ yPoints = new DoubleListOffsetExposed(((DoubleListOffsetExposed)this.ys).list, offsetY = this.offsetY + y); -+ zPoints = new DoubleListOffsetExposed(((DoubleListOffsetExposed)this.zs).list, offsetZ = this.offsetZ + z); -+ } else { -+ xPoints = new DoubleListOffsetExposed(getList(this.xs), offsetX = x); -+ yPoints = new DoubleListOffsetExposed(getList(this.ys), offsetY = y); -+ zPoints = new DoubleListOffsetExposed(getList(this.zs), offsetZ = z); -+ } -+ -+ return new ArrayVoxelShape(this.shape, xPoints, yPoints, zPoints, this.boundingBoxesRepresentation, offsetX, offsetY, offsetZ); -+ } -+ -+ @Override -+ public final boolean intersects(net.minecraft.world.phys.AABB axisalingedbb) { -+ // this can be optimised by checking an "overall shape" first, but not needed -+ double offX = this.offsetX; -+ double offY = this.offsetY; -+ double offZ = this.offsetZ; -+ -+ for (net.minecraft.world.phys.AABB boundingBox : this.boundingBoxesRepresentation) { -+ if (com.tuinity.tuinity.util.CollisionUtil.voxelShapeIntersect(axisalingedbb, boundingBox.minX + offX, boundingBox.minY + offY, boundingBox.minZ + offZ, -+ boundingBox.maxX + offX, boundingBox.maxY + offY, boundingBox.maxZ + offZ)) { -+ return true; -+ } -+ } -+ -+ return false; -+ } -+ -+ @Override -+ public void forAllBoxes(Shapes.DoubleLineConsumer doubleLineConsumer) { -+ if (this.boundingBoxesRepresentation == null) { -+ super.forAllBoxes(doubleLineConsumer); -+ return; -+ } -+ for (final net.minecraft.world.phys.AABB boundingBox : this.boundingBoxesRepresentation) { -+ doubleLineConsumer.consume(boundingBox.minX + this.offsetX, boundingBox.minY + this.offsetY, boundingBox.minZ + this.offsetZ, -+ boundingBox.maxX + this.offsetX, boundingBox.maxY + this.offsetY, boundingBox.maxZ + this.offsetZ); -+ } -+ } -+ -+ @Override -+ public VoxelShape optimize() { -+ if (this == Shapes.empty() || this.boundingBoxesRepresentation.length == 0) { -+ return this; -+ } -+ -+ VoxelShape simplified = Shapes.empty(); -+ for (final net.minecraft.world.phys.AABB boundingBox : this.boundingBoxesRepresentation) { -+ simplified = Shapes.joinUnoptimized(simplified, Shapes.box(boundingBox.minX + this.offsetX, boundingBox.minY + this.offsetY, boundingBox.minZ + this.offsetZ, -+ boundingBox.maxX + this.offsetX, boundingBox.maxY + this.offsetY, boundingBox.maxZ + this.offsetZ), BooleanOp.OR); -+ } -+ -+ if (!(simplified instanceof ArrayVoxelShape)) { -+ return simplified; -+ } -+ -+ final net.minecraft.world.phys.AABB[] boundingBoxesRepresentation = ((ArrayVoxelShape)simplified).getBoundingBoxesRepresentation(); -+ -+ if (boundingBoxesRepresentation.length == 1) { -+ return new com.tuinity.tuinity.voxel.AABBVoxelShape(boundingBoxesRepresentation[0]).optimize(); -+ } -+ -+ return simplified; -+ } -+ // Tuinity end -+ - } -diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java -index 16bc18cacbf7a23fb744c8a12e7fd8da699b2fea..472c47a585da7d95b3f4774d3caef1d864b6337a 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java -@@ -26,16 +26,17 @@ public final class Shapes { - DiscreteVoxelShape discreteVoxelShape = new BitSetDiscreteVoxelShape(1, 1, 1); - discreteVoxelShape.fill(0, 0, 0); - return new CubeVoxelShape(discreteVoxelShape); -- }); -+ }); public static VoxelShape getFullUnoptimisedCube() { return BLOCK; } // Tuinity - OBFHELPER - public static final VoxelShape INFINITY = box(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); - private static final VoxelShape EMPTY = new ArrayVoxelShape(new BitSetDiscreteVoxelShape(0, 0, 0), (DoubleList)(new DoubleArrayList(new double[]{0.0D})), (DoubleList)(new DoubleArrayList(new double[]{0.0D})), (DoubleList)(new DoubleArrayList(new double[]{0.0D}))); -+ public static final com.tuinity.tuinity.voxel.AABBVoxelShape BLOCK_OPTIMISED = new com.tuinity.tuinity.voxel.AABBVoxelShape(new AABB(0.0, 0.0, 0.0, 1.0, 1.0, 1.0)); // Tuinity - - public static VoxelShape empty() { - return EMPTY; - } - - public static VoxelShape block() { -- return BLOCK; -+ return BLOCK_OPTIMISED; // Tuinity - } - - public static VoxelShape box(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { -@@ -47,30 +48,11 @@ public final class Shapes { - } - - public static VoxelShape create(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { -- if (!(maxX - minX < 1.0E-7D) && !(maxY - minY < 1.0E-7D) && !(maxZ - minZ < 1.0E-7D)) { -- int i = findBits(minX, maxX); -- int j = findBits(minY, maxY); -- int k = findBits(minZ, maxZ); -- if (i >= 0 && j >= 0 && k >= 0) { -- if (i == 0 && j == 0 && k == 0) { -- return block(); -- } else { -- int l = 1 << i; -- int m = 1 << j; -- int n = 1 << k; -- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.withFilledBounds(l, m, n, (int)Math.round(minX * (double)l), (int)Math.round(minY * (double)m), (int)Math.round(minZ * (double)n), (int)Math.round(maxX * (double)l), (int)Math.round(maxY * (double)m), (int)Math.round(maxZ * (double)n)); -- return new CubeVoxelShape(bitSetDiscreteVoxelShape); -- } -- } else { -- return new ArrayVoxelShape(BLOCK.shape, (DoubleList)DoubleArrayList.wrap(new double[]{minX, maxX}), (DoubleList)DoubleArrayList.wrap(new double[]{minY, maxY}), (DoubleList)DoubleArrayList.wrap(new double[]{minZ, maxZ})); -- } -- } else { -- return empty(); -- } -+ return new com.tuinity.tuinity.voxel.AABBVoxelShape(new AABB(minX, minY, minZ, maxX, maxY, maxZ)); // Tuinity - } - - public static VoxelShape create(AABB box) { -- return create(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ); -+ return new com.tuinity.tuinity.voxel.AABBVoxelShape(box); // Tuinity - } - - @VisibleForTesting -@@ -132,6 +114,20 @@ public final class Shapes { - } - - public static boolean joinIsNotEmpty(VoxelShape shape1, VoxelShape shape2, BooleanOp predicate) { -+ // Tuinity start - optimise voxelshape -+ if (predicate == BooleanOp.AND) { -+ if (shape1 instanceof com.tuinity.tuinity.voxel.AABBVoxelShape && shape2 instanceof com.tuinity.tuinity.voxel.AABBVoxelShape) { -+ return com.tuinity.tuinity.util.CollisionUtil.voxelShapeIntersect(((com.tuinity.tuinity.voxel.AABBVoxelShape)shape1).aabb, ((com.tuinity.tuinity.voxel.AABBVoxelShape)shape2).aabb); -+ } else if (shape1 instanceof com.tuinity.tuinity.voxel.AABBVoxelShape && shape2 instanceof ArrayVoxelShape) { -+ return ((ArrayVoxelShape)shape2).intersects(((com.tuinity.tuinity.voxel.AABBVoxelShape)shape1).aabb); -+ } else if (shape2 instanceof com.tuinity.tuinity.voxel.AABBVoxelShape && shape1 instanceof ArrayVoxelShape) { -+ return ((ArrayVoxelShape)shape1).intersects(((com.tuinity.tuinity.voxel.AABBVoxelShape)shape2).aabb); -+ } -+ } -+ return joinIsNotEmptyVanilla(shape1, shape2, predicate); -+ } -+ public static boolean joinIsNotEmptyVanilla(VoxelShape shape1, VoxelShape shape2, BooleanOp predicate) { -+ // Tuinity end - optimise voxelshape - if (predicate.apply(false, false)) { - throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException()); - } else { -@@ -285,6 +281,43 @@ public final class Shapes { - } - - public static VoxelShape getFaceShape(VoxelShape shape, Direction direction) { -+ // Tuinity start - optimise shape creation here for lighting, as this shape is going to be used -+ // for transparency checks -+ if (shape == BLOCK || shape == BLOCK_OPTIMISED) { -+ return BLOCK_OPTIMISED; -+ } else if (shape == empty()) { -+ return empty(); -+ } -+ -+ if (shape instanceof com.tuinity.tuinity.voxel.AABBVoxelShape) { -+ final AABB box = ((com.tuinity.tuinity.voxel.AABBVoxelShape)shape).aabb; -+ switch (direction) { -+ case WEST: // -X -+ case EAST: { // +X -+ final boolean useEmpty = direction == Direction.EAST ? !DoubleMath.fuzzyEquals(box.maxX, 1.0, com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON) : -+ !DoubleMath.fuzzyEquals(box.minX, 0.0, com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON); -+ return useEmpty ? empty() : new com.tuinity.tuinity.voxel.AABBVoxelShape(new AABB(0.0, box.minY, box.minZ, 1.0, box.maxY, box.maxZ)).optimize(); -+ } -+ case DOWN: // -Y -+ case UP: { // +Y -+ final boolean useEmpty = direction == Direction.UP ? !DoubleMath.fuzzyEquals(box.maxY, 1.0, com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON) : -+ !DoubleMath.fuzzyEquals(box.minY, 0.0, com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON); -+ return useEmpty ? empty() : new com.tuinity.tuinity.voxel.AABBVoxelShape(new AABB(box.minX, 0.0, box.minZ, box.maxX, 1.0, box.maxZ)).optimize(); -+ } -+ case NORTH: // -Z -+ case SOUTH: { // +Z -+ final boolean useEmpty = direction == Direction.SOUTH ? !DoubleMath.fuzzyEquals(box.maxZ, 1.0, com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON) : -+ !DoubleMath.fuzzyEquals(box.minZ,0.0, com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON); -+ return useEmpty ? empty() : new com.tuinity.tuinity.voxel.AABBVoxelShape(new AABB(box.minX, box.minY, 0.0, box.maxX, box.maxY, 1.0)).optimize(); -+ } -+ } -+ } -+ -+ // fall back to vanilla -+ return getFaceShapeVanilla(shape, direction); -+ } -+ public static VoxelShape getFaceShapeVanilla(VoxelShape shape, Direction direction) { -+ // Tuinity end - if (shape == block()) { - return block(); - } else { -@@ -299,7 +332,7 @@ public final class Shapes { - i = 0; - } - -- return (VoxelShape)(!bl ? empty() : new SliceShape(shape, axis, i)); -+ return (VoxelShape)(!bl ? empty() : new SliceShape(shape, axis, i).optimize().optimize()); // Tuinity - first optimize converts to ArrayVoxelShape, second optimize could convert to AABBVoxelShape - } - } - -@@ -324,6 +357,53 @@ public final class Shapes { - } - - public static boolean faceShapeOccludes(VoxelShape one, VoxelShape two) { -+ // Tuinity start - try to optimise for the case where the shapes do _not_ occlude -+ // which is _most_ of the time in lighting -+ if (one == getFullUnoptimisedCube() || one == BLOCK_OPTIMISED -+ || two == getFullUnoptimisedCube() || two == BLOCK_OPTIMISED) { -+ return true; -+ } -+ boolean v1Empty = one == empty(); -+ boolean v2Empty = two == empty(); -+ if (v1Empty && v2Empty) { -+ return false; -+ } -+ if ((one instanceof com.tuinity.tuinity.voxel.AABBVoxelShape || v1Empty) -+ && (two instanceof com.tuinity.tuinity.voxel.AABBVoxelShape || v2Empty)) { -+ if (!v1Empty && !v2Empty && (one != two)) { -+ AABB boundingBox1 = ((com.tuinity.tuinity.voxel.AABBVoxelShape)one).aabb; -+ AABB boundingBox2 = ((com.tuinity.tuinity.voxel.AABBVoxelShape)two).aabb; -+ // can call it here in some cases -+ -+ // check overall bounding box -+ double minY = Math.min(boundingBox1.minY, boundingBox2.minY); -+ double maxY = Math.max(boundingBox1.maxY, boundingBox2.maxY); -+ if (minY > com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON || maxY < (1 - com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON)) { -+ return false; -+ } -+ double minX = Math.min(boundingBox1.minX, boundingBox2.minX); -+ double maxX = Math.max(boundingBox1.maxX, boundingBox2.maxX); -+ if (minX > com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON || maxX < (1 - com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON)) { -+ return false; -+ } -+ double minZ = Math.min(boundingBox1.minZ, boundingBox2.minZ); -+ double maxZ = Math.max(boundingBox1.maxZ, boundingBox2.maxZ); -+ if (minZ > com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON || maxZ < (1 - com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON)) { -+ return false; -+ } -+ // fall through to full merge check -+ } else { -+ AABB boundingBox = v1Empty ? ((com.tuinity.tuinity.voxel.AABBVoxelShape)two).aabb : ((com.tuinity.tuinity.voxel.AABBVoxelShape)one).aabb; -+ // check if the bounding box encloses the full cube -+ return (boundingBox.minY <= com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON && boundingBox.maxY >= (1 - com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON)) && -+ (boundingBox.minX <= com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON && boundingBox.maxX >= (1 - com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON)) && -+ (boundingBox.minZ <= com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON && boundingBox.maxZ >= (1 - com.tuinity.tuinity.util.CollisionUtil.COLLISION_EPSILON)); -+ } -+ } -+ return faceShapeOccludesVanilla(one, two); -+ } -+ public static boolean faceShapeOccludesVanilla(VoxelShape one, VoxelShape two) { -+ // Tuinity end - if (one != block() && two != block()) { - if (one.isEmpty() && two.isEmpty()) { - return false; -diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java -index f325d76c79d63629200262a77eab7cdcc9beedfa..ad23eafd6d9e7901f726977ad8404fa34dc0874e 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java -@@ -16,11 +16,17 @@ import net.minecraft.world.phys.BlockHitResult; - import net.minecraft.world.phys.Vec3; - - public abstract class VoxelShape { -- protected final DiscreteVoxelShape shape; -+ public final DiscreteVoxelShape shape; // Tuinity - public - @Nullable - private VoxelShape[] faces; - -- VoxelShape(DiscreteVoxelShape voxels) { -+ // Tuinity start -+ public boolean intersects(AABB shape) { -+ return Shapes.joinIsNotEmpty(this, new com.tuinity.tuinity.voxel.AABBVoxelShape(shape), BooleanOp.AND); -+ } -+ // Tuinity end -+ -+ protected VoxelShape(DiscreteVoxelShape voxels) { // Tuinity - protected - this.shape = voxels; - } - -@@ -163,7 +169,7 @@ public abstract class VoxelShape { - } - } - -- private VoxelShape calculateFace(Direction direction) { -+ protected VoxelShape calculateFace(Direction direction) { // Tuinity - Direction.Axis axis = direction.getAxis(); - DoubleList doubleList = this.getCoords(axis); - if (doubleList.size() == 2 && DoubleMath.fuzzyEquals(doubleList.getDouble(0), 0.0D, 1.0E-7D) && DoubleMath.fuzzyEquals(doubleList.getDouble(1), 1.0D, 1.0E-7D)) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -index 0a76032b48af4327580b99730e534f628924fe35..c9c668aa5b2ddf21ffcce8b395e3d88b4b8cf822 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -@@ -110,13 +110,7 @@ public class CraftChunk implements Chunk { - this.getWorld().getChunkAt(x, z); // Transient load for this tick - } - -- // Paper start - improve CraftChunk#getEntities -- return this.worldServer.entityManager.sectionStorage.getExistingSectionsInChunk(ChunkPos.asLong(this.x, this.z)) -- .flatMap(net.minecraft.world.level.entity.EntitySection::getEntities) -- .map(net.minecraft.world.entity.Entity::getBukkitEntity) -- .filter(entity -> entity != null && entity.isValid()) -- .toArray(Entity[]::new); -- // Paper end -+ return ((CraftWorld)this.getWorld()).getHandle().getChunkEntities(this.x, this.z); // Tuinity - optimise this better than paper :) - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 6d7f16fede01c19f638e1dcdae8b07b79cd86dc0..57dab1be4bfa91c7c9d7e53e7fe388a94dc60e0b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -240,7 +240,7 @@ import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper - - public final class CraftServer implements Server { -- private final String serverName = "Paper"; // Paper -+ private final String serverName = "Tuinity"; // Tuinity // Paper - private final String serverVersion; - private final String bukkitVersion = Versioning.getBukkitVersion(); - private final Logger logger = Logger.getLogger("Minecraft"); -@@ -886,6 +886,7 @@ public final class CraftServer implements Server { - - org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot - com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper -+ com.tuinity.tuinity.config.TuinityConfig.init((File) console.options.valueOf("tuinity-settings")); // Tuinity - Server Config - for (ServerLevel world : this.console.getAllLevels()) { - world.serverLevelData.setDifficulty(config.difficulty); - world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals); -@@ -920,6 +921,7 @@ public final class CraftServer implements Server { - } - world.spigotConfig.init(); // Spigot - world.paperConfig.init(); // Paper -+ world.tuinityConfig.init(); // Tuinity - Server Config - } - - Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper -@@ -2453,6 +2455,14 @@ public final class CraftServer implements Server { - return com.destroystokyo.paper.PaperConfig.config; - } - -+ // Tuinity start - add config to timings report -+ @Override -+ public YamlConfiguration getTuinityConfig() -+ { -+ return com.tuinity.tuinity.config.TuinityConfig.config; -+ } -+ // Tuinity end - add config to timings report -+ - @Override - public void restart() { - org.spigotmc.RestartCommand.restart(); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index eda5af586fa9710e8bb945bc65b8fe1579daea5a..2d59a2ee00feb596f5066b4a118dd06ec156ace7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -290,7 +290,7 @@ public class CraftWorld implements World { - public int getTileEntityCount() { - return net.minecraft.server.MCUtil.ensureMain(() -> { - // We don't use the full world tile entity list, so we must iterate chunks -- Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.visibleChunkMap; -+ Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Tuinity - change updating chunks map - int size = 0; - for (ChunkHolder playerchunk : chunks.values()) { - net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk(); -@@ -313,7 +313,7 @@ public class CraftWorld implements World { - return net.minecraft.server.MCUtil.ensureMain(() -> { - int ret = 0; - -- for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) { -+ for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().values()) { // Tuinity - change updating chunks map - if (chunkHolder.getTickingChunk() != null) { - ++ret; - } -@@ -352,13 +352,20 @@ public class CraftWorld implements World { - this.generator = gen; - - this.environment = env; -+ // Tuinity start - per world spawn limits -+ this.monsterSpawn = world.tuinityConfig.spawnLimitMonsters; -+ this.animalSpawn = world.tuinityConfig.spawnLimitAnimals; -+ this.waterAmbientSpawn = world.tuinityConfig.spawnLimitWaterAmbient; -+ this.waterAnimalSpawn = world.tuinityConfig.spawnLimitWaterAnimals; -+ this.ambientSpawn = world.tuinityConfig.spawnLimitAmbient; - // Paper start - per world spawn limits -- this.monsterSpawn = this.world.paperConfig.spawnLimitMonsters; -- this.animalSpawn = this.world.paperConfig.spawnLimitAnimals; -- this.waterAnimalSpawn = this.world.paperConfig.spawnLimitWaterAnimals; -- this.waterAmbientSpawn = this.world.paperConfig.spawnLimitWaterAmbient; -- this.ambientSpawn = this.world.paperConfig.spawnLimitAmbient; -+ if (this.monsterSpawn == -1) this.monsterSpawn = this.world.paperConfig.spawnLimitMonsters; -+ if (this.animalSpawn == -1) this.animalSpawn = this.world.paperConfig.spawnLimitAnimals; -+ if (this.waterAnimalSpawn == -1) this.waterAnimalSpawn = this.world.paperConfig.spawnLimitWaterAnimals; -+ if (this.waterAmbientSpawn == -1) this.waterAmbientSpawn = this.world.paperConfig.spawnLimitWaterAmbient; -+ if (this.ambientSpawn == -1) this.ambientSpawn = this.world.paperConfig.spawnLimitAmbient; - // Paper end -+ // Tuinity end - per world spawn limits - } - - @Override -@@ -432,14 +439,7 @@ public class CraftWorld implements World { - - @Override - public Chunk getChunkAt(int x, int z) { -- // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it -- net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); -- if (chunk == null) { -- addTicket(x, z); -- chunk = this.world.getChunkSource().getChunk(x, z, true); -- } -- return chunk.bukkitChunk; -- // Paper end -+ return this.world.getChunkSource().getChunk(x, z, true).bukkitChunk; // Tuinity - revert paper diff - } - - // Paper start -@@ -487,13 +487,16 @@ public class CraftWorld implements World { - public Chunk[] getLoadedChunks() { - // Paper start - if (Thread.currentThread() != world.getLevel().thread) { -- synchronized (world.getChunkSource().chunkMap.visibleChunkMap) { -- Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.visibleChunkMap; -- return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); -+ // Tuinity start - change updating chunks map -+ Long2ObjectLinkedOpenHashMap chunks; -+ synchronized (world.getChunkSource().chunkMap.updatingChunks) { -+ chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().clone(); - } -+ return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); -+ // Tuinity end - change updating chunks map - } - // Paper end -- Long2ObjectLinkedOpenHashMap chunks = this.world.getChunkSource().chunkMap.visibleChunkMap; -+ Long2ObjectLinkedOpenHashMap chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Tuinity - change updating chunks map - return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); - } - -@@ -2702,7 +2705,7 @@ public class CraftWorld implements World { - // Paper end - return this.world.getChunkSource().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { - net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null); -- if (chunk != null) addTicket(x, z); // Paper -+ if (false && chunk != null) addTicket(x, z); // Paper // Tuinity - revert - return java.util.concurrent.CompletableFuture.completedFuture(chunk == null ? null : chunk.getBukkitChunk()); - }, net.minecraft.server.MinecraftServer.getServer()); - } -@@ -2727,14 +2730,14 @@ public class CraftWorld implements World { - throw new IllegalArgumentException("View distance " + viewDistance + " is out of range of [2, 32]"); - } - net.minecraft.server.level.ChunkMap chunkMap = getHandle().getChunkSource().chunkMap; -- if (viewDistance != chunkMap.getEffectiveViewDistance()) { -+ if (true) { // Tuinity - replace old player chunk management - chunkMap.setViewDistance(viewDistance); - } - } - - @Override - public int getNoTickViewDistance() { -- return getHandle().getChunkSource().chunkMap.getEffectiveNoTickViewDistance(); -+ return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance(); // Tuinity - replace old player chunk management - } - - @Override -@@ -2743,11 +2746,22 @@ public class CraftWorld implements World { - throw new IllegalArgumentException("View distance " + viewDistance + " is out of range of [2, 32]"); - } - net.minecraft.server.level.ChunkMap chunkMap = getHandle().getChunkSource().chunkMap; -- if (viewDistance != chunkMap.getRawNoTickViewDistance()) { -+ if (true) { // Tuinity - replace old player chunk management - chunkMap.setNoTickViewDistance(viewDistance); - } - } - // Paper end - per player view distance -+ // Tuinity start - add view distances -+ @Override -+ public int getSendViewDistance() { -+ return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance(); -+ } -+ -+ @Override -+ public void setSendViewDistance(int viewDistance) { -+ getHandle().getChunkSource().chunkMap.playerChunkManager.setTargetSendDistance(viewDistance); -+ } -+ // Tuinity end - add view distances - - // Spigot start - private final org.bukkit.World.Spigot spigot = new org.bukkit.World.Spigot() -diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 22e9dd17f62103c5061435099ce96a3d70d54808..673fce7aa55cffc2c9ee017242d194a0dfd8be6b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/Main.java -+++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -146,6 +146,13 @@ public class Main { - .defaultsTo(new File("paper.yml")) - .describedAs("Yml file"); - // Paper end -+ // Tuinity start - Server Config -+ acceptsAll(asList("tuinity", "tuinity-settings"), "File for tuinity settings") -+ .withRequiredArg() -+ .ofType(File.class) -+ .defaultsTo(new File("tuinity.yml")) -+ .describedAs("Yml file"); -+ // Tuinity end - Server Config - - // Paper start - acceptsAll(asList("server-name"), "Name of the server") -@@ -269,7 +276,7 @@ public class Main { - if (buildDate.before(deadline.getTime())) { - // Paper start - This is some stupid bullshit - System.err.println("*** Warning, you've not updated in a while! ***"); -- System.err.println("*** Please download a new build as per instructions from https://papermc.io/downloads ***"); // Paper -+ System.err.println("*** Please download a new build ***"); // Paper // Tuinity - //System.err.println("*** Server will start in 20 seconds ***"); - //Thread.sleep(TimeUnit.SECONDS.toMillis(20)); - // Paper End -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 85ca30aef0703db6859e66c62781ecfd334426e7..8ce49478441e77cedf5148ecb81d78b32660329e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -519,27 +519,36 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - this.entity.setYHeadRot(yaw); - } - -- @Override// Paper start -- public java.util.concurrent.CompletableFuture teleportAsync(Location loc, @javax.annotation.Nonnull org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { -- net.minecraft.server.level.ChunkMap playerChunkMap = ((CraftWorld) loc.getWorld()).getHandle().getChunkSource().chunkMap; -- java.util.concurrent.CompletableFuture future = new java.util.concurrent.CompletableFuture<>(); -- -- loc.getWorld().getChunkAtAsyncUrgently(loc).thenCompose(chunk -> { -- net.minecraft.world.level.ChunkPos pair = new net.minecraft.world.level.ChunkPos(chunk.getX(), chunk.getZ()); -- ((CraftWorld) loc.getWorld()).getHandle().getChunkSource().addTicketAtLevel(TicketType.POST_TELEPORT, pair, 31, 0); -- net.minecraft.server.level.ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pair.toLong()); -- if (updatingChunk != null) { -- return updatingChunk.getEntityTickingChunkFuture(); -- } else { -- return java.util.concurrent.CompletableFuture.completedFuture(com.mojang.datafixers.util.Either.left(((org.bukkit.craftbukkit.CraftChunk)chunk).getHandle())); -+ // Tuinity start - implement teleportAsync better -+ @Override -+ public java.util.concurrent.CompletableFuture teleportAsync(Location location, TeleportCause cause) { -+ Preconditions.checkArgument(location != null, "location"); -+ location.checkFinite(); -+ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. -+ -+ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); -+ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); -+ -+ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), location.getX(), location.getZ(), (list) -> { -+ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource(); -+ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) { -+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); - } -- }).thenAccept((chunk) -> future.complete(teleport(loc, cause))).exceptionally(ex -> { -- future.completeExceptionally(ex); -- return null; -+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { -+ try { -+ ret.complete(CraftEntity.this.teleport(locationClone, cause) ? Boolean.TRUE : Boolean.FALSE); -+ } catch (Throwable throwable) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ ret.completeExceptionally(throwable); -+ } -+ }); - }); -- return future; -+ -+ return ret; - } -- // Paper end -+ // Tuinity end - implement teleportAsync better - - @Override - public boolean teleport(Location location) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 63aa742c505e14faa9bf5df29a8f759486fac80b..b2c6d1611422a3900e5c9d4b1983cc74dd820973 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -517,15 +517,70 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - } - -+ // Tuinity start - implement view distances -+ @Override -+ public int getSendViewDistance() { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ com.tuinity.tuinity.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ return chunkMap.playerChunkManager.getTargetSendDistance(); -+ } -+ return data.getTargetSendViewDistance(); -+ } -+ -+ @Override -+ public void setSendViewDistance(int viewDistance) { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ com.tuinity.tuinity.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ throw new IllegalStateException("Player is not attached to world"); -+ } -+ -+ data.setTargetSendViewDistance(viewDistance); -+ } -+ -+ @Override -+ public int getNoTickViewDistance() { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ com.tuinity.tuinity.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ return chunkMap.playerChunkManager.getTargetNoTickViewDistance(); -+ } -+ return data.getTargetNoTickViewDistance(); -+ } -+ -+ @Override -+ public void setNoTickViewDistance(int viewDistance) { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ com.tuinity.tuinity.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ throw new IllegalStateException("Player is not attached to world"); -+ } -+ -+ data.setTargetNoTickViewDistance(viewDistance); -+ } -+ - @Override - public int getViewDistance() { -- throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ com.tuinity.tuinity.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ return chunkMap.playerChunkManager.getTargetViewDistance(); -+ } -+ return data.getTargetTickViewDistance(); - } - - @Override - public void setViewDistance(int viewDistance) { -- throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ com.tuinity.tuinity.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ throw new IllegalStateException("Player is not attached to world"); -+ } -+ -+ data.setTargetTickViewDistance(viewDistance); - } -+ // Tuinity end - implement view distances - - @Override - public T getClientOption(com.destroystokyo.paper.ClientOption type) { -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java -index 2f3e2a404f55f09ae4db8261e495275e31228034..eb6cde923012d34a53a31f72b86870837e5f0824 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java -@@ -25,7 +25,10 @@ class CraftAsyncTask extends CraftTask { - @Override - public void run() { - final Thread thread = Thread.currentThread(); -- synchronized (this.workers) { -+ // Tuinity start - name threads according to running plugin -+ final String nameBefore = thread.getName(); -+ thread.setName(nameBefore + " - " + this.getOwner().getName()); -+ try { synchronized (this.workers) { // Tuinity end - name threads according to running plugin - if (getPeriod() == CraftTask.CANCEL) { - // Never continue running after cancelled. - // Checking this with the lock is important! -@@ -92,6 +95,7 @@ class CraftAsyncTask extends CraftTask { - } - } - } -+ } finally { thread.setName(nameBefore); } // Tuinity - name worker thread according - } - - LinkedList getWorkers() { -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -index 8ccfe9488db44d7d2cf4040a5b4cead33da1d5f4..d8c572b686c332eca722922c8a96d4629232856a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -@@ -113,9 +113,18 @@ public final class CraftScoreboardManager implements ScoreboardManager { - - // CraftBukkit method - public void getScoreboardScores(ObjectiveCriteria criteria, String name, Consumer consumer) { -+ // Tuinity start - add timings for scoreboard search -+ // plugins leaking scoreboards will make this very expensive, let server owners debug it easily -+ co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.startTimingIfSync(); -+ try { -+ // Tuinity end - add timings for scoreboard search - for (CraftScoreboard scoreboard : this.scoreboards) { - Scoreboard board = scoreboard.board; - board.forAllObjectives(criteria, name, (score) -> consumer.accept(score)); - } -+ } finally { // Tuinity start - add timings for scoreboard search -+ co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.stopTimingIfSync(); -+ } -+ // Tuinity end - add timings for scoreboard search - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -index 08634e060b35d653c5677b7c1012cfda266bf002..70ff3b27d3dae162d05edba7987136ee53decf2f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.util; - -+import java.util.Collections; - import java.util.List; - import java.util.Random; - import java.util.function.Predicate; -@@ -235,4 +236,20 @@ public class DummyGeneratorAccess implements LevelAccessor { - public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) { - return false; // SPIGOT-6515 - } -+ -+ // Tuinity start -+ @Override -+ public List getHardCollidingEntities(Entity except, AABB box, Predicate predicate) { -+ return Collections.emptyList(); -+ } -+ -+ @Override -+ public void getEntities(Entity except, AABB box, Predicate predicate, List into) {} -+ -+ @Override -+ public void getHardCollidingEntities(Entity except, AABB box, Predicate predicate, List into) {} -+ -+ @Override -+ public void getEntitiesByClass(Class clazz, Entity except, AABB box, List into, Predicate predicate) {} -+ // Tuinity end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java b/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java -index d40c0d8be1b0153d62021b8bcb6e8b37fd0acb4e..025540a62e805816cb93307c472bf0de64e2b01f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java -@@ -119,6 +119,32 @@ public class UnsafeList extends AbstractList implements List, RandomAcc - return this.indexOf(o) >= 0; - } - -+ // Tuinity start -+ protected transient int maxSize; -+ public void setSize(int size) { -+ if (this.maxSize < this.size) { -+ this.maxSize = this.size; -+ } -+ this.size = size; -+ } -+ -+ public void completeReset() { -+ if (this.data != null) { -+ Arrays.fill(this.data, 0, Math.max(this.size, this.maxSize), null); -+ } -+ this.size = 0; -+ this.maxSize = 0; -+ if (this.iterPool != null) { -+ for (Iterator temp : this.iterPool) { -+ if (temp == null) { -+ continue; -+ } -+ ((Itr)temp).valid = false; -+ } -+ } -+ } -+ // Tuinity end -+ - @Override - public void clear() { - // Create new array to reset memory usage to initial capacity -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 774556a62eb240da42e84db4502e2ed43495be17..001b1e5197eaa51bfff9031aa6c69876c9a47960 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -@@ -11,7 +11,7 @@ public final class Versioning { - public static String getBukkitVersion() { - String result = "Unknown-Version"; - -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); -+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/com.tuinity/tuinity-api/pom.properties"); // Tuinity - Properties properties = new Properties(); - - if (stream != null) { -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index a08583863f9fa08016bdfc7949a273eaa4429927..966639cc6ba6684bfb52e91ac047808cf4d003e4 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -205,7 +205,13 @@ public class ActivationRange - ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, 256, waterActivationRange ); - // Paper end - -- world.getEntities().get(maxBB, ActivationRange::activateEntity); -+ // Tuinity start -+ java.util.List entities = world.getEntities((Entity)null, maxBB, null); -+ for (int i = 0; i < entities.size(); i++) { -+ Entity entity = entities.get(i); -+ ActivationRange.activateEntity(entity); -+ } -+ // Tuinity end - } - MinecraftTimings.entityActivationCheckTimer.stopTiming(); - } -diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java -index 7a23b56752f6733ee626a8b1e4c3b78591855c4e..17151d9dc8c7030b54f1ba0956424d9d704c81ab 100644 ---- a/src/main/java/org/spigotmc/AsyncCatcher.java -+++ b/src/main/java/org/spigotmc/AsyncCatcher.java -@@ -10,8 +10,9 @@ public class AsyncCatcher - - public static void catchOp(String reason) - { -- if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) -+ if ( (AsyncCatcher.enabled || com.tuinity.tuinity.util.TickThread.STRICT_THREAD_CHECKS) && Thread.currentThread() != MinecraftServer.getServer().serverThread ) // Tuinity - { -+ MinecraftServer.LOGGER.fatal("Thread " + Thread.currentThread().getName() + " failed thread check for reason: Asynchronous " + reason, new Throwable()); // Tuinity - not all exceptions are printed - throw new IllegalStateException( "Asynchronous " + reason + "!" ); - } - } -diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index dcfbe77bdb25d9c58ffb7b75c48bdb580bc0de47..fcd3917e0af080ae4726e7f511abf586df4dc7de 100644 ---- a/src/main/java/org/spigotmc/WatchdogThread.java -+++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -23,6 +23,78 @@ public class WatchdogThread extends Thread - private volatile long lastTick; - private volatile boolean stopping; - -+ // Tuinity start - log detailed tick information -+ private void dumpEntity(net.minecraft.world.entity.Entity entity) { -+ Logger log = Bukkit.getServer().getLogger(); -+ double posX, posY, posZ; -+ net.minecraft.world.phys.Vec3 mot; -+ double moveStartX, moveStartY, moveStartZ; -+ net.minecraft.world.phys.Vec3 moveVec; -+ synchronized (entity.posLock) { -+ posX = entity.getX(); -+ posY = entity.getY(); -+ posZ = entity.getZ(); -+ mot = entity.getDeltaMovement(); -+ moveStartX = entity.getMoveStartX(); -+ moveStartY = entity.getMoveStartY(); -+ moveStartZ = entity.getMoveStartZ(); -+ moveVec = entity.getMoveVector(); -+ } -+ -+ String entityType = entity.getMinecraftKey().toString(); -+ java.util.UUID entityUUID = entity.getUUID(); -+ net.minecraft.world.level.Level world = entity.level; -+ -+ log.log(Level.SEVERE, "Ticking entity: " + entityType + ", entity class: " + entity.getClass().getName()); -+ log.log(Level.SEVERE, "Entity status: removed: " + entity.isRemoved() + ", valid: " + entity.valid + ", alive: " + entity.isAlive() + ", is passenger: " + entity.isPassenger()); -+ log.log(Level.SEVERE, "Entity UUID: " + entityUUID); -+ log.log(Level.SEVERE, "Position: world: '" + (world == null ? "unknown world?" : world.getWorld().getName()) + "' at location (" + posX + ", " + posY + ", " + posZ + ")"); -+ log.log(Level.SEVERE, "Velocity: " + (mot == null ? "unknown velocity" : mot.toString()) + " (in blocks per tick)"); -+ log.log(Level.SEVERE, "Entity AABB: " + entity.getBoundingBox()); -+ if (moveVec != null) { -+ log.log(Level.SEVERE, "Move call information: "); -+ log.log(Level.SEVERE, "Start position: (" + moveStartX + ", " + moveStartY + ", " + moveStartZ + ")"); -+ log.log(Level.SEVERE, "Move vector: " + moveVec.toString()); -+ } -+ } -+ -+ private void dumpTickingInfo() { -+ Logger log = Bukkit.getServer().getLogger(); -+ -+ // ticking entities -+ for (net.minecraft.world.entity.Entity entity : net.minecraft.server.level.ServerLevel.getCurrentlyTickingEntities()) { -+ this.dumpEntity(entity); -+ net.minecraft.world.entity.Entity vehicle = entity.getVehicle(); -+ if (vehicle != null) { -+ log.log(Level.SEVERE, "Detailing vehicle for above entity:"); -+ this.dumpEntity(vehicle); -+ } -+ } -+ -+ // packet processors -+ for (net.minecraft.network.PacketListener packetListener : net.minecraft.network.protocol.PacketUtils.getCurrentPacketProcessors()) { -+ if (packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl) { -+ net.minecraft.server.level.ServerPlayer player = ((net.minecraft.server.network.ServerGamePacketListenerImpl)packetListener).player; -+ long totalPackets = net.minecraft.network.protocol.PacketUtils.getTotalProcessedPackets(); -+ if (player == null) { -+ log.log(Level.SEVERE, "Handling packet for player connection or ticking player connection (null player): " + packetListener); -+ log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets); -+ } else { -+ this.dumpEntity(player); -+ net.minecraft.world.entity.Entity vehicle = player.getVehicle(); -+ if (vehicle != null) { -+ log.log(Level.SEVERE, "Detailing vehicle for above entity:"); -+ this.dumpEntity(vehicle); -+ } -+ log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets); -+ } -+ } else { -+ log.log(Level.SEVERE, "Handling packet for connection: " + packetListener); -+ } -+ } -+ } -+ // Tuinity end - log detailed tick information -+ - private WatchdogThread(long timeoutTime, boolean restart) - { - super( "Paper Watchdog Thread" ); -@@ -121,6 +193,7 @@ public class WatchdogThread extends Thread - log.log( Level.SEVERE, "------------------------------" ); - log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper - com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper -+ this.dumpTickingInfo(); // Tuinity - log detailed tick information - WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( server.serverThread.getId(), Integer.MAX_VALUE ), log ); - log.log( Level.SEVERE, "------------------------------" ); - // -diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png -index a7d785f60c884ee4ee487cc364402d66c3dc2ecc..1e6ee83b1a207eca59d82b25c06895ce894e8173 100644 -GIT binary patch -literal 23418 -zcmeFYWmH_-wk=#}0m0oV+}+*X-CYZUyF+mI1a}V}+)04oE&+lQG(i$vzslbGp0n?J -z=ic{jYv22KpcSyj9HY-U`xv9I#adM{YAUiQNQ6iL002c^PD%svd*t^E0Uq+RRpJCnpDr?!(Jf-{(g()1mU$77W~Nxy+`GL;Hd+mDj%< -z`hrC2`H9Xp$xKhL+Bo|HKmFo7=M-Xnd+W#BZSvAC(iiMjve~^o$4Z89_W8CRjpga8 -zv+emII+5u5MEB{@eX9E4yRDb7&Bx>ddEq2BvbJprC(KVzdi!1Hv=?V?eMFm!UV_HW -z<0^u;`E~qf&`C*71k3BLYs^6^yabk)Yj{C^qJi!8i)sPCIKOO3EVK#shU4l~4n!S! -zBamlrZCbkCbo>x;?i@>dx2tj1p0!K)a=rGr2p4?tkPD7Uai7@eu^4La)+NpTh=0lZ -zE(P78GpKSAt^%r$xC~`T`{upc*$uzT!TfrA3JV59PrYKoJM^id?usWu%mjxS3 -zGIWly9E+e~H|x~U79-+u{MV>MAb|`0-4G}cnLI5ADba_gfd16vBrVvaLTf}7i67f- -zUV>Jio#tHA0!~sm0$WpoKSN7XaeXh@QicB@RolHM98-~@BV9w0u_uzyp}OO(fy4Wr -zJ6yWa1vkdp)+N7#EaB{Yfr3+`*@tt=c)q!jl6ZmDL#*2gzWIp{69Q}B$Lkw*6d3E9 -zj_uz&w}qyzxK`wOuXwhtqv;8552mSzd|Q}T3AX)_u}HT0BEIyM(c#%fVL8Kl$)^Q- -z{cz)BjBTo$%y58*RW}_BV3pCfwG+RGqat@@zbbZ*z)HjE?T7VtC8S+15t5s!b=&=C -zuMOnJ=l9)reQEq93r~0)2a~9Mdp~&f4J|(Ua$ai{S=hrYe&$}+ef~hR0L`9fAlnp& -zU~_CYxN1ByF`|jyx`3l081=asXX^0V#MfW0Y0VrDu1g;K6Cwtlws(!g$mm8Fc@kmk -zHk0P``>>$trX -zOKO@8`AeIqg~@X}4s0Zdc8nGX+gS2a=5c65je_?zXn&ci*C*B5)?qG%26@N56+L?} -z_?X#4UxDE@4hnDzJay4|Cf4;AR@J+8U27CLTh9I}A5l!L!2P|^Ua+g%qMzCQE@)hL -zA~-&6za6OQ9%Z{iDi=UpL2anxJKdKrIBFb}_xMXd-+yzVJCa`;xB$c`45(a{uL_?H -z^UnJDof4?Z78^HM^tq81kY(+E0IU@LG@-q&gT3lP`C0BLFBi5s1Hd|u9H{b+){b^? -zVfdKsCmro&{*7zt>f#S%YdjlEHqY`MS=yCESuK;xK&3U=$+|Z6v2q#ROz^|kPh-CI -z>sUvd=>Cp2gT~p^Qg3DBWn_`9>(sprp=nf0XDapeDmb1HW5tc+++|m7V{%gSN~|TR -z2bCXzg_I)5(8c;v>pwESE4h025uEHWm_tcvSv0-E6WR7g3T6}C=sFV%aA~|;mXOgp -zbsW9;LREE09ya@GgH3vFkvo)fU+79v^vy#Rp>OwSYk=3Vr;1)qSCZpdl#Z+8kNuNv -zr^K;X5$X^A^f#^C!Z%c=re|~`tieWGWEBCuDKtv+o*#NWII)B$(msOTpG_kyd|Tr} -zl)isjXV6?~MrnDMVo}|bMAWHywlydwi}d}AA=Ng?^q9luER>~(DYgLsJPsoth{ -z^L0l>OMO@3z^=mT0BbDwT+^};TfH95K77HfImHl;O0l6Aa0i~unu9BP)>#ALajXQY -z(IAA-I$io%FzIkRDIA|X@Q&P^4W(}lk35PWxacGM{hEaQV`_!->QPK!o8{@lbl2vF -zAcCregL@&8&6g|$_T4n2`{CTidQJRh@uSlrAblg^dVxZ_UF{=zb0Tl@30I07F>s); -zB&Kq)g3KwCC(YS#qB6%v(@u$+^UMy-IEbUBQRDrBd@SheXBkgd<+C)wHq7gZ(RrO} -zX!YuqAdL^xp06x-d@$GZi>I*hU^L$u?W*m7&ycfFm$3!GKI38q6HzRhlyDjtX3lk -zl_?UG_9#t6uvIWv*&fx{vD>Y@YE%u*tmbl(Bt~m|8qUIR0E|ALe6o5B=)H;yd_lB9t3rQ!Y&l&## -zzEU*<$W>9t0Q=QZHACiN3EfqjA0BYIZ~f*20=YI6 -z{Em>2YX%d;v8O`|!SJKCxu8K^-rF~)StR^C_LzNYw?u|A-=xtK-E-CjvDW|v%}GaV -zP>LRLIvV@eU*8rL+c>f^D~|Rho639&VFj+l>yKJ4eIbWwD1l)MhOwTp9h+ -zK!7t0Oq{PSv;PgWzj^ -zi2;$Q6@7i22*WE_EZhAtRz=}@`u0)mfGB7G72hJ-GiF`^`eUMM(=a7(D(M}eL3wZG -zFgJ!gwvo5oi;MJpB%3^>s1ziW!x29I>H*20qpye1QzPY>*ui(rBWy_*%W{S`Y{OcR -z;zbDin`pyGAs3FMCRuEgvf!aoa@6cdNO8fd3@T}3!-A}!yy%eqNH6iIQ=srUm7A-3 -z!8WfxcESolm%~pvfNKS|ZTrS^QSb(nHCJKWNSZP1GS$UHdHlbS(qQ*g+7V7wT2`i! -zCxckawhv=4=em7PU-BOj;j-nuX7I#<1U2USu!s`sw|Qj0q(K7!e^j9MdH2b -zX}Up?>zr*gO%5&!lvoTUo{7b6mpGhRS1CzUtDJF4sWML|SaLy?OkcEgdVghZenRPl -zT*Mv9rd-4+A|eydl#C&mDzu6tWq+O)Y&AkmU>Bp27=kM5vFtu`ZzpZj@vGCo%vv{! -zzD)2e@LRT0LJOtL8t(XrO%vUysrYBGv+PiA9+s_+d00Q+Os}~m2GF=$VK(3)kO;U) -zjZ(o|6V%dWCy8&B&RJwqs2^}HSFy}|r+o@ApT97fjefwV(2k_5KvPxZ-@*}agR2!XW+R!#l>B$r!C#W9v@`sABQLji9L~ -z)E1^q%&2Ce@bIuybSCHF!L{|^5@~kU7GR9=h@2P6w~h<7IaY-IJ<_^ooUV+zZ666S -zPKvBHrs$lAcyJSiemBCBcrQMAiG$%VZ0yLA$2k;--khf~luvd6wPK;ZDyK5m5)H1l -z<8p|zfHgHurFh+Dl3F&5`tfWjh%Edv0XKZ&3cWqpoOL`l`+Y7Se&h#|a#-sSP{z-G -ziX!wTBm`(FcNsQuP1zVT*(2S!mL~Je1pw;qTk?&33{E4vlsj$W -zD3L=e#5ax!b$WJjG1qUw*eHu{+CGOFQ05#}RKFBY}O*@~B?zB{4V4QR~FA90s~- -zTKiB$qixoEEs{0}1i#-YNRS~(W -z+{it>$5Jd1@V3{zx5SblB_?Fu@}BAY>4MKV7)uaD@B0o|-X&pb@X`s!e#p -za}k=v@U~28t!OD3agfASR#`p6-YSbF+?KXJ0zQs@_^7C>zkHs;MZi&y>RCd9LkN`Q -zJRK@|*Nj#HK83KbiBT-{+q#NH`_$I98#vTp~vq(WNYq`8zQ!0Z_?>pjekqE&Jk -z6>6!8e$D3%XC;=(2A4j?jm*Hbk9?*^SL`5wFqWEiFL_TdMyfL_rVlL{*ObwlYlxAh -zVH!e4p`PV~jdCFi4Wy0ML>51?9<~8#Ag!|4C%nF!S_?IAf&I&r4;c`LVFeW9L -zajZu)Pq4%1+b_!)#4 -zV5`C%5cC}Rf|#gMmiRC}MHb?qMNtZR3GT8u8tlCp_pM&%K3$7kGKyx_>gilk&0Q3M -zT52YLk0#NRvl?xnB^|!Sp+lvsiqP|!Ib-zj-ICTVI;u}U6|gJ21zvgZ2=$zd{5n)+ -z+#wEOy%@GD6J$Ub>x~*&iLtd@+xN|4b4G^E7Z`M> -z#%ESGzLCqN5C%_G*l)|8+_vjhJvprN{H*nTr_}qic0be&HDBX%p;jgBt45ycsTmaH -zHCCI~uF*<}&178-@c5V^wC9;K_$vf*&5LQzzkG4x8EchNJ<05*$Y2lF>%8Bi6-Ll3 -zL1S@6ChLdHvxaH50O!`9;4?a5*H@zl$i&e3$gJq@mq`gxNLMvNO&F13kjC?;>M{li -zk=Z4eoD}aXu7wXN8_9U9xV*yZ~=F;wK)KM@Rc?AOHCXJ|CY -z?hshFPBFrd*z49R)eok%Eli-{C7VRFEBcda;lRV{&HVy&#rLoAefF-PkhLtrznBe2 -zw8$Cw=?*e?BZWa})K4;^p7eN&R9? -zD^F$@_(;-5){)bDug8pywS=C!bbs8Lua;QlFY@IN>3*{r-Q|^$znkGx7uVMX8BScP -ztPzM42}my8tn80z=Hu0>>>mx>wV2JJe?0lHyxv3Pcq-XqpFU!^|MPW0f8HR*Xk+tc -z9ZA$WJy9*&Y<`*Q5u05|4Dm!I?>&8PLl=Kw -zn3#G`ePZiV<*SCvxPM|rm6Z(^ca~V%n<_u#Z1K#>weTPYHK#|CUk=>ztkM5^J692u -zu1V2wDf?nTKhM%;JL3=r@9Om&ehaT3>93f-eP0@U0bhv6H{fk>gc1^RB;8GJuMq`$ -zGuTDABs2W={xdz}lR)H-RA?w>z!gCw<)Iq6Cs>ns;?3ED%N7&)3*J{}!^!%Fwy!D_ -zxZk352@DLZ9tFILkv}SmrN;4U_3O1PhBWf&`>!Ba*f*1EJ0_p1=i4D(S0An75>$`? -zYXf~+dXw8CR@fcV;CIp)E-{$7KhB;-ONcxBFH#Mk{@53GWn)9_G*0@dGc8lBV}M`6 -zDfaDB-q?frPE6|Y`t=pRqo^M%4u?m!6ej$OR9taQUN^Qeg)z|a9(9Ybgsc0n -zO!3-sFuAT@F+E{Q_Fbm*`J+i3io#Xi;S@pBadS~cn4y=#-&8mY)LXyf;~Z?N`VrF7 -z+OgDiI)ROBkh-aUwYNihC5Ztm|18l={{Sq5TcPB}Zen?eRb%c)D%^i1@h;-{&5aA}224huiur53b(2brgGoHD-H9le75aejeU-313HaR?~OWN*gVryiulZz4N_cM$T4d2 -zA+Y9$@O{OW8#Q?F&f;}xhswErtv)cVaott4#wF<#+33e}iCk3f7W(?I$&s&f5Kctv`YB@nB{(|$VJQYEmw=-`{@Ovm-R|fzz{$er(YBw3T1F-;98A-h^HA6flZT2^ -z1M`+o$;eAeP)c6GA`JVLLCe^Vuu}X~-^?oWn5)3om2iFfX4#I&F1@Nn)e3z5c&p{H -zuea!<6QIqvzCQ4ISwS(MhSv+li#kOPQDwWB94Sp_=%PC<=NO}KOI`{}4zPswUqVSM -zC{=%Y2_gD2y`N(joV}}xxDJD-j1-3j^>m>!D;M|R=9w$HrK~bIt)`JwerC^&-<-tp -zsuaorH593+$W(nRsr_OP1yejXhwk*Wlt7ZncB8To8ytA -zytu(cLN?tr$G&cJ-`i_ZHH!{i*Q3$*tj>#-h)I=sFYGf%_CoM+pb}bgaf1gpsqXTL -zium=nhJ(3W@O+{*hoF81@>1A?1zHTrIXlxj;_?xqv??})960xo6DbWS54n5pu2NO&g_dytq09An2Sr#iVIwp{9rSUbiGkS -za>{_uZVpZ=8}=vt@c?jc@gEaBRgt>*9*Y`eIB8rF_pPj*9owF%I{n!%b(x=Y%=yS? -zj)*k0vV1mg@<)#cEY7I$*)JUSeKIkb=tcv@LGsNj-7Jlgd7vJ_&M -z3Q#+wbQFNoe68YJu`dGMvIOroH5CN~z8<&CzEKi3@CPC^185`c&4>&pd^klX+Qu@y -zJRaRpVnkMA)x!LyUQtTCE^Zy|3Umy!4-DX^ylKCgZRMW`mLqx6GaiZ(*n90i!{Cbf -z~xJ9nMmsDIjVhJ3*<7BXsV>hyj- -zy=uR_Io=%^227&XsLnC3N^UX*`mOg_^0Er -z<)UdsVJ3V_;yjDM(^rojm)u9rZ9TIrUHL#>t*xQSS3JC{0?n7iGl44it=~yo-HDhK -zZ+xPWZ>9Lfkz7Fwh7nn6#=j0rm1U;b1DWkq(9Sp=N~t|V#+IRYO5fqOHs^6@@l8Xm -ztX>8?ZN2il159#ae47qP8aNPYw!EF#rFEJ)M@JG$&E2c3$gcLC;(*CjB;G89ak=cn -z-d=o*W>B*5Y?pTX7`>SgxV7(EVlR63YBgz!--3of+P3xT?#ty(u1FmZ>>|ZkzygW~ -zEP|kBj$(4T8~kQH!xcrsDG>D;0rHL`7lpJ1O6pa4TM55yLT1Ucyd0=>>R74 -zXqTK2@JrPFQg!rx&&Km`=kO5)Q^RnKk%u^ViQH!u1zUMdZ2Cy*<4Ln7t?ud&+Y3;} -zi{j-TsiYGCfC>joN~+0AO8&>gLdYY++`trJxldxmL#Bph#W+zm=&mDbc}&p?uIUW8 -z0}^1y=3_IrBRnp!oQ4rG-13_+vN&xZo~<#75uErr%;4mt{H(OXqp5}+#_oWt=*GJL -z*B+S1Ne0cye0i}&Cd$0%xQ@qa`~YbH41%PXl0|v`1e47+fA8t`?ul`_t#84DJ2C@Y -z8k9(iPvTLebhkM1TC>O0!yq)HBGLu_MYuQ~RnT7N_n$-ush@)K>G4-Cg&M_}-gfGp -zTIld-?GWrl7u%Nlp0G!(jlxAu$=^QKGez4_Ya=hk%r -zDCp__jHQd^?EdexM+u3z{LqoDp>ZdPG-pun1pCj^SO`)n;q30?q_>{pd+E`_okO3w -z+uE*0RLDY@JX-=_h>4+hsmDxie7sG)onP|7H#acv2HjdCx2GVFaM8hF$irJbWhDVi -zXGa!uD`yL979U3!$Or%+B`# -zXE$3`c7A?-RyGb+4i09B2eZ4clZUwvvy(gJZ-_rJq^#X7-M}s$U}q=LZ%lIwXHO4d -z3JSj(tpCZ${{;lZ{XYS?y!Lee`=UMFt$&;T*!XKJ8&=4!{#g3oCzX{~R{KZH?>yLo -z9bNv2`0f37Pblh -zb6fNN4MNoo3~3+p*Z*oId~7z>JeHQc%}aj&Vg8#cb{=+aE`ByH -zes*47HZI=3#p_tRxkGy6H!3?D3&)>3x3UzFfnb_LY832fZfniz;$-^=?(bv>K(+&+ -z)BJZ!L6HBjLwFUCbh9@1aCXyjc782P@q4wP-;jTFB1q`39urV#QNVk|8Gc|cFx{T|93e5bo~d4xSNN!vzvpeo2rGqwWY^@kMpmb|AC|d -zkw|wBH(&Yx!>0ZhKcPR1R1OmB?B@Ho`8BOw|2+Cr$6kZ~pb7-~Lpub_E&rt7-Q3IC -z>W>sac>Ht7($3t;)*2$xe>K>D*unpzkokBytj*cEd70TPAsWiXZehdB$IZ{f%*AiX -zYt3$H$-~F?zo5H2+jw}JyIG6dLTUh#XNUm&k!KLyU-d`-pI75;XZ^dl*f`jk**KZm -z*|pf&1vuCRIN2%w%r;1f^|vhl$8Lpw>yEOrz~A}!iy|p&H!x(gGH%X}e^Bv<0t#6D -z*WJzY-*z{IEr=uv{3}-eQU~t;GXAeZ{jHY*^1mBI)6>P}HQ3tiKj-g1>iNI$6Z)t9 -zuip7Th5y~{&uB?!7hj0F*muQ{|m=I5tP7|)=uuu|J~C6?(%24{&rS{toctH -zBn{zuOLuC9O6^*>_Z -zf8_k{>iYkUE~J0nKd^R!T#tG~?hf3j&(lKgEWleR%1QxVet#GCRHQ*Hh%R#a?f}3m -ztluvvKz1%Z#0d0|SC$5TgL#F8L)J^q7!3e`0P<4eT0W~k@_Yld7Vlm}555XMDA}Yo -zj3(0A4|WccWH6BHdDkl9XjS8=#~Jo5RKvk0w3M~Bw6ZLAHea8>H^m@j-nX>cw|p@@ -zk%14ldi#BpDeG#(|Mc#O9Sb=#dBryM>%rB|)ehW;b@!9@j$^_tB(^u6k}h_McuCQllCx6WPr8fi`+7H|R$TCT;+X9jpc< -z;Cg{WkWB@B6vLowwmB>?bkK#f5=qg05G@=_d>rk{Z2$W#2y157K;9MfTvKqk99$hGMBYd~U|5{&@WZKL#cU -zRsF5{wriLICSMtb&4Mta{zRXPW9M*LOAY);avRt%Z@$v_5s`iFuCO5la1LV!g@7PY -z=Otwj@Zgiwlec>iGDyyVG}hyU(8vc6!+}HNJl6eOyJRbTQhz*apbukp7@@i5_4bpJ -zQz7m)PqdYg&ri`#sAlTtF$<1PQAgriNqn(R%vo%00)}pr=oGoLm+ESho0!)e8>~cE -z&VD>h$t^m|0Qx5v`(0GwmN-20oQ5}tqbXZ~tL>C`w0Eonc_xETDKOWlN84gl;&|J{ -zIFlxa5=FiBDOn~jkyhOGTGHF1rzo$u0*j$E-V`nDlVHwbImE&sUN2a$rlOej6HvBkUOrN#vK7qhp&|SuQaJd0VAY)C(tz -z(&aZFn|O1f0r}x24<}3e3{fxccloYN!zMZd_%?tby|~+x46FC4WND -z-K(+SUD42K@MhW%KIR4D0~Bg+jENDD;0vfXqns;Vy9cp0UN+93>g~ -zV^td=!tDIKT$Yb0d-6QH9ykQL9|g1&%&53de(TL0X0^5_lu{7^MHNqtAJWo-v)7+Y -zHLr6S{C1)oXk70AW+Vh1^*2uPC%lbejE*rvl~4-n6<7I)K}OfQefV61$dq3)d5SOg -z21fO9Uk%-Qk~z#bbx;*6oX3XikpjZWj}N5KFYYI*IM~Lx31mq -z^#lqH=b*q_6um=#-~Q%sBtCsLf=W2@1mFVdsCfWmX}#T5Glh>n>n{MuhMV8`XhgsQ -zu*;X7H7ACxW5r*bZzAui;YSc!N9%tST6DNjG$Ou_4$X%Xle?SjaiIe`t*coQ760&! -zHG(Fl3fdZQj+faw_W^JxG^)tUu@mN}C=V|x=hR=>g~UtMH!k|JwZwU2P#Ob}+&c*Y -zEXZ`}H!7dE@gGe)=QI1~x!z)b4-4oe#|`_m3vUj7t>PxOh)4>dhQoca(8YcEt(4M&J2s=;GEZo{ASO$i+lo0u`eu>oK#h;xYW31JWJ)V -z&4PzHjj6nLW4TU?ODvKSpUC^L(pV^GHC%fprG(S(8XZ$`k6w!LqK*{SyKVnv0ABz4 -zhl7B;M8`4;gLUBmVhm@PQ^{+d+H{nA*6x$K9YWA2^7Pf_uvCro-tjnDi%A$NQPEn+Gf|E&UkLAH@TN -zz6r68;WK0lqf_dGsk9g4$VO@AdtBdtTiiK@JCgh!WS^fOu+ -zKXQb@8qsFXJ6aT35Rej*mAGYedyR&Q58sM7(%ZNs@y1B)S=9O^|?ChZ9%je -z4&(Xlhtzb$HjP(3IO%+DKZ}0IEhJUoymg1|^^ipU9JdBi&*wWN&l4}KrgL@(70FD) -z3U9B*BC`4bjwoKP^>*$wm;=y9F8c&VsW+UkL`JaC3b^S_<(I*2(xoVu;aL6%-8+hw -zcEZnB5|?*}VpjjSh7>kkkdw?PN+N -z^!L#k?sPfg-sund_})-@h-SvuA -zZ1+uI0k3J~AL|9B6Q4T+b*7c+2OC(|b>O!I0HV-r?6s(gZlIA5$6$vUGzZ1! -zxjHRz7e<@iY3sBj-<#n(a+Ktto?+A+Hihm)y`eHGDy*M6QslJTBQ~D-RIEMV*Q&B3 -zJWxIe{jWk7-8l(iuglhGp!ATo9so7;eT{~2>P`M8?y3+?pByoDeWg{7C;FCoAE#-> -z=*-wZq8JL=?06rZq!Gb(p2Hk&HqCP2mrrA5xVWN~=COR%z>Pko7Ihi(2`EGq`qtX) -z>T3;JMl0*O43rja&x}!N(*!f^ujVG#%U}0nnL4iGU$k!{MoBR -zWLT8Ouu#?`H-s`=h_a~nTP-H&1-vA$sC*fI={v@mKvMCPPQi#%e!zU@mp}Ro}CQ6Ddqh!_uD&6;P -z?AxxOtxGW^)J%#E_$@rZb8^+x2y{AF-r0>BVA;p2&?v-H8a?H(V@Ex;P1;tVSLyc -z{G4Xz=u_{la6_~KQ@1i-GQ?ZYLX~KT)K6W*#v*3tb5rp-@lD<;4+FC|+P#*OfmW+I -zD$r0-b8hPj79hN^ezk_#RGB9qg}jpL^T7Sp7Y`};t@_cdhu!|;4rQBe$@5# -zF|lvll87X_3o%3A3tT7;*>$V(5b;2+laeE0LGv3PG%EDXh~tok@13T88_~dZ@>vrz -zHZ}fq+Gs0g9-}K+4(-knQh}*`4kfCqV}XDvU}01$a*LZCv?bk5C%KFzT#!UDTbR>( -zEB0D5fhXF0l#WGOexh!yg8TGCG@g99?;l}Cxjc%tO31@7SF{W&58mqxcKYoAmOv?F -zi^(U}YtSJS(3Nlv(EW&1Bl1h*y$|}Ly4rYCdFYrHG*2H~-(Qj648u)Q|IXi3%mVp_ -zWc(%Jj8It=vW>Bv7WDp?bh-G4UYB5m#BYEN#F~7;QZyP!quanWpd)*yIC)ysNt#wy -z)1CEHXJZH9h5o*dCM1nrW199|vJQ>`>!`9ho~Q^m&Ye`nJR?vLn5L7`%Cr4M|L!ui -zR?NJP7XCGF8lEhlwYx{UJ1#bxS~kqv88=B3#@TJ^PAX7=uIEjDsR -z*oC$lJL5ZZ_HE*C%qEBav6=pI(G$p>38|w#vhz8c-nM%foL*($b{3^nZE$fCmvTQ9 -zRW>z6L|C}*JkKP2B0vS4i|W6>FQ^N|^P32ZJ`tNumQ)68iesU-t;OAhg65DMoTu?0^2S4-Y9(EitJ1@_gHIp%vqo7S#UXlGZ24ZKiJ-cHzXsGsI?b4 -zqCO;6F$AivQw5mHZfTBp2vuLrqFo}1n#gqg`R1gvoq;|$MRHdELhLp)1@&`p;lgQ1 -zs1XWD2Rb$xIq(i4bZizOiJ;auxtle2FyCgLO>p|1cI)@9Ta`IU;D%AxB -zz=j*s>OCobA3U;mn570!!HOn35(xWkD-TL??x$HpiX1p%Bkh}p%tub#cP1{IK3ZCz -zKyYf$YDDno?Uu7kC~CJFmF=X&t;oCjm+878n$QjohP|)qWe`AN#*Mj{_(FwaV`&Oh -z&kYa5SwB`ArV-L@0N#8~Uw+!swWBfgrp?}N6Bls+`HC7^o00try2`~-tu&Tg=&EaK -z)ITwOjb0{WCb(@={ny!$y!6Y^h5%Fu^5VeaKY#o?9* -zLtURX9Xg+*S(}UUB;`o!wI73P))9oW;4l=$ITU}!=s6x{sjVibn?y^WUokfkP$9Tz -zJDR8dbjOW(neDl)Oyb4oCBqWAgq*Z3yk~tg^Qd^*$gg(d|MSj^E4H4rO -zLq(9KLIf(F1ja(Hw?>Qfl)vJc>~t25m7%Oqi2ame{v~Ss;EnG>D%Hfc-ki}s8+|ID -zHUL*tny<)2z$YR18oK<{n&0*q75AMkeaaVs=}FnoE#?MDg%fd5J_D}1Z<&)DVHupD -zWQVqT5ar-0J1dmLJJz%t1a6A9#ox%CxWLs_lQ1zbr$MSF;T4*{d{_zg)o3>=f)$(; -z$17~skW#O=Wi|69{&U!DJ-t->;vRQ*B7Ovoo6QFj&DjSolTz>U8 -zfEORGa}O?3Fg)^&0Tx_eMLwt -zsZvn+Tyf9?Ls=CXO(fRf-(aFEMG}BT6Pgt-{q$q#0t6d#e=&fDd|;%V$5bZ-x{@+= -zd@jOOKmn_f)+a#u3^&@H*wD4ZFqpz7{tP9@m=!k19Q)8W9T@GKoH($(W%R?0-M3>e -zDR;x?M?4-EUnB-yaHV4yl((d;3UEk~uU{Hl34I0x(mKj-(U -zu5L(LXb)hG8#(KA=2uXZBtt9|;#Y-gn1p2HrpSyOKL|Pz@e8YS4i@xgJ7UADTDJSg -zPsqvQb$a_sSCvf~72y=YZkqv0QbatInCWaGo4@N0En*V|XA`)|>llI6FX~539Nz!s -z2N6w(3$hW#xNqj@7@5A*eU`&)O6@A!?8Hly0c!}EfYX&qD@|3Z03Y0JeT^tuN=$_5;=6PEvo?B~WomoH9H -zivvKf!H+m^Z9xKYm+7Z(}x+@u;#kEL{zv#Ko@|c -zH31KzI{pf$XK3K|+|zLdLc%;cM&!$^rdvx_YvwscW1ZcaVWKS*`Yq(uPe5coJc>Ht -z0E-LA%Dd3^<85xiFZz9ARKzVMM>E&EAZkp*66;m_w|Hup;Hzmth$z8peMKF1Mlu{9 -zyMukh;e2}PKAiwef#QM|n(ERsGN1ucR`9S0eP^XaNigx;7+yr0Z4^fh{4WX{HT8#lV2QOCIHdwNlLz2|-0YjHXf=uStu#ZtS@`K@dG4}+2L=7VCXa)v8V!dYl3xnwN{qDV@) -zr9X+&&ux~oFxXmR0{bQA+^Dewm;Fy%kL93uQ+Ih|g%vzh)M9J0^?9Ce8G62%K2zlX -zqI&3>?a&k*H`2e>$qMThIAOFkW`aMsrnEiBfPyFTE0|~RZ<98N@pgM)BZ!yvq}E|e -z8Trbjxm$C+Sr!qo7>-^EMiSz0;|6>cwi)n~9DpJKyBGz0gtwGSG+iZ0V$$Uk49Ap6 -zY*CGrbPi)L(?mr2CWDZU%Nzc4_S}a60qXm=OBZoaFs?LH?p206oaOE9Cjw3xCBCoE -zAEgQW(UB%m?cU|x!V5oq;jZu)_TNBYm_5LrLM;nVw)~!^W=tjjq5_s -z9^4^}3{`*xD5kT>ACh>s=h$tdJ@Zgm@Y98%Vide-Z_yOkdH($9w&y5sZ3~SKE8*H4 -zh{=Fry|sl7Py(naFk~`v=-HlZJW?e^ksm4wAVYspk#%Y`7>(NW;t%%GkPOp4IT8xj -z`(zaU?uu?!T7=(?cK2Ak=Y<9Rjq?hvMS9U|R&*Qy6E!>nLg0t0I9;yOD -zZ_Bbfm90HMQ{hs7!HjpoWqR2pf>t;tnCwU#7V0yR@*Z~@LH*?F`Z=>Bwq3|&2`5k5 -zha^LHBeB?C(&Q4>vFgt0A3fNnpJtbl0WulcH~q_(47E-nGtcBJ-X;39v3mg@vYvO9 -zZl1}u{MBrQZpTB2eR=B`el=_wZ^QPhk2cu%UFf>)1iY}twfF&A -zofj5f$&b_rm4v@R*YouI3T{jeo^o;vdMPDQ`6Wk2MyV5)YuYnKs9E;@Nn`Ibl5WMd -z;4mOyTm-{19`&+qoV`)2N0t@25h1hhmBi4Yv)GOsrxJO{qDo)NvMihuH^Lsh`ryZT -zFF{=e%#EkRa{?t8E7&g)izh>s4AWPm+c-^QD)=LD8qmbrJZ!`n0EM8tC^fo#8HAEy -z=!f;50sfgii%cQJ1_8U^(pPVyIVUJqYL)Xr6n~S7&Wb$DCvlhNKn={qpillv;!}!fKP_tBqX@0Oh_m&gWHLD2TXVV&OLz^TvenX7gOQ&s(gcUAZf{%5OrjxRvu0!Rwp -z`S@IMlOxyk`1WTzPC>PGO^b~7r`n{esOo%qefh*mnD#P|*qNS}~lpY>&-v+k% -z#ofBbA!)?>d3gVxnXdHrZ76)V{2>{t>$*Ork)UWNoWMU!TtR* -z2J}@!tKQZ|d$rLNzv>Y#F7%e6H5Qv6Kzw7F0g#T;@pfCy@GJTlF_2062TEJ{%(HIW -zy{ihmx-2ddG{1N2_+5@3cGAnQ27=yguJXtPU`L_fQzb&&`ZBfjMjX4ZxPi+TT8sE9 -z;wq{dRl?$g@@Bt&YkIhJ%=d;x0M)xndI|PbGZ5OB*Lyvj*}1y8=ikm}X?NHFpU}0- -z&b&s8AT@$Y4Q67&xMcbEHmpJou@cB;6CI)J5A4MTp1h9YbNaYd|4l4SaUgvZn#n8s -z7zT@BORhxB1YNp2aFz6+seMrN?zZ7mWU~lC6Y1W^UEUe@L__yCrl`&cW3!_43^^&N -z#Odh7)&*`Pwd@>?;T-q=ZwlYrD+G^XDfri{D9-dIFLf)vdn7{c -z5VkMr36j&vlKyy0ad!ERG!==MbDRdbeVRQPh1>NRrSbF(8ZAmQI8Y-k{Ea=0kO8E> -zY#LL8r@Z*_3ckN?unXB+bI_`9o8sRuTYJ>l+eJuo+TQ~63P7>V^N?C5BsOp8qV`9U -zI~hfM-B&&#Hq3x=!jt67)Gw8yry)e%V~@*tzKW-@{n1!}S_>%*SP))8gL;kd_2RFt -zZ!`Yn)X$7%s)T->I@&xU^ds~7FwiuXcHeW+c!V2tc>CuR-)p1^o~9&c9}&z-p}Q0h -z$no%x9mQ1yeG}5aI^u6oRQV!hQGHqKMDJmmOMl>UUPINNV!i8{O#gIzQN%RW2jx$N -zjC-g;#a8Yrl~N6@tc%znXt_)zJ+5s0y}QQ6P60GJ6a8qUcz0uPr~33Lb4zQyQGzWVXH()vr)3Fr%U9+ -zgk&N2lCF_K3(De%=zl%Va#)Hzk0SFkymEI_G*It1jN@D`0wC|6SqNAH@wm-2WnCAAg~7d(dcNiI9zD11;_j{3F^;@ -z8sjNRF0tzmXIk~b5ZxCdOE1Z>%E(i4D~yuos3Eki8S%M3!#ViGV$SSaDak`ycq4&% -zI=UiKsJ@WmFro7^X@%uLxZ=B;fQ%3bkF>AoXN{$a(YJRW&t$WN3dlex!f6f1AWdnV -zq7>5pFXp%=KS;KOgDQ*6yb1=Obg{;%sX(xn$nZZyhLko$OB%OhvAnqsWr;y}Bz*&X -zH<`M1KjML+$n*LDbq3+)BXN<8MlYJRW -zOo(I&O^8T#USwwwDQgXq#*(R|cx7KQjdilk$dYaBV+$#gJrr3cYqC@H{k;Fc_m}h2 -zbDrxt_kEx1xz4$s>n0}Xd&vi}_JC?g#oqjOqtl%DQ^&U2jtjdvhnKk7FH9itn&n8+ -zJo=Z3^3NqpPca6OEqdJ0yYlp_`3T{^;rHe&D2mUS8+KlsFKCYX-DXVRtcF}_yk?y~ -z*>JMqiiWG$E-}J2V?3O~2~bTj=<2{nb^W_kKGt6mmHuPPeUjB#5e}{ixx|rAvx4e) -zmj@jNhM`)`=OnIaKUX>Qh3907B#~2oBO5e4BTI^EixtLRy$UM!Lw_16S%7f^dA$Dt -zmiN)%3xRg;Lwz;r?N_X -zNGRS=Nk#?OBEs@p_N!>c&hzYiL;5m;gFoyh!<&$8pMfPMP*gB$_Ke~D22 -zKc)>tjYcBlQP&9=9~mY1N|sGtm6fh)*^*j+Dk5!p_hxCgiT2C&pz|7iSyRIj!3@2y -zo{Ed($nC9#L^_>5AeZTT;h^Qw|h3%~zez?08A -z4B|%}HL1&~>$yblVv3BJAF}Fwwbdr1LMHawmfZBd=rk|9C1={NF6l0~X#m$= -z$BL$-%lywtgN{ab$8;r?twc-lsDIq2|0bgBuIn -zl}tuOm}@B%TT*b{Rqdo$2Z^GUKThs9nj!x_gE5i2bBR#kA~BH^~LcNOK*u;!u+DLn0p- -z?5pPs{z@oAtr(j?QVJM?jFM*o?oeW;9|zK*EVKr1YHii(Y=nB^7$(n%0fpDE0C1lunj-a!?$m# -zRAHglXz>#~7I@}hI5#WV0Rc#mm$g;71c&`lUCw85M!QebGH#93L1XHEv5gx$OX -zb#=o6U(0Q=vrQ4Q0b;!2!FqOKnfSv^#sx(GkAfK6$Zp(I^|fK1RfRiOtm4Es&Vv3W -z48AGN(9iO{#g08om*p?o23piA=ejmslX5>PPdQL9d7Gmzhd|-P<)5KoxU-*HTsafRtv4%10MRl^oK= -zW2^4_~7F?f6DI+MYJo=+_yB|t#IU_J8GO_uv@sCd}3yecEOFH -zF2SOoc#<0!h6CnJ$fv@)8%j90%gi`o`7sP<_M5&3dGufgp2+kGfpnXx*?TmGXql`Z -zK-mK5TJ{;#bn?y^nE1=PN};IlEYt -z-BHe>`zH(tBjD~}*ad$cldWkY*yGoYa*?&gywKGZ*~xDLnP}ntN+K?$43gz*Len+b -z;Z4J3=$lM<1SS;Cm{_P9+u^}_W)V{dDNmsU^k5>$ncjuS~W07QO~BbZYhP!Wj@Fw_q9yk)?=tjyUU>;!iv~ezvMD3et4m<8rJB*+hxi9 -zOa=%1VW0(nC6IGmRwjs!n8*+*{42-^Fu|55t4mJ0=P8Ull#YHBQp5Y(eg}BKNIMJ0 -z8V0i(4nU0c3dTn5qgZAmfN=oJ-`HJ4*zS1hXi`maIL!~;GK&KCp|ZWok;pGT>oCrva0XmkI$3-QGAjqraem~wa6j_a*bHt^gF>m; -zgE~Om`SF>_bgvsE=>c|epIZJk%Vz^$s}|mrhIKn%@7_9o3N!96qf{(~?2fvjx_{#U -z?JHs%{cF2opyVHUX4`R5Q^uW33xFIbRu2EWMJ-Els>lx}Y6`});R8U3PPFldzy_0& -zT4s&kobB9;9#6|AO^JA+T))d5z#k|r2#8XQ?vagSUS>|iVj_3N0V0EYNcoQOnK){l -z*5~dT@>Zu(O2tD_nm_OtDzPY9;u=^!9OGlvd2Z}Glf#!}grVf+1qNWdMa|YN -z%r8MU3s=4n_wVWoC46Ot5|ut8lL!&4*~Cj!1(*AF)=(`_$BYI7cxMQ48N^gxpy7I_ -zSdw<0D&*iaw`Sp8q)~1fw9;q3TD958x852C{9&URgCh6_a%EC?M1GxEYQB;R%1^e` -zN_)obR!Q%iM%As!e|HnW4;JlDQKrDye#{WKVaz%z=X78~Feb9r#on!jKX$ad2~xAi -zM<=NTx~jb66DlKxL@9PaA{b_afJ_jZlhnbTq*Kfwl7B$1bPOc}7P*kmXU -z14}x`!zEpTP*lh}rn~0pT4`dpjlMEkf~iGl=5m%7;0H3}NF$%v-8?Q|s!Uv$WPjg( -z+HF>|ZO=bAcXf{(-+1J^n}4*z^_@mUU}d0$+I&ah2t@XYXJNxKlBFXhqA*|JeN2Sw -zx5C}g8$jEn((T{E?AXLp)C})MiSF2P{p@Fg<~maRtHGidF=9gSK~?|r&W)9=U#dl@ -z-OR+Z5a%SLd&6Z2cZ6_(!M2p%;!B>Ujh4fzfvJjEj?CL4cJ;{$nR{ig%3E;Jzi2VNm^~p*Q{zrsqZjq^T;;iJYC)?L!{&-#a9vvf^r1In1`EyG -zypR3?eJUjPRI1mR+6ncLX>~W@axRUspViH;TfdCMwLZZ<#4!wR>(9Nol@$!J%zp~D -zJl1s2TcI=657x0Uo)ck7t?F&91n9)!XX5&}GyZlN?f9rmJ1&p&peEYjrQnCCe6NJu -zkgtK}^G3L}Q^8VO`zw^m!`;!SRmK50gN`LP>=J)U~Ti@(v-%DUi -zIsWKyJgW)QLwP8*nDomJBHqP2f5p)|?!T$8MaYX--UME`W>p`HGH*hqHhCa|n!Gbi -zL(BC%)geM0@7`cST}au1`H&RQ0k>6yarWXW-QUd*`p_3Bm&W@Tp*eN^r45F!j<}xO -z>q(*1+!ImgdQV9Tt%v-3OmkG(w6}iivx}5KnY~#0#?D8wSUXx)Nc6>e<9W?;iS};C -zH`uXv5DvY7%vpuV0z}IV_7EH5nfNTMUr#oBi&KTqX}k9I_eU#&cmdb!>SG1XN`0<~ -zrd|djclMo&%FdZqBrngNb@uO0iavJSbwztTTem*$6*Zp57%EifHTj4@ihzmay|FQ{{!khsA>QJ - -literal 14310 -zcmXY21yoy2uugDycPmm{N^yd_Q`}vP7YOd|PH`>8wLo!q*HRn`6f5rV?*HD)IX5{c -zxpy-=`|Zxo_svGBD$Agwkf4A-AaprdNp;|J21vifLD%hMrT$lZeEex|7Xe0mqFAZArC{!qp)zJmbab@utqA`6 -z61Z~|e!k$IbXNT?PvGuuzT7G514$8e!}lsR>%nURMm+~pde``@(!O=ISt0%B93;Ez -za-qRi4n0Q>zQ2#2^_y08QOl3jT*!Ir5@<8VrFx(6f9sP|H8ttjftN;wrX>jP4BcG1;MfU5x^L`zc09u!bDBt#+ll=7@ -zB;}A$BKgu}V?#qfHvm`~pt%wG2y{MOc%B!8I`p|pc -zO#?sq!Zd&j8UPmvY4RQnfo>!6{a}GFV!}g@qu<3Wu$07X(O`vikNW$~q!ngF23Ls2 -z53p8js<-B_Qd?xX6rtq43Mdz(jOg2QXx#Wng_9^1^^~KqFNq{Kvb@Ap9}bf&xFA-C -z5+#cQ`#v$A=kd0O=agATcleBaxXf_(dnqbQz|cL9R&&Ni1omTs+6~YApmk)MCghxj -z1}mq&IU>1nEiF=q=PI`%jQbyRd=hVI83Sm{E-4uTc#w;NNwEW)C(C`xvWzY_%`_MmO -zD&g-sEaE)}6(&g)y-N&rNy;5@+{M`}!{60Y8wMgF5;HmO#B~hG`W$;7xLG*yF((rq -zxP6I#r#o`B3FppK{v(q1!C+YLFSfySDcHyoW!}EfzuCB1B|C5+oP}dtocnwkcNy1EZ6#5JX4=ePl&cu~0tMnt&79+I4%PaK>VqFx;r!QdNmnxlEqdU-QR%Nmu{aWP -zJxwXvt5fFTCOVgB)Zq -z%H0U=9q7Y0lu&1kc4zYT3*lHA@XJfoK>3WFM&WWf2u6^+wCm8##D$x@Gkw+t^HoO( -z4pxDRqg;$5S=t^k22H5^V3V0Qfy%Ogl8I%LD$52=7)J>Ki9Ej1HyEi_ujELlz8$-+?cdD1Zxi02kW0 -zaY=caFq4~s^R?zxcc3Z0X|az}Aww<{P$>6rk+5Di5J7$kWor0{Q&>+DWSBH^Gf`SP -zT{4}IOFh-hB7xwBdewq%de)q6QvxorV(()2>@j8i!kj)=^hN -zl_N{$9xTHHA;V&Zx#tX&1pOO;v^NiOP#_UK@J;;lp+OOhOOO2mlMdxM;Qv-mWG+^vzox|8t`w| -z=gPlM3)y6G*hfV1WwuMe>bO-vP9g`h5BqgO9x{ROBD;aPl>XDmvt(3PUxt|4RFRpK -z5OEtRz{(Oa_W_!Z4XHf#h;Z-~71XM7wlF*L!-#h_Uy2tGuy-rAZ)4{qE~feNkp}qf -zgvBtLkFPI~I7%C=OHZfPZz$j>L9)rb;l -z@J^dxncy52;wmHg=wC3|Xn6jPYCR7xc}~D0wNjoYxmoRh_zh=6@8coM1UQIa_z*1)cZPw4v40qoZQp-uy#DLv=oP -zX9b3vzFA2r8}|_AO8W1(OMG__0{1AUD&Z%&7-(>s+Z-X6Sv}G5QguIbZ3mYa--?09 -z;wNw?n=yAag4%m#w$$-YZ{(ZJUcwHfzu&!gykNjG)e}!=q8xy2_KS=ULsQwv45NK! -zVqqD8#S{vRjg4(Q6HM_F&tihNIQns<%DVjE$cv33ET>Dvc^#{z&#u&&9RgXO?ZLuebczKv#;! -zCS|2lIa37Bp#3RWj0$V3=I2>o40{(J^LD|EUH?!2;Z&HS*>7*V%{v1)wHaUP85mcX -z%q!K}Ntr*IzJD%++btJ;VQO*OjJL1t{GvR3cy@OC-~pe^bV?N`z0QKCr?Tom)4u%A -z3mi2k&eIgh0^rGI#Di+&3lrsy-r+}zwBkDQtswtPbkj!Y^l`{f!# -zLseC0M;DiifDa!({-G4{W$Wxsgv*(NX%HMyXhArVwY105dUHg?+=@6Sy8n@slS76x -zU7%PI8ToKm#qahfR;7kn#|t@9y(0EkooWBDqA1(mpO)>BBz))giBi8xVHlj#dR9U8 -zRo%`iBdlj8%_tRn^qa%T>{nsLLwTNld&WHLyfbPzv2W62m6q=Nsdxnk -z#{P==5!Lidx3bcr_qlUl%BX!xjywA?jv>FU^mJDa0zQT9Kw8RRHq>7B -zb~DXw0(oqBrOQunsm2ghWV2i1VmN{F?)U;0%*j{FEUxazAJ3)KSWomuhklkDi?5h*MTLDS5ma_Nk1sNZYzZ#$maGRyiXBzjG@(G__fuyBl(^A>s&{jF+J%5| -zv#7nD1XK806#_U_4#N2ANAxznk%;U$Y$z#{K*O07mADqx6LjACqwP<`HFV#C6Q*wx -z8JVP_qGF}V7B?^8)f*2F5AON7v$L~Kr?2}oPai_kG!_6MI(U`LS~+Mo*CSyrw>pPE -zllqxy -z^&rnDn4XA@AUY7~`1lwTCrm8KlVRqX&!kZFH&;i9@=R}UDxNSh*)Iq2U+#9}@ag1t -z%KUOEw0DXT)>hQoLTprY^z=BC=8NAyi3pZWT7A`?;rI<3%65Nqb93%pJ=!+dNtB>W -z7f3O-e-S7ZBgBntcyt~wOG_p$AU2zlGH8=%TEm+z8kLYReEMTkIo#2YiA=iKWrH); -zS%uT3xAyyY=!U)0Evpgx{{38MPR2nN<3913M<0O#YCO=TSt^4IzV3^D%2zC>t_OO} -z_h~AVOk+IIi$Ov;-g93a4j@WaekCC#HFm2_Vu9s)8-GbYtr{LgrxnSIN^PW9)!jYX -z?%-yssA~&R3F)C)wj5i|@!atCx?Qy%P1QEGSZm;iUNai`-F(8a%y+_a>CMzx$XEKx -z>sW|JbN36s+Y{4SZsrspH%UH=+Q6J`c&_-JLGL&5|$XUA1vFOC+rgoc&xT{dFT&pMaEBKwyD;plX0>2nla;jTlQ{!fn2M=Ak*=K*g% -zBm0-$ly1~}CT-5gv){jex9)7&b8u!a+vYHXU>=NF2>g3+_rN{(LUMGwRWKk49sS$v -zazyX8zZ1hwZ|U*5{fK@i@hRl*U%Q2cg+!iIfb)6W%S5F{91qinEZE%~4Gl>rBw9S< -zMP5$exl1jESyt}d~jo?hf`z^32b!}UGtJH+w9(0UrI#~Ei*ii&6z(AVE?(}k_A -zE9Z@mj7HF-ch46I0ipe3gapRj{=zk_J1E^b_JwdrhKi4ytBuwP)m>e$@9v`A{1N{h -zwUN6H=_W+h(a?rGaQ%%LP5C4)XiZ*`1uUwgqWvk`LyDD!Ps#Q5oI($KDJ%8n5kBi- -zghsLx`~mf<>WT)6-cJBbp|htk1NfkZ@e#B4@l?UH7!MDMpO?1NETGk_Eg{z!N3!D< -zWg8gtgS%b(0Bg7dw9u35xq)1vNdnM8iu7Eje*u?#sZ~%^q*HDaZC?5z4ZzhSA%ndS -z4&$M&7(|(9nWY%QShCnuN0 -z`n9&UeypypUgx;R+x;XM#8uDM{p`9~j<49)^dotHJVO*A@HL&g7F={FP#trj@{dzm -zeQUiqRWJ&pkKkA1O-|vOf8O1UQ$$0lIExffio|}F@ROV#MXcPH$ -z?$$kxAF@B#KT}u;R@SVyIO>1sw1!i?C(_013w9@?8$bKaLQi34zC$g*^}F&(%NEO6 -zQzD-^6}HQMnGJ{h$J*)HjSxjblWegsW&rLC8Ov_r_20jLjUS$Ptnm|p9fK%r0j+4; -z57^mjL&lISh8>DC;eB$B69$h4XxE3qU4T&zUpDeV@4g>or%D-x@qhie>6mqD959ck74(h?S0BA0}YQ18d?hr6}%}y{%ZNJ^-(?=Op~; -z#2-UNh)jH9>RXmvPJ(Y!8(uhyW|sFpyvv)AaNeljHj^Fx+RC -z!`@c->W1C^FUKHmG2w_atkdsMnzY+l!CV8havQ8-Gu)<8t{#V*2Pwp4h?ayXsi5Z> -zo!guta>TA~iv#iJpQkN>#)QF%As@2WgU&V_Y^qm#E*O}M_ijJfFWq}ts)-l4>D)kCqJJ@MG2$69ph0jzwI8ry1u8D@CyinC$oT?7S*Z}Eg -zYs}PWLqr4u@)w}#!{cMx;KxO6W2H6~3k$laJjAt+C{0mmCRnfs=OJYbh}HMh&e`#> -zj;jrpjqKCh41OK{FOS`@_sPP$iCm46G^EMNk8(l-1f>!gEV+4vMVRZ#8infUenP+k -zL^tBOHF^=)k&U-Tw{gfijqQ&^ -z-RHHII5yp}2|o8pTsf6x7$teW9Em!~iy2DN?D@|U)g%I6VG%JBO$|~;c~1Q^3|x`1 -z6HRbq1#~Ke)wWpALcc&@P;m+*sGavR0{aOx3=IwUE3YPWAwV45pzD$~02inxi7(6X -z$zk683M=_r#M*+6fQ)&FK0y|lm7JLwS)K=t&ZJk!U_-y%_o@fhr{s37MUEQOF*M)3 -zB$;4>Zx;Xk*(hwFjb>1iJ1f*D#nyWL{=>{2|9*^vCNN!%bF8Oe<`xz#s;jFz?;I}4M3lL;!fy_;J-E96Of+;sG%K=fZdR)99pJ}fM( -zq%(s8UrsEL{NrdF`!#RY+VjFyPpE_vtqPMM!MQ+QnE)+_g9Z^{4^;k&Sa^=w*yuxB_*Z!U%!3{_9Qr)Jfz4IeS#io4oj_Kqhq`HCUub|Ke!v$1-$v=kc+O#rlCej?%dhY -zxxKUTsFPG1nfoFp3%7@gh9S?vM0N27#*fpJyaX;Vy{!pt*}!9_mX9uC#J5RyjknW2Dm3dCvZYU -zSW?0kvI9!o2un}*%`AYhr^CQT1aZF=-Nt^atn@Kt%b2!hT(pK!|MclbBv3-<+6{>_ -z8toMfWc9rpOk(8|KW>Z-k>Fr(xc_+q9ocf`8!_n}XYUrW?Ax|*_|=5m*4F0V+46wJ -z1IGS^Z5t=0Zj86J2MfJc -zUq#WKCfhoB<;P2&&`*_G4^_0uqDR20m!>T8ay_rxSzA&9_v5##g6tzXTkx+KRfz32 -z9vvpp?+YxHTxDthCBu7)&Q052y4s9*$M4_2w-OdPyK?F-EBoUuSsIk@@(!gA*A_!0 -z2eu1y;-Q$Ut(M>8FCOtw?vZR-%*ly^x)<95vK@P0tJoZws@+M*NGhg_NU`!}DZnWBHQz%*@6))$BWN;EM0xAF+B4Mph#S??J?K+&viwPmes*n^HGDL9iBf -zCk|mDu46wwughN!isu&G((DO>Ws`(VLY?^#w=RONxUgFGby--Y=5NJ|(>qXOS`;lZhmXyMEyBdVM@jJh71E-})~`?t4w8^Kwy) -z<+KACjs!F^TS-;FT24_iWF+=l(nR}j7U#;Vd -z)IT3=b&}A}1PUKFa6DKfgHkJci!~7u?a%k9h7Rri^{y`|;;xNDoQbV}+oJ=LdApL}|77o@C= -z;~aed)XpbrMtt1x3gHPWxbliQH4nKBCew{9 -z*-_PTyn~`1VrwKcc4ZrhI^!MsZ{D0O0%O2!SHHi^Dfyr9*x*DGFKwc()b;q6nM*M7 -zvA$x_?$BMJJHN5HIn9Ps{_7-sn79~BZegaa5V;s(BA<5BnU?^AeJHXtd)cIj_UCjA -zW|N@MjV~vrJz{sE0Dzv}tXxUDQAXm)1(kX7C_ZVFX%!TlZ850i(P1A0BxaJu)#LcH -zoxMFRzxoxw$bM=B6gpuMD#vcsa^00?%=D+T9-dQqV*=zD|)W!3BLun2&^n)~$ -z2_^{i9~sGXOAsF_S=k&4mWJ@`mD+G%MiPTlhuomboeFNwHb(< -zVpVR!mwf;JmpO3JL|B%L-!;@7TG}+`HZA;-{VIlQGY|T=f|!9!S=!c?sq5|KeEQ*~ -zm!1xeZcJPbSsfjU9e>K|=Ni<+YgrIG!|5@|Z>4bjx+`1j^O-{QK8XARf -zUG$nLRiTEtt;)9F30rvw>nj)@vCF{$d7>o2n>}~Y2^^C79l@s`uXRZOcuy>^%2@t- -zRGv={pKlDXFUgvG_^DWGR==il1rIzn{$p4r(FVOQxZi!_*Ksfl2hR{Aj>01RbFAM= -zpr0wzMwlOwlkt4|JLK)$>VL+{4nv>^`yMa)T;(9f*B(9;{T+)_=M4dN>M&&hS-#(G -z)-sW(WxVkHR)`x#g)25Lu7qnN;~Q-bvKDZ=;^fyLy@okDpvt&ZU{!U)WVtmnp -zAN-CzM{jPFWep9NAKDDq@=kynkGi_GQ@Z2y_Wn)xc_q3-&+9`qdGy_{PF-2c^$)%x -zd0sonEJhtG*2|P*Q-f_3`Akk96HzBz2 -z!5tnJaCcA2hGQrSw*{F)epvfYX?7toP=O0dN -zizY2w`>O@4Vqff!dBhQ^><#TjMP}loM9ProiD-Og@$V=*zQ|Avg0D!+96lr^u(1fl -z3J52PHoJYDdvdiIW?q?JIC*r?88VruLx#bp0lys39v$(c6uC*j}2IFFh -zViOX|K+DH18cd9%Rgjs$*sXuoW<>p^Fv-7CV|zpgTUnj812pyyX-nhA4TZ^UyYY9; -z?}BOarTT1q;0xSTjV_DPWE11?Y2+wSA*ybzebDoy8JwhznKa6SvYxE$WswX7Z6pG$ -zsA2GgHFFL3^zA@XTYK{a+6$Q8di%@1-|q9U15y+~R-L7Kwx8*xr(FP{g*JDPa`e((jSl#~?Rx=3ne(nLfeP9k0grubJK -zU4euzZqt~$Cl%k^{-!e6YQZi|D3#+MUS}VsYZ)0S>y@)kyqRI?A_esvAu-{`1Uq@! -zC+b`wnMK&<_mitl+k@e*$*{&S>vayX*>D>Q5sw2FZ?l(8ff%(8lo<^mBMrwQXOXe+ -z*7sZdWzBTIwZO$y^F)qZL1XbOMY<@M_a56y{({Vg@YN<_y}toq41V%~w=+4ZQvg)X -zVw~l$z-sId^nKU%dlk7W(mG}eS&KV2BdYqNJnX-p=YrG&&`_m0fzA_|iKD${5?oL* -zdS$heR@%Q+(3!!T&k;tIN|v2j=UI))rgkvyC7MTTrKP3g>Fma@_R0`GE5(tL%sS$7 -zG41ag%(Y(xZ5cjlk=R~(3XC+$25r*Fo=G5OhGgR}i!nDoG?^sult?Eo*x$x6CH-3L@LtZ0dfq!Bbbw-S}RwlN%lpH8c=4l2qH -z1wRszHSPh~=esnWvXD8B{D4<}?}6cA+@Ob1760Is6`g!zl@WL(L&={LA}SxAt0>Tw -z%b7i^&yNKM;(vGcNwuxAK{g|S3Y1&pH_6U1G -z3M4zx5FU=O;=l_?VzQ-~bx~xN1axPgYI0am3d25BjYmfSTX7Q}==Vcryl6@Se0(Jv -zxKW_o%H`jdnC7QXlkFbCsACHN1Dx=0gf<~@PW-&<=`1Hd)@#ypH7%OpalDj-P=ts+3^~yWs~TV}BD20HjkW6zc1L -z0#HzMkn3JV%7N-18_@tgE82*YnmEzxirriDSx#_|<|q1vL{k}7>^mRzO(ueTSN2~H -zG}kxp)Qn!&)><3|e>62+GXSpQKcemfqU!&BHZ5Ca;DT<63bBM&uV1BDS?MM$M;x8w>gShAPMxJM^BbMZn}Unm{OC9^4x3%% -zlmX8!km-u$N4fQXQ>jRe`7)3+RFGjhz -z18zf(Fo2<>YV^7LJO^UTZ2Ivd#mpN}o?7pBV&q=f%ID>haV7M8R3jsF*@a%iwIy>| -zsZ!-y{!%&j7`B?W8TcF4NH-RHH1xZ{;7BsA<#APu!;cND)te)FhoXz$BIU}2&^7WP -zT}TX>ZO58$VNPuh6JV7~s(W$vAj`^%AtUamex3YdVl3~4+pqk?G)qUibNMrj0*M25 -zY>5Ac|Dnv6xBQmV#$3JA?&HTN(lYl~J}@$l{*TY^kORrCB)3dDO}^^v!dcLf^CHty -zanjllIQeSLmpuG+h&ae`r*v!C*0A&W^a&q>93?BAXzG7n -z2*3TGPIcN`-_hY9&oaiv#fiv~>}7`T`4=pInEqWX*3e8+yPm^9h-tr&ts55$l+388 -zW)~F}2JH!}VLbQ>?6~H@&k`MnSsTeVj0TRVP4jGbP*!!CwM6`Z11c)yI2w$+R0zxo -zT|obYS1&&`{>>Z9(jnVU&=yI*%PGe*f78ie*_9oap?sd7fx7{r^WT>=XHF -zl`f{=UJEn2?tRw`Fem?eRE6#*nOes(ebRcmaK3~a3{a3EyE1zXSF0p7I_iDJ&%;3V -zU;AS}e?*mH#Yh2P9E3QBigIqu2iXf=@t)2+I~f*_E^JtEP1@IR{CBfTj%T}E3e#n% -zUa{@vU?D$l4DEANwkkK@ruP4ta)E*e^KLGg%$PizyPmHvKNMWtuJQ6sPXY=(1m#>W -z7V?9E!Vj}>a|KfQx5ESpH+q6$@gAp-P#~lbz`aj1_?xinN>3o8b2-Z3w>UZ3QZ}W0 -zWg-!>p>AADDcU^4;0*L4UFgB0QLlXd^y1E&4>txV!T|!`RwjZGl`;-4ZgFf>luHIy -zZ8d8Rh{I3r!g-ht6mAZxMB6VxRqnA0UY`h|mJZy2 -z17BazT$jMKFL3J6Ue_HL1^)4s%$Jj~Qx~1HG#tS@kwL(KP_ZI3dWz0SH(sqj#-*TNGsIWqPj>cj?!GyWvfdEiNOu4$>MIqL=F&Cc0{g*~L5 -zA1wt)=_zMFUkCT5$l!G{1-Y9QtGQ#qm5E(3fYPms_EP*sSVI)bfXN|uNO`BqVuCvd -zv)z8IGRgtM1<_trndVhQ^xA)wn~*W~#d*X@E=W)jcQWI8+?kdzHe;DZ`%+JE%gE}m -z6H=FO8rJxM{N90S=Gi!Mel)TyanxPa;E}C?hJl@e9UWad->;S|v;axgFjrY$z3(rV{MiJ}3M)t;Q?P5wZy0e3G{dcDO7n}3slDXLMrB$;#*W@Qv)D$=?Xs$F(8eTcyGIQ~IWgD%Gn&E>F9y#o>cR-7spE;Rur<_E~Pu)e0I -z#&y1|@8D~8c55<|KMf;&x;hg!A%VOZ38_+uk`jH4#=b9M&xcpxV-7cMN{jXVRnKSe -zlKJJ%=VBV{$DNeI1QkiA;DfdVT?$;O#22z6v6bTK9)fjrfIh!Hq__l~KzuNqT{&kA -zKs@YV6^1ZLGjTgR%(=NHS-DvWnnP)NM#qbHINqmQdCE5??co$3nuikqgm=s7*#Kd*+j_weKrZjMeLeHEoiJm>zuDRU` -zh~ggr^knneWU!Nn}AQt=0Id6Hk; -z4bJqse|V$H`stT?NS0yreYvaZ9YF!fw+N}{3#yXRU!C7?exl35BDC%+!jDMGT^DN# -zN9FGd#5t#;$h}5UgQ?q-Gr15>C6=nLUszle9<+_!!oi_m@_L^-R>_Qty7_g|C%m|5 -z-7^5X5V_ARi?h9_LW%2vByD3X_IvUktqBv{%SYXO1&;e&O#Ll_cfC`Wv1u+l_#RI< -zQ5Kly0;P`%TXaQN(heOg~>V&L{d+ZDA%eq-UKo#1)$rkjSm=nzAE2r -z5--RyKhxfXoGVU3^ab{5XGlyL1+26foG)4HZvN -zG@&I3h0fnK5lIjcrg*XxPy1(gK3_TN`&VYnxP;C|j$~0rT$0f|*#=OzM^NbE-1T5D -z%Csnt)n!sx3N#b(8G&+G3W~Q_B#StA6jZZ=p#wuu`DrAMXm{T@#S;ku4Dme@{Njmk -zCtrh3z6O>o)~o{&Htx+6kn*)$NNBH-biu^aYtWUq -z(G>4rCEKr#tO>!x8A@%W@6g)Xs%2Hq!y#Mbb@9R2@GDWi&!{jhZvzQ1D9nMuPoOS+ -z+cj{9nx5X{jJOIavbFf)Kz5Jnbe5Bu#(XE-z$j&iaP%c9W59OoT0~|N#D*(N2kz={ -zs(|)nH!_+_g1)#ZH2xk>ZTG#6WN#qa3BxZM{NWxq`*#$H255k6Ky?hw*hSA6`c_fl -zT@Ua%E5Ez3;~`kQFmrC#$Nlvc_Uy3#yzhd-6UYuuIwgIBZZC-`dwOBJbfurL(FfhH -z{YkjE+9OrOveY`{t{sGw&51YO1@{iO4)Ki=!Z5#q=m_Hi)_j0`>?;t2j);vv%BUif -z;wpTZdLQLsGvZ()DCdxYudn^Pt;BZ}Rin$4F8h{R`HxT2z`uc&aMXIQOvwgA5%{&) -zFW52MiN!$!EXgx}Px~e1!EMp;#&kY65oDho95j~!qD%YJr`+aK4jCJ4UJ^;q>w@Lf -zvDfg|M`S^@DGxu+7aR3Cx#;%?advj&1~L-m -zJqCP9&TW3migV*`Z$#)Qa>3>Jf)g9D6Ki28P@iX(uso)hic8Dp1F< -zeF;(n8Po8A*~^T{De(J)Z2nqLl@Vv3yoSlGwq0aeOg4ymI(KIkTeur-=J-yp9z?qe)it6gq-wl@I -z0D-_I{|T<5kwD9uH3yf1GWXp5*8eOgJf*q0IRoK|+r{}Fug&0WpNDKMTC@(Xc)9K8 -zy`lByMn!1fnY)1KYP(0Je1)c~WilUuh<&Q8^OE?L9Q^xK*Y@M$`6D6TDCZ^@l8{|} -zxmmNw)mng$hYBii+&ZqedxWT0dnV#LG4zC%+kzcK+-??vEHT>Q-T8zu|s_1IbA#OV)^+1pg1OmmZn` - diff --git a/patches/server/0003-Change-Airplane-defaults-closer-to-vanilla.patch b/patches/server/0002-Change-Airplane-defaults-closer-to-vanilla.patch similarity index 96% rename from patches/server/0003-Change-Airplane-defaults-closer-to-vanilla.patch rename to patches/server/0002-Change-Airplane-defaults-closer-to-vanilla.patch index ed08fcecc..12b2ec104 100644 --- a/patches/server/0003-Change-Airplane-defaults-closer-to-vanilla.patch +++ b/patches/server/0002-Change-Airplane-defaults-closer-to-vanilla.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Change Airplane defaults closer to vanilla diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index cba14fd282d1294eba4581336c5e438484df76f9..5b4000d1f63e2b028e7a4450dcd084eb507f7f91 100644 +index 25f1656a47037b0245cdd32e475b41e64dbad1de..c6dd2567ac88c7bfff0a23201752fa6561f2565b 100644 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java @@ -202,7 +202,7 @@ public class PaperConfig { diff --git a/patches/server/0003-Rebrand.patch b/patches/server/0003-Rebrand.patch new file mode 100644 index 000000000..8179d4ea8 --- /dev/null +++ b/patches/server/0003-Rebrand.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 May 2019 01:02:11 -0500 +Subject: [PATCH] Rebrand + + +diff --git a/build.gradle.kts b/build.gradle.kts +index 8a56862f59b7b7d64580b46c561643a1d99348c7..c3fe90ad080917b69e506618e42f1a0a5b2acbd5 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -29,7 +29,7 @@ repositories { + } + + dependencies { +- implementation(project(":Airplane-API")) // Airplane // Tuinity ++ implementation(project(":Purpur-API"))// Airplane // Purpur + implementation("io.papermc.paper:paper-mojangapi:1.17.1-R0.1-SNAPSHOT") // Airplane + // Paper start + implementation("org.jline:jline-terminal-jansi:3.12.1") +@@ -61,6 +61,7 @@ dependencies { + + implementation("co.aikar:cleaner:1.0-SNAPSHOT") // Paper + implementation("io.netty:netty-all:4.1.65.Final") // Paper ++ implementation("cat.inspiracio:rhino-js-engine:1.7.7.1") // Purpur + + implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation + implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Paper +@@ -86,7 +87,7 @@ tasks.jar { + attributes( + "Main-Class" to "org.bukkit.craftbukkit.Main", + "Implementation-Title" to "CraftBukkit", +- "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane ++ "Implementation-Version" to "git-Purpur-$implementationVersion", // Airplane // Purpur + "Implementation-Vendor" to date, // Paper + "Specification-Title" to "Bukkit", + "Specification-Version" to project.version, +diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +index 030731923811f7748e8f9086f88e913031f1ec21..e2c0717066ac16a9274daff1a192bf70f0c119a0 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java ++++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +@@ -18,7 +18,7 @@ import java.util.stream.StreamSupport; + + public class PaperVersionFetcher implements VersionFetcher { + private static final java.util.regex.Pattern VER_PATTERN = java.util.regex.Pattern.compile("^([0-9\\.]*)\\-.*R"); // R is an anchor, will always give '-R' at end +- private static final String GITHUB_BRANCH_NAME = "master"; ++ private static final String JENKINS_URL = "https://ci.pl3x.net/job/Purpur/lastSuccessfulBuild/buildNumber"; // Purpur + private static @Nullable String mcVer; + + @Override +@@ -29,8 +29,8 @@ public class PaperVersionFetcher implements VersionFetcher { + @Nonnull + @Override + public Component getVersionMessage(@Nonnull String serverVersion) { +- String[] parts = serverVersion.substring("git-Airplane-".length()).split("[-\\s]"); // Airplane +- final Component updateMessage = getUpdateStatusMessage("TECHNOVE/Airplane", GITHUB_BRANCH_NAME, parts[0]); // Airplane ++ String[] parts = serverVersion.substring("git-Purpur-".length()).split("[-\\s]"); // Airplane // Purpur ++ final Component updateMessage = getUpdateStatusMessage("pl3xgaming/Purpur", "ver/" + getMinecraftVersion(), parts[0]); // Airplane // Purpur + final Component history = getHistory(); + + return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage; +@@ -43,7 +43,7 @@ public class PaperVersionFetcher implements VersionFetcher { + String result = matcher.group(); + mcVer = result.substring(0, result.length() - 2); // strip 'R' anchor and trailing '-' + } else { +- org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to PaperMC!"); ++ org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to Purpur!"); // Purpur + org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString()); + org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion()); + } +@@ -78,15 +78,11 @@ public class PaperVersionFetcher implements VersionFetcher { + if (siteApiVersion == null) { return -1; } + try { + try (BufferedReader reader = Resources.asCharSource( +- new URL("https://papermc.io/api/v2/projects/paper/versions/" + siteApiVersion), ++ new URL("https://api.pl3x.net/v2/purpur/" + siteApiVersion), // Purpur + Charsets.UTF_8 + ).openBufferedStream()) { + JsonObject json = new Gson().fromJson(reader, JsonObject.class); +- JsonArray builds = json.getAsJsonArray("builds"); +- int latest = StreamSupport.stream(builds.spliterator(), false) +- .mapToInt(e -> e.getAsInt()) +- .max() +- .getAsInt(); ++ int latest = json.getAsJsonObject("builds").getAsJsonPrimitive("latest").getAsInt(); // Purpur + return latest - jenkinsBuild; + } catch (JsonSyntaxException ex) { + ex.printStackTrace(); +diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java +index e0b1f0671d16ddddcb6725acd25a1d1d69e42701..8c3c68465197fafc14849dc38a572e309931e2a2 100644 +--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java ++++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java +@@ -17,7 +17,7 @@ public final class PaperConsole extends SimpleTerminalConsole { + @Override + protected LineReader buildReader(LineReaderBuilder builder) { + builder +- .appName("Paper") ++ .appName("Purpur") // Purpur + .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history")) + .completer(new ConsoleCommandCompleter(this.server)) + .option(LineReader.Option.COMPLETE_IN_WORD, true); +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 1490753c9f47769177212051924306493efdc5d5..080ccf4092de52292175c9333b530b82bf3aa5c8 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1730,7 +1730,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! ++ return "Purpur"; // Purpur - Purpur > // Airplane - Airplane > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! + } + + public SystemReport fillSystemReport(SystemReport details) { +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 8242200f073aee40482b190c7c0aafd5320ac4fe..f15a8118880ee3c9a71f450a84b873aa076c6350 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -283,11 +283,12 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); + // Spigot start +- if (org.spigotmc.SpigotConfig.bungee) { +- DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); ++ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) { // Purpur ++ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord or Velocity, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); // Purpur + DedicatedServer.LOGGER.warn("Please see http://www.spigotmc.org/wiki/firewall-guide/ for further information."); + } else { + DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); ++ DedicatedServer.LOGGER.warn("You will not be offered any support as long as the server allows offline-mode players to join."); // Purpur + } + // Spigot end + DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index fe1b046f707ee145327475b7f923928f4dfcad05..c757e4fe3e511f699512dccbcb11137fab82ea5e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -246,7 +246,7 @@ import javax.annotation.Nullable; // Paper + import javax.annotation.Nonnull; // Paper + + public final class CraftServer implements Server { +- private final String serverName = "Airplane"; // Paper // Airplane ++ private final String serverName = "Purpur"; // Paper // Airplane // Purpur + private final String serverVersion; + private final String bukkitVersion = Versioning.getBukkitVersion(); + private final Logger logger = Logger.getLogger("Minecraft"); +diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +index 7217088fda330c97c6edd007159aa6b2dee41bfb..e7d740e191c5ac408ba1fa493e9367dd52900a02 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +@@ -11,7 +11,7 @@ public final class Versioning { + public static String getBukkitVersion() { + String result = "Unknown-Version"; + +- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/gg.airplane/airplane-api/pom.properties"); // Airplane ++ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/net.pl3x.purpur/purpur-api/pom.properties"); // Airplane // Purpur + Properties properties = new Properties(); + + if (stream != null) { diff --git a/patches/server/0005-Purpur-config-files.patch b/patches/server/0004-Purpur-config-files.patch similarity index 90% rename from patches/server/0005-Purpur-config-files.patch rename to patches/server/0004-Purpur-config-files.patch index 0c4e82dca..0c3b7cfcf 100644 --- a/patches/server/0005-Purpur-config-files.patch +++ b/patches/server/0004-Purpur-config-files.patch @@ -5,31 +5,32 @@ Subject: [PATCH] Purpur config files diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index f5d01bce4d5547b4aeca96b7962b2090f47ea541..b3e7a11adf333d412ffde82aca9c9848d99bfc92 100644 +index 9d70f944af2c81ab5ab23b06857d740db74709d9..05f1b6d103ec20f196b60944f5bc007384c449f1 100644 --- a/src/main/java/com/destroystokyo/paper/Metrics.java +++ b/src/main/java/com/destroystokyo/paper/Metrics.java -@@ -593,7 +593,7 @@ public class Metrics { +@@ -593,8 +593,7 @@ public class Metrics { boolean logFailedRequests = config.getBoolean("logFailedRequests", false); // Only start Metrics, if it's enabled in the config if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Airplane", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page // Airplane -+ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page // Airplane // Purpur - +- Metrics metrics = new Metrics("Airplane", serverUUID, logFailedRequests, Bukkit.getLogger()); // Airplane +- ++ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Airplane // Purpur metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { String minecraftVersion = Bukkit.getVersion(); -@@ -602,8 +602,8 @@ public class Metrics { + minecraftVersion = minecraftVersion.substring(minecraftVersion.indexOf("MC: ") + 4, minecraftVersion.length() - 1); +@@ -602,8 +601,8 @@ public class Metrics { })); metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); - metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline")); -- metrics.addCustomChart(new Metrics.SimplePie("airplane_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page // Airplane +- metrics.addCustomChart(new Metrics.SimplePie("airplane_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Airplane + metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (PaperConfig.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur -+ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page // Airplane // Purpur ++ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Airplane // Purpur metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { Map> map = new HashMap<>(); diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 5b4000d1f63e2b028e7a4450dcd084eb507f7f91..b294fa10dc0fa804b94757eaa3becb104f20565a 100644 +index c6dd2567ac88c7bfff0a23201752fa6561f2565b..7c1852f3ffce977506689f86d6b875fe1c8e11b7 100644 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java @@ -118,6 +118,11 @@ public class PaperConfig { @@ -45,10 +46,10 @@ index 5b4000d1f63e2b028e7a4450dcd084eb507f7f91..b294fa10dc0fa804b94757eaa3becb10 config.save(CONFIG_FILE); } catch (IOException ex) { diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index 134bb2a4826419110c10a483834747b942576e58..d9e868b6c70da18b4ce23c80e2aaf347f2dc6d50 100644 +index 71e29d29ed5c2d61832e2f124967bb223708406f..224669ecaad37ac2f16900700eea40ef52d938a5 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -234,6 +234,30 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy +@@ -236,6 +236,30 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy return this.anchor; } @@ -80,7 +81,7 @@ index 134bb2a4826419110c10a483834747b942576e58..d9e868b6c70da18b4ce23c80e2aaf347 if (this.source.acceptsSuccess() && !this.silent) { this.source.sendMessage(message, Util.NIL_UUID); diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index bcd45ecf7dc97fc5b80313c22a0f7145053b9e49..5bb730ea49a5ecc5e2ded4fa8dec8c4656321f07 100644 +index f15a8118880ee3c9a71f450a84b873aa076c6350..ef0d4086af9a05bf5f0dd1eae965e496b1de6199 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -219,6 +219,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -100,26 +101,25 @@ index bcd45ecf7dc97fc5b80313c22a0f7145053b9e49..5bb730ea49a5ecc5e2ded4fa8dec8c46 io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc. diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 496000e65ffd5df5ea23783341dac5e2b9b63d0c..d49e53404b77eedd24e9824ef5b16a8c4fc8b2db 100644 +index 6f4e6105aa1d6546daa2424f57972fd29db25fa3..4c55bb04ff41fabb47c6477ba33e0e0aabd1c843 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -166,8 +166,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - +@@ -167,6 +167,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray -- - public final com.tuinity.tuinity.config.TuinityConfig.WorldConfig tuinityConfig; // Tuinity - Server Config -+ public final net.pl3x.purpur.PurpurWorldConfig purpurConfig; // Purpur ++ public final net.pl3x.purpur.PurpurWorldConfig purpurConfig; // Purpur ++ public final co.aikar.timings.WorldTimingsHandler timings; // Paper public static BlockPos lastPhysicsProblem; // Spigot -@@ -318,6 +318,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + private org.spigotmc.TickLimiter entityLimiter; +@@ -315,6 +317,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, final DimensionType dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper - this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData)worlddatamutable).getLevelName()); // Tuinity - Server Config + this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((ServerLevel) this, ((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur this.generator = gen; - this.world = new CraftWorld((ServerLevel) this, gen, env); + this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java new file mode 100644 @@ -459,26 +459,26 @@ index 0000000000000000000000000000000000000000..6e7f56fe2b78d7a09d5d130f2c88338f + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index b848812314552fe3058b338adcb81f0754bdc693..01bb2583330ae15e1540d48cba63c7712743e7a6 100644 +index c757e4fe3e511f699512dccbcb11137fab82ea5e..535089a8f48d155883a105110f68056c5838ee83 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -887,6 +887,7 @@ public final class CraftServer implements Server { +@@ -892,6 +892,7 @@ public final class CraftServer implements Server { + org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper - com.tuinity.tuinity.config.TuinityConfig.init((File) console.options.valueOf("tuinity-settings")); // Tuinity - Server Config + net.pl3x.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur for (ServerLevel world : this.console.getAllLevels()) { world.serverLevelData.setDifficulty(config.difficulty); world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals); -@@ -922,6 +923,7 @@ public final class CraftServer implements Server { +@@ -926,6 +927,7 @@ public final class CraftServer implements Server { + } world.spigotConfig.init(); // Spigot world.paperConfig.init(); // Paper - world.tuinityConfig.init(); // Tuinity - Server Config + world.purpurConfig.init(); // Purpur } Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper -@@ -937,6 +939,7 @@ public final class CraftServer implements Server { +@@ -941,6 +943,7 @@ public final class CraftServer implements Server { this.reloadData(); org.spigotmc.SpigotConfig.registerCommands(); // Spigot com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper @@ -486,9 +486,9 @@ index b848812314552fe3058b338adcb81f0754bdc693..01bb2583330ae15e1540d48cba63c771 this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); -@@ -2468,6 +2471,18 @@ public final class CraftServer implements Server { +@@ -2518,6 +2521,18 @@ public final class CraftServer implements Server { + return com.destroystokyo.paper.PaperConfig.config; } - // Tuinity end - add config to timings report + // Purpur start + @Override @@ -506,12 +506,12 @@ index b848812314552fe3058b338adcb81f0754bdc693..01bb2583330ae15e1540d48cba63c771 public void restart() { org.spigotmc.RestartCommand.restart(); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 673fce7aa55cffc2c9ee017242d194a0dfd8be6b..f2fab27d5e8f87691de3526ab6cafd904abeab5f 100644 +index 22e9dd17f62103c5061435099ce96a3d70d54808..5b527a32f56a82131168879106f76c1f6cbb7b30 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -154,6 +154,14 @@ public class Main { +@@ -147,6 +147,14 @@ public class Main { .describedAs("Yml file"); - // Tuinity end - Server Config + // Paper end + // Purpur Start + acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings") diff --git a/patches/server/0004-Rebrand.patch b/patches/server/0004-Rebrand.patch deleted file mode 100644 index 094e4e0ea..000000000 --- a/patches/server/0004-Rebrand.patch +++ /dev/null @@ -1,956 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 May 2019 01:02:11 -0500 -Subject: [PATCH] Rebrand - - -diff --git a/build.gradle.kts b/build.gradle.kts -index 467ac5ba77cc35dc84c38161881db37e8f9adc14..9b844735f37de2f833b59f619c88045e8ad336c9 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -35,7 +35,7 @@ repositories { - } - - dependencies { -- implementation(project(":Airplane-API")) // Airplane // Tuinity -+ implementation(project(":Purpur-API")) // Tuinity // Airplane // Purpur - implementation("io.papermc.paper:paper-mojangapi:1.17.1-R0.1-SNAPSHOT") // Tuinity - // Paper start - implementation("org.jline:jline-terminal-jansi:3.12.1") -@@ -67,6 +67,7 @@ dependencies { - - implementation("co.aikar:cleaner:1.0-SNAPSHOT") // Paper - implementation("io.netty:netty-all:4.1.65.Final") // Paper -+ implementation("cat.inspiracio:rhino-js-engine:1.7.7.1") // Purpur - - implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation - implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Tuinity -@@ -86,13 +87,13 @@ tasks.jar { - manifest { - val git = Git(rootProject.layout.projectDirectory.path) - val gitHash = git("rev-parse", "--short=7", "HEAD").getText().trim() -- val implementationVersion = /* System.getenv("BUILD_NUMBER") ?: */ "\"$gitHash\"" // Tuinity - Do not use CI build number for implementation version (always use git hash) -+ val implementationVersion = System.getenv("BUILD_NUMBER") ?: "\"$gitHash\"" // Purpur - we use both CI build numbers _and_ git hashes - val date = git("show", "-s", "--format=%ci", gitHash).getText().trim() // Paper - val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper - attributes( - "Main-Class" to "org.bukkit.craftbukkit.Main", - "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Airplane-$implementationVersion", // Airplane // Tuinity -+ "Implementation-Version" to "git-Purpur-$implementationVersion", // Tuinity // Airplane // Purpur - "Implementation-Vendor" to date, // Paper - "Specification-Title" to "Bukkit", - "Specification-Version" to project.version, -diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -index 5460f57f0473868b3fb09c526a1767f717a2740e..247ddb242011a21536f4399657c8019888158a15 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -@@ -18,7 +18,7 @@ import java.util.stream.StreamSupport; - - public class PaperVersionFetcher implements VersionFetcher { - private static final java.util.regex.Pattern VER_PATTERN = java.util.regex.Pattern.compile("^([0-9\\.]*)\\-.*R"); // R is an anchor, will always give '-R' at end -- private static final String GITHUB_BRANCH_NAME = "master"; -+ private static final String JENKINS_URL = "https://ci.pl3x.net/job/Purpur/lastSuccessfulBuild/buildNumber"; // Purpur - private static @Nullable String mcVer; - - @Override -@@ -29,8 +29,8 @@ public class PaperVersionFetcher implements VersionFetcher { - @Nonnull - @Override - public Component getVersionMessage(@Nonnull String serverVersion) { -- String[] parts = serverVersion.substring("git-Airplane-".length()).split("[-\\s]"); // Tuinity -- final Component updateMessage = getUpdateStatusMessage("TECHNOVE/Airplane", GITHUB_BRANCH_NAME, parts[0]); // Tuinity -+ String[] parts = serverVersion.substring("git-Purpur-".length()).split("[-\\s]"); // Tuinity // Airplane // Purpur -+ final Component updateMessage = getUpdateStatusMessage("pl3xgaming/Purpur", "ver/" + getMinecraftVersion(), parts[0]); // Tuinity // Airplane // Purpur - final Component history = getHistory(); - - return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage; -@@ -43,7 +43,7 @@ public class PaperVersionFetcher implements VersionFetcher { - String result = matcher.group(); - mcVer = result.substring(0, result.length() - 2); // strip 'R' anchor and trailing '-' - } else { -- org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to PaperMC!"); -+ org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to Purpur!"); // Purpur - org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString()); - org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion()); - } -@@ -54,10 +54,18 @@ public class PaperVersionFetcher implements VersionFetcher { - - private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) { - int distance; -- // Tuinity - we don't have jenkins setup -+ // Purpur start - put this back... -+ try { -+ int build = Integer.parseInt(versionInfo); -+ distance = fetchDistanceFromSiteApi(build, getMinecraftVersion()); -+ if (distance < 0) { -+ distance = fetchDistanceFromJenkins(build); -+ } -+ } catch (NumberFormatException ignored) { - versionInfo = versionInfo.replace("\"", ""); - distance = fetchDistanceFromGitHub(repo, branch, versionInfo); -- // Tuinity - we don't have jenkins setup -+ } -+ // Purpur end - - switch (distance) { - case -1: -@@ -75,15 +83,11 @@ public class PaperVersionFetcher implements VersionFetcher { - if (siteApiVersion == null) { return -1; } - try { - try (BufferedReader reader = Resources.asCharSource( -- new URL("https://papermc.io/api/v2/projects/paper/versions/" + siteApiVersion), -+ new URL("https://api.pl3x.net/v2/purpur/" + siteApiVersion), // Purpur - Charsets.UTF_8 - ).openBufferedStream()) { - JsonObject json = new Gson().fromJson(reader, JsonObject.class); -- JsonArray builds = json.getAsJsonArray("builds"); -- int latest = StreamSupport.stream(builds.spliterator(), false) -- .mapToInt(e -> e.getAsInt()) -- .max() -- .getAsInt(); -+ int latest = json.getAsJsonObject("builds").getAsJsonPrimitive("latest").getAsInt(); // Purpur - return latest - jenkinsBuild; - } catch (JsonSyntaxException ex) { - ex.printStackTrace(); -@@ -95,6 +99,22 @@ public class PaperVersionFetcher implements VersionFetcher { - } - } - -+ // Purpur start -+ private static int fetchDistanceFromJenkins(int jenkinsBuild) { -+ try { -+ try (BufferedReader reader = Resources.asCharSource(new URL(JENKINS_URL), Charsets.UTF_8).openBufferedStream()) { -+ return Integer.decode(reader.readLine()) - jenkinsBuild; -+ } catch (NumberFormatException ex) { -+ ex.printStackTrace(); -+ return -2; -+ } -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return -1; -+ } -+ } -+ // Purpur end -+ - // Contributed by Techcable in GH-65 - private static int fetchDistanceFromGitHub(@Nonnull String repo, @Nonnull String branch, @Nonnull String hash) { - try { -diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -index e0b1f0671d16ddddcb6725acd25a1d1d69e42701..8c3c68465197fafc14849dc38a572e309931e2a2 100644 ---- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -@@ -17,7 +17,7 @@ public final class PaperConsole extends SimpleTerminalConsole { - @Override - protected LineReader buildReader(LineReaderBuilder builder) { - builder -- .appName("Paper") -+ .appName("Purpur") // Purpur - .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history")) - .completer(new ConsoleCommandCompleter(this.server)) - .option(LineReader.Option.COMPLETE_IN_WORD, true); -diff --git a/src/main/java/net/minecraft/server/Eula.java b/src/main/java/net/minecraft/server/Eula.java -index 3789df8ef9c0b4150c3baccf84dbaff57c0fb65a..43a88bc58716eef4040584944f52893c5a47699f 100644 ---- a/src/main/java/net/minecraft/server/Eula.java -+++ b/src/main/java/net/minecraft/server/Eula.java -@@ -64,7 +64,7 @@ public class Eula { - try { - Properties properties = new Properties(); - properties.setProperty("eula", "false"); -- properties.store(outputStream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula)."); // Paper - fix lag; // Tuinity - Tacos are disgusting -+ properties.store(outputStream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\nYou also agree that tacos are tasty, and the best food in the world."); // Paper - fix lag; // Tuinity - Tacos are disgusting // Purpur - no they're not - } catch (Throwable var5) { - if (outputStream != null) { - try { -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0a78b208cbafc850e24501f65197e1cd2e8efcf5..961af809af47ea3fa0575f17a8e783de7253fb0b 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1716,7 +1716,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Tuinity - Tuinity > //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! -+ return "Purpur"; // Purpur - Purpur > // Airplane - Airplane > // Tuinity - Tuinity > //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! - } - - public SystemReport fillSystemReport(SystemReport details) { -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index aa9ddbec584129694e975ff1083c1ff651a5d7c8..bcd45ecf7dc97fc5b80313c22a0f7145053b9e49 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -284,11 +284,12 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); - DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); - // Spigot start -- if (org.spigotmc.SpigotConfig.bungee) { -- DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); -+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) { // Purpur -+ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord or Velocity, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); // Purpur - DedicatedServer.LOGGER.warn("Please see http://www.spigotmc.org/wiki/firewall-guide/ for further information."); - } else { - DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); -+ DedicatedServer.LOGGER.warn("You will not be offered any support as long as the server allows offline-mode players to join."); // Purpur - } - // Spigot end - DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index fe5eac5f01461c9ca81301142218aa131475dfe7..b848812314552fe3058b338adcb81f0754bdc693 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -240,7 +240,7 @@ import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper - - public final class CraftServer implements Server { -- private final String serverName = "Airplane"; // Airplane // Tuinity // Paper -+ private final String serverName = "Purpur"; // Paper // Tuinity // Airplane // Purpur - private final String serverVersion; - private final String bukkitVersion = Versioning.getBukkitVersion(); - private final Logger logger = Logger.getLogger("Minecraft"); -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 1788d79ea489e446d3d9f541693d4ba3dfc26015..191f5331f0c7871f80f0da9cc38345ce33353577 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -@@ -11,7 +11,7 @@ public final class Versioning { - public static String getBukkitVersion() { - String result = "Unknown-Version"; - -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/gg.airplane/airplane-api/pom.properties"); // Tuinity // Airplane -+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/net.pl3x.purpur/purpur-api/pom.properties"); // Tuinity // Airplane // Purpur - Properties properties = new Properties(); - - if (stream != null) { -diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png -index 1e6ee83b1a207eca59d82b25c06895ce894e8173..35ae7a94cebd4a9a16fc9112ccc248fa3cac5f32 100644 -GIT binary patch -literal 17292 -zcmZr%Q+Op^)18@QV%ye9GO?|RZQHi36Wiv*wrwX9TNB&<&--2f7v25zRqxunYE`XO -z)#388V(>6HFyFp?gO?B&Q3O3l|GS_dK=&&3>KxGHyOW}r(6{Poyc5t1xS61g;J0se -zv9Rw3KSA%%_Tm~&-@YLX{C9mHu`4zH_Dz^rLPSv6UH3uIKHN$(9lRBV*i2#hI- -z_~Y$^N~A|I!$ek*IvIctFG)?DTtpI0Ha@GZC`npujzS(T5(-7(X4 -zbQ|h))t2-2q5jDCR@pVPHt=-bHPc~+FHRHyj`IKBcEm$x4SqQIGwUWNa2>4tx*iJ5 -zFQ`h+5Qq~;B15?Lt087ATEwRQJAaPK@$cklh);?pfGCbg+`rX5E34(u{dkW8GGL!f -z?;bha7X~Uk6!9Co4ryW!H=?6Il>bNs6jx;{Hs6{G*ryq4Fq3{-@U6u*xPoD{NYDsY -z$xK~}lC2}lD-LxxgTy%re!m7icdAaM-W%q#`!Kiz!U-9Y4;d5+>ATyX$tl2h3Cmer -zu%3R^XH@nBN_EX$bN=EXy?2Xd(kZhtomkO#7CQg -zB+1Sw*O(!vrQitB3t?DT?PGJd!seWZKW})+(SIKCo^_pWMbSnzAc>` -z1wdPjL)gIDoGKv*Ok0tnye0ON2*wE&{6q!Yf6N=qo3=b=_e*jQcMj||k#k=Oaoj_k -zb=ZKr30IUP+7?GD^5-~`Xmc@xFC7Pqg)}@B9Mzo{OR8-Q96^tjI%$qSSX@V$s178W -zQ~&9o!Acbf7VY~gm?!vT)AEexJn%Mpw!{v!pb!+F_2sk*miJSY*qH^n3ZeOD`%``K -zomU)-XS-y$)jbZqlZoQ9-p#~$V6xIkq!MivcxN2ZDDmt&d?Z!`64v#%iZ|F!#xFjH -zHbt($S+CB-W9mt;(k7U3{^y95!Xy-XB0(fX=QI+`i%JN55297@zP@{%EV`20NQH}{ -z=LXaR&eK1KAzmnNsO%{4hC8pH_3!N22JDDfiyU0tomMwEJi-tYYLCi6y2|XCWLU-5 -zs|wHs3@GsVbLUgnC49~s$GB8)Dn^=b#W-}x0U@JqMx&O5q}jmmFQz4nCss_Km?k*HOfJFo!Hf%kJ3{2 -zhGi29gjW=PS7ZR!Sb$S*T!$+jBzhX22!>_a0p6(A{Q6gJ*$A%ffeHF@E(&ATyS%aC -zhHqvPDgoeg5U_;aXXr|rlENktPOC{JA`}PS -z?)&j~B=hi%S@X@AE`FzdqsAo~K|&o{n!~tKmDTTxjH}H>=!0t!vID5qU+dOVCPXG*M3HN=-Y~pJbRw6 -zU_{I4!p&XdT+dg>8hcitE&eqiJOOaJCTxMofb&tSRFs6Ea7&nK$p+tcBIw2#>r#rf -zF2I``X7?S@lvNN*1AhVhVBBEH7FF`q^`zw-)ZIT%t>ghuR+|v}*ta6uU{bc7F8#*Z -z>g$av&I#2f$8-L{VmC;Xp01bBj<{-kLS8#h2MKn$A}(84LrC@Z -zHHVU8!pl4ZxeO_lq|jwNGzD(}G|CkW1j_O6*sKTfnpEL885C+DrT__P+8H;Ugig>U -zf9H0nQIG(%&03UCPDzE5EgcGKP~b03;S$Rh9jNcM&+YQ_6g`jW3E##cS|C7=%p!YY -zun{~ZNV_*4ix4{Ln1`BaeXC*K8`8HU`PqkTVE*;JeoGCrKX+Vxb9UpHUvJOOC{wm@ -zv8gfZnK|oa!)TAD_&}({f(sEQV4w2+8zmp3Ol5;&A@K7FSX~p0!dTe|Z5r#Ld#@-- -z2iFG1zFfL*E4PsehkN7MXSyqFaQfnSaEWv6?*ZR@vvhJJm(@DI9|tOJR&Bp>Rv%TH)$IOD?5O}I`7>?PQ|>k+DJRLn)ku? -z$_jyyw#BqKBun<1i3)&u5Ij=w#N7ydGvqfsx#X8lnGE)`&7qG`l5_|wbt2-vn_ -zYOg^K$BK1Hd0@}_VYTt9oGNDYoER?_PBr|H%qyN@X|?lwxgGwHqWVr`3ZJOwj6?6I -zzKxav7?>0tM(}Ngb2*uuUU-P -z!QEL0pbmWjiiP}j?U`(LZga8mJ>n3%7qF7tCvU_k2V<~od3;SqDSm{oWNyA&+Ov5O -zS4UYqciXaX%|?se=+Q;QijtPhAfdFgR~fepk)xDGHlrcOgxExuRfM7WgrAAZLeJEAmUrLf;bbl(xu@tT -z)j2=ZB^dqgw7=g3W}-DKKbRLb7ar{NPhbs|dC>Qa%GbW{@AV;J2+$E{)1^R=j&$aH -z9Z}|UcX{mQYbjv2awgDZ%%ZRha&GkV_Trw}KAy|sKu~dPgdjXNz-+IKK-@T7rr*^N -zC&Z#-r-_d+k|0Hufy4Mn1Q&igxvdpU72lLiI+}mCCKfWhJ&B+O%e^qG;S=rHa!m$b -z+O3B@)E%)u(>5O0bt#w&P3^^5cZ2At%iHW(PUn^PILqf5XJ!jCT{-CTHZ4Sff)9_d -z;X0q8xWc8-IJ1r5Ll1HKQGjmaQo`ekpR(WF7W@bMWI61952=jydr^gwOXoXV+DAXu -zl~^S&C049@G*2>HUvRiw#I9QGT+jxGnBtY0x$6_p4Qlf4aBoL64{h4kffLn&U)j?w -zJ;9Btl7@km@QTS&!2ZWp#K%h5$xpju%Aq}5|0ngrJ?9?-i(*)e8`sV_(SmnF@~4+A -zLxS@T`{ND-2adcD#qML$D=&XJuJ~2Aqz8Lv>4ahF(6E(ppJX3GiWmZ|=9QZ)yCFrZ&rhUEuw$E; -zUSo@3>mY(E9~J9!t?k*hD4ZY`%Z*>h59X{oSOakyt?O6S`~DvJTu~P8${+#K2=Pw2>BWmi9oW@xr&XC)61tBlUk>Zg)Ohdy{NW}!^tjj{GQdG71^h_&b2*h1z%1$^?E -zGw~W4#Sf9O)sy4z$zh&Vf4Y48ESI|5^HoQ78v7`@CqAgG>-T~Y -zC%6sN@g7uhTlSGwnl+!bjzl6Vn7TRg?ttoh5HRj|?OtQQZ(-klZYbI#4oO{xR3B9# -z-Te(G>1_#h{@S@-v8i>E=((0L29G^GV0jI@RDSSahHK+1_oZ4uyeW#{iJ?Nle!XN8 -zKZb3OmA?NBybQ}{!d=FB+)h`QybACk)k7IEZz4r-TA!HAQj~>6p`Hvnr{QyL9#VTK -zdTzAX{ZF2Ho@h3$oT#U^_HMS -z?;9NHfNojV2tCa6n1p3v!D-O3CrB(WE>hNs{2H4>m(${BFJ3UC#J#BT(`@^;`dQh; -zad$djlps6yb_Y&pcf6QH2Y~-w{jY%Prtgo^n|^jg0#Y4*7(!gT<|lJMt^k80`u!*( -zTVZItC&wYDVcPWU#0WS3C@0fB1P`HH1=H<{BZT@PouJ+e?@hiQ% -zEiQT6Ev?l7bU8L-envX)&{}-zW2-VRD9)Xk -zkc?ZFluil~O%2(QzZcU{7&~_=I7py)hYurI-{9Kc|6=^(h7+6JdD+^3!;Q}pZSjDO -z@iI2oP#ii1DWQ+=BEt^p+q*hxe+3eZo$p)20j6)WqPkAkw-jgVw8~ -z3)n|z6Pn;{s@!f;(8}&1i-DRy$eu-sB;0RKqckDtI`p^Dwt%7efT#Cn5z&_7qDWdW -zhimJnCLC8&!{{pT_4oZ_yH)}oi%T1%NUHbrIb`cc0ufqdMTec?jUWNWuO#-;AEsqY -zhf$;r=YWm&=OQ5Y(nEnoNs=y#fXE@HKS1ou!Y84=W4DXgX(&VzATVh|iD{A=5TlK$ -z75Bc05rX;>-5_iu;qeUNGIzA}tnS#!!~4OZK78n+iDL%73)8N1GYfp4>iDI$6BQD7 -z`}dAynae2uNyl+FS7uk6E;4Tq%a@=pUaJxLgk1%_xxal3waZV@wtY__TOu4wRSWSd -zDuV=rAbIqv8h#c+N>Q&(~*>cE3pm=osYPM -z?c)b-9a_0hB(-#7?7aOC>yv}G49W$|r$t&0G_<}xt;Ygfa}bxze{8B?m(!c;@#(jB -zH=l)p2(@?+FA1na!I7 -z!eX|}+_>xr;3G74!Q)4jDBP9Guy&1!6-3xL=?_ZH`*2Qkn7hoAYAz=0J|iKY96p!J -zziU$M;GM>`REMB}x6xjg#%=m)tjES`s%m&olsQsmuFO#-MqG$0-6xpxx8ax~82F-K -zELOqr6iMmGVT^T&v@P|lMI8?(?x(~&F=#)HyvEd?)PgS`zxA_p+k#SQV*8j0)K* -z47@+RW*n0E^4mu1+Kklx7WCCE_LVF@ -z&nW-G@Jd7zI#8?w%qgsx-Y_7&5d7U<}R*`=`x?J!T{h+|kxt>tG -z!KTjmEaQ+-d^i|f(KLnCa;N{kBEwL2ML8Yqpm05meY+YpKAXGu&xPt-ke|cZz*nq9 -z=kK=2!MLA*;#rT1qzG*p>CC1Y7>47PQ_2vsU`7{m`vT^m+@+tHhcg|4*9CifRBG;d -z^$)X5Pqg{-27Q4!oWdvd^lYX6=OA2iLv;##Ha>1qDlu4FZEhU)zWZpG`tKoQUXuvV -zuXAI2J(7S>{gOFTe5%Sf*rG?x(~qjVk!r`oxfh5j>en657oiI4MY?uvm_>RAoix9g -zoI0I$fCfYU9SY;dJQqvKVlw7=8N!tUpU{XqiMSIHk0 -z21a9py|eO*_o#D%>L;9>CIX^d4u$Bffv~mU;%{UEd=b3{WzsEAD62t=X -z{aIi-Ooys=H-tW9S!_n3Lx0n!A3-djmbx3Pw+vueC|A7L9~!<9Wk`&;4ASw8Dq#1E8U -zhh332D?9R1eRh;T3Te%lY(3l@?+@Aw7LDzBF+E;NpViwJjQiCgBic)qP&Gp+)@nS} -zJPQcB5tLBU-O``&3dpjxHj9rGhXPx*>05dW8Lnj;i7GfT20oU!hF*>s=RKEG17EfG -zhp-3V)4|E7T!|$%5j#43sbiWNh0=fx5NB&2{*EUlAyyM6E(a!W<$Y)6v^;!o9R*Jk -z@v!=hS%jK~zv%a_%GY|xc=^v3@1;0Q_96|*vkl=oG*iAV;8tWDmiBo-5TA(3-l2{5 -zBg92bDAi$M=u9;N^<$W0Y|xFnvFs);cF?jI4d~vQ%bq`R9{Rc5Lz>glnC0H?MTHn} -zrfEx~y|gcN^Cuan|9z=mOq4vW3PP?PVZpL!F-jBv -zcA8Ej#LlaGtC(Z84Rx6ATc=XJ%8&N=NHWZs&`pi^xInUDcA)caGS?#(%Pc+X7 -zVb@Y{yk9%|lR?%fFwc9v>Nu3Kx=RINZ3QZ4rykl{%xl}o$al=R5lmPqcb|ImITJ>L -zY&qBMDY=V{)n83LwR&VZ`XGXG>t+qReu)2}DUujeEVjc(?XY;-TCLi-!Mh8dbgWI& -z1_jF-FyFUbdoeC>)nEHcaoX#dq@9nJ9M+Re<4|;0(0E-{fHSZDY2L={vfhp=L^N_N -zPIYY(HD3;8 -z41Fd(l(J)Nlj-NUQx_Cok3)s8F(a4->kdk=xXY+{fehTj4Pe1lrf;Rx~po3rk -zHHcb4FU6z!jNrV%fog)<+im;lXS3i}FlC2+C0-#P)1{7Au4A_`n4|3iEc&?w7-1*2 -zw%e}jX20mL0OHiL@sYfH+t%m6!#(`@8{7%239C4wnF_1Dn{@s`WWh=LVc(0J1!R6k -zn5$cwcHrgh-{;OUKO_6+rW#Ly&xoV)nN~IBSqX#<4x!5_TEtVDN^J^sMMHjL8GKY< -zHCo%W`Cs>1zZyP4R9D7t|M<@K`NiYHMAcSeUn^EK!I9{wex~3}=jG7F_-j%!KenRz -zg)s)I-w(S)^t0W}8M?pqlda8MOXn;b?gzWHBi+GN+rxEcH*~gfc+LBl*oq_}TzG(EOL-=%bgYtGP-Iggi -z2a&ihB*9rKCTokD6$H99yHeS{)=fsNntEhgFUtaVWq`*HwYK8wD^)P27=g~9{r*to -zL0=~tl|i%7m{0AWqmhFAV&oWc1a#^TguQe4I;&~)rURKbnm#3K;j`Sxt<;EX-(FiR -z7$dmX$L%xW5YJsv-k87jg%muFewf%dUDiuV*%h%TsAi`J3Sk~qCchy$8yni4P{>!Q3N>t?w)+`;bGy%WlKag8$nj8HDB+B5fG(<)2#9ayNL@5dx`L -z^lwUq)Q-FV?%Lmq@Ej|&tt{~I-7lE{3l)6`w(N@-X}T`>WO~=a#x=~gj?TXgoj+x@ -z^JIsy#!wQh*T)D5ci!L%$ONJ?>3k0nCgezY*(J$({3obwl__2V>h1UZy^8S`R0!-W -zFywgL+LC5SIa@zzIbb`No@|Jx^(0!NMj7sqIGr7ddfWKZ&x!2Sm7hHaN|y3N5pY~f -z6gDL5=dQlD0e#t+PP8@TC;_wE92wp=yhoI~Ol;Y3XSM_y?Sypm+x#uoXTm@1&B8G+&_Jc$n^Cpum_vRAfLH{24#dTw0Lj<&@sfgemtZ;WJWJolU?Ri1-}4m#=gv?%)moaX&5jo~*bNFoST<^F@C -ztXN>J;gLR+Gva>;yE46fy^ -z4&z|0Co{~S1=S|U_=ZnY2 -zV2$c -zDSyz60v5|`u(3&GZ196ixJjs>5WMlG_@P_CKK-uqG|x;>4q3yGtlw|ZBivFWiS(}+ -zkbYZHE)uFuft~BXp{shUrPbR{3lTWvTh3xzWA!JiEwq9o!?~sTMuEY!@P<$gF>?19 -zp+(oUW$;{5XdH9lgi|$|OW1c(D2Xfw(ByCf#er`Hd5jk@fG3q;uSw7NS-Hi{hGCj)~fnGVvpB%nPEzI4n|goB!KPFCz1>2p0vub&q+ -z7i7QaMpK!ZsI^+YT<`Zq|v+4uG{i`Im2E~fFj>EU-Mg{ -znSHL{AcGCD#8{vXi3MLui~01G1I;7`=yiPJ%(;j|=t;x)8~tihIWBTacwO`O^XX -zJ79HtePcpNAPu?IyBnfy58Er+Dg7VjvDs;d)iGx9J)D3eK1yNFjVA5xBEl{FLzP2R -zgAG^ic}T-Bxzvz=6f<5k9Srh#@V<6$Z+jVb@YxaMJ7pLj0*a;oyuYBtmC^bHsKuJODBizz0%UT@Xp!6AAce>9_DpPJ#Q1<=s_Y! -z`xn{~+u(n?SN76khQ`Hx#kM}4cAd+RKsTkLdlzvVtH7DIa8&Txf2!*ZGJL&yfyWHy -zR9cM!2po7c9MgxWh_dKqo!dJ#Q`8cHOpV*_%|Xu3Fa)f>p-_G+Fa2I!`IZvZ(R@8o -zZAPE6zBnO+)nX&i=c9@-g`-A`%CDJ$aeTo~0zAb;snWB7Pr8b32vr=1oa~G@MPhdd -z{Fa_Snm>ey_C=oJkCt4jfX02Y?uRG?vz_*}3B~ugW*6lx8m3vX!;(lwb`Sy7_Oomn -zFqE~@0BYYHBn6KD(m4VtVuQ~1tT3?}Ph!W|h2|pa{nm3&lL6St-DZ40?muY319?fDyP2dXPvoHBE!?Y@ -zd=A+P3@BU042GGX2>XmRdXLXyNGME`TySVH2rg4ZJfjh7{=!>mS6i`f(SK<60rO%lmDZMQ+0|wHpv6WhF}ApOY1*`J|fX%VFdmljdE^^Fp{P`c>T%Mhz@9 -z)Hh@kmXX_9NTQlun(hS+-8ogLpsaD7H-deplL^4>oARi~_aGyV;0$S@6&*=v>+T&C -z7;iZhBKTPIPNz%?&nw`fK}@`*hfHL1amjQ(>B41aozipH_n%PPt^`SF+wz>_fHrZv -zA05O=0h+FWVPy@HV{OT4$jx6c`L5DI{p*J|UyA1}JFqgUypc}ib6VPWN+?(BS$VJ! -z+;DGB?AnVWC%!#`4LcTX+pb!p@qy*wEB1CeREBdC;&D4*oh0G{RS~zZszzzy9#^#S -zH-X2uFWr)}v5&Z#Q^PVf(1H!a$%K)* -zToM6z)JU9ohx#8etI!SAj$OxS@Yk%Qzv{v`1gD647UQ;2I7j)M9>u4ErzP{luA_+# -zUK=I}#9MGt7pOW73zB$8#-yca*z|FeT2D)@7mf@=448vU+X=?Y*aUaa7EH5plmX<3 -zo%Zn?(g(F?{eeg3OUJjx$2JzCnEzZBX$=DxbeN@RYs(4fSfvDLngfdaM2TaziMJ@T -z3;NjukxVzqspHP%8kj8@4pRK*?=N~fY7&kt7fbsW^9|(co@G&`?mvaj@tKsu6tQa) -zYHGO9gkR5Ei_t;&JSr7{^M?Ss3rA{8l(uTczvg1m)|)N`0+~_#dCd~ZNZpcNnZl8Z -zJa>mi5bF*I!-yDCqN96R$^8@K(UaqKg05S5!R2Ne=miq0pEID-@r5JL@Qa0i~76jZ+a*?2^f(*r|AKv8RSCA%YVqGJ- -zNLLFj9EuG@>k6Dn-G~yL#%a#)z0-(k%M#;vpThZXvRL4=!`k&B5IO4v%}UvbSk^#H -zJMKFT#QyFk6Z7n!Mt~$#M^}Rz4S!Df0fM?YL^&9#5 -zaKVg6%wH1yLuf@5&hy&`)`TZv9}*x)C?Xt@coBmKI4$T8y^i0qXKRx^iy~Ej3!#|_ -zUgV{8r_a~z77oL9(-cvNmU)p+aS5*cEd0=LEjx^$!`v+`tWOjngoJy@39tXnC1c1v -z0Ac)%h+ElfK41c5Vd6bD&Edn-Xf9xE@ECi~`yn6auLIK0!(p$Y&YGJ0ces^ZftQPV5}qLv -zXuSTlRELiAFkD>ZaSVh_*95e=rQCQd4{`(MSj=wS!iWFRApzFPN-{k1cG=ozJW~Eq -zUW5=6y&HKDZ{wcW7sg{Y5swyLriOs@(CBEQ)(z#jqV81qy>!GR&bkKP2XgDz;lhzR -zA>BB=vM;`vJ1S^Hp&N;T>(N4})@D4D&gC~vyg72~@-WOqeq0KYB#?;aFlChov}qy- -zdB*HvSY+NZ(}@}1eS0;!ChhLslj{JXjr0pNWPr$>0D+0XBZfa!zyD3cI@Zg-%=uS9kWF7{{o=P0Ok<*| -zN*Z>M+b~7fGNKgjnldT_aGtyVY={jqj9}{|_V2eqDOlA!6YR%iR{r;OZ%P*2>*?i? -zqS(L6uaFdVbF{j$h0rbCq>nrwc}Rz@{q&bSEm3ifgZdAQufqM4!oX8M_zvMprvMWA -zpY>(JD(fdKq4n`XXAJTyJ{3d3T&A3GOR5Qn;aE&REmt2FJTl+I*_C58jC_8tem-eh -zrT~OTTnPqmzMupTYGabJm)vw2E}I)_K}#v`CnJyw6r+sH2N9djLhdUZssk2JZ8gq` -zc{qdfg@O~~0SA_&F#t56WiwQ&sk%PC7#o2Zkxl&>u7KP;4&EEHD26rPdayYPl6$J7 -zew~2J^anl+e-7E!{I -z@gd+BFyy@MJ?M!TZ^Q7iSi6>+HPcS(hM*Eti0^TJhvsH8U$%SeG!psK -znw$5Wah=>ejjccjA(CpUg4eH_28hbYV7a+LB_u{A6OTn{hhpF-t*fQ;*$|qdRCF~- -zx>#AK(pi8;>VL0NdiVBS&nzwwt}~M#rDM#(`Nc1LYaZmiJr8W@Cio!?`ti^D{e?ng -zN1E;4yq0P4LB)73LGP*ec!zB%>YYUjM?XTlf`uI1z}K-bT@%c?Hy_=LzvT70Za8x8 -z95UH;D8b`}0d3c~(>Se^71gqe9$4}@sO+!~d;Bk6QVI7qa~8jUchhAN#wnB+0%*St -z%Obl-m&_&Qicknrb4L3XRls>28Jv?556k@ZxK2x@W2;;iVz3ojl#!a1ca;~1r1Ls=!t&h~kR$=7izcKXe1Tvejt+@Ye8WTXJOD)mL5gO( -zHbosAArfjEN+`QBil)fGwq%Z0>$HDzoi|Gqbu@e(%ke-IvM8Vc0vF~;j3Y(ed8?UK -zp9&Ws@}H@M?5+i+%}%K4BDsi(JS$!>DEq;FL(3_yP(6!tgT1Zuiw2Ge?=C1Pg^#)p -zD<#Rg3>PW)h*X0j;^1T$spnfxX!?lg(-yXm=PsDdP0aC&71lM -zy0RX>gKVKLzl1=04F*y~-Zn3oQ{ygB`R36oQ#yGvNl -zfg}!W&A`x?wA8_1$--GKI1KAZV79yPn%t2hQ~oBvstb~nQ-#Q}G_f5nB9-IY;^~_p -z96WWHjq^H)3rZqUPtp%a*Djck`1jxIY4u)$Vi22CCafbD-tJvoDuYOWZLfLc{5&t; -zR@Rtic=IucQ6VCV7l>*BMv_FzuruD6K6i_M7>$Z5F27fWB~7yx{gkY%OsJ9v$J_+ -z6&)@$NZ|1oSq=!vqTZqCELVL%H{E{y=?5)T5L+06yNxOQAZFSBzC15xnbRuNU8usl -zI~w#wp#wO~TDryY;rheC{ddzge%>hjN;bvO&tt`EO@jnXRNbsgP!_#js=ucBqa8s6 -zE`yb}ib_x~QegQ3>=Q)JH|6uAnyy9Y0aY+(=CzQ@Iix?h<>zB=koo>!+ewn{I_D{J5ymn3+)V2?Iu+25AM0bED1NykRs*Rx1W|P2e6l5hHIo -zPzp5$g4YrFuO_d> -z#(Z~cnW2`6Bc7YFgTI`JIiwD%92(+A4)zw_Yj -zm2IowJL@Dpf7^yKL@3Y8Ki`>sP(odcqA8hc-3Ce8vp`D_SrgMXS<#DXYJ3k^HFf@l -zI)~#vA(wDrzSL`8uG5X6^+_Spz%Q~g5WU!Ru-}|Z&Cb!|f<~pB8UJh^YX`n78j~41 -z|F{#-5VIzV;)wHcUhJ4E$v%7GKx^RVr2&(QgBOaEIae^BG{H -zkk){EmyZt{p-}tH*b!-p{x3T!89*JqbhT&MWY_7Z9u{VYK&<9n+*E9OlZIJRq2MVC -z4m5}0jD7Gy{YiJb>_jVNsESOw$|jMUrDhwYqzj*4G|ul#Kg`>#yeodM?{@a~ZOf~@ -z=;a8ZQ09U;K||kWiBA~qGpR2k@W+)M(Ac-O66X}y5)H#cD}hk3jGURxQS -zAC24WuoDJorF6uErY(A498NtMWk5C1>P5uJe2WlxD3>X*?yL5|DQU!uapD*AfBH}P -zKqGIMec*BJIo-z?ovc{?3}6BHoLmokzqn%LI>4?iHqCsb4LEXx@&miImv=Ko(TRcP -zo=VOktSqCOn5&FWg)>p+O#5R!%z+GM7R|sv+OrgQ^xJW$@O;*RUAimJU_H;~fAF(( -zP9`Yql0i%{dA~&%X;$sE`5exZJHj>D3;%LvHlA9gO|0E1@?LWEV=~Co@}*GN6U@<9 -z48U&wUijx+T>qB(~@xF`YKR05ryW))W~n~CsI -z^w>>0D)ZPSro5RUu%v9Rd$7-GA}#`!q+g(-G5mMn(PV(zlorWJ2D<~%wSTb)9P{`< -zGBf>kj!Zi}TERN-^@=h{4EA68=fBk#EmsN0pdymf+3(E@XIYpjZ1EnTkO{Jp+(e8F -z$4f~;Jx~rXgD;N#J|uMxWX7*{ch-32u~?TsdDWiP#~mf;*#U8*-gtwbUHiYmTuU_e -z$iifwaNO^ImSp$|Nh~S2^gFM`&0HSv9(T~86rAeKY9bPN#dU4UN}?2_eV5EN)q&f* -z7-oyZgV|<_TR>+F*7dXUfsqq4WcgBZu2mFzesO;R>)2CxU%t>tw%a>529rfFHtnPuQOVazOy7XGlmP}jVBN5q -z^%bsIGw%?k?RqzQP?(B0uJf6X1asp8Nm*iiu;rh8v -zO&o@&xj39rUVk3@u&CuT)oP7mNq@_RGA4(9c5=4!MHgHG4rT+nI7OccLX->MSt=9l -z-dgT$%hFnq%;LOVx7qs6tkA=L$*QbDm+lsml*^VP+*lqh#fLhgeOspMO02H;N9ZFg~-a6e6nZ@Y87CMM3Hk?*?VXM5AdEdO{0f12d}us -zhM&YiIc)Ma>7c(~yxP6r{}p`t>|5%QEaDGqu+_rC-@og$4eRh(u4fsV9IVEp%gK@N1QPxAkcz>2@N~#Qy1Hmnhzwm!>&-J+NSEH>&2uJw -zRiYL2xz;HIumltjytilD3C$u@tfm=!)^#;HTFyPO-9f$7=^Zkul+^Z_B7}t?u{f-LwTKfaYa3M#kkiIDc9n#F2a0g_cR;M5NBe|!)B>DGPYhrI1ZAVjCQX-QJ0+uR%m$+`j&S4ba -z=#l79(lmZ*gnbo&+JXsS6Y*G_ELUY409d(qT6e5~AXjFs= -zPqi+*SIbMFitv_b@&YziZc}MTX!$=v(F;FxEAI!;1J!&c+0poaA6&w~Ml*?==^&1; -ztB{JB^wVDt=|E=pSkoP6 -zFtQ2I;_z6=uaoT+qE?^kXRWz -zEL?T=!_+TaOs|s6m%_d=iRz@gL@iiOuza)P725d3JPyH -z|04Cl!JV^mBn6ak1;q&4*ICSGS)~3&!U%jfK6;V#uG-B@eQ8RMb80~DB}ohQ5S5@# -zWX+kbVf?X^VE$CBP|`LuzBR5w?MUom$**h9C`IvxVF0d(*qO1l!MXu7L5O}!i3=9% -z?53e#M0=m>fz^!*I-_?MtF%Z6QIw#Q$l@;jY4Oj^UjUIYYIqgOhZIL!Tn*uhSD5aY -ztuSt!X+9tdS;prtjMP=I3({31P;);(tI=R3=nE)dVTuKh#E4Kt6|<5pu^dUkh^0Ud -zwcmUq6wDbteD8PK|IeHw+Etr!UWpdeJDX)YD?=Nq>V?3knL7#!-qcO`H7&zMqIr>? -zPSWsDX)skv9T->3zBZ^o7)%7`h@<0#52pklQ9yuP@O;6N!7bgC_l6kqnla})nMqii -z{hsQE+MEpv^f-JT0mjSPq#29b=O1Ll=;>vax%oM>WoL@uH44;fVTvBR+k8eogfYCr56Ug64>W^1$I6i5roZE#TIN-D?wrFB~)m -zn>#M(X+b|SP9C;9m4@#wo7_gHp$0SBHzS?1tR+Rk%z`M6Rg+NP`+jl<*`20fkd3kf -zJvU=fJ2-svZ$$Mga#iGuNdZGD$Ll7fa-Um$qWA&HaNZxJP(gU2h-tWvg#+1wvKufU -z3nv8onDC<~4k4HJAZ9Vn9EzLAz)O^L_P&dDgwWSPg*2ju#|t0qw3oZ)A%%+%QUQjP -zlF-n8P(tm$dI%-0|73R8uZ>$c#?CIjTYWRoPYH;wTFWv>jGO)mX9CoP@w^Z`|BlL# -z26RA&ckR3h%4 -zi8I=k)Jro12yvw3q2nj9>_&N}-7A1A#2mJs!%?4TZP539zldqIbl{z&Fqq8L*q%>C -zE-GbO&@fNlv6HA8G^YccQ)^f-7Y2pJSu#}2hIE=ooOKMBC|=z6-o^#^%Hc>_%Lo0FOQVmk -zBsK^M@E`N&LMYK_auX_lG -zwn0kApy0k44Vicf=hq#Gub%1SVb*WZ!}D~P4TkD)RqmV8QPX}-BKZgJ14=({P9V`vdNT_#&s -zz@~ll185WLVoq9pPKMjaixo;=N9DZQR#TKzM&3xb972X@iOi||itJAs3iA8CVc9~N -zmlBNk`%uuD{up6$o*r{xGR#7pwecg6w(y>E=$@0!HRo0B_WWbD-iRE`(-;th;UYGW -z(QMX~4QUgNFvD{IHvl=p_}8)C;OTeKTUBnWs)>*}^td4}CzLvUS?g-nS+E -zeP71OqiAfz(e2Zeh6ceM4Ko^9n`b25_PqV^kZQNsP?VhSJ -z%;qcZ#joOG)6c`t#~w6^&8`Ny$GRx7Z4bUwWxY6*^bD~fTB^o?NF6Cu;iBfv5_V6d -z*+V`&1*Ds29)mR$u7)uwgahMV)MLMo?g{~TIP#;y>|UUuRGfG%VOfFq8q=-bzR`EQ -z_ZUiBic%wG&t9p@`}ygTz!h5qaKJRjE0j`+qM%(#8Qqt5&QK+k9P>O^3*+#D3lskHFxP*v5DNE>l!bVe?|&TbQ+0Uuo?j8< -zGY|@+H;av%yOwJcR{ns7my@Q^6&{Q*W;n{B`^`TRku0$7BXNj4^%K0;#U&4S86vL9 -zAOjaHYS4b|SkD1X;j?gQuZUkY(NGx2O~dC^$LCFou4ac0mbA}(2ZlL9#!MG0laZMs -zVSd^*iSzlOBcR~0gc>IYrtq`GISQknWU{;9gpmE+eeGJl(g-Rf(@N*I8 -z3kTxuf_||6q4_~QXhHQ)pqN+E(_{4WM8q#e$MR*+L`#D0?+*FRp`;~PcWhYxn0{*P -zD6wG@x4O44!5$?FI49gFJ>8{T3YMEDtGQYZ(INc<%s-nUc#3a8gzJZhuqZSQTQ%%M -zvV1uF%m=C#!f=PY=TGzvL^7xZM3xQOwb`R7bNM+Py^nb0pYe_5{}+Vl6w*kr-JeAYGM%$6Qu2}E929MIY6AI0f*^%Not{V6GcE0l0 -z$P}VXme^xyCQuY42;wtN+$==t47kKSaOp4Oe^m)1iaMtAZbTwSdYU{}5d-5~K9iA% -zQSN|fOi2m&g9JgMfEwxI?c=wo*(B`e9Di4qa&twwoRWB8^LZ1TP9fvpW2DSUf`#h9 -z$agFfgUF%M6Yv!YfZBEi!sS#Ua$ -zLuE)HDo8YLjIh0|OwK9=IXvhIJkWVIsJ1&a*teIn2tf$bM;x1xAVw^Zm_cHMD*Hrk -z&3}bR$${r+WV^{hp@}eZXdz-G$Pqgv8ag0ssUXQ6gEi7MNvfuY20ksT%o(HNz62?P -zKw<_72-SCsBouppVv>Vk&m6fhB0-J>5=bC{1QJLffdmprAb|uDNZ=?3!2biBdNN#> -SDfV^%0000pJCnpDr?!(Jf-{(g()1mU$77W~Nxy+`GL;Hd+mDj%< -z`hrC2`H9Xp$xKhL+Bo|HKmFo7=M-Xnd+W#BZSvAC(iiMjve~^o$4Z89_W8CRjpga8 -zv+emII+5u5MEB{@eX9E4yRDb7&Bx>ddEq2BvbJprC(KVzdi!1Hv=?V?eMFm!UV_HW -z<0^u;`E~qf&`C*71k3BLYs^6^yabk)Yj{C^qJi!8i)sPCIKOO3EVK#shU4l~4n!S! -zBamlrZCbkCbo>x;?i@>dx2tj1p0!K)a=rGr2p4?tkPD7Uai7@eu^4La)+NpTh=0lZ -zE(P78GpKSAt^%r$xC~`T`{upc*$uzT!TfrA3JV59PrYKoJM^id?usWu%mjxS3 -zGIWly9E+e~H|x~U79-+u{MV>MAb|`0-4G}cnLI5ADba_gfd16vBrVvaLTf}7i67f- -zUV>Jio#tHA0!~sm0$WpoKSN7XaeXh@QicB@RolHM98-~@BV9w0u_uzyp}OO(fy4Wr -zJ6yWa1vkdp)+N7#EaB{Yfr3+`*@tt=c)q!jl6ZmDL#*2gzWIp{69Q}B$Lkw*6d3E9 -zj_uz&w}qyzxK`wOuXwhtqv;8552mSzd|Q}T3AX)_u}HT0BEIyM(c#%fVL8Kl$)^Q- -z{cz)BjBTo$%y58*RW}_BV3pCfwG+RGqat@@zbbZ*z)HjE?T7VtC8S+15t5s!b=&=C -zuMOnJ=l9)reQEq93r~0)2a~9Mdp~&f4J|(Ua$ai{S=hrYe&$}+ef~hR0L`9fAlnp& -zU~_CYxN1ByF`|jyx`3l081=asXX^0V#MfW0Y0VrDu1g;K6Cwtlws(!g$mm8Fc@kmk -zHk0P``>>$trX -zOKO@8`AeIqg~@X}4s0Zdc8nGX+gS2a=5c65je_?zXn&ci*C*B5)?qG%26@N56+L?} -z_?X#4UxDE@4hnDzJay4|Cf4;AR@J+8U27CLTh9I}A5l!L!2P|^Ua+g%qMzCQE@)hL -zA~-&6za6OQ9%Z{iDi=UpL2anxJKdKrIBFb}_xMXd-+yzVJCa`;xB$c`45(a{uL_?H -z^UnJDof4?Z78^HM^tq81kY(+E0IU@LG@-q&gT3lP`C0BLFBi5s1Hd|u9H{b+){b^? -zVfdKsCmro&{*7zt>f#S%YdjlEHqY`MS=yCESuK;xK&3U=$+|Z6v2q#ROz^|kPh-CI -z>sUvd=>Cp2gT~p^Qg3DBWn_`9>(sprp=nf0XDapeDmb1HW5tc+++|m7V{%gSN~|TR -z2bCXzg_I)5(8c;v>pwESE4h025uEHWm_tcvSv0-E6WR7g3T6}C=sFV%aA~|;mXOgp -zbsW9;LREE09ya@GgH3vFkvo)fU+79v^vy#Rp>OwSYk=3Vr;1)qSCZpdl#Z+8kNuNv -zr^K;X5$X^A^f#^C!Z%c=re|~`tieWGWEBCuDKtv+o*#NWII)B$(msOTpG_kyd|Tr} -zl)isjXV6?~MrnDMVo}|bMAWHywlydwi}d}AA=Ng?^q9luER>~(DYgLsJPsoth{ -z^L0l>OMO@3z^=mT0BbDwT+^};TfH95K77HfImHl;O0l6Aa0i~unu9BP)>#ALajXQY -z(IAA-I$io%FzIkRDIA|X@Q&P^4W(}lk35PWxacGM{hEaQV`_!->QPK!o8{@lbl2vF -zAcCregL@&8&6g|$_T4n2`{CTidQJRh@uSlrAblg^dVxZ_UF{=zb0Tl@30I07F>s); -zB&Kq)g3KwCC(YS#qB6%v(@u$+^UMy-IEbUBQRDrBd@SheXBkgd<+C)wHq7gZ(RrO} -zX!YuqAdL^xp06x-d@$GZi>I*hU^L$u?W*m7&ycfFm$3!GKI38q6HzRhlyDjtX3lk -zl_?UG_9#t6uvIWv*&fx{vD>Y@YE%u*tmbl(Bt~m|8qUIR0E|ALe6o5B=)H;yd_lB9t3rQ!Y&l&## -zzEU*<$W>9t0Q=QZHACiN3EfqjA0BYIZ~f*20=YI6 -z{Em>2YX%d;v8O`|!SJKCxu8K^-rF~)StR^C_LzNYw?u|A-=xtK-E-CjvDW|v%}GaV -zP>LRLIvV@eU*8rL+c>f^D~|Rho639&VFj+l>yKJ4eIbWwD1l)MhOwTp9h+ -zK!7t0Oq{PSv;PgWzj^ -zi2;$Q6@7i22*WE_EZhAtRz=}@`u0)mfGB7G72hJ-GiF`^`eUMM(=a7(D(M}eL3wZG -zFgJ!gwvo5oi;MJpB%3^>s1ziW!x29I>H*20qpye1QzPY>*ui(rBWy_*%W{S`Y{OcR -z;zbDin`pyGAs3FMCRuEgvf!aoa@6cdNO8fd3@T}3!-A}!yy%eqNH6iIQ=srUm7A-3 -z!8WfxcESolm%~pvfNKS|ZTrS^QSb(nHCJKWNSZP1GS$UHdHlbS(qQ*g+7V7wT2`i! -zCxckawhv=4=em7PU-BOj;j-nuX7I#<1U2USu!s`sw|Qj0q(K7!e^j9MdH2b -zX}Up?>zr*gO%5&!lvoTUo{7b6mpGhRS1CzUtDJF4sWML|SaLy?OkcEgdVghZenRPl -zT*Mv9rd-4+A|eydl#C&mDzu6tWq+O)Y&AkmU>Bp27=kM5vFtu`ZzpZj@vGCo%vv{! -zzD)2e@LRT0LJOtL8t(XrO%vUysrYBGv+PiA9+s_+d00Q+Os}~m2GF=$VK(3)kO;U) -zjZ(o|6V%dWCy8&B&RJwqs2^}HSFy}|r+o@ApT97fjefwV(2k_5KvPxZ-@*}agR2!XW+R!#l>B$r!C#W9v@`sABQLji9L~ -z)E1^q%&2Ce@bIuybSCHF!L{|^5@~kU7GR9=h@2P6w~h<7IaY-IJ<_^ooUV+zZ666S -zPKvBHrs$lAcyJSiemBCBcrQMAiG$%VZ0yLA$2k;--khf~luvd6wPK;ZDyK5m5)H1l -z<8p|zfHgHurFh+Dl3F&5`tfWjh%Edv0XKZ&3cWqpoOL`l`+Y7Se&h#|a#-sSP{z-G -ziX!wTBm`(FcNsQuP1zVT*(2S!mL~Je1pw;qTk?&33{E4vlsj$W -zD3L=e#5ax!b$WJjG1qUw*eHu{+CGOFQ05#}RKFBY}O*@~B?zB{4V4QR~FA90s~- -zTKiB$qixoEEs{0}1i#-YNRS~(W -z+{it>$5Jd1@V3{zx5SblB_?Fu@}BAY>4MKV7)uaD@B0o|-X&pb@X`s!e#p -za}k=v@U~28t!OD3agfASR#`p6-YSbF+?KXJ0zQs@_^7C>zkHs;MZi&y>RCd9LkN`Q -zJRK@|*Nj#HK83KbiBT-{+q#NH`_$I98#vTp~vq(WNYq`8zQ!0Z_?>pjekqE&Jk -z6>6!8e$D3%XC;=(2A4j?jm*Hbk9?*^SL`5wFqWEiFL_TdMyfL_rVlL{*ObwlYlxAh -zVH!e4p`PV~jdCFi4Wy0ML>51?9<~8#Ag!|4C%nF!S_?IAf&I&r4;c`LVFeW9L -zajZu)Pq4%1+b_!)#4 -zV5`C%5cC}Rf|#gMmiRC}MHb?qMNtZR3GT8u8tlCp_pM&%K3$7kGKyx_>gilk&0Q3M -zT52YLk0#NRvl?xnB^|!Sp+lvsiqP|!Ib-zj-ICTVI;u}U6|gJ21zvgZ2=$zd{5n)+ -z+#wEOy%@GD6J$Ub>x~*&iLtd@+xN|4b4G^E7Z`M> -z#%ESGzLCqN5C%_G*l)|8+_vjhJvprN{H*nTr_}qic0be&HDBX%p;jgBt45ycsTmaH -zHCCI~uF*<}&178-@c5V^wC9;K_$vf*&5LQzzkG4x8EchNJ<05*$Y2lF>%8Bi6-Ll3 -zL1S@6ChLdHvxaH50O!`9;4?a5*H@zl$i&e3$gJq@mq`gxNLMvNO&F13kjC?;>M{li -zk=Z4eoD}aXu7wXN8_9U9xV*yZ~=F;wK)KM@Rc?AOHCXJ|CY -z?hshFPBFrd*z49R)eok%Eli-{C7VRFEBcda;lRV{&HVy&#rLoAefF-PkhLtrznBe2 -zw8$Cw=?*e?BZWa})K4;^p7eN&R9? -zD^F$@_(;-5){)bDug8pywS=C!bbs8Lua;QlFY@IN>3*{r-Q|^$znkGx7uVMX8BScP -ztPzM42}my8tn80z=Hu0>>>mx>wV2JJe?0lHyxv3Pcq-XqpFU!^|MPW0f8HR*Xk+tc -z9ZA$WJy9*&Y<`*Q5u05|4Dm!I?>&8PLl=Kw -zn3#G`ePZiV<*SCvxPM|rm6Z(^ca~V%n<_u#Z1K#>weTPYHK#|CUk=>ztkM5^J692u -zu1V2wDf?nTKhM%;JL3=r@9Om&ehaT3>93f-eP0@U0bhv6H{fk>gc1^RB;8GJuMq`$ -zGuTDABs2W={xdz}lR)H-RA?w>z!gCw<)Iq6Cs>ns;?3ED%N7&)3*J{}!^!%Fwy!D_ -zxZk352@DLZ9tFILkv}SmrN;4U_3O1PhBWf&`>!Ba*f*1EJ0_p1=i4D(S0An75>$`? -zYXf~+dXw8CR@fcV;CIp)E-{$7KhB;-ONcxBFH#Mk{@53GWn)9_G*0@dGc8lBV}M`6 -zDfaDB-q?frPE6|Y`t=pRqo^M%4u?m!6ej$OR9taQUN^Qeg)z|a9(9Ybgsc0n -zO!3-sFuAT@F+E{Q_Fbm*`J+i3io#Xi;S@pBadS~cn4y=#-&8mY)LXyf;~Z?N`VrF7 -z+OgDiI)ROBkh-aUwYNihC5Ztm|18l={{Sq5TcPB}Zen?eRb%c)D%^i1@h;-{&5aA}224huiur53b(2brgGoHD-H9le75aejeU-313HaR?~OWN*gVryiulZz4N_cM$T4d2 -zA+Y9$@O{OW8#Q?F&f;}xhswErtv)cVaott4#wF<#+33e}iCk3f7W(?I$&s&f5Kctv`YB@nB{(|$VJQYEmw=-`{@Ovm-R|fzz{$er(YBw3T1F-;98A-h^HA6flZT2^ -z1M`+o$;eAeP)c6GA`JVLLCe^Vuu}X~-^?oWn5)3om2iFfX4#I&F1@Nn)e3z5c&p{H -zuea!<6QIqvzCQ4ISwS(MhSv+li#kOPQDwWB94Sp_=%PC<=NO}KOI`{}4zPswUqVSM -zC{=%Y2_gD2y`N(joV}}xxDJD-j1-3j^>m>!D;M|R=9w$HrK~bIt)`JwerC^&-<-tp -zsuaorH593+$W(nRsr_OP1yejXhwk*Wlt7ZncB8To8ytA -zytu(cLN?tr$G&cJ-`i_ZHH!{i*Q3$*tj>#-h)I=sFYGf%_CoM+pb}bgaf1gpsqXTL -zium=nhJ(3W@O+{*hoF81@>1A?1zHTrIXlxj;_?xqv??})960xo6DbWS54n5pu2NO&g_dytq09An2Sr#iVIwp{9rSUbiGkS -za>{_uZVpZ=8}=vt@c?jc@gEaBRgt>*9*Y`eIB8rF_pPj*9owF%I{n!%b(x=Y%=yS? -zj)*k0vV1mg@<)#cEY7I$*)JUSeKIkb=tcv@LGsNj-7Jlgd7vJ_&M -z3Q#+wbQFNoe68YJu`dGMvIOroH5CN~z8<&CzEKi3@CPC^185`c&4>&pd^klX+Qu@y -zJRaRpVnkMA)x!LyUQtTCE^Zy|3Umy!4-DX^ylKCgZRMW`mLqx6GaiZ(*n90i!{Cbf -z~xJ9nMmsDIjVhJ3*<7BXsV>hyj- -zy=uR_Io=%^227&XsLnC3N^UX*`mOg_^0Er -z<)UdsVJ3V_;yjDM(^rojm)u9rZ9TIrUHL#>t*xQSS3JC{0?n7iGl44it=~yo-HDhK -zZ+xPWZ>9Lfkz7Fwh7nn6#=j0rm1U;b1DWkq(9Sp=N~t|V#+IRYO5fqOHs^6@@l8Xm -ztX>8?ZN2il159#ae47qP8aNPYw!EF#rFEJ)M@JG$&E2c3$gcLC;(*CjB;G89ak=cn -z-d=o*W>B*5Y?pTX7`>SgxV7(EVlR63YBgz!--3of+P3xT?#ty(u1FmZ>>|ZkzygW~ -zEP|kBj$(4T8~kQH!xcrsDG>D;0rHL`7lpJ1O6pa4TM55yLT1Ucyd0=>>R74 -zXqTK2@JrPFQg!rx&&Km`=kO5)Q^RnKk%u^ViQH!u1zUMdZ2Cy*<4Ln7t?ud&+Y3;} -zi{j-TsiYGCfC>joN~+0AO8&>gLdYY++`trJxldxmL#Bph#W+zm=&mDbc}&p?uIUW8 -z0}^1y=3_IrBRnp!oQ4rG-13_+vN&xZo~<#75uErr%;4mt{H(OXqp5}+#_oWt=*GJL -z*B+S1Ne0cye0i}&Cd$0%xQ@qa`~YbH41%PXl0|v`1e47+fA8t`?ul`_t#84DJ2C@Y -z8k9(iPvTLebhkM1TC>O0!yq)HBGLu_MYuQ~RnT7N_n$-ush@)K>G4-Cg&M_}-gfGp -zTIld-?GWrl7u%Nlp0G!(jlxAu$=^QKGez4_Ya=hk%r -zDCp__jHQd^?EdexM+u3z{LqoDp>ZdPG-pun1pCj^SO`)n;q30?q_>{pd+E`_okO3w -z+uE*0RLDY@JX-=_h>4+hsmDxie7sG)onP|7H#acv2HjdCx2GVFaM8hF$irJbWhDVi -zXGa!uD`yL979U3!$Or%+B`# -zXE$3`c7A?-RyGb+4i09B2eZ4clZUwvvy(gJZ-_rJq^#X7-M}s$U}q=LZ%lIwXHO4d -z3JSj(tpCZ${{;lZ{XYS?y!Lee`=UMFt$&;T*!XKJ8&=4!{#g3oCzX{~R{KZH?>yLo -z9bNv2`0f37Pblh -zb6fNN4MNoo3~3+p*Z*oId~7z>JeHQc%}aj&Vg8#cb{=+aE`ByH -zes*47HZI=3#p_tRxkGy6H!3?D3&)>3x3UzFfnb_LY832fZfniz;$-^=?(bv>K(+&+ -z)BJZ!L6HBjLwFUCbh9@1aCXyjc782P@q4wP-;jTFB1q`39urV#QNVk|8Gc|cFx{T|93e5bo~d4xSNN!vzvpeo2rGqwWY^@kMpmb|AC|d -zkw|wBH(&Yx!>0ZhKcPR1R1OmB?B@Ho`8BOw|2+Cr$6kZ~pb7-~Lpub_E&rt7-Q3IC -z>W>sac>Ht7($3t;)*2$xe>K>D*unpzkokBytj*cEd70TPAsWiXZehdB$IZ{f%*AiX -zYt3$H$-~F?zo5H2+jw}JyIG6dLTUh#XNUm&k!KLyU-d`-pI75;XZ^dl*f`jk**KZm -z*|pf&1vuCRIN2%w%r;1f^|vhl$8Lpw>yEOrz~A}!iy|p&H!x(gGH%X}e^Bv<0t#6D -z*WJzY-*z{IEr=uv{3}-eQU~t;GXAeZ{jHY*^1mBI)6>P}HQ3tiKj-g1>iNI$6Z)t9 -zuip7Th5y~{&uB?!7hj0F*muQ{|m=I5tP7|)=uuu|J~C6?(%24{&rS{toctH -zBn{zuOLuC9O6^*>_Z -zf8_k{>iYkUE~J0nKd^R!T#tG~?hf3j&(lKgEWleR%1QxVet#GCRHQ*Hh%R#a?f}3m -ztluvvKz1%Z#0d0|SC$5TgL#F8L)J^q7!3e`0P<4eT0W~k@_Yld7Vlm}555XMDA}Yo -zj3(0A4|WccWH6BHdDkl9XjS8=#~Jo5RKvk0w3M~Bw6ZLAHea8>H^m@j-nX>cw|p@@ -zk%14ldi#BpDeG#(|Mc#O9Sb=#dBryM>%rB|)ehW;b@!9@j$^_tB(^u6k}h_McuCQllCx6WPr8fi`+7H|R$TCT;+X9jpc< -z;Cg{WkWB@B6vLowwmB>?bkK#f5=qg05G@=_d>rk{Z2$W#2y157K;9MfTvKqk99$hGMBYd~U|5{&@WZKL#cU -zRsF5{wriLICSMtb&4Mta{zRXPW9M*LOAY);avRt%Z@$v_5s`iFuCO5la1LV!g@7PY -z=Otwj@Zgiwlec>iGDyyVG}hyU(8vc6!+}HNJl6eOyJRbTQhz*apbukp7@@i5_4bpJ -zQz7m)PqdYg&ri`#sAlTtF$<1PQAgriNqn(R%vo%00)}pr=oGoLm+ESho0!)e8>~cE -z&VD>h$t^m|0Qx5v`(0GwmN-20oQ5}tqbXZ~tL>C`w0Eonc_xETDKOWlN84gl;&|J{ -zIFlxa5=FiBDOn~jkyhOGTGHF1rzo$u0*j$E-V`nDlVHwbImE&sUN2a$rlOej6HvBkUOrN#vK7qhp&|SuQaJd0VAY)C(tz -z(&aZFn|O1f0r}x24<}3e3{fxccloYN!zMZd_%?tby|~+x46FC4WND -z-K(+SUD42K@MhW%KIR4D0~Bg+jENDD;0vfXqns;Vy9cp0UN+93>g~ -zV^td=!tDIKT$Yb0d-6QH9ykQL9|g1&%&53de(TL0X0^5_lu{7^MHNqtAJWo-v)7+Y -zHLr6S{C1)oXk70AW+Vh1^*2uPC%lbejE*rvl~4-n6<7I)K}OfQefV61$dq3)d5SOg -z21fO9Uk%-Qk~z#bbx;*6oX3XikpjZWj}N5KFYYI*IM~Lx31mq -z^#lqH=b*q_6um=#-~Q%sBtCsLf=W2@1mFVdsCfWmX}#T5Glh>n>n{MuhMV8`XhgsQ -zu*;X7H7ACxW5r*bZzAui;YSc!N9%tST6DNjG$Ou_4$X%Xle?SjaiIe`t*coQ760&! -zHG(Fl3fdZQj+faw_W^JxG^)tUu@mN}C=V|x=hR=>g~UtMH!k|JwZwU2P#Ob}+&c*Y -zEXZ`}H!7dE@gGe)=QI1~x!z)b4-4oe#|`_m3vUj7t>PxOh)4>dhQoca(8YcEt(4M&J2s=;GEZo{ASO$i+lo0u`eu>oK#h;xYW31JWJ)V -z&4PzHjj6nLW4TU?ODvKSpUC^L(pV^GHC%fprG(S(8XZ$`k6w!LqK*{SyKVnv0ABz4 -zhl7B;M8`4;gLUBmVhm@PQ^{+d+H{nA*6x$K9YWA2^7Pf_uvCro-tjnDi%A$NQPEn+Gf|E&UkLAH@TN -zz6r68;WK0lqf_dGsk9g4$VO@AdtBdtTiiK@JCgh!WS^fOu+ -zKXQb@8qsFXJ6aT35Rej*mAGYedyR&Q58sM7(%ZNs@y1B)S=9O^|?ChZ9%je -z4&(Xlhtzb$HjP(3IO%+DKZ}0IEhJUoymg1|^^ipU9JdBi&*wWN&l4}KrgL@(70FD) -z3U9B*BC`4bjwoKP^>*$wm;=y9F8c&VsW+UkL`JaC3b^S_<(I*2(xoVu;aL6%-8+hw -zcEZnB5|?*}VpjjSh7>kkkdw?PN+N -z^!L#k?sPfg-sund_})-@h-SvuA -zZ1+uI0k3J~AL|9B6Q4T+b*7c+2OC(|b>O!I0HV-r?6s(gZlIA5$6$vUGzZ1! -zxjHRz7e<@iY3sBj-<#n(a+Ktto?+A+Hihm)y`eHGDy*M6QslJTBQ~D-RIEMV*Q&B3 -zJWxIe{jWk7-8l(iuglhGp!ATo9so7;eT{~2>P`M8?y3+?pByoDeWg{7C;FCoAE#-> -z=*-wZq8JL=?06rZq!Gb(p2Hk&HqCP2mrrA5xVWN~=COR%z>Pko7Ihi(2`EGq`qtX) -z>T3;JMl0*O43rja&x}!N(*!f^ujVG#%U}0nnL4iGU$k!{MoBR -zWLT8Ouu#?`H-s`=h_a~nTP-H&1-vA$sC*fI={v@mKvMCPPQi#%e!zU@mp}Ro}CQ6Ddqh!_uD&6;P -z?AxxOtxGW^)J%#E_$@rZb8^+x2y{AF-r0>BVA;p2&?v-H8a?H(V@Ex;P1;tVSLyc -z{G4Xz=u_{la6_~KQ@1i-GQ?ZYLX~KT)K6W*#v*3tb5rp-@lD<;4+FC|+P#*OfmW+I -zD$r0-b8hPj79hN^ezk_#RGB9qg}jpL^T7Sp7Y`};t@_cdhu!|;4rQBe$@5# -zF|lvll87X_3o%3A3tT7;*>$V(5b;2+laeE0LGv3PG%EDXh~tok@13T88_~dZ@>vrz -zHZ}fq+Gs0g9-}K+4(-knQh}*`4kfCqV}XDvU}01$a*LZCv?bk5C%KFzT#!UDTbR>( -zEB0D5fhXF0l#WGOexh!yg8TGCG@g99?;l}Cxjc%tO31@7SF{W&58mqxcKYoAmOv?F -zi^(U}YtSJS(3Nlv(EW&1Bl1h*y$|}Ly4rYCdFYrHG*2H~-(Qj648u)Q|IXi3%mVp_ -zWc(%Jj8It=vW>Bv7WDp?bh-G4UYB5m#BYEN#F~7;QZyP!quanWpd)*yIC)ysNt#wy -z)1CEHXJZH9h5o*dCM1nrW199|vJQ>`>!`9ho~Q^m&Ye`nJR?vLn5L7`%Cr4M|L!ui -zR?NJP7XCGF8lEhlwYx{UJ1#bxS~kqv88=B3#@TJ^PAX7=uIEjDsR -z*oC$lJL5ZZ_HE*C%qEBav6=pI(G$p>38|w#vhz8c-nM%foL*($b{3^nZE$fCmvTQ9 -zRW>z6L|C}*JkKP2B0vS4i|W6>FQ^N|^P32ZJ`tNumQ)68iesU-t;OAhg65DMoTu?0^2S4-Y9(EitJ1@_gHIp%vqo7S#UXlGZ24ZKiJ-cHzXsGsI?b4 -zqCO;6F$AivQw5mHZfTBp2vuLrqFo}1n#gqg`R1gvoq;|$MRHdELhLp)1@&`p;lgQ1 -zs1XWD2Rb$xIq(i4bZizOiJ;auxtle2FyCgLO>p|1cI)@9Ta`IU;D%AxB -zz=j*s>OCobA3U;mn570!!HOn35(xWkD-TL??x$HpiX1p%Bkh}p%tub#cP1{IK3ZCz -zKyYf$YDDno?Uu7kC~CJFmF=X&t;oCjm+878n$QjohP|)qWe`AN#*Mj{_(FwaV`&Oh -z&kYa5SwB`ArV-L@0N#8~Uw+!swWBfgrp?}N6Bls+`HC7^o00try2`~-tu&Tg=&EaK -z)ITwOjb0{WCb(@={ny!$y!6Y^h5%Fu^5VeaKY#o?9* -zLtURX9Xg+*S(}UUB;`o!wI73P))9oW;4l=$ITU}!=s6x{sjVibn?y^WUokfkP$9Tz -zJDR8dbjOW(neDl)Oyb4oCBqWAgq*Z3yk~tg^Qd^*$gg(d|MSj^E4H4rO -zLq(9KLIf(F1ja(Hw?>Qfl)vJc>~t25m7%Oqi2ame{v~Ss;EnG>D%Hfc-ki}s8+|ID -zHUL*tny<)2z$YR18oK<{n&0*q75AMkeaaVs=}FnoE#?MDg%fd5J_D}1Z<&)DVHupD -zWQVqT5ar-0J1dmLJJz%t1a6A9#ox%CxWLs_lQ1zbr$MSF;T4*{d{_zg)o3>=f)$(; -z$17~skW#O=Wi|69{&U!DJ-t->;vRQ*B7Ovoo6QFj&DjSolTz>U8 -zfEORGa}O?3Fg)^&0Tx_eMLwt -zsZvn+Tyf9?Ls=CXO(fRf-(aFEMG}BT6Pgt-{q$q#0t6d#e=&fDd|;%V$5bZ-x{@+= -zd@jOOKmn_f)+a#u3^&@H*wD4ZFqpz7{tP9@m=!k19Q)8W9T@GKoH($(W%R?0-M3>e -zDR;x?M?4-EUnB-yaHV4yl((d;3UEk~uU{Hl34I0x(mKj-(U -zu5L(LXb)hG8#(KA=2uXZBtt9|;#Y-gn1p2HrpSyOKL|Pz@e8YS4i@xgJ7UADTDJSg -zPsqvQb$a_sSCvf~72y=YZkqv0QbatInCWaGo4@N0En*V|XA`)|>llI6FX~539Nz!s -z2N6w(3$hW#xNqj@7@5A*eU`&)O6@A!?8Hly0c!}EfYX&qD@|3Z03Y0JeT^tuN=$_5;=6PEvo?B~WomoH9H -zivvKf!H+m^Z9xKYm+7Z(}x+@u;#kEL{zv#Ko@|c -zH31KzI{pf$XK3K|+|zLdLc%;cM&!$^rdvx_YvwscW1ZcaVWKS*`Yq(uPe5coJc>Ht -z0E-LA%Dd3^<85xiFZz9ARKzVMM>E&EAZkp*66;m_w|Hup;Hzmth$z8peMKF1Mlu{9 -zyMukh;e2}PKAiwef#QM|n(ERsGN1ucR`9S0eP^XaNigx;7+yr0Z4^fh{4WX{HT8#lV2QOCIHdwNlLz2|-0YjHXf=uStu#ZtS@`K@dG4}+2L=7VCXa)v8V!dYl3xnwN{qDV@) -zr9X+&&ux~oFxXmR0{bQA+^Dewm;Fy%kL93uQ+Ih|g%vzh)M9J0^?9Ce8G62%K2zlX -zqI&3>?a&k*H`2e>$qMThIAOFkW`aMsrnEiBfPyFTE0|~RZ<98N@pgM)BZ!yvq}E|e -z8Trbjxm$C+Sr!qo7>-^EMiSz0;|6>cwi)n~9DpJKyBGz0gtwGSG+iZ0V$$Uk49Ap6 -zY*CGrbPi)L(?mr2CWDZU%Nzc4_S}a60qXm=OBZoaFs?LH?p206oaOE9Cjw3xCBCoE -zAEgQW(UB%m?cU|x!V5oq;jZu)_TNBYm_5LrLM;nVw)~!^W=tjjq5_s -z9^4^}3{`*xD5kT>ACh>s=h$tdJ@Zgm@Y98%Vide-Z_yOkdH($9w&y5sZ3~SKE8*H4 -zh{=Fry|sl7Py(naFk~`v=-HlZJW?e^ksm4wAVYspk#%Y`7>(NW;t%%GkPOp4IT8xj -z`(zaU?uu?!T7=(?cK2Ak=Y<9Rjq?hvMS9U|R&*Qy6E!>nLg0t0I9;yOD -zZ_Bbfm90HMQ{hs7!HjpoWqR2pf>t;tnCwU#7V0yR@*Z~@LH*?F`Z=>Bwq3|&2`5k5 -zha^LHBeB?C(&Q4>vFgt0A3fNnpJtbl0WulcH~q_(47E-nGtcBJ-X;39v3mg@vYvO9 -zZl1}u{MBrQZpTB2eR=B`el=_wZ^QPhk2cu%UFf>)1iY}twfF&A -zofj5f$&b_rm4v@R*YouI3T{jeo^o;vdMPDQ`6Wk2MyV5)YuYnKs9E;@Nn`Ibl5WMd -z;4mOyTm-{19`&+qoV`)2N0t@25h1hhmBi4Yv)GOsrxJO{qDo)NvMihuH^Lsh`ryZT -zFF{=e%#EkRa{?t8E7&g)izh>s4AWPm+c-^QD)=LD8qmbrJZ!`n0EM8tC^fo#8HAEy -z=!f;50sfgii%cQJ1_8U^(pPVyIVUJqYL)Xr6n~S7&Wb$DCvlhNKn={qpillv;!}!fKP_tBqX@0Oh_m&gWHLD2TXVV&OLz^TvenX7gOQ&s(gcUAZf{%5OrjxRvu0!Rwp -z`S@IMlOxyk`1WTzPC>PGO^b~7r`n{esOo%qefh*mnD#P|*qNS}~lpY>&-v+k% -z#ofBbA!)?>d3gVxnXdHrZ76)V{2>{t>$*Ork)UWNoWMU!TtR* -z2J}@!tKQZ|d$rLNzv>Y#F7%e6H5Qv6Kzw7F0g#T;@pfCy@GJTlF_2062TEJ{%(HIW -zy{ihmx-2ddG{1N2_+5@3cGAnQ27=yguJXtPU`L_fQzb&&`ZBfjMjX4ZxPi+TT8sE9 -z;wq{dRl?$g@@Bt&YkIhJ%=d;x0M)xndI|PbGZ5OB*Lyvj*}1y8=ikm}X?NHFpU}0- -z&b&s8AT@$Y4Q67&xMcbEHmpJou@cB;6CI)J5A4MTp1h9YbNaYd|4l4SaUgvZn#n8s -z7zT@BORhxB1YNp2aFz6+seMrN?zZ7mWU~lC6Y1W^UEUe@L__yCrl`&cW3!_43^^&N -z#Odh7)&*`Pwd@>?;T-q=ZwlYrD+G^XDfri{D9-dIFLf)vdn7{c -z5VkMr36j&vlKyy0ad!ERG!==MbDRdbeVRQPh1>NRrSbF(8ZAmQI8Y-k{Ea=0kO8E> -zY#LL8r@Z*_3ckN?unXB+bI_`9o8sRuTYJ>l+eJuo+TQ~63P7>V^N?C5BsOp8qV`9U -zI~hfM-B&&#Hq3x=!jt67)Gw8yry)e%V~@*tzKW-@{n1!}S_>%*SP))8gL;kd_2RFt -zZ!`Yn)X$7%s)T->I@&xU^ds~7FwiuXcHeW+c!V2tc>CuR-)p1^o~9&c9}&z-p}Q0h -z$no%x9mQ1yeG}5aI^u6oRQV!hQGHqKMDJmmOMl>UUPINNV!i8{O#gIzQN%RW2jx$N -zjC-g;#a8Yrl~N6@tc%znXt_)zJ+5s0y}QQ6P60GJ6a8qUcz0uPr~33Lb4zQyQGzWVXH()vr)3Fr%U9+ -zgk&N2lCF_K3(De%=zl%Va#)Hzk0SFkymEI_G*It1jN@D`0wC|6SqNAH@wm-2WnCAAg~7d(dcNiI9zD11;_j{3F^;@ -z8sjNRF0tzmXIk~b5ZxCdOE1Z>%E(i4D~yuos3Eki8S%M3!#ViGV$SSaDak`ycq4&% -zI=UiKsJ@WmFro7^X@%uLxZ=B;fQ%3bkF>AoXN{$a(YJRW&t$WN3dlex!f6f1AWdnV -zq7>5pFXp%=KS;KOgDQ*6yb1=Obg{;%sX(xn$nZZyhLko$OB%OhvAnqsWr;y}Bz*&X -zH<`M1KjML+$n*LDbq3+)BXN<8MlYJRW -zOo(I&O^8T#USwwwDQgXq#*(R|cx7KQjdilk$dYaBV+$#gJrr3cYqC@H{k;Fc_m}h2 -zbDrxt_kEx1xz4$s>n0}Xd&vi}_JC?g#oqjOqtl%DQ^&U2jtjdvhnKk7FH9itn&n8+ -zJo=Z3^3NqpPca6OEqdJ0yYlp_`3T{^;rHe&D2mUS8+KlsFKCYX-DXVRtcF}_yk?y~ -z*>JMqiiWG$E-}J2V?3O~2~bTj=<2{nb^W_kKGt6mmHuPPeUjB#5e}{ixx|rAvx4e) -zmj@jNhM`)`=OnIaKUX>Qh3907B#~2oBO5e4BTI^EixtLRy$UM!Lw_16S%7f^dA$Dt -zmiN)%3xRg;Lwz;r?N_X -zNGRS=Nk#?OBEs@p_N!>c&hzYiL;5m;gFoyh!<&$8pMfPMP*gB$_Ke~D22 -zKc)>tjYcBlQP&9=9~mY1N|sGtm6fh)*^*j+Dk5!p_hxCgiT2C&pz|7iSyRIj!3@2y -zo{Ed($nC9#L^_>5AeZTT;h^Qw|h3%~zez?08A -z4B|%}HL1&~>$yblVv3BJAF}Fwwbdr1LMHawmfZBd=rk|9C1={NF6l0~X#m$= -z$BL$-%lywtgN{ab$8;r?twc-lsDIq2|0bgBuIn -zl}tuOm}@B%TT*b{Rqdo$2Z^GUKThs9nj!x_gE5i2bBR#kA~BH^~LcNOK*u;!u+DLn0p- -z?5pPs{z@oAtr(j?QVJM?jFM*o?oeW;9|zK*EVKr1YHii(Y=nB^7$(n%0fpDE0C1lunj-a!?$m# -zRAHglXz>#~7I@}hI5#WV0Rc#mm$g;71c&`lUCw85M!QebGH#93L1XHEv5gx$OX -zb#=o6U(0Q=vrQ4Q0b;!2!FqOKnfSv^#sx(GkAfK6$Zp(I^|fK1RfRiOtm4Es&Vv3W -z48AGN(9iO{#g08om*p?o23piA=ejmslX5>PPdQL9d7Gmzhd|-P<)5KoxU-*HTsafRtv4%10MRl^oK= -zW2^4_~7F?f6DI+MYJo=+_yB|t#IU_J8GO_uv@sCd}3yecEOFH -zF2SOoc#<0!h6CnJ$fv@)8%j90%gi`o`7sP<_M5&3dGufgp2+kGfpnXx*?TmGXql`Z -zK-mK5TJ{;#bn?y^nE1=PN};IlEYt -z-BHe>`zH(tBjD~}*ad$cldWkY*yGoYa*?&gywKGZ*~xDLnP}ntN+K?$43gz*Len+b -z;Z4J3=$lM<1SS;Cm{_P9+u^}_W)V{dDNmsU^k5>$ncjuS~W07QO~BbZYhP!Wj@Fw_q9yk)?=tjyUU>;!iv~ezvMD3et4m<8rJB*+hxi9 -zOa=%1VW0(nC6IGmRwjs!n8*+*{42-^Fu|55t4mJ0=P8Ull#YHBQp5Y(eg}BKNIMJ0 -z8V0i(4nU0c3dTn5qgZAmfN=oJ-`HJ4*zS1hXi`maIL!~;GK&KCp|ZWok;pGT>oCrva0XmkI$3-QGAjqraem~wa6j_a*bHt^gF>m; -zgE~Om`SF>_bgvsE=>c|epIZJk%Vz^$s}|mrhIKn%@7_9o3N!96qf{(~?2fvjx_{#U -z?JHs%{cF2opyVHUX4`R5Q^uW33xFIbRu2EWMJ-Els>lx}Y6`});R8U3PPFldzy_0& -zT4s&kobB9;9#6|AO^JA+T))d5z#k|r2#8XQ?vagSUS>|iVj_3N0V0EYNcoQOnK){l -z*5~dT@>Zu(O2tD_nm_OtDzPY9;u=^!9OGlvd2Z}Glf#!}grVf+1qNWdMa|YN -z%r8MU3s=4n_wVWoC46Ot5|ut8lL!&4*~Cj!1(*AF)=(`_$BYI7cxMQ48N^gxpy7I_ -zSdw<0D&*iaw`Sp8q)~1fw9;q3TD958x852C{9&URgCh6_a%EC?M1GxEYQB;R%1^e` -zN_)obR!Q%iM%As!e|HnW4;JlDQKrDye#{WKVaz%z=X78~Feb9r#on!jKX$ad2~xAi -zM<=NTx~jb66DlKxL@9PaA{b_afJ_jZlhnbTq*Kfwl7B$1bPOc}7P*kmXU -z14}x`!zEpTP*lh}rn~0pT4`dpjlMEkf~iGl=5m%7;0H3}NF$%v-8?Q|s!Uv$WPjg( -z+HF>|ZO=bAcXf{(-+1J^n}4*z^_@mUU}d0$+I&ah2t@XYXJNxKlBFXhqA*|JeN2Sw -zx5C}g8$jEn((T{E?AXLp)C})MiSF2P{p@Fg<~maRtHGidF=9gSK~?|r&W)9=U#dl@ -z-OR+Z5a%SLd&6Z2cZ6_(!M2p%;!B>Ujh4fzfvJjEj?CL4cJ;{$nR{ig%3E;Jzi2VNm^~p*Q{zrsqZjq^T;;iJYC)?L!{&-#a9vvf^r1In1`EyG -zypR3?eJUjPRI1mR+6ncLX>~W@axRUspViH;TfdCMwLZZ<#4!wR>(9Nol@$!J%zp~D -zJl1s2TcI=657x0Uo)ck7t?F&91n9)!XX5&}GyZlN?f9rmJ1&p&peEYjrQnCCe6NJu -zkgtK}^G3L}Q^8VO`zw^m!`;!SRmK50gN`LP>=J)U~Ti@(v-%DUi -zIsWKyJgW)QLwP8*nDomJBHqP2f5p)|?!T$8MaYX--UME`W>p`HGH*hqHhCa|n!Gbi -zL(BC%)geM0@7`cST}au1`H&RQ0k>6yarWXW-QUd*`p_3Bm&W@Tp*eN^r45F!j<}xO -z>q(*1+!ImgdQV9Tt%v-3OmkG(w6}iivx}5KnY~#0#?D8wSUXx)Nc6>e<9W?;iS};C -zH`uXv5DvY7%vpuV0z}IV_7EH5nfNTMUr#oBi&KTqX}k9I_eU#&cmdb!>SG1XN`0<~ -zrd|djclMo&%FdZqBrngNb@uO0iavJSbwztTTem*$6*Zp57%EifHTj4@ihzmay|FQ{{!khsA>QJ - diff --git a/patches/server/0006-Purpur-client-support.patch b/patches/server/0005-Purpur-client-support.patch similarity index 91% rename from patches/server/0006-Purpur-client-support.patch rename to patches/server/0005-Purpur-client-support.patch index eabfd39d2..ba9ee7552 100644 --- a/patches/server/0006-Purpur-client-support.patch +++ b/patches/server/0005-Purpur-client-support.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Purpur client support diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 53ef5ecc750f9d0e2634267a33042f24c969f305..52a81eaac0a080738fc2d12b30693ad161066d77 100644 +index 483df59a805d2724551042aa4470bc439fc2e7e9..a471d30e8cc289e750db32a343f7d21a589dd1b8 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -258,6 +258,7 @@ public class ServerPlayer extends Player { @@ -17,7 +17,7 @@ index 53ef5ecc750f9d0e2634267a33042f24c969f305..52a81eaac0a080738fc2d12b30693ad1 public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 162a4b3b3312867a64425caa0d6ec6af157b20e1..f99d06e53856c14f5b94c28d379b8188ac1411db 100644 +index 559572d3ff37e016ed07d428cf5d73a00ef48d70..2dc4c7695dab7d03316f5473e29baa1db29debf2 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -3104,6 +3104,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser @@ -43,7 +43,7 @@ index 162a4b3b3312867a64425caa0d6ec6af157b20e1..f99d06e53856c14f5b94c28d379b8188 try { byte[] data = new byte[packet.data.readableBytes()]; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index b2c6d1611422a3900e5c9d4b1983cc74dd820973..03ac2878f54ca994b5faf28fa68aa547bd7388c3 100644 +index 8c8698f6e17562651fe790dc19825e428d5d0352..bc88b15dc5c2d2d63edd4bb382affce1d5d7312e 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -2549,4 +2549,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0007-Component-related-conveniences.patch b/patches/server/0006-Component-related-conveniences.patch similarity index 92% rename from patches/server/0007-Component-related-conveniences.patch rename to patches/server/0006-Component-related-conveniences.patch index b3f929c87..7ea95dc0e 100644 --- a/patches/server/0007-Component-related-conveniences.patch +++ b/patches/server/0006-Component-related-conveniences.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Component related conveniences diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 52a81eaac0a080738fc2d12b30693ad161066d77..6d25b3397a45d77b96d04a5b099d58a092d43177 100644 +index a471d30e8cc289e750db32a343f7d21a589dd1b8..3becbc139ea6510ecc7e6e160620b8fa3b66dc46 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1680,6 +1680,26 @@ public class ServerPlayer extends Player { @@ -36,10 +36,10 @@ index 52a81eaac0a080738fc2d12b30693ad161066d77..6d25b3397a45d77b96d04a5b099d58a0 public void displayClientMessage(Component message, boolean actionBar) { this.sendMessage(message, actionBar ? ChatType.GAME_INFO : ChatType.CHAT, Util.NIL_UUID); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index ea8956b2c4cbe7059512ebfa9fd7a865e5fae0ac..1bbb3f0658628ec36cd9e177df3acc07ef107428 100644 +index ad9fb50791779a5fe7d22268b71bd10d9c9ff3f0..1c1602f839828252748e1acacfe42c7cac194332 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1396,6 +1396,62 @@ public abstract class PlayerList { +@@ -1395,6 +1395,62 @@ public abstract class PlayerList { } // CraftBukkit end @@ -103,10 +103,10 @@ index ea8956b2c4cbe7059512ebfa9fd7a865e5fae0ac..1bbb3f0658628ec36cd9e177df3acc07 this.server.sendMessage(message, sender); Iterator iterator = this.players.iterator(); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index da01861990da0307cfba14cb2492baf7761a3930..b2ccdd8f687e3bf0dc64110259a301e879bd3657 100644 +index 16ee8991b8993c243b23131da7d4790d9c71bccd..cfbca7cc9cfde0a17f13487bde3471445568cbb8 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3589,6 +3589,34 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -3592,6 +3592,34 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return SlotAccess.NULL; } diff --git a/patches/server/0008-Ridables.patch b/patches/server/0007-Ridables.patch similarity index 99% rename from patches/server/0008-Ridables.patch rename to patches/server/0007-Ridables.patch index 70bac8b9b..b6defc188 100644 --- a/patches/server/0008-Ridables.patch +++ b/patches/server/0007-Ridables.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Ridables diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java -index b01d7da333bac7820e42b6f645634a15ef88ae4f..30a4b80eacf76ad7f0a48b79bcf01b752c0af48a 100644 +index 0cc0242d981586413bcc349df6e6fd3bc09710f1..ae394b3d8b8a157d345e102f5997058da03abfaf 100644 --- a/src/main/java/net/minecraft/core/BlockPos.java +++ b/src/main/java/net/minecraft/core/BlockPos.java @@ -41,6 +41,12 @@ public class BlockPos extends Vec3i { @@ -22,10 +22,10 @@ index b01d7da333bac7820e42b6f645634a15ef88ae4f..30a4b80eacf76ad7f0a48b79bcf01b75 super(x, y, z); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 961af809af47ea3fa0575f17a8e783de7253fb0b..55b85ff37287d1f0e114073c86bbff445f6d7848 100644 +index 080ccf4092de52292175c9333b530b82bf3aa5c8..4350a9507deded551e709bf333f0cbddc7ebe6d3 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1592,6 +1592,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper @@ -34,7 +34,7 @@ index 961af809af47ea3fa0575f17a8e783de7253fb0b..55b85ff37287d1f0e114073c86bbff44 this.profiler.push(() -> { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 29ce41330bd291a050441fc5aecd7eef65ff471c..e38444328c0e3e6e5f4d51926bc58d9f0e0975ac 100644 +index 2db8a773c035a74ceb6cd31311b1b0e053775434..7e9bff1a8ec45551086550b4e5098dc5304f794a 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -201,6 +201,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -46,7 +46,7 @@ index 29ce41330bd291a050441fc5aecd7eef65ff471c..e38444328c0e3e6e5f4d51926bc58d9f return new Throwable(entity + " Added to world at " + new java.util.Date()); } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 6d25b3397a45d77b96d04a5b099d58a092d43177..651423979d4d5acbcf0bc25d6225a72a16e21826 100644 +index 3becbc139ea6510ecc7e6e160620b8fa3b66dc46..6ea2657daf537a0aa75aa5e5c03fca9610c01f7e 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -665,6 +665,15 @@ public class ServerPlayer extends Player { @@ -65,7 +65,7 @@ index 6d25b3397a45d77b96d04a5b099d58a092d43177..651423979d4d5acbcf0bc25d6225a72a } public void doTick() { -@@ -2439,4 +2448,6 @@ public class ServerPlayer extends Player { +@@ -2441,4 +2450,6 @@ public class ServerPlayer extends Player { return (CraftPlayer) super.getBukkitEntity(); } // CraftBukkit end @@ -73,7 +73,7 @@ index 6d25b3397a45d77b96d04a5b099d58a092d43177..651423979d4d5acbcf0bc25d6225a72a + } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index f99d06e53856c14f5b94c28d379b8188ac1411db..c02b3cdd93df7806d52138b02612dd48a451962b 100644 +index 2dc4c7695dab7d03316f5473e29baa1db29debf2..eaca5e3c6d26d5fff1eae1cacabfd389b74aec4d 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2412,6 +2412,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser @@ -86,7 +86,7 @@ index f99d06e53856c14f5b94c28d379b8188ac1411db..c02b3cdd93df7806d52138b02612dd48 if ((entity instanceof AbstractFish && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { ServerGamePacketListenerImpl.this.send(new ClientboundAddMobPacket((AbstractFish) entity)); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index b2ccdd8f687e3bf0dc64110259a301e879bd3657..20b29275c5b0f1e1c9d97af274abdc2e1ca3d847 100644 +index cfbca7cc9cfde0a17f13487bde3471445568cbb8..4fc93b94c97a0b9bca7de40d7db8c3f02104b1bd 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -230,7 +230,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n @@ -107,7 +107,7 @@ index b2ccdd8f687e3bf0dc64110259a301e879bd3657..20b29275c5b0f1e1c9d97af274abdc2e private float eyeHeight; public boolean isInPowderSnow; public boolean wasInPowderSnow; -@@ -2625,6 +2625,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -2628,6 +2628,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n this.passengers = ImmutableList.copyOf(list); } @@ -120,7 +120,7 @@ index b2ccdd8f687e3bf0dc64110259a301e879bd3657..20b29275c5b0f1e1c9d97af274abdc2e } return true; // CraftBukkit } -@@ -2665,6 +2671,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -2668,6 +2674,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return false; } // Spigot end @@ -135,7 +135,7 @@ index b2ccdd8f687e3bf0dc64110259a301e879bd3657..20b29275c5b0f1e1c9d97af274abdc2e if (this.passengers.size() == 1 && this.passengers.get(0) == entity) { this.passengers = ImmutableList.of(); } else { -@@ -4252,4 +4266,41 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -4255,4 +4269,41 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return ((ServerChunkCache) level.getChunkSource()).isPositionTicking(this); } // Paper end @@ -201,7 +201,7 @@ index d28cecd9bea7c82fa675d333810e2e63a91c615e..8f8bc29d847801938e251904b8334b4b protected ParticleOptions getInkParticle() { return ParticleTypes.GLOW_SQUID_INK; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index f025d03149089a8acdfa55f54b5b754cba4bd4d1..f508bf68172cd5e86c3f0c01f573514b8e302c02 100644 +index f0ce1e4364e1a549163c8a3a714fb20df42ae3c3..69acb18fb715c751e3c3c412dae151fb6a8239b6 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -219,9 +219,9 @@ public abstract class LivingEntity extends Entity { @@ -230,11 +230,11 @@ index f025d03149089a8acdfa55f54b5b754cba4bd4d1..f508bf68172cd5e86c3f0c01f573514b this.pushEntities(); this.level.getProfiler().pop(); // Paper start -- if (((ServerLevel) this.level).hasEntityMoveEvent) { +- if (((ServerLevel) this.level).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { - if (this.xo != getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { + // Purpur start + if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { -+ if (((ServerLevel) level).hasEntityMoveEvent) { ++ if (((ServerLevel) this.level).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { + // Purpur end Location from = new Location(this.level.getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); Location to = new Location (this.level.getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); @@ -262,7 +262,7 @@ index f025d03149089a8acdfa55f54b5b754cba4bd4d1..f508bf68172cd5e86c3f0c01f573514b // Paper end if (!this.level.isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index c7a400e72ca2aae31ae8882b8df946b14b18e006..4af25f8d4d48a8d886c9ec823b65fdd0dd199066 100644 +index b8e512e1c4b00b468b2d22add5653b98f4a2c81a..4cf2bc22e1b6452d056b7bc85f84b6177d1091dc 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -140,6 +140,8 @@ public abstract class Mob extends LivingEntity { @@ -3739,7 +3739,7 @@ index ccf706acafc20e7ba5408d1648b873d6937a030c..059a62da29b7ec11e2ff9baf18dde788 protected void defineSynchedData() { super.defineSynchedData(); diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java -index e1a593b464c35f68b22e84a09f99ee72af73da32..25ce1910a03947ce070b318f57379f0da5ac5db8 100644 +index bb6cc0e05ebc5d39968fd2b923ba1cb540720a15..342c6158f6fc145a779ed60b48698e14a944726b 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java +++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java @@ -67,18 +67,50 @@ public class Slime extends Mob implements Enemy { @@ -3793,7 +3793,7 @@ index e1a593b464c35f68b22e84a09f99ee72af73da32..25ce1910a03947ce070b318f57379f0d this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; })); -@@ -360,11 +392,12 @@ public class Slime extends Mob implements Enemy { +@@ -361,11 +393,12 @@ public class Slime extends Mob implements Enemy { } @Override @@ -3807,7 +3807,7 @@ index e1a593b464c35f68b22e84a09f99ee72af73da32..25ce1910a03947ce070b318f57379f0d } @Nullable -@@ -397,7 +430,7 @@ public class Slime extends Mob implements Enemy { +@@ -398,7 +431,7 @@ public class Slime extends Mob implements Enemy { return super.getDimensions(pose).scale(0.255F * (float) this.getSize()); } @@ -3816,7 +3816,7 @@ index e1a593b464c35f68b22e84a09f99ee72af73da32..25ce1910a03947ce070b318f57379f0d private float yRot; private int jumpDelay; -@@ -416,21 +449,33 @@ public class Slime extends Mob implements Enemy { +@@ -417,21 +450,33 @@ public class Slime extends Mob implements Enemy { } public void setWantedMovement(double speed) { @@ -3853,7 +3853,7 @@ index e1a593b464c35f68b22e84a09f99ee72af73da32..25ce1910a03947ce070b318f57379f0d if (this.jumpDelay-- <= 0) { this.jumpDelay = this.slime.getJumpDelay(); if (this.isAggressive) { -@@ -447,7 +492,7 @@ public class Slime extends Mob implements Enemy { +@@ -448,7 +493,7 @@ public class Slime extends Mob implements Enemy { this.mob.setSpeed(0.0F); } } else { @@ -4471,7 +4471,7 @@ index c4f7c94255e4631a3c0355f9260132ba28296f50..d6c31596e21041a124a263054ccb6447 this.setTradingPlayer(player); this.openTradingScreen(player, this.getDisplayName(), 1); diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 9e0eec259fdae57e235bfe00ece4df9957edc642..19b65c0d2fd96b4516c0717511a6bb02b2d66065 100644 +index cea92f1dc663bf0648b2bd877d86ca380a517bc9..d7850a9bc7cf78e2b17d9d171302ce07596f9735 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -193,6 +193,19 @@ public abstract class Player extends LivingEntity { @@ -5717,10 +5717,10 @@ index 0000000000000000000000000000000000000000..8eefb7b7eb33aecf48ac206d3f0139e0 + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 8ce49478441e77cedf5148ecb81d78b32660329e..fb5cd6fe7903f3f96af1abb55832bafb7ca7f4a8 100644 +index d4277ca70124292c6a79f0c01f992f3732e52f02..705fab389cc8efa65432bbcb766e4afd185c0856 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1234,4 +1234,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -1239,4 +1239,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { return getHandle().isTicking(); } // Paper end diff --git a/patches/server/0009-Configurable-entity-base-attributes.patch b/patches/server/0008-Configurable-entity-base-attributes.patch similarity index 99% rename from patches/server/0009-Configurable-entity-base-attributes.patch rename to patches/server/0008-Configurable-entity-base-attributes.patch index e4a4fe3cf..ab8bc22db 100644 --- a/patches/server/0009-Configurable-entity-base-attributes.patch +++ b/patches/server/0008-Configurable-entity-base-attributes.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configurable entity base attributes diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 20b29275c5b0f1e1c9d97af274abdc2e1ca3d847..034f53ddce67a2f1a8efca09ca20f175cd2fa399 100644 +index 4fc93b94c97a0b9bca7de40d7db8c3f02104b1bd..c813f28c56b54bd3870cc12e3ecf0ae98545a6b0 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -150,7 +150,7 @@ import org.bukkit.plugin.PluginManager; @@ -34,7 +34,7 @@ index 8f8bc29d847801938e251904b8334b4b31bd21c5..87d01bebbb179eec53323e9e23db011a @Override diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index f508bf68172cd5e86c3f0c01f573514b8e302c02..63a59b0ca02503a677bd12509eee4e4b86799fb4 100644 +index 69acb18fb715c751e3c3c412dae151fb6a8239b6..a7e0126d1fed75bfa810f405a4dd5b70668bf08e 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -287,6 +287,7 @@ public abstract class LivingEntity extends Entity { @@ -1099,7 +1099,7 @@ index 059a62da29b7ec11e2ff9baf18dde788bec4923c..5a2759e636717920a6b34ddbda34a110 @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java -index 25ce1910a03947ce070b318f57379f0da5ac5db8..7a9654a365a968592d706a13fb46615effcc2399 100644 +index 342c6158f6fc145a779ed60b48698e14a944726b..01d04bf183743bf892be25fe839f3f5cf7ccff42 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java +++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java @@ -101,6 +101,30 @@ public class Slime extends Mob implements Enemy { diff --git a/patches/server/0010-Timings-stuff.patch b/patches/server/0009-Timings-stuff.patch similarity index 86% rename from patches/server/0010-Timings-stuff.patch rename to patches/server/0009-Timings-stuff.patch index 5b5a746e8..3b5ae8de1 100644 --- a/patches/server/0010-Timings-stuff.patch +++ b/patches/server/0009-Timings-stuff.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Timings stuff diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index 4cd8116fd623fbc9e175986526d3ae51a72b76e0..0e86ceb4d70c45835c9d1c6ca0908fdddf14d55a 100644 +index 5fc65b0224b5c56039d60baf30f2de35f8bfb1c6..6d4f049cd77599d9cc0ed79e70902eb1ddc03f02 100644 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -226,11 +226,15 @@ public class TimingsExport extends Thread { +@@ -226,10 +226,14 @@ public class TimingsExport extends Thread { // Information on the users Config parent.put("config", createObject( @@ -17,8 +17,7 @@ index 4cd8116fd623fbc9e175986526d3ae51a72b76e0..0e86ceb4d70c45835c9d1c6ca0908fdd + pair("server.properties", mapAsJSON(Bukkit.spigot().getServerProperties())), pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), + pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), - pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Tuinity - add config to timings report - pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)), // Tuinity - add config to timings report + pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), - pair("airplane", mapAsJSON(gg.airplane.AirplaneConfig.getConfigCopy(), null)) + pair("airplane", mapAsJSON(gg.airplane.AirplaneConfig.getConfigCopy(), null)), + pair("purpur", mapAsJSON(Bukkit.spigot().getPurpurConfig(), null)) @@ -26,7 +25,7 @@ index 4cd8116fd623fbc9e175986526d3ae51a72b76e0..0e86ceb4d70c45835c9d1c6ca0908fdd )); new TimingsExport(listeners, parent, history).start(); -@@ -271,6 +275,19 @@ public class TimingsExport extends Thread { +@@ -270,6 +274,19 @@ public class TimingsExport extends Thread { return timingsCost; } @@ -47,7 +46,7 @@ index 4cd8116fd623fbc9e175986526d3ae51a72b76e0..0e86ceb4d70c45835c9d1c6ca0908fdd JSONObject object = new JSONObject(); diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index b294fa10dc0fa804b94757eaa3becb104f20565a..aed391418d867e79d7236a3a3d8de54cb35807b1 100644 +index 7c1852f3ffce977506689f86d6b875fe1c8e11b7..0c1c88a79d055566c0e19f9372a74f6da8c1ecda 100644 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java @@ -217,7 +217,7 @@ public class PaperConfig { @@ -60,7 +59,7 @@ index b294fa10dc0fa804b94757eaa3becb104f20565a..aed391418d867e79d7236a3a3d8de54c TimingsManager.url += "/"; } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index ad7dbfa8dd5f38af87ec8980fd972ea4449da7ed..7e1938263ecb02c7d2a1fc3dff7aa35b958c6113 100644 +index 41134227b3902f6e008f1db7b0803a1f81e7fd6e..b634d1a67b741feadf3f8fda5439a501fef3d132 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -161,4 +161,17 @@ public class PurpurConfig { diff --git a/patches/server/0011-Barrels-and-enderchests-6-rows.patch b/patches/server/0010-Barrels-and-enderchests-6-rows.patch similarity index 99% rename from patches/server/0011-Barrels-and-enderchests-6-rows.patch rename to patches/server/0010-Barrels-and-enderchests-6-rows.patch index e1884b72a..c0be89185 100644 --- a/patches/server/0011-Barrels-and-enderchests-6-rows.patch +++ b/patches/server/0010-Barrels-and-enderchests-6-rows.patch @@ -142,7 +142,7 @@ index f494063ead9c6303fb3ca880aba2a877ae8d83ab..3b027111ed933856ae86ad5f62aac744 } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 7e1938263ecb02c7d2a1fc3dff7aa35b958c6113..d7ed125553530e28644f5fb9c09f7a06eb79199a 100644 +index b634d1a67b741feadf3f8fda5439a501fef3d132..e9c2ad24aea7861d8d3c1f8879f70e8fa514fa05 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -174,4 +174,23 @@ public class PurpurConfig { diff --git a/patches/server/0012-Advancement-API.patch b/patches/server/0011-Advancement-API.patch similarity index 100% rename from patches/server/0012-Advancement-API.patch rename to patches/server/0011-Advancement-API.patch diff --git a/patches/server/0013-Llama-API.patch b/patches/server/0012-Llama-API.patch similarity index 100% rename from patches/server/0013-Llama-API.patch rename to patches/server/0012-Llama-API.patch diff --git a/patches/server/0014-AFK-API.patch b/patches/server/0013-AFK-API.patch similarity index 96% rename from patches/server/0014-AFK-API.patch rename to patches/server/0013-AFK-API.patch index 4113aff1d..ed7458eef 100644 --- a/patches/server/0014-AFK-API.patch +++ b/patches/server/0013-AFK-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] AFK API diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 651423979d4d5acbcf0bc25d6225a72a16e21826..bd4583ff7d76b83003ca327e8301fb1d5ff18f66 100644 +index 6ea2657daf537a0aa75aa5e5c03fca9610c01f7e..19ac7822b4e1c4f1a21600c5e31f971eb87f839f 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1955,8 +1955,58 @@ public class ServerPlayer extends Player { @@ -68,7 +68,7 @@ index 651423979d4d5acbcf0bc25d6225a72a16e21826..bd4583ff7d76b83003ca327e8301fb1d return this.stats; } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index c02b3cdd93df7806d52138b02612dd48a451962b..f6a091ab2f549761b8d19fb35e1db907954a9717 100644 +index eaca5e3c6d26d5fff1eae1cacabfd389b74aec4d..9de4ca41c22fc92762b8c2705cdc8a5ffbe60233 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -390,6 +390,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser @@ -96,7 +96,7 @@ index c02b3cdd93df7806d52138b02612dd48a451962b..f6a091ab2f549761b8d19fb35e1db907 @@ -1420,7 +1428,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser if (!this.player.isChangingDimension() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot - flag1 = true; // Tuinity - diff on change, this should be moved wrongly + flag1 = true; // Paper - diff on change, this should be moved wrongly - ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); + ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur } @@ -161,7 +161,7 @@ index 8a0aea6b28295e03aaac1768336b1bc36d9ad9e9..30fef94aa85d7caa4c785ef0a7de4f3c if (baseEntity == null) { if (this.isCombat && (!targetEntity.canBeSeenAsEnemy() || targetEntity.level.getDifficulty() == Difficulty.PEACEFUL)) { diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 19b65c0d2fd96b4516c0717511a6bb02b2d66065..d761865eabfc67651b0a2a92ad35fc236886b61d 100644 +index d7850a9bc7cf78e2b17d9d171302ce07596f9735..9ffe8832ef9b74ed3794243965d0cc3d3fbc4ef5 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -196,6 +196,13 @@ public abstract class Player extends LivingEntity { @@ -179,7 +179,7 @@ index 19b65c0d2fd96b4516c0717511a6bb02b2d66065..d761865eabfc67651b0a2a92ad35fc23 public boolean processClick(InteractionHand hand) { Entity vehicle = getRootVehicle(); diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java -index 6a4e44dd8935018d1b5283761dfb8e855be62987..afe70b0d5bd98d05bbb7afc756108f09d35a5848 100644 +index 7224c56e8a68870364c6538c82c04f371b74aabd..730e8a856b9e9560a62d959cefb6efadd056e9d3 100644 --- a/src/main/java/net/minecraft/world/level/EntityGetter.java +++ b/src/main/java/net/minecraft/world/level/EntityGetter.java @@ -161,7 +161,7 @@ public interface EntityGetter { @@ -242,7 +242,7 @@ index 3627b50dd3af5da225004cd3f8158fcbd30d8ea3..61a0bc8acff72431318bf8fe4f9d5018 public boolean untamedTamablesAreRidable = true; public boolean useNightVisionWhenRiding = false; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 03ac2878f54ca994b5faf28fa68aa547bd7388c3..4254b3168f34b5d6ab9ac8bcece37ab02478b8e9 100644 +index bc88b15dc5c2d2d63edd4bb382affce1d5d7312e..59f7b83332a6eaaeb9b0e24f1329d5b11a8ae053 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -424,10 +424,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @@ -284,7 +284,7 @@ index 03ac2878f54ca994b5faf28fa68aa547bd7388c3..4254b3168f34b5d6ab9ac8bcece37ab0 // Purpur end } diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 0d56df555b8d2de12447cc2e869c9eba20c5ea6d..e58db9acba9fd4f0b7e93ad82ae823c43246fde7 100644 +index 79c9f8e81f6592e6d922f6fdfe088a4dd54d44f8..1f70281055634f06cfe7e8026c552aff525e973a 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -198,6 +198,7 @@ public class ActivationRange diff --git a/patches/server/0015-Bring-back-server-name.patch b/patches/server/0014-Bring-back-server-name.patch similarity index 91% rename from patches/server/0015-Bring-back-server-name.patch rename to patches/server/0014-Bring-back-server-name.patch index 97b6169c6..2b02800ca 100644 --- a/patches/server/0015-Bring-back-server-name.patch +++ b/patches/server/0014-Bring-back-server-name.patch @@ -17,10 +17,10 @@ index 0544ac93513d3a274bfb53bb6120bd598f4d603b..9ce5984fbeba4839290c9d213d441957 public final boolean spawnNpcs = this.get("spawn-npcs", true); public final boolean pvp = this.get("pvp", true); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 01bb2583330ae15e1540d48cba63c7712743e7a6..0b35921fc924fa701e37107aee0f78e25fdf69be 100644 +index 535089a8f48d155883a105110f68056c5838ee83..0f19709d6fa4a2b14c472dfe54bebe0c617a93c0 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2637,4 +2637,11 @@ public final class CraftServer implements Server { +@@ -2687,4 +2687,11 @@ public final class CraftServer implements Server { } // Paper end diff --git a/patches/server/0016-Configurable-server-mod-name.patch b/patches/server/0015-Configurable-server-mod-name.patch similarity index 75% rename from patches/server/0016-Configurable-server-mod-name.patch rename to patches/server/0015-Configurable-server-mod-name.patch index a96125d5d..0de5d83d1 100644 --- a/patches/server/0016-Configurable-server-mod-name.patch +++ b/patches/server/0015-Configurable-server-mod-name.patch @@ -5,20 +5,20 @@ Subject: [PATCH] Configurable server mod name diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 55b85ff37287d1f0e114073c86bbff445f6d7848..4cf3af5e933294026c4f2aa00a65b31609f93cf0 100644 +index 4350a9507deded551e709bf333f0cbddc7ebe6d3..be32f41d1ec6f8a4f8c6835fe262c3d86f163f34 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1717,7 +1717,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Airplane - Airplane > // Tuinity - Tuinity > //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! -+ return net.pl3x.purpur.PurpurConfig.serverModName; // Purpur - Purpur > // Airplane - Airplane > // Tuinity - Tuinity > //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! +- return "Purpur"; // Purpur - Purpur > // Airplane - Airplane > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! ++ return net.pl3x.purpur.PurpurConfig.serverModName; // Purpur - Purpur > // Airplane - Airplane > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! } public SystemReport fillSystemReport(SystemReport details) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 439143a24ad57cf749544164fe3cd131df78ea01..9577355817a71b2e398ccf411cbcfd3a77bfafaf 100644 +index 4451d9fca6dad1406b8da348e34d62123b0a08e5..e0a7010c6d1499499d0b5b305306897061e5b640 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -170,6 +170,11 @@ public class PurpurConfig { diff --git a/patches/server/0017-LivingEntity-safeFallDistance.patch b/patches/server/0016-LivingEntity-safeFallDistance.patch similarity index 94% rename from patches/server/0017-LivingEntity-safeFallDistance.patch rename to patches/server/0016-LivingEntity-safeFallDistance.patch index 40c0c53a8..e7a4f7b14 100644 --- a/patches/server/0017-LivingEntity-safeFallDistance.patch +++ b/patches/server/0016-LivingEntity-safeFallDistance.patch @@ -5,7 +5,7 @@ Subject: [PATCH] LivingEntity safeFallDistance diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 63a59b0ca02503a677bd12509eee4e4b86799fb4..68fe72f4248ddf6712a09565eaa083bf3afc1f58 100644 +index a7e0126d1fed75bfa810f405a4dd5b70668bf08e..8026d97279013a3fd830e9ccd579d8043ca7a3c9 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -254,6 +254,7 @@ public abstract class LivingEntity extends Entity { @@ -62,10 +62,10 @@ index c67f33f2e2e0ff5c2a85782185103325a6bf4535..a8ffdc8810152d77668aad7bad15a00c // Purpur start diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 646ea844ed2cf674569937653f9920e4fdbf62a0..81b26444a7be0b20e83f32ec2ba3648e4997af45 100644 +index fe71123dc07cb13ffad8f13e57aa9bda1cb0abf5..fd6a4e9a611e60ebbbbdc8974f77244d20eb169c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -893,4 +893,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { +@@ -916,4 +916,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { throw new IllegalArgumentException(entityCategory + " is an unrecognized entity category"); } // Paper end diff --git a/patches/server/0018-Lagging-threshold.patch b/patches/server/0017-Lagging-threshold.patch similarity index 82% rename from patches/server/0018-Lagging-threshold.patch rename to patches/server/0017-Lagging-threshold.patch index b951f3a2a..63d7584b4 100644 --- a/patches/server/0018-Lagging-threshold.patch +++ b/patches/server/0017-Lagging-threshold.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Lagging threshold diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4cf3af5e933294026c4f2aa00a65b31609f93cf0..bb9059fe10e65975553e41d893deb88cc0c15534 100644 +index be32f41d1ec6f8a4f8c6835fe262c3d86f163f34..41eccbed6dda81f7d50c6ccb3539db3927b96021 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -305,6 +305,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit itemstack1 = ItemStack.EMPTY; } -@@ -296,6 +317,12 @@ public class AnvilMenu extends ItemCombinerMenu { - +@@ -297,6 +318,12 @@ public class AnvilMenu extends ItemCombinerMenu { org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit + sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client this.broadcastChanges(); + // Purpur start + if (canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) { diff --git a/patches/server/0024-Configurable-villager-brain-ticks.patch b/patches/server/0023-Configurable-villager-brain-ticks.patch similarity index 100% rename from patches/server/0024-Configurable-villager-brain-ticks.patch rename to patches/server/0023-Configurable-villager-brain-ticks.patch diff --git a/patches/server/0025-Alternative-Keepalive-Handling.patch b/patches/server/0024-Alternative-Keepalive-Handling.patch similarity index 95% rename from patches/server/0025-Alternative-Keepalive-Handling.patch rename to patches/server/0024-Alternative-Keepalive-Handling.patch index 14212c0bf..226a7b570 100644 --- a/patches/server/0025-Alternative-Keepalive-Handling.patch +++ b/patches/server/0024-Alternative-Keepalive-Handling.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Alternative Keepalive Handling diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e4b9edb4226ce3213181b6deb2fca6e9fab3e569..41d64ced05f0cfe8e2e9e8f30fb5492c99de6486 100644 +index 8ea53a2c6f62c6e65257fa7eb094187529e6525b..cf10b1025fa3c6da91cfefbf8b31b83ee254f92d 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -228,6 +228,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser @@ -56,7 +56,7 @@ index e4b9edb4226ce3213181b6deb2fca6e9fab3e569..41d64ced05f0cfe8e2e9e8f30fb5492c if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) { int i = (int) (Util.getMillis() - this.keepAliveTime); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index dd9fca23e1f96ad261589d9b66d4306a228ec76a..2175b355c9c05bec3cac9d9f392a4992261ff63e 100644 +index 2553768892562869efdad56e31c4db17e3d86b39..20f57abd6420466002e2413a59482c0af224d830 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -193,6 +193,11 @@ public class PurpurConfig { diff --git a/patches/server/0026-Silk-touch-spawners.patch b/patches/server/0025-Silk-touch-spawners.patch similarity index 100% rename from patches/server/0026-Silk-touch-spawners.patch rename to patches/server/0025-Silk-touch-spawners.patch diff --git a/patches/server/0027-MC-168772-Fix-Add-turtle-egg-block-options.patch b/patches/server/0026-MC-168772-Fix-Add-turtle-egg-block-options.patch similarity index 100% rename from patches/server/0027-MC-168772-Fix-Add-turtle-egg-block-options.patch rename to patches/server/0026-MC-168772-Fix-Add-turtle-egg-block-options.patch diff --git a/patches/server/0028-Fix-vanilla-command-permission-handler.patch b/patches/server/0027-Fix-vanilla-command-permission-handler.patch similarity index 81% rename from patches/server/0028-Fix-vanilla-command-permission-handler.patch rename to patches/server/0027-Fix-vanilla-command-permission-handler.patch index 198a8d744..c9a502e9a 100644 --- a/patches/server/0028-Fix-vanilla-command-permission-handler.patch +++ b/patches/server/0027-Fix-vanilla-command-permission-handler.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Fix vanilla command permission handler diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java -index 39708be1b445791b053023dec16ad7d4efcc9048..797c0c86c4a99e1608106881be849a3326de1bab 100644 +index 30274979d8dafc7c0a374c3e6b1d1b5dbd6cfe4c..a3bc8192c10f888c0d395709108019670f0bad62 100644 --- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java @@ -34,6 +34,7 @@ public abstract class CommandNode implements Comparable> { @@ -17,7 +17,7 @@ index 39708be1b445791b053023dec16ad7d4efcc9048..797c0c86c4a99e1608106881be849a33 public void removeCommand(String name) { this.children.remove(name); diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -index 0377c706c9aec6f367e83f859f9a3432ad5bba4a..96691990aa3ede953e41df6e3b36bb1eb1e3fd13 100644 +index e9d1fb479855194da5a05e86861848158736cbb4..b06f070a8030e5a6d965a2705749874895db58b6 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java @@ -87,6 +87,7 @@ public final class VanillaCommandWrapper extends BukkitCommand { @@ -25,6 +25,6 @@ index 0377c706c9aec6f367e83f859f9a3432ad5bba4a..96691990aa3ede953e41df6e3b36bb1e public static String getPermission(CommandNode vanillaCommand) { + if (vanillaCommand.getPermission() != null) return vanillaCommand.getPermission(); // Purpur - return "minecraft.command." + ((vanillaCommand.getRedirect() == null) ? vanillaCommand.getName() : vanillaCommand.getRedirect().getName()); - } - + // Paper start + final String commandName; + if (vanillaCommand.getRedirect() == null) { diff --git a/patches/server/0029-Logger-settings-suppressing-pointless-logs.patch b/patches/server/0028-Logger-settings-suppressing-pointless-logs.patch similarity index 96% rename from patches/server/0029-Logger-settings-suppressing-pointless-logs.patch rename to patches/server/0028-Logger-settings-suppressing-pointless-logs.patch index 8f7933f31..1061f37c6 100644 --- a/patches/server/0029-Logger-settings-suppressing-pointless-logs.patch +++ b/patches/server/0028-Logger-settings-suppressing-pointless-logs.patch @@ -17,7 +17,7 @@ index 7d6dc0a8ee35274052b122bbc446bc54750de0a6..c46df052a5a39d92688f51377ee1f7b5 } // CraftBukkit end diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 2175b355c9c05bec3cac9d9f392a4992261ff63e..ce0648631f5a63d4872e04f6615ca097be5f3d17 100644 +index 20f57abd6420466002e2413a59482c0af224d830..eade7d7ac8800f7f19b83e1da8c36eeeab796f37 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -216,4 +216,11 @@ public class PurpurConfig { diff --git a/patches/server/0030-Disable-outdated-build-check.patch b/patches/server/0029-Disable-outdated-build-check.patch similarity index 88% rename from patches/server/0030-Disable-outdated-build-check.patch rename to patches/server/0029-Disable-outdated-build-check.patch index c5f6c8f37..9e1ff1871 100644 --- a/patches/server/0030-Disable-outdated-build-check.patch +++ b/patches/server/0029-Disable-outdated-build-check.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Disable outdated build check diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index f2fab27d5e8f87691de3526ab6cafd904abeab5f..6ebf61329e7ae7fc6b863d8dfbb43a23c31d6a74 100644 +index 5b527a32f56a82131168879106f76c1f6cbb7b30..56674053351962a75b2731dde137dbbc0c70dbde 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -276,7 +276,7 @@ public class Main { +@@ -269,7 +269,7 @@ public class Main { System.setProperty(TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper } diff --git a/patches/server/0031-Giants-AI-settings.patch b/patches/server/0030-Giants-AI-settings.patch similarity index 100% rename from patches/server/0031-Giants-AI-settings.patch rename to patches/server/0030-Giants-AI-settings.patch diff --git a/patches/server/0032-Zombie-horse-naturally-spawn.patch b/patches/server/0031-Zombie-horse-naturally-spawn.patch similarity index 97% rename from patches/server/0032-Zombie-horse-naturally-spawn.patch rename to patches/server/0031-Zombie-horse-naturally-spawn.patch index 07f4e90c3..9ce7c2b3a 100644 --- a/patches/server/0032-Zombie-horse-naturally-spawn.patch +++ b/patches/server/0031-Zombie-horse-naturally-spawn.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Zombie horse naturally spawn diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index e38444328c0e3e6e5f4d51926bc58d9f0e0975ac..a667c540b85a4afbb1beece7decb5d0e3e8c9572 100644 +index 7e9bff1a8ec45551086550b4e5098dc5304f794a..d95e45c2867cf3232cebd4b4c43bd890bfb70847 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -871,9 +871,15 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0033-Charged-creeper-naturally-spawn.patch b/patches/server/0032-Charged-creeper-naturally-spawn.patch similarity index 100% rename from patches/server/0033-Charged-creeper-naturally-spawn.patch rename to patches/server/0032-Charged-creeper-naturally-spawn.patch diff --git a/patches/server/0034-Rabbit-naturally-spawn-toast-and-killer.patch b/patches/server/0033-Rabbit-naturally-spawn-toast-and-killer.patch similarity index 100% rename from patches/server/0034-Rabbit-naturally-spawn-toast-and-killer.patch rename to patches/server/0033-Rabbit-naturally-spawn-toast-and-killer.patch diff --git a/patches/server/0035-Fix-outdated-server-showing-in-ping-before-server-fu.patch b/patches/server/0034-Fix-outdated-server-showing-in-ping-before-server-fu.patch similarity index 100% rename from patches/server/0035-Fix-outdated-server-showing-in-ping-before-server-fu.patch rename to patches/server/0034-Fix-outdated-server-showing-in-ping-before-server-fu.patch diff --git a/patches/server/0036-Dont-send-useless-entity-packets.patch b/patches/server/0035-Dont-send-useless-entity-packets.patch similarity index 94% rename from patches/server/0036-Dont-send-useless-entity-packets.patch rename to patches/server/0035-Dont-send-useless-entity-packets.patch index 1e88f949e..ba4a313cc 100644 --- a/patches/server/0036-Dont-send-useless-entity-packets.patch +++ b/patches/server/0035-Dont-send-useless-entity-packets.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Dont send useless entity packets diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 7eb6614c126d03435689a92c0064baffd446ec5e..61c4d3ec612195f31bcce7e5d46d012767c5e231 100644 +index c71bc00973899feec0ec5530bf3d237928810cf4..c85ca046acbb976f32a671c18ee4efde7be16fd3 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java +++ b/src/main/java/net/minecraft/server/level/ServerEntity.java @@ -190,6 +190,7 @@ public class ServerEntity { @@ -40,7 +40,7 @@ index 7eb6614c126d03435689a92c0064baffd446ec5e..61c4d3ec612195f31bcce7e5d46d0127 this.entity.stopSeenByPlayer(player); player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()})); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index ce0648631f5a63d4872e04f6615ca097be5f3d17..cc1b102949e9236b8b7960e76f712348c9e02022 100644 +index eade7d7ac8800f7f19b83e1da8c36eeeab796f37..30e17e8d8c0adeaefb64cd9500d727d8cf89e27a 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -217,6 +217,11 @@ public class PurpurConfig { diff --git a/patches/server/0037-Tulips-change-fox-type.patch b/patches/server/0036-Tulips-change-fox-type.patch similarity index 100% rename from patches/server/0037-Tulips-change-fox-type.patch rename to patches/server/0036-Tulips-change-fox-type.patch diff --git a/patches/server/0038-Breedable-Polar-Bears.patch b/patches/server/0037-Breedable-Polar-Bears.patch similarity index 100% rename from patches/server/0038-Breedable-Polar-Bears.patch rename to patches/server/0037-Breedable-Polar-Bears.patch diff --git a/patches/server/0039-Chickens-can-retaliate.patch b/patches/server/0038-Chickens-can-retaliate.patch similarity index 100% rename from patches/server/0039-Chickens-can-retaliate.patch rename to patches/server/0038-Chickens-can-retaliate.patch diff --git a/patches/server/0040-Add-option-to-set-armorstand-step-height.patch b/patches/server/0039-Add-option-to-set-armorstand-step-height.patch similarity index 94% rename from patches/server/0040-Add-option-to-set-armorstand-step-height.patch rename to patches/server/0039-Add-option-to-set-armorstand-step-height.patch index c42af1439..92d976eeb 100644 --- a/patches/server/0040-Add-option-to-set-armorstand-step-height.patch +++ b/patches/server/0039-Add-option-to-set-armorstand-step-height.patch @@ -17,7 +17,7 @@ index 5fc66d7096afcfe63eba774e1dc330ac3263e4b0..7a3a364f5e3b025cc0a5694401cb9298 if (!this.canTick) { if (this.noTickPoseDirty) { diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 0002582bca86c13d014c5d4291241840ae5d70f9..0ab41948063fff3de291f538334dd6e28027df74 100644 +index 1c8560ac101cf418b3e65d537132c47be27eac92..048fc7e4ac798e7e9b561558b25d74b81563b706 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -93,6 +93,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0041-Cat-spawning-options.patch b/patches/server/0040-Cat-spawning-options.patch similarity index 100% rename from patches/server/0041-Cat-spawning-options.patch rename to patches/server/0040-Cat-spawning-options.patch diff --git a/patches/server/0042-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch b/patches/server/0041-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch similarity index 100% rename from patches/server/0042-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch rename to patches/server/0041-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch diff --git a/patches/server/0043-Cows-eat-mushrooms.patch b/patches/server/0042-Cows-eat-mushrooms.patch similarity index 100% rename from patches/server/0043-Cows-eat-mushrooms.patch rename to patches/server/0042-Cows-eat-mushrooms.patch diff --git a/patches/server/0044-Fix-cow-rotation-when-shearing-mooshroom.patch b/patches/server/0043-Fix-cow-rotation-when-shearing-mooshroom.patch similarity index 100% rename from patches/server/0044-Fix-cow-rotation-when-shearing-mooshroom.patch rename to patches/server/0043-Fix-cow-rotation-when-shearing-mooshroom.patch diff --git a/patches/server/0045-Pigs-give-saddle-back.patch b/patches/server/0044-Pigs-give-saddle-back.patch similarity index 100% rename from patches/server/0045-Pigs-give-saddle-back.patch rename to patches/server/0044-Pigs-give-saddle-back.patch diff --git a/patches/server/0046-Snowman-drop-and-put-back-pumpkin.patch b/patches/server/0045-Snowman-drop-and-put-back-pumpkin.patch similarity index 100% rename from patches/server/0046-Snowman-drop-and-put-back-pumpkin.patch rename to patches/server/0045-Snowman-drop-and-put-back-pumpkin.patch diff --git a/patches/server/0047-Ender-dragon-always-drop-full-exp.patch b/patches/server/0046-Ender-dragon-always-drop-full-exp.patch similarity index 100% rename from patches/server/0047-Ender-dragon-always-drop-full-exp.patch rename to patches/server/0046-Ender-dragon-always-drop-full-exp.patch diff --git a/patches/server/0048-Signs-editable-on-right-click.patch b/patches/server/0047-Signs-editable-on-right-click.patch similarity index 100% rename from patches/server/0048-Signs-editable-on-right-click.patch rename to patches/server/0047-Signs-editable-on-right-click.patch diff --git a/patches/server/0049-Signs-allow-color-codes.patch b/patches/server/0048-Signs-allow-color-codes.patch similarity index 96% rename from patches/server/0049-Signs-allow-color-codes.patch rename to patches/server/0048-Signs-allow-color-codes.patch index 01a77d7fc..8489f99d1 100644 --- a/patches/server/0049-Signs-allow-color-codes.patch +++ b/patches/server/0048-Signs-allow-color-codes.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Signs allow color codes diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 59fa9a9bcfde0a0137fa322343052ed68e47edbe..b13328e1563fa01c141a52bf898ebc520098d0d2 100644 +index ac0e43ed7f3385eb89e9b6e80f169b1f31508951..1196de6eab3c621e8f165b9431576fa267787404 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1464,6 +1464,7 @@ public class ServerPlayer extends Player { @@ -17,7 +17,7 @@ index 59fa9a9bcfde0a0137fa322343052ed68e47edbe..b13328e1563fa01c141a52bf898ebc52 this.connection.send(new ClientboundBlockUpdatePacket(this.level, sign.getBlockPos())); this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos())); diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 41d64ced05f0cfe8e2e9e8f30fb5492c99de6486..e71f9a3256eed2361ac8c5c058ceaeeeabbeefa3 100644 +index cf10b1025fa3c6da91cfefbf8b31b83ee254f92d..1efc3021619d4ddc5c1c305ee29730438fdf6858 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -3072,11 +3072,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser diff --git a/patches/server/0050-Allow-soil-to-moisten-from-water-directly-under-it.patch b/patches/server/0049-Allow-soil-to-moisten-from-water-directly-under-it.patch similarity index 90% rename from patches/server/0050-Allow-soil-to-moisten-from-water-directly-under-it.patch rename to patches/server/0049-Allow-soil-to-moisten-from-water-directly-under-it.patch index ec2ba91ac..21099a1fa 100644 --- a/patches/server/0050-Allow-soil-to-moisten-from-water-directly-under-it.patch +++ b/patches/server/0049-Allow-soil-to-moisten-from-water-directly-under-it.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Allow soil to moisten from water directly under it diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index a242a80b16c7d074d52a52728646224b1a0091d4..ee5bc54e37e5ae120e846ddd2cae5ca39c293c98 100644 +index 5955c95efbfa3e614ecf03de3e485a1ea88b7859..f638c7b27a846bf9db73e98ce9eb5d579bc25cac 100644 --- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java @@ -159,7 +159,7 @@ public class FarmBlock extends Block { @@ -14,7 +14,7 @@ index a242a80b16c7d074d52a52728646224b1a0091d4..ee5bc54e37e5ae120e846ddd2cae5ca3 - return false; + return ((ServerLevel) world).purpurConfig.farmlandGetsMoistFromBelow && world.getFluidState(pos.relative(Direction.DOWN)).is(FluidTags.WATER); // Purpur - // Tuinity end - remove abstract block iteration + // Paper end - remove abstract block iteration } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java diff --git a/patches/server/0051-Minecart-settings-and-WASD-controls.patch b/patches/server/0050-Minecart-settings-and-WASD-controls.patch similarity index 97% rename from patches/server/0051-Minecart-settings-and-WASD-controls.patch rename to patches/server/0050-Minecart-settings-and-WASD-controls.patch index 227a61967..b118d4249 100644 --- a/patches/server/0051-Minecart-settings-and-WASD-controls.patch +++ b/patches/server/0050-Minecart-settings-and-WASD-controls.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Minecart settings and WASD controls diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index b13328e1563fa01c141a52bf898ebc520098d0d2..b9f7812f19b194dc19b63cabd9369c5ed56dbe73 100644 +index 1196de6eab3c621e8f165b9431576fa267787404..af5c80da6c1c2a4ef49b3e9ef15b6f67cfe479a9 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -991,6 +991,7 @@ public class ServerPlayer extends Player { @@ -135,7 +135,7 @@ index 9ea3837acc315e5c57f28c63c356efd633f1e6cf..e8b76b67f972c2f44e7611434246a822 } } diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 04d5ef90cd4171f9360017ac0c01ce48ae6ec983..7538262e14c86e4da9cd4cb887b76f649bfef2e6 100644 +index c5663df749dd2bbfd2ba9bf7e1e7a9e21992b81a..4853025530de9c22bde9e54b81120102dae5477c 100644 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -70,7 +70,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; @@ -148,7 +148,7 @@ index 04d5ef90cd4171f9360017ac0c01ce48ae6ec983..7538262e14c86e4da9cd4cb887b76f64 protected final float explosionResistance; protected final boolean isRandomlyTicking; diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 9ce64a3d7a00877688f1e45a3961159cb35c8d9f..51f8045f4f607db3cf63d30fa6783257466a6022 100644 +index 1a6c882a9c30c5970383ae14a8718cb5cfc66713..0cc349ff27e2d0c4e9cbe239af7aca5a90e8cce3 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -98,6 +98,68 @@ public class PurpurWorldConfig { diff --git a/patches/server/0052-Disable-loot-drops-on-death-by-cramming.patch b/patches/server/0051-Disable-loot-drops-on-death-by-cramming.patch similarity index 95% rename from patches/server/0052-Disable-loot-drops-on-death-by-cramming.patch rename to patches/server/0051-Disable-loot-drops-on-death-by-cramming.patch index 33b6023c8..39b5001ed 100644 --- a/patches/server/0052-Disable-loot-drops-on-death-by-cramming.patch +++ b/patches/server/0051-Disable-loot-drops-on-death-by-cramming.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Disable loot drops on death by cramming diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 68fe72f4248ddf6712a09565eaa083bf3afc1f58..fb629ebb9f63efa56ab8baebc30248e48e5169a8 100644 +index 8026d97279013a3fd830e9ccd579d8043ca7a3c9..f165e468130f219c78ea1c66f235eb32721c9100 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -1707,8 +1707,10 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0053-Option-to-toggle-milk-curing-bad-omen.patch b/patches/server/0052-Option-to-toggle-milk-curing-bad-omen.patch similarity index 100% rename from patches/server/0053-Option-to-toggle-milk-curing-bad-omen.patch rename to patches/server/0052-Option-to-toggle-milk-curing-bad-omen.patch diff --git a/patches/server/0054-End-gateway-should-check-if-entity-can-use-portal.patch b/patches/server/0053-End-gateway-should-check-if-entity-can-use-portal.patch similarity index 100% rename from patches/server/0054-End-gateway-should-check-if-entity-can-use-portal.patch rename to patches/server/0053-End-gateway-should-check-if-entity-can-use-portal.patch diff --git a/patches/server/0055-Fix-the-dead-lagging-the-server.patch b/patches/server/0054-Fix-the-dead-lagging-the-server.patch similarity index 84% rename from patches/server/0055-Fix-the-dead-lagging-the-server.patch rename to patches/server/0054-Fix-the-dead-lagging-the-server.patch index ce8786b2b..f6c3c0c62 100644 --- a/patches/server/0055-Fix-the-dead-lagging-the-server.patch +++ b/patches/server/0054-Fix-the-dead-lagging-the-server.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix the dead lagging the server diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 034f53ddce67a2f1a8efca09ca20f175cd2fa399..60d51a580672e8a943738c947e84353dbf2dba05 100644 +index c813f28c56b54bd3870cc12e3ecf0ae98545a6b0..176b17217c41801d8b49622ad341f37111941795 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1761,6 +1761,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -1764,6 +1764,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n this.setXRot(Mth.clamp(pitch, -90.0F, 90.0F) % 360.0F); this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); @@ -17,7 +17,7 @@ index 034f53ddce67a2f1a8efca09ca20f175cd2fa399..60d51a580672e8a943738c947e84353d public void absMoveTo(double x, double y, double z) { diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index fb629ebb9f63efa56ab8baebc30248e48e5169a8..6100efd3d5de767ecb257b2a1f4ccfb161e94522 100644 +index f165e468130f219c78ea1c66f235eb32721c9100..5529b1bcfeeb234a5629d3d7eaeb3ba759bce131 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -2897,7 +2897,7 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0056-Skip-events-if-there-s-no-listeners.patch b/patches/server/0055-Skip-events-if-there-s-no-listeners.patch similarity index 59% rename from patches/server/0056-Skip-events-if-there-s-no-listeners.patch rename to patches/server/0055-Skip-events-if-there-s-no-listeners.patch index 40b4a367a..996db0ab2 100644 --- a/patches/server/0056-Skip-events-if-there-s-no-listeners.patch +++ b/patches/server/0055-Skip-events-if-there-s-no-listeners.patch @@ -5,22 +5,22 @@ Subject: [PATCH] Skip events if there's no listeners diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index a6f10d47bc4e2cadcc3e06cffa011ed7fb97c68d..59881c845cc88508736cc3d2a61860512d28964d 100644 +index 6fec6a47538da4c0c5a4505e9bedf492bb3376dd..8c019cede209c1c022a843146f16db36ca292012 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -375,6 +375,7 @@ public class Commands { +@@ -382,6 +382,7 @@ public class Commands { } - private void runSync(ServerPlayer entityplayer, Collection bukkit, RootCommandNode rootcommandnode) { + private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { + if (PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - skip all this crap if there's nothing listening // Paper end - Async command map building - new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(entityplayer.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - PlayerCommandSendEvent event = new PlayerCommandSendEvent(entityplayer.getBukkitEntity(), new LinkedHashSet<>(bukkit)); -@@ -387,6 +388,7 @@ public class Commands { + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper + PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit)); +@@ -394,6 +395,7 @@ public class Commands { } } // CraftBukkit end + } // Purpur - skip event - entityplayer.connection.send(new ClientboundCommandsPacket(rootcommandnode)); + player.connection.send(new ClientboundCommandsPacket(rootcommandnode)); } diff --git a/patches/server/0057-Add-permission-for-F3-N-debug.patch b/patches/server/0056-Add-permission-for-F3-N-debug.patch similarity index 56% rename from patches/server/0057-Add-permission-for-F3-N-debug.patch rename to patches/server/0056-Add-permission-for-F3-N-debug.patch index c7fc935a4..ac96154ef 100644 --- a/patches/server/0057-Add-permission-for-F3-N-debug.patch +++ b/patches/server/0056-Add-permission-for-F3-N-debug.patch @@ -5,14 +5,14 @@ Subject: [PATCH] Add permission for F3+N debug diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 3f8dc9192287d6eb3f966e0d8d4fdee82c753724..c1d79527abc7c8a165872758db3d5240615a63aa 100644 +index 5b1641eae57b974997803fbc42710032ba914b21..bd5ab259d37f13542c2510530fdf5fc5d6496975 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1163,6 +1163,7 @@ public abstract class PlayerList { +@@ -1162,6 +1162,7 @@ public abstract class PlayerList { } else { - b0 = (byte) (24 + i); + b0 = (byte) (24 + permissionLevel); } -+ if (b0 < 28 && entityplayer.getBukkitEntity().hasPermission("purpur.debug.f3n")) b0 = 28; // Purpur ++ if (b0 < 28 && player.getBukkitEntity().hasPermission("purpur.debug.f3n")) b0 = 28; // Purpur - entityplayer.connection.send(new ClientboundEntityEventPacket(entityplayer, b0)); + player.connection.send(new ClientboundEntityEventPacket(player, b0)); } diff --git a/patches/server/0058-Configurable-TPS-Catchup.patch b/patches/server/0057-Configurable-TPS-Catchup.patch similarity index 89% rename from patches/server/0058-Configurable-TPS-Catchup.patch rename to patches/server/0057-Configurable-TPS-Catchup.patch index 339d18376..41ab7e24b 100644 --- a/patches/server/0058-Configurable-TPS-Catchup.patch +++ b/patches/server/0057-Configurable-TPS-Catchup.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configurable TPS Catchup diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index bb9059fe10e65975553e41d893deb88cc0c15534..b18b75efe8d475cb90f0fe2e66d277d0be1455c9 100644 +index 41eccbed6dda81f7d50c6ccb3539db3927b96021..88038c8286e46a89eed94169db9de5b880009481 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1263,7 +1263,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= this.level.paperConfig.netherVoidTopDamageHeight)) { // Paper end diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 6100efd3d5de767ecb257b2a1f4ccfb161e94522..c6cfc4f83ec5b67c62fbf82ef4b795c3c6b27282 100644 +index 5529b1bcfeeb234a5629d3d7eaeb3ba759bce131..1c75911afb5a2de6f0099f43cb0660f49792f301 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -2402,7 +2402,7 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0068-Add-canSaveToDisk-to-Entity.patch b/patches/server/0067-Add-canSaveToDisk-to-Entity.patch similarity index 93% rename from patches/server/0068-Add-canSaveToDisk-to-Entity.patch rename to patches/server/0067-Add-canSaveToDisk-to-Entity.patch index 6158f1493..49e6841c5 100644 --- a/patches/server/0068-Add-canSaveToDisk-to-Entity.patch +++ b/patches/server/0067-Add-canSaveToDisk-to-Entity.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add canSaveToDisk to Entity diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 1d29ff3feaf95628dc84b67f430ddfc88b7bd507..fd3aff71f8e4ffd4faabc2650d8d83c8e6e85946 100644 +index bb33d9e8e54ce17e51fbf10d5b618fb0fe7e29ae..9043422cfa025e98d9c2bb3d9511c8d735d5b476 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4303,5 +4303,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -4306,5 +4306,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n public boolean processClick(InteractionHand hand) { return false; } @@ -35,7 +35,7 @@ index f52420f27f51d9dbf214f96a0530c0f17f2bc5fc..12cd1b453150e098975c34e00ec9277f skull.setPosRaw(headX, headY, headZ); level.addFreshEntity(skull); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -index 91d692e9337c2ec6824829259ea6ea1ad343d21a..6c9b139cfb1dfa1eb80fdb72651c8c3f921e74ea 100644 +index 05af8f292a598a242a396afe4c2ddb2aa2c6b42e..47d138627286ef03339ac06b6c7f4a151bdcb823 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java @@ -92,6 +92,7 @@ public class EntityStorage implements EntityPersistentStorage { diff --git a/patches/server/0069-Dispenser-curse-of-binding-protection.patch b/patches/server/0068-Dispenser-curse-of-binding-protection.patch similarity index 97% rename from patches/server/0069-Dispenser-curse-of-binding-protection.patch rename to patches/server/0068-Dispenser-curse-of-binding-protection.patch index a90db2402..136e65230 100644 --- a/patches/server/0069-Dispenser-curse-of-binding-protection.patch +++ b/patches/server/0068-Dispenser-curse-of-binding-protection.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Dispenser curse of binding protection diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index b0ac198041a319d33fa65398c1564dfa57aaf8e1..8e5c1ee1023a76f7619ffc0cdc3940582da81509 100644 +index 20862d2c4a10f24f76b627f66af292813b1d0264..e985f795747e25c5456658df3e1d65a520d8a2cc 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -62,6 +62,7 @@ import net.minecraft.world.item.ProjectileWeaponItem; diff --git a/patches/server/0070-Add-option-for-boats-to-eject-players-on-land.patch b/patches/server/0069-Add-option-for-boats-to-eject-players-on-land.patch similarity index 95% rename from patches/server/0070-Add-option-for-boats-to-eject-players-on-land.patch rename to patches/server/0069-Add-option-for-boats-to-eject-players-on-land.patch index d2cd407e5..154eb8c0f 100644 --- a/patches/server/0070-Add-option-for-boats-to-eject-players-on-land.patch +++ b/patches/server/0069-Add-option-for-boats-to-eject-players-on-land.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add option for boats to eject players on land diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -index 99124b70d82140b108d424a5206657efe94f184e..4688cfb6f24066d3034efcd6b4816ceb37561f1f 100644 +index 391454a58d18d7373b974e094fd62514ca0d0b6b..6acd2dc6ec9c3761fa330c74df8c7e7b19266f8e 100644 --- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java +++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java @@ -520,6 +520,7 @@ public class Boat extends Entity { diff --git a/patches/server/0071-Mending-mends-most-damages-equipment-first.patch b/patches/server/0070-Mending-mends-most-damages-equipment-first.patch similarity index 100% rename from patches/server/0071-Mending-mends-most-damages-equipment-first.patch rename to patches/server/0070-Mending-mends-most-damages-equipment-first.patch diff --git a/patches/server/0072-Add-5-second-tps-average-in-tps.patch b/patches/server/0071-Add-5-second-tps-average-in-tps.patch similarity index 93% rename from patches/server/0072-Add-5-second-tps-average-in-tps.patch rename to patches/server/0071-Add-5-second-tps-average-in-tps.patch index ba118be7c..135d05529 100644 --- a/patches/server/0072-Add-5-second-tps-average-in-tps.patch +++ b/patches/server/0071-Add-5-second-tps-average-in-tps.patch @@ -27,10 +27,10 @@ index fa56cd09102a89692b42f1d14257990508c5c720..f9251183df72ddc56662fd3f02acf216 setListData(vector); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index b18b75efe8d475cb90f0fe2e66d277d0be1455c9..1622eedaaada332f589eddfdb1dae38387ce0a0c 100644 +index 88038c8286e46a89eed94169db9de5b880009481..023566ddf2b1910dc90955289baff3bb4404abb7 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -304,7 +304,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> consumer, Set trackedPlayers) { this.trackedPlayers = trackedPlayers; diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index 2dac4bc346eb1dde1f8d92c3e5b9648b2c433617..d3c09c1b3951cf11d6eff798d3b3e5a85c879b20 100644 +index dae6f7a05426ea31d13c82458b33e20abc2571b6..c51161136bec4b4dbe10c0bff5fc197be4a30507 100644 --- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java @@ -53,6 +53,12 @@ public class ItemEntity extends Entity { @@ -96,7 +96,7 @@ index 2dac4bc346eb1dde1f8d92c3e5b9648b2c433617..d3c09c1b3951cf11d6eff798d3b3e5a8 + // Purpur end } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index dd00807ca9893f5919c6e76e30145e118ce343ea..18463b61d54170c1cce788e2175789f030da644c 100644 +index 08768d2159e663036f652aff9b0e089da943db28..2a1cc21584f9e9765d8c00766450c2fc6e49f35d 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -111,6 +111,49 @@ public class PurpurWorldConfig { diff --git a/patches/server/0075-Add-ping-command.patch b/patches/server/0074-Add-ping-command.patch similarity index 95% rename from patches/server/0075-Add-ping-command.patch rename to patches/server/0074-Add-ping-command.patch index 385e6ca93..f1f00dd16 100644 --- a/patches/server/0075-Add-ping-command.patch +++ b/patches/server/0074-Add-ping-command.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add ping command diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 59881c845cc88508736cc3d2a61860512d28964d..3a1e1ff3c9154db6b1b23d1898c8e6ec198f103f 100644 +index 8c019cede209c1c022a843146f16db36ca292012..688835cb5116c245e1e25449d41999a944da54cf 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -198,6 +198,7 @@ public class Commands { @@ -17,7 +17,7 @@ index 59881c845cc88508736cc3d2a61860512d28964d..3a1e1ff3c9154db6b1b23d1898c8e6ec if (environment.includeIntegrated) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 03b88ddc349fc7cfa48573ec93c22cd9cef3b58d..8f84848950c2bab5123766edd6131e98be97a92a 100644 +index 6226e04e34f88579e4cd8b9fae5fddfcc0d01912..bd0078f2859384c4cfddf897ee86fd1c0617a0d0 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -162,12 +162,14 @@ public class PurpurConfig { diff --git a/patches/server/0076-Add-demo-command.patch b/patches/server/0075-Add-demo-command.patch similarity index 95% rename from patches/server/0076-Add-demo-command.patch rename to patches/server/0075-Add-demo-command.patch index e2b4a8845..d2887aa50 100644 --- a/patches/server/0076-Add-demo-command.patch +++ b/patches/server/0075-Add-demo-command.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add demo command diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 3a1e1ff3c9154db6b1b23d1898c8e6ec198f103f..880efd832a2029bdb7a404e27797b316cbbe5703 100644 +index 688835cb5116c245e1e25449d41999a944da54cf..98392e818d1f2df9f82af630206d0cd2bdbddb50 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -198,6 +198,7 @@ public class Commands { @@ -17,7 +17,7 @@ index 3a1e1ff3c9154db6b1b23d1898c8e6ec198f103f..880efd832a2029bdb7a404e27797b316 } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 8f84848950c2bab5123766edd6131e98be97a92a..72cfd435cc68ee42ea28b0afc5b42c75e1e2813a 100644 +index bd0078f2859384c4cfddf897ee86fd1c0617a0d0..f9401fb20fa152ce88c7b7ccbfd812992c500930 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -162,6 +162,7 @@ public class PurpurConfig { diff --git a/patches/server/0077-Add-credits-command.patch b/patches/server/0076-Add-credits-command.patch similarity index 95% rename from patches/server/0077-Add-credits-command.patch rename to patches/server/0076-Add-credits-command.patch index ceede018a..54f45f05e 100644 --- a/patches/server/0077-Add-credits-command.patch +++ b/patches/server/0076-Add-credits-command.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add credits command diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 880efd832a2029bdb7a404e27797b316cbbe5703..a5712108fbbe5ddc61cdfd390f667ab013ba609d 100644 +index 98392e818d1f2df9f82af630206d0cd2bdbddb50..42deff516bd363d0882b441fa6928ac7eecbfccc 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -198,6 +198,7 @@ public class Commands { @@ -17,7 +17,7 @@ index 880efd832a2029bdb7a404e27797b316cbbe5703..a5712108fbbe5ddc61cdfd390f667ab0 net.pl3x.purpur.command.PingCommand.register(this.dispatcher); // Purpur } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 72cfd435cc68ee42ea28b0afc5b42c75e1e2813a..35be2f773d33b1c13f8732217c5520b384305b18 100644 +index f9401fb20fa152ce88c7b7ccbfd812992c500930..53051c4d193cdc5ac7e624a4c7def0ea10e3285e 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -162,6 +162,7 @@ public class PurpurConfig { diff --git a/patches/server/0078-Configurable-jockey-options.patch b/patches/server/0077-Configurable-jockey-options.patch similarity index 100% rename from patches/server/0078-Configurable-jockey-options.patch rename to patches/server/0077-Configurable-jockey-options.patch diff --git a/patches/server/0079-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/patches/server/0078-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch similarity index 100% rename from patches/server/0079-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch rename to patches/server/0078-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch diff --git a/patches/server/0080-Add-phantom-spawning-options.patch b/patches/server/0079-Add-phantom-spawning-options.patch similarity index 100% rename from patches/server/0080-Add-phantom-spawning-options.patch rename to patches/server/0079-Add-phantom-spawning-options.patch diff --git a/patches/server/0081-Implement-bed-explosion-options.patch b/patches/server/0080-Implement-bed-explosion-options.patch similarity index 97% rename from patches/server/0081-Implement-bed-explosion-options.patch rename to patches/server/0080-Implement-bed-explosion-options.patch index 55bd00c39..209cc67e6 100644 --- a/patches/server/0081-Implement-bed-explosion-options.patch +++ b/patches/server/0080-Implement-bed-explosion-options.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Implement bed explosion options diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java -index 163a7861f987c3832aac51cc6df950c768546731..bf5765b6af9c7807d50f7daaacb5d52477ebf291 100644 +index e3ff04fe21761db65fb03c5e58ecd5823f0507c6..6362c9dcfbc980a0591ac6dfebe45e475b73d020 100644 --- a/src/main/java/net/minecraft/world/level/block/BedBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java @@ -97,7 +97,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock diff --git a/patches/server/0082-Implement-respawn-anchor-explosion-options.patch b/patches/server/0081-Implement-respawn-anchor-explosion-options.patch similarity index 100% rename from patches/server/0082-Implement-respawn-anchor-explosion-options.patch rename to patches/server/0081-Implement-respawn-anchor-explosion-options.patch diff --git a/patches/server/0083-Add-allow-water-in-end-world-option.patch b/patches/server/0082-Add-allow-water-in-end-world-option.patch similarity index 91% rename from patches/server/0083-Add-allow-water-in-end-world-option.patch rename to patches/server/0082-Add-allow-water-in-end-world-option.patch index 3c9c2fc07..3d11e524c 100644 --- a/patches/server/0083-Add-allow-water-in-end-world-option.patch +++ b/patches/server/0082-Add-allow-water-in-end-world-option.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add allow water in end world option diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java -index 4fdb99240e6ebda946fd2e0a847654d92b7c56a1..e6dbe6e2d65aa4432f469910fd060649171c697b 100644 +index 69c992ef0c526adf35907de7726832605187beb6..6356d5fdb349063071c9119ae776c22e0b321d77 100644 --- a/src/main/java/net/minecraft/world/item/BucketItem.java +++ b/src/main/java/net/minecraft/world/item/BucketItem.java -@@ -169,7 +169,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { +@@ -170,7 +170,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { // CraftBukkit end if (!flag1) { return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit // Paper - add enumhand @@ -17,7 +17,7 @@ index 4fdb99240e6ebda946fd2e0a847654d92b7c56a1..e6dbe6e2d65aa4432f469910fd060649 int i = blockposition.getX(); int j = blockposition.getY(); int k = blockposition.getZ(); -@@ -177,7 +177,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { +@@ -178,7 +178,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { world.playSound(entityhuman, blockposition, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); for (int l = 0; l < 8; ++l) { @@ -27,10 +27,10 @@ index 4fdb99240e6ebda946fd2e0a847654d92b7c56a1..e6dbe6e2d65aa4432f469910fd060649 return true; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index d49e53404b77eedd24e9824ef5b16a8c4fc8b2db..514e4ff64275a45ddd9aa4e0c8245aaa5483306c 100644 +index 4c55bb04ff41fabb47c6477ba33e0e0aabd1c843..25422752c79ea4ee547caa46fa4ed920622e682e 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1584,4 +1584,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1583,4 +1583,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } } @@ -68,7 +68,7 @@ index df4f2c729f09d5229553308e4876f29de648543f..f2b0278679fa649bbc2904660e0dc9ab } else { world.setBlockAndUpdate(pos, Blocks.WATER.defaultBlockState()); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 35be2f773d33b1c13f8732217c5520b384305b18..3bfddb1111f543a5badb26ca52b4dcef32a7cf1a 100644 +index 53051c4d193cdc5ac7e624a4c7def0ea10e3285e..a6aa607e5b085fdcddab8aa29258be0ba4aa1ac8 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -228,6 +228,11 @@ public class PurpurConfig { diff --git a/patches/server/0084-Allow-color-codes-in-books.patch b/patches/server/0083-Allow-color-codes-in-books.patch similarity index 97% rename from patches/server/0084-Allow-color-codes-in-books.patch rename to patches/server/0083-Allow-color-codes-in-books.patch index ed8b2fa45..39ab5d992 100644 --- a/patches/server/0084-Allow-color-codes-in-books.patch +++ b/patches/server/0083-Allow-color-codes-in-books.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Allow color codes in books diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e71f9a3256eed2361ac8c5c058ceaeeeabbeefa3..e5c08a0305aed04906e5a5578023c9b0b0821381 100644 +index 1efc3021619d4ddc5c1c305ee29730438fdf6858..f4d8b168671d8008ba47324468f0aa4a5ff89bf9 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1200,13 +1200,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser diff --git a/patches/server/0085-Entity-lifespan.patch b/patches/server/0084-Entity-lifespan.patch similarity index 95% rename from patches/server/0085-Entity-lifespan.patch rename to patches/server/0084-Entity-lifespan.patch index 1719c58ad..c9e1041f4 100644 --- a/patches/server/0085-Entity-lifespan.patch +++ b/patches/server/0084-Entity-lifespan.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Entity lifespan diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 8e5c1ee1023a76f7619ffc0cdc3940582da81509..8e678245600bb3eaa4dca0360e3505aa5cd35030 100644 +index e985f795747e25c5456658df3e1d65a520d8a2cc..437015eef7404362cb564dec72e3e87c79b4ff0b 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -126,6 +126,7 @@ public abstract class Mob extends LivingEntity { @@ -89,7 +89,7 @@ index 8e5c1ee1023a76f7619ffc0cdc3940582da81509..8e678245600bb3eaa4dca0360e3505aa } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 059dad063ac6e9d9fc5713df54705ee65a683dc2..fc521ed7418ce1dd53726f3621b68ccb01b1b3d2 100644 +index 492156452dd6f91a3cd638ff8bbf88db458b5c12..f1de0689c36fbbc422a38b1692cba32ba48b155c 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -111,6 +111,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0086-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch b/patches/server/0085-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch similarity index 94% rename from patches/server/0086-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch rename to patches/server/0085-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch index 6963409c0..32271d8fe 100644 --- a/patches/server/0086-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch +++ b/patches/server/0085-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add option to teleport to spawn if outside world border diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index b9f7812f19b194dc19b63cabd9369c5ed56dbe73..32b56e8b042e32daa44638688ea663556627b382 100644 +index af5c80da6c1c2a4ef49b3e9ef15b6f67cfe479a9..f688693ae25999bdbb2a7bf402fdfffd3f62795a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -2519,5 +2519,25 @@ public class ServerPlayer extends Player { +@@ -2521,5 +2521,25 @@ public class ServerPlayer extends Player { } // CraftBukkit end @@ -35,7 +35,7 @@ index b9f7812f19b194dc19b63cabd9369c5ed56dbe73..32b56e8b042e32daa44638688ea66355 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 93df077de01e88b97359d0409db9e3043cda902b..115dea3414f484897aa514f446b4d5e9810dd4d8 100644 +index d08a9032a0551361e5ced4fe20cf803d68898665..8896f8aa3f21dba3fe78b5cf6f3ee1adfac2bac3 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -45,6 +45,7 @@ import net.minecraft.network.syncher.EntityDataAccessor; diff --git a/patches/server/0087-Squid-EAR-immunity.patch b/patches/server/0086-Squid-EAR-immunity.patch similarity index 93% rename from patches/server/0087-Squid-EAR-immunity.patch rename to patches/server/0086-Squid-EAR-immunity.patch index d99f0e142..eb4f1f08b 100644 --- a/patches/server/0087-Squid-EAR-immunity.patch +++ b/patches/server/0086-Squid-EAR-immunity.patch @@ -25,7 +25,7 @@ index 0e076eb9afad6b974d140d8f439e4d689d171eff..6264540a68771b03210bf7f91268aa08 public boolean spiderRidable = false; diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index e58db9acba9fd4f0b7e93ad82ae823c43246fde7..2c13393247d35635dfb038fc987ddd11345615ce 100644 +index 1f70281055634f06cfe7e8026c552aff525e973a..bb9050a31d7eb482b8c5446c356bd74c3a842f87 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -14,6 +14,7 @@ import net.minecraft.world.entity.ambient.AmbientCreature; @@ -36,7 +36,7 @@ index e58db9acba9fd4f0b7e93ad82ae823c43246fde7..2c13393247d35635dfb038fc987ddd11 import net.minecraft.world.entity.animal.WaterAnimal; import net.minecraft.world.entity.animal.horse.Llama; import net.minecraft.world.entity.boss.EnderDragonPart; -@@ -373,6 +374,7 @@ public class ActivationRange +@@ -376,6 +377,7 @@ public class ActivationRange */ public static boolean checkIfActive(Entity entity) { diff --git a/patches/server/0088-Configurable-feature-seed-settings.patch b/patches/server/0087-Configurable-feature-seed-settings.patch similarity index 99% rename from patches/server/0088-Configurable-feature-seed-settings.patch rename to patches/server/0087-Configurable-feature-seed-settings.patch index 87e0dbb45..7a144a7d1 100644 --- a/patches/server/0088-Configurable-feature-seed-settings.patch +++ b/patches/server/0087-Configurable-feature-seed-settings.patch @@ -835,7 +835,7 @@ index ed3944a60d09495eb424dd11d00e8c3585177d51..fcf25cc905ece0213a0eb6365a0a5756 return false; } else { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 3bfddb1111f543a5badb26ca52b4dcef32a7cf1a..f8aeba21a04bcf3cc6c63bcf99ea3b5c2773741a 100644 +index a6aa607e5b085fdcddab8aa29258be0ba4aa1ac8..ac1c4d984928cd284183b4ff713155b2bbbdcfbe 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -176,6 +176,128 @@ public class PurpurConfig { diff --git a/patches/server/0089-Phantoms-burn-in-light.patch b/patches/server/0088-Phantoms-burn-in-light.patch similarity index 100% rename from patches/server/0089-Phantoms-burn-in-light.patch rename to patches/server/0088-Phantoms-burn-in-light.patch diff --git a/patches/server/0090-Configurable-villager-breeding.patch b/patches/server/0089-Configurable-villager-breeding.patch similarity index 95% rename from patches/server/0090-Configurable-villager-breeding.patch rename to patches/server/0089-Configurable-villager-breeding.patch index d4fd1c2a3..5a9f4b9ac 100644 --- a/patches/server/0090-Configurable-villager-breeding.patch +++ b/patches/server/0089-Configurable-villager-breeding.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configurable villager breeding diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 8a6a0825e7d4cc42f4325d2882461065b11a3202..1d03e936b696f3b7e88b411816a8195a716fc3eb 100644 +index 69465bc31cff3e96904fa2fabbe31061e9f5ba4b..a1725ccc7b194c26c4f94561a228da9f56e24cfc 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -759,7 +759,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler diff --git a/patches/server/0091-Redstone-deactivates-spawners.patch b/patches/server/0090-Redstone-deactivates-spawners.patch similarity index 100% rename from patches/server/0091-Redstone-deactivates-spawners.patch rename to patches/server/0090-Redstone-deactivates-spawners.patch diff --git a/patches/server/0092-Totems-work-in-inventory.patch b/patches/server/0091-Totems-work-in-inventory.patch similarity index 96% rename from patches/server/0092-Totems-work-in-inventory.patch rename to patches/server/0091-Totems-work-in-inventory.patch index d17fde516..6d3cb4a47 100644 --- a/patches/server/0092-Totems-work-in-inventory.patch +++ b/patches/server/0091-Totems-work-in-inventory.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Totems work in inventory diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 115dea3414f484897aa514f446b4d5e9810dd4d8..cb408accd66598017365aaa2693a57c2efd7b76c 100644 +index 8896f8aa3f21dba3fe78b5cf6f3ee1adfac2bac3..7339ec31aba03974991fdb247beefc747fa003a5 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -1516,6 +1516,19 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0093-Add-vindicator-johnny-spawn-chance.patch b/patches/server/0092-Add-vindicator-johnny-spawn-chance.patch similarity index 100% rename from patches/server/0093-Add-vindicator-johnny-spawn-chance.patch rename to patches/server/0092-Add-vindicator-johnny-spawn-chance.patch diff --git a/patches/server/0094-Add-option-to-disable-certain-block-updates.patch b/patches/server/0093-Add-option-to-disable-certain-block-updates.patch similarity index 99% rename from patches/server/0094-Add-option-to-disable-certain-block-updates.patch rename to patches/server/0093-Add-option-to-disable-certain-block-updates.patch index 0ffae8201..db3ae4abf 100644 --- a/patches/server/0094-Add-option-to-disable-certain-block-updates.patch +++ b/patches/server/0093-Add-option-to-disable-certain-block-updates.patch @@ -117,7 +117,7 @@ index f8e58d9f71703139a736d93e7f1996e027a29444..d3c8fd8399629efb8bcbaf7d9a0c4334 } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index f8aeba21a04bcf3cc6c63bcf99ea3b5c2773741a..73b0bbc63606475bf27e665b7b280cdfed05d31a 100644 +index ac1c4d984928cd284183b4ff713155b2bbbdcfbe..6522045a99d93fc756571d8f43949a050cefb246 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -355,6 +355,15 @@ public class PurpurConfig { diff --git a/patches/server/0095-Dispensers-place-anvils-option.patch b/patches/server/0094-Dispensers-place-anvils-option.patch similarity index 100% rename from patches/server/0095-Dispensers-place-anvils-option.patch rename to patches/server/0094-Dispensers-place-anvils-option.patch diff --git a/patches/server/0096-Allow-anvil-colors.patch b/patches/server/0095-Allow-anvil-colors.patch similarity index 96% rename from patches/server/0096-Allow-anvil-colors.patch rename to patches/server/0095-Allow-anvil-colors.patch index ad1dc422f..43ba14a3d 100644 --- a/patches/server/0096-Allow-anvil-colors.patch +++ b/patches/server/0095-Allow-anvil-colors.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Allow anvil colors diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index ddfb89d62d2ec316683e9f0f5550e298ab26d137..410ac71efff92dfa1f1e11895d0f5bf3fca1be17 100644 +index 3ce51ff7af5b907cc044c9dd5894be1a03dc2719..81ffe2c1597487188cfcce09c5e160d81529c710 100644 --- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java +++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java @@ -2,6 +2,9 @@ package net.minecraft.world.inventory; diff --git a/patches/server/0097-Add-no-random-tick-block-list.patch b/patches/server/0096-Add-no-random-tick-block-list.patch similarity index 95% rename from patches/server/0097-Add-no-random-tick-block-list.patch rename to patches/server/0096-Add-no-random-tick-block-list.patch index d7fc17d62..35b789083 100644 --- a/patches/server/0097-Add-no-random-tick-block-list.patch +++ b/patches/server/0096-Add-no-random-tick-block-list.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add no-random-tick block list diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a667c540b85a4afbb1beece7decb5d0e3e8c9572..e4651dc35114ee9fd296f7efb6a2d6b808c27d45 100644 +index d95e45c2867cf3232cebd4b4c43bd890bfb70847..750e1900204a1d8717ec78ab2a5863a464e84431 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -483,7 +483,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -18,7 +18,7 @@ index a667c540b85a4afbb1beece7decb5d0e3e8c9572..e4651dc35114ee9fd296f7efb6a2d6b8 DefaultedRegistry registryblocks = Registry.BLOCK; diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 7538262e14c86e4da9cd4cb887b76f649bfef2e6..f34973be478de4f088a0593b45bd89e558a13609 100644 +index 4853025530de9c22bde9e54b81120102dae5477c..35887a72e8e5c1193fd5b484946512df128b25c1 100644 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -915,10 +915,12 @@ public abstract class BlockBehaviour { diff --git a/patches/server/0098-Add-option-to-disable-dolphin-treasure-searching.patch b/patches/server/0097-Add-option-to-disable-dolphin-treasure-searching.patch similarity index 100% rename from patches/server/0098-Add-option-to-disable-dolphin-treasure-searching.patch rename to patches/server/0097-Add-option-to-disable-dolphin-treasure-searching.patch diff --git a/patches/server/0099-Short-enderman-height.patch b/patches/server/0098-Short-enderman-height.patch similarity index 97% rename from patches/server/0099-Short-enderman-height.patch rename to patches/server/0098-Short-enderman-height.patch index a16cc25df..72d058c8d 100644 --- a/patches/server/0099-Short-enderman-height.patch +++ b/patches/server/0098-Short-enderman-height.patch @@ -31,7 +31,7 @@ index a36313c321f9057350a9edb8b0959fd49a8e21a3..10c3a0c49579fbd9f1fe7ec82eebd42b if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper start for (int i = 0; i < 64; ++i) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 73b0bbc63606475bf27e665b7b280cdfed05d31a..05d4f65c5c0de043add313675357d96aa585aa47 100644 +index 6522045a99d93fc756571d8f43949a050cefb246..336a6afbcd5359a1e82d8bac23cd8bfac5e4cd1e 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -345,6 +345,12 @@ public class PurpurConfig { diff --git a/patches/server/0100-Stop-squids-floating-on-top-of-water.patch b/patches/server/0099-Stop-squids-floating-on-top-of-water.patch similarity index 93% rename from patches/server/0100-Stop-squids-floating-on-top-of-water.patch rename to patches/server/0099-Stop-squids-floating-on-top-of-water.patch index ea00c420f..0a61fb3c1 100644 --- a/patches/server/0100-Stop-squids-floating-on-top-of-water.patch +++ b/patches/server/0099-Stop-squids-floating-on-top-of-water.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Stop squids floating on top of water diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index fd3aff71f8e4ffd4faabc2650d8d83c8e6e85946..6bd301f998f66eb8c4f9cccac2f72f42be4c1b00 100644 +index 9043422cfa025e98d9c2bb3d9511c8d735d5b476..ff1592b73dbcf45b6936fe36fe0c3bb17bff198f 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3868,11 +3868,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -3871,11 +3871,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n this.yRotO = this.getYRot(); } @@ -45,7 +45,7 @@ index f96def2ebdf114823c322c2d4318d039e20eab97..2affff346a7fe81480e86cb61996039d @Override diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java -index 6f7e6429c35eea346517cbf08cf223fc6d838a8c..6a77112180556675af38cb1b3ce0b38a42ce9525 100644 +index 68cc6f2a78a06293a29317fda72ab3ee79b3533a..cfb2e46b34b2982d6724f18214557fc80cf4adfa 100644 --- a/src/main/java/net/minecraft/world/phys/AABB.java +++ b/src/main/java/net/minecraft/world/phys/AABB.java @@ -367,4 +367,10 @@ public class AABB { diff --git a/patches/server/0101-Use-configured-height-for-nether-surface-builders.patch b/patches/server/0100-Use-configured-height-for-nether-surface-builders.patch similarity index 100% rename from patches/server/0101-Use-configured-height-for-nether-surface-builders.patch rename to patches/server/0100-Use-configured-height-for-nether-surface-builders.patch diff --git a/patches/server/0102-Crying-obsidian-valid-for-portal-frames.patch b/patches/server/0101-Crying-obsidian-valid-for-portal-frames.patch similarity index 96% rename from patches/server/0102-Crying-obsidian-valid-for-portal-frames.patch rename to patches/server/0101-Crying-obsidian-valid-for-portal-frames.patch index db005bd63..f0c7e388a 100644 --- a/patches/server/0102-Crying-obsidian-valid-for-portal-frames.patch +++ b/patches/server/0101-Crying-obsidian-valid-for-portal-frames.patch @@ -18,7 +18,7 @@ index c07b5d1f1ef8b5e6026c7555d476880c8802d6c5..068f1b184a3694603f564d49fa45d5ce private final LevelAccessor level; private final Direction.Axis axis; diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 05d4f65c5c0de043add313675357d96aa585aa47..c055119e839c24a2de1cd399c7ab6a57281be41b 100644 +index 336a6afbcd5359a1e82d8bac23cd8bfac5e4cd1e..8065d13f4036d62e39aa1f8f081a2cf80edef708 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -329,6 +329,7 @@ public class PurpurConfig { diff --git a/patches/server/0103-Entities-can-use-portals-configuration.patch b/patches/server/0102-Entities-can-use-portals-configuration.patch similarity index 92% rename from patches/server/0103-Entities-can-use-portals-configuration.patch rename to patches/server/0102-Entities-can-use-portals-configuration.patch index d42bde33b..06072ed6e 100644 --- a/patches/server/0103-Entities-can-use-portals-configuration.patch +++ b/patches/server/0102-Entities-can-use-portals-configuration.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Entities can use portals configuration diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 6bd301f998f66eb8c4f9cccac2f72f42be4c1b00..09f68cf24f813755b6e946e6c464a76f8cb2b9ae 100644 +index ff1592b73dbcf45b6936fe36fe0c3bb17bff198f..1c74a0b488048a250b1c2af6974cb8a1e18d7cec 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2725,7 +2725,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -2728,7 +2728,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n public void handleInsidePortal(BlockPos pos) { if (this.isOnPortalCooldown()) { this.setPortalCooldown(); @@ -17,7 +17,7 @@ index 6bd301f998f66eb8c4f9cccac2f72f42be4c1b00..09f68cf24f813755b6e946e6c464a76f if (!this.level.isClientSide && !pos.equals(this.portalEntrancePos)) { this.portalEntrancePos = pos.immutable(); } -@@ -3357,7 +3357,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -3360,7 +3360,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n } public boolean canChangeDimensions() { diff --git a/patches/server/0104-LivingEntity-broadcastItemBreak.patch b/patches/server/0103-LivingEntity-broadcastItemBreak.patch similarity index 85% rename from patches/server/0104-LivingEntity-broadcastItemBreak.patch rename to patches/server/0103-LivingEntity-broadcastItemBreak.patch index fb44e724f..e7c1f536f 100644 --- a/patches/server/0104-LivingEntity-broadcastItemBreak.patch +++ b/patches/server/0103-LivingEntity-broadcastItemBreak.patch @@ -5,10 +5,10 @@ Subject: [PATCH] LivingEntity#broadcastItemBreak diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 81b26444a7be0b20e83f32ec2ba3648e4997af45..6234d72de5b6c4c3dd3f65cc53c99c63ab2f251d 100644 +index fd6a4e9a611e60ebbbbdc8974f77244d20eb169c..7a888d9c464f080297fa27e39837734a06b013a9 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -904,5 +904,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { +@@ -927,5 +927,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { public void setSafeFallDistance(float safeFallDistance) { getHandle().safeFallDistance = safeFallDistance; } diff --git a/patches/server/0105-Customizable-wither-health-and-healing.patch b/patches/server/0104-Customizable-wither-health-and-healing.patch similarity index 100% rename from patches/server/0105-Customizable-wither-health-and-healing.patch rename to patches/server/0104-Customizable-wither-health-and-healing.patch diff --git a/patches/server/0106-Allow-toggling-special-MobSpawners-per-world.patch b/patches/server/0105-Allow-toggling-special-MobSpawners-per-world.patch similarity index 97% rename from patches/server/0106-Allow-toggling-special-MobSpawners-per-world.patch rename to patches/server/0105-Allow-toggling-special-MobSpawners-per-world.patch index cc8d55f38..19bfd90cd 100644 --- a/patches/server/0106-Allow-toggling-special-MobSpawners-per-world.patch +++ b/patches/server/0105-Allow-toggling-special-MobSpawners-per-world.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Allow toggling special MobSpawners per world In vanilla, these are all hardcoded on for world type 0 (overworld) and hardcoded off for every other world type. Default config behaviour matches this. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index e4651dc35114ee9fd296f7efb6a2d6b808c27d45..f8801c73d4e96949143a5917761b35c7563a6725 100644 +index 750e1900204a1d8717ec78ab2a5863a464e84431..f959fab7c941505fcb39b116c05a9e9cd401b090 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -83,6 +83,7 @@ import net.minecraft.world.entity.MobCategory; @@ -94,7 +94,7 @@ index f8ede3588bfda9a7d4d5807311a3e9c2651fd0a3..56967cef0f184def046935e20148574f if (NaturalSpawner.isSpawnPositionOk(SpawnPlacements.Type.ON_GROUND, world, blockposition2, EntityType.WANDERING_TRADER)) { blockposition1 = blockposition2; diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 21133a596e586e6713ccec9c78fde6b07bcff3e0..316469509ed3ff88229323c488e48b1fc439a0df 100644 +index ee548f39f3b0c32bd6abd673ea778e7c433bdf89..3ea46e674461916261030bdd8b693789c34a324a 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -72,6 +72,12 @@ public class PurpurWorldConfig { diff --git a/patches/server/0107-Raid-cooldown-setting.patch b/patches/server/0106-Raid-cooldown-setting.patch similarity index 100% rename from patches/server/0107-Raid-cooldown-setting.patch rename to patches/server/0106-Raid-cooldown-setting.patch diff --git a/patches/server/0108-Despawn-rate-config-options-per-projectile-type.patch b/patches/server/0107-Despawn-rate-config-options-per-projectile-type.patch similarity index 100% rename from patches/server/0108-Despawn-rate-config-options-per-projectile-type.patch rename to patches/server/0107-Despawn-rate-config-options-per-projectile-type.patch diff --git a/patches/server/0109-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/server/0108-Add-option-to-disable-zombie-aggressiveness-towards-.patch similarity index 100% rename from patches/server/0109-Add-option-to-disable-zombie-aggressiveness-towards-.patch rename to patches/server/0108-Add-option-to-disable-zombie-aggressiveness-towards-.patch diff --git a/patches/server/0110-Persistent-TileEntity-Lore-and-DisplayName.patch b/patches/server/0109-Persistent-TileEntity-Lore-and-DisplayName.patch similarity index 98% rename from patches/server/0110-Persistent-TileEntity-Lore-and-DisplayName.patch rename to patches/server/0109-Persistent-TileEntity-Lore-and-DisplayName.patch index 0ae926b2d..13ae75cc5 100644 --- a/patches/server/0110-Persistent-TileEntity-Lore-and-DisplayName.patch +++ b/patches/server/0109-Persistent-TileEntity-Lore-and-DisplayName.patch @@ -37,7 +37,7 @@ index 8e6df16568c0dab482e10ad1b38920d77f6e684f..6c261b9ddee80139140bd1f091fcdacc @Nullable diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 1a5605b11170dfe1bd37165de886bad0f2e38ecd..94a69b7a1443231cf807fb792478c35334f73e62 100644 +index 8c30e28b97ac7e8b54322c903e0b75ee8135620b..577f38fcff55ef23fcacce1b05b6d0de117efd5e 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java @@ -20,6 +20,9 @@ import net.minecraft.core.IdMapper; @@ -67,7 +67,7 @@ index 1a5605b11170dfe1bd37165de886bad0f2e38ecd..94a69b7a1443231cf807fb792478c353 }); state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY); } -@@ -335,13 +339,53 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -352,13 +356,53 @@ public class Block extends BlockBehaviour implements ItemLike { public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, Entity entity, ItemStack stack) { if (world instanceof ServerLevel) { Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, stack).forEach((itemstack1) -> { diff --git a/patches/server/0111-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch b/patches/server/0110-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch similarity index 100% rename from patches/server/0111-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch rename to patches/server/0110-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch diff --git a/patches/server/0112-Flying-squids-Oh-my.patch b/patches/server/0111-Flying-squids-Oh-my.patch similarity index 100% rename from patches/server/0112-Flying-squids-Oh-my.patch rename to patches/server/0111-Flying-squids-Oh-my.patch diff --git a/patches/server/0113-Infinity-bow-settings.patch b/patches/server/0112-Infinity-bow-settings.patch similarity index 97% rename from patches/server/0113-Infinity-bow-settings.patch rename to patches/server/0112-Infinity-bow-settings.patch index ad2af30d6..06c39fa43 100644 --- a/patches/server/0113-Infinity-bow-settings.patch +++ b/patches/server/0112-Infinity-bow-settings.patch @@ -27,7 +27,7 @@ index afe33f20578177cb517e1c116e6319481642e66c..fe4695adbb506733b4029ecfabcfda3d } else { user.startUsingItem(hand); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 33e2317646ca7b77537c8d52235f5a194717c439..9a4e52097e767ac00a5a9dde3137efc28858300e 100644 +index 0653652a130841d15365d4843f864c3169c82e12..c7bac948061bacbd50560bddc5a4a4108853f28f 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -122,6 +122,17 @@ public class PurpurWorldConfig { diff --git a/patches/server/0114-Stonecutter-damage.patch b/patches/server/0113-Stonecutter-damage.patch similarity index 96% rename from patches/server/0114-Stonecutter-damage.patch rename to patches/server/0113-Stonecutter-damage.patch index 0b5d08449..47e8ff2aa 100644 --- a/patches/server/0114-Stonecutter-damage.patch +++ b/patches/server/0113-Stonecutter-damage.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Stonecutter damage diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 09f68cf24f813755b6e946e6c464a76f8cb2b9ae..d262196f88f32ecaca476e4a1d549bd456516f77 100644 +index 1c74a0b488048a250b1c2af6974cb8a1e18d7cec..e049dd0e1d068ab80e78fb5989979a266f132eb6 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1027,7 +1027,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -1030,7 +1030,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n } // CraftBukkit end diff --git a/patches/server/0115-Configurable-daylight-cycle.patch b/patches/server/0114-Configurable-daylight-cycle.patch similarity index 94% rename from patches/server/0115-Configurable-daylight-cycle.patch rename to patches/server/0114-Configurable-daylight-cycle.patch index f2672be73..57a5000be 100644 --- a/patches/server/0115-Configurable-daylight-cycle.patch +++ b/patches/server/0114-Configurable-daylight-cycle.patch @@ -18,7 +18,7 @@ index 689ad22925b2561f7c8db961743eb1f821dbb25f..fa3c960992cc240161817e54659d83fe public ClientboundSetTimePacket(long time, long timeOfDay, boolean doDaylightCycle) { this.gameTime = time % 192000; // Paper - fix guardian beam diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index f8801c73d4e96949143a5917761b35c7563a6725..33ee5844fed6cca2aecf8b84b03c396b445ba0c2 100644 +index f959fab7c941505fcb39b116c05a9e9cd401b090..f0b62a3ec03cdbba853be815834e56c4d136197c 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -196,6 +196,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -26,9 +26,9 @@ index f8801c73d4e96949143a5917761b35c7563a6725..33ee5844fed6cca2aecf8b84b03c396b private final StructureFeatureManager structureFeatureManager; private final boolean tickTime; + private double fakeTime; // Purpur - // Tuinity start - execute chunk tasks mid tick + // Paper start - execute chunk tasks mid tick public long lastMidTickExecuteFailure; - // Tuinity end - execute chunk tasks mid tick + // Paper end - execute chunk tasks mid tick @@ -573,6 +574,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit @@ -70,7 +70,7 @@ index f8801c73d4e96949143a5917761b35c7563a6725..33ee5844fed6cca2aecf8b84b03c396b public void tickCustomSpawners(boolean spawnMonsters, boolean spawnAnimals) { diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 90ace8ccf344a0f7b496e7d9cb5d49d6789d166b..f21a02e3763d42ebe8130802269a99be54b24163 100644 +index 05556f2d9f414a8718a616afcb1d15b2b97e2717..fd8430ad5419655f9d53f532e0f5c3d8391425f2 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -104,6 +104,13 @@ public class PurpurWorldConfig { diff --git a/patches/server/0116-Allow-infinite-and-mending-enchantments-together.patch b/patches/server/0115-Allow-infinite-and-mending-enchantments-together.patch similarity index 95% rename from patches/server/0116-Allow-infinite-and-mending-enchantments-together.patch rename to patches/server/0115-Allow-infinite-and-mending-enchantments-together.patch index 2cf8192c2..a52871fa4 100644 --- a/patches/server/0116-Allow-infinite-and-mending-enchantments-together.patch +++ b/patches/server/0115-Allow-infinite-and-mending-enchantments-together.patch @@ -17,7 +17,7 @@ index 3aece8245060dd1ba269c08d226c84247a6f0a83..6763d0b96c83d1b462999f525bf1f31c } } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index c055119e839c24a2de1cd399c7ab6a57281be41b..731c85911c3d763d06f9f6a602f93e33eeadf3f6 100644 +index 8065d13f4036d62e39aa1f8f081a2cf80edef708..b87478ce6f9ed3ef0f329622268e9133930ae7b8 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -347,6 +347,16 @@ public class PurpurConfig { diff --git a/patches/server/0117-Furnace-uses-lava-from-underneath.patch b/patches/server/0116-Furnace-uses-lava-from-underneath.patch similarity index 100% rename from patches/server/0117-Furnace-uses-lava-from-underneath.patch rename to patches/server/0116-Furnace-uses-lava-from-underneath.patch diff --git a/patches/server/0118-Arrows-should-not-reset-despawn-counter.patch b/patches/server/0117-Arrows-should-not-reset-despawn-counter.patch similarity index 100% rename from patches/server/0118-Arrows-should-not-reset-despawn-counter.patch rename to patches/server/0117-Arrows-should-not-reset-despawn-counter.patch diff --git a/patches/server/0119-Ability-to-re-add-farmland-mechanics-from-Alpha.patch b/patches/server/0118-Ability-to-re-add-farmland-mechanics-from-Alpha.patch similarity index 95% rename from patches/server/0119-Ability-to-re-add-farmland-mechanics-from-Alpha.patch rename to patches/server/0118-Ability-to-re-add-farmland-mechanics-from-Alpha.patch index 6670e2365..ab6b4aee1 100644 --- a/patches/server/0119-Ability-to-re-add-farmland-mechanics-from-Alpha.patch +++ b/patches/server/0118-Ability-to-re-add-farmland-mechanics-from-Alpha.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Ability to re-add farmland mechanics from Alpha diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index ee5bc54e37e5ae120e846ddd2cae5ca39c293c98..f2ddc1c9c4fa029544866b779b4b035924014048 100644 +index f638c7b27a846bf9db73e98ce9eb5d579bc25cac..e0ef42c2613374bedc8eb114aef7dd2aaeebb7b7 100644 --- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java @@ -113,6 +113,14 @@ public class FarmBlock extends Block { diff --git a/patches/server/0120-Add-adjustable-breeding-cooldown-to-config.patch b/patches/server/0119-Add-adjustable-breeding-cooldown-to-config.patch similarity index 94% rename from patches/server/0120-Add-adjustable-breeding-cooldown-to-config.patch rename to patches/server/0119-Add-adjustable-breeding-cooldown-to-config.patch index df28f1030..1810aca00 100644 --- a/patches/server/0120-Add-adjustable-breeding-cooldown-to-config.patch +++ b/patches/server/0119-Add-adjustable-breeding-cooldown-to-config.patch @@ -33,7 +33,7 @@ index 43841b5c77beb73169e2ff1645afe1234d8f74c7..d5d9f8e9c7119ae159a085aa414fc7f3 entityageable.setBaby(true); entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 514e4ff64275a45ddd9aa4e0c8245aaa5483306c..27674fb28825b48eee86b93d6bbd1e7af94c0fe0 100644 +index 25422752c79ea4ee547caa46fa4ed920622e682e..5e06dbb25359b593c6960652ee99f8227bf4deb0 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -188,6 +188,49 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -86,13 +86,13 @@ index 514e4ff64275a45ddd9aa4e0c8245aaa5483306c..27674fb28825b48eee86b93d6bbd1e7a public CraftWorld getWorld() { return this.world; } -@@ -319,6 +362,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -318,6 +361,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper - this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData)worlddatamutable).getLevelName()); // Tuinity - Server Config this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((ServerLevel) this, ((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur + this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur this.generator = gen; - this.world = new CraftWorld((ServerLevel) this, gen, env); + this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java index 74544421716246a73876f4a39711ee25438a8f2c..db50fe00f2e725d0ab44f8704443cf6107e39d4e 100644 diff --git a/patches/server/0121-Make-entity-breeding-times-configurable.patch b/patches/server/0120-Make-entity-breeding-times-configurable.patch similarity index 100% rename from patches/server/0121-Make-entity-breeding-times-configurable.patch rename to patches/server/0120-Make-entity-breeding-times-configurable.patch diff --git a/patches/server/0122-Apply-display-names-from-item-forms-of-entities-to-e.patch b/patches/server/0121-Apply-display-names-from-item-forms-of-entities-to-e.patch similarity index 97% rename from patches/server/0122-Apply-display-names-from-item-forms-of-entities-to-e.patch rename to patches/server/0121-Apply-display-names-from-item-forms-of-entities-to-e.patch index 4a3c65e46..6d098c2d7 100644 --- a/patches/server/0122-Apply-display-names-from-item-forms-of-entities-to-e.patch +++ b/patches/server/0121-Apply-display-names-from-item-forms-of-entities-to-e.patch @@ -63,7 +63,7 @@ index a853e2cc2e3f06a0ca0bb1799b3fd02890ae6521..a8265cd631d335d4eaec1918bd48570e } diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -index 4688cfb6f24066d3034efcd6b4816ceb37561f1f..0f6e577e47a3b1ce5a356801b6192d1d306d19c2 100644 +index 6acd2dc6ec9c3761fa330c74df8c7e7b19266f8e..f46ebe98c173d9a6cb6d6e375b55fd9b3f75e13c 100644 --- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java +++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java @@ -209,7 +209,13 @@ public class Boat extends Entity { @@ -101,7 +101,7 @@ index 44d63145480d38a4ec3a38be108200af070bcffa..7de67b75010f0da52004c911f6ee98eb world.playSound((Player) null, entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F); world.gameEvent((Entity) context.getPlayer(), GameEvent.ENTITY_PLACE, (Entity) entityarmorstand); diff --git a/src/main/java/net/minecraft/world/item/BoatItem.java b/src/main/java/net/minecraft/world/item/BoatItem.java -index 9a11248b13d231c1797e14f843cb8cbec0d35a6e..eb8f15432200856dc49129a4a3fe1ee1ae516d02 100644 +index 8998f6233a3135fda928469ae8bb7119e16eee1a..62a8600e0d684a147f4bfe027b3dd4f71bf665ad 100644 --- a/src/main/java/net/minecraft/world/item/BoatItem.java +++ b/src/main/java/net/minecraft/world/item/BoatItem.java @@ -67,6 +67,11 @@ public class BoatItem extends Item { @@ -113,7 +113,7 @@ index 9a11248b13d231c1797e14f843cb8cbec0d35a6e..eb8f15432200856dc49129a4a3fe1ee1 + entityboat.setCustomName(itemstack.getHoverName()); + } + // Purpur end - if (!world.noCollision(entityboat, entityboat.getBoundingBox().inflate(-net.minecraft.Util.COLLISION_EPSILON))) { // Paper + if (!world.noCollision(entityboat, entityboat.getBoundingBox())) { // Paper return InteractionResultHolder.fail(itemstack); } else { diff --git a/src/main/java/net/minecraft/world/item/HangingEntityItem.java b/src/main/java/net/minecraft/world/item/HangingEntityItem.java diff --git a/patches/server/0123-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch b/patches/server/0122-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch similarity index 95% rename from patches/server/0123-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch rename to patches/server/0122-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch index 3f062ab33..e4164d811 100644 --- a/patches/server/0123-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch +++ b/patches/server/0122-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch @@ -17,7 +17,7 @@ index 623f78c078fb3aa2665d7e8a37672438227bce6b..500c69e555c7247e20ef8cc59d834155 ((Mob) newEntityLiving).setPersistenceRequired(); // Paper end diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 525c05f3d64c76b2a0d470ba38125b49232a8dbd..923baa127fd13fae044d67c674ce2882ddda191b 100644 +index e79720605098b1773227f02705c29415a4723ccc..45363eb67ab0c30c687a556392afe8e44e3d5f0d 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -101,9 +101,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0124-Add-twisting-and-weeping-vines-growth-rates.patch b/patches/server/0123-Add-twisting-and-weeping-vines-growth-rates.patch similarity index 100% rename from patches/server/0124-Add-twisting-and-weeping-vines-growth-rates.patch rename to patches/server/0123-Add-twisting-and-weeping-vines-growth-rates.patch diff --git a/patches/server/0125-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch b/patches/server/0124-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch similarity index 100% rename from patches/server/0125-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch rename to patches/server/0124-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch diff --git a/patches/server/0126-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch b/patches/server/0125-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch similarity index 100% rename from patches/server/0126-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch rename to patches/server/0125-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch diff --git a/patches/server/0127-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch b/patches/server/0126-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch similarity index 97% rename from patches/server/0127-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch rename to patches/server/0126-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch index 5fa551ed1..85b3d6e2f 100644 --- a/patches/server/0127-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch +++ b/patches/server/0126-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add critical hit check to EntityDamagedByEntityEvent diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 3e04510519ca5d03eb16aab8b1094e24101cebf4..12a3304c3b465f2a9d7cf279ea7b945bb3b8f6a1 100644 +index c557bee52a3f136696bb55853622b03220735109..5b0647a8b8d2dd8a44b38c378312ad917d5314d9 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -182,6 +182,7 @@ public abstract class Player extends LivingEntity { diff --git a/patches/server/0128-Add-configurable-snowball-damage.patch b/patches/server/0127-Add-configurable-snowball-damage.patch similarity index 100% rename from patches/server/0128-Add-configurable-snowball-damage.patch rename to patches/server/0127-Add-configurable-snowball-damage.patch diff --git a/patches/server/0129-Zombie-break-door-minimum-difficulty-option.patch b/patches/server/0128-Zombie-break-door-minimum-difficulty-option.patch similarity index 100% rename from patches/server/0129-Zombie-break-door-minimum-difficulty-option.patch rename to patches/server/0128-Zombie-break-door-minimum-difficulty-option.patch diff --git a/patches/server/0130-Left-handed-API.patch b/patches/server/0129-Left-handed-API.patch similarity index 83% rename from patches/server/0130-Left-handed-API.patch rename to patches/server/0129-Left-handed-API.patch index c85afcc0d..f0ac2d079 100644 --- a/patches/server/0130-Left-handed-API.patch +++ b/patches/server/0129-Left-handed-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Left handed API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -index 6549d7c40d6a0ca307fdcb6fd3ca01d2ab732b59..c128bb7fbea43e9b4245870d78f920dfb23e23f3 100644 +index 2386edf499cb292241f6ba60c1cdb46f2fe704ff..2f87513408972b7eed7fd0f3f94ac9799858f58a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -@@ -132,4 +132,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { +@@ -135,4 +135,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { return getHandle().getMaxHeadXRot(); } // Paper end diff --git a/patches/server/0131-Changeable-Mob-Left-Handed-Chance.patch b/patches/server/0130-Changeable-Mob-Left-Handed-Chance.patch similarity index 90% rename from patches/server/0131-Changeable-Mob-Left-Handed-Chance.patch rename to patches/server/0130-Changeable-Mob-Left-Handed-Chance.patch index 0bbdf9e85..42e55ea39 100644 --- a/patches/server/0131-Changeable-Mob-Left-Handed-Chance.patch +++ b/patches/server/0130-Changeable-Mob-Left-Handed-Chance.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Changeable Mob Left Handed Chance diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 8e678245600bb3eaa4dca0360e3505aa5cd35030..be8439e06c1ed9a05f55ec3467e5ab6748318677 100644 +index 437015eef7404362cb564dec72e3e87c79b4ff0b..e6aa1a5040bbd483a752f9c646fdb062a8e88871 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -1210,7 +1210,7 @@ public abstract class Mob extends LivingEntity { @@ -18,7 +18,7 @@ index 8e678245600bb3eaa4dca0360e3505aa5cd35030..be8439e06c1ed9a05f55ec3467e5ab67 } else { this.setLeftHanded(false); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index e567f3d21b047654750aadc7cfa84e9972905215..76eb2d3dfd5455448140ef69bdb9698fbc82e105 100644 +index a589e2292aae4402cef2a6a6cea68ab1f81d7f5a..6060068efe2ad4e3a2c6113a92e1e02db2da5d18 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -129,8 +129,10 @@ public class PurpurWorldConfig { diff --git a/patches/server/0132-Add-boat-fall-damage-config.patch b/patches/server/0131-Add-boat-fall-damage-config.patch similarity index 97% rename from patches/server/0132-Add-boat-fall-damage-config.patch rename to patches/server/0131-Add-boat-fall-damage-config.patch index d21b2cb62..f2b12b734 100644 --- a/patches/server/0132-Add-boat-fall-damage-config.patch +++ b/patches/server/0131-Add-boat-fall-damage-config.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add boat fall damage config diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 32b56e8b042e32daa44638688ea663556627b382..8c93a84f9b44316fedc1544a309d27ef14e7d6d7 100644 +index f688693ae25999bdbb2a7bf402fdfffd3f62795a..a78d1068802c98d888fe2e139a327a089a2b2bf8 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -991,7 +991,16 @@ public class ServerPlayer extends Player { diff --git a/patches/server/0133-Snow-Golem-rate-of-fire-config.patch b/patches/server/0132-Snow-Golem-rate-of-fire-config.patch similarity index 100% rename from patches/server/0133-Snow-Golem-rate-of-fire-config.patch rename to patches/server/0132-Snow-Golem-rate-of-fire-config.patch diff --git a/patches/server/0134-EMC-Configurable-disable-give-dropping.patch b/patches/server/0133-EMC-Configurable-disable-give-dropping.patch similarity index 95% rename from patches/server/0134-EMC-Configurable-disable-give-dropping.patch rename to patches/server/0133-EMC-Configurable-disable-give-dropping.patch index 70c681b20..d0bd2169c 100644 --- a/patches/server/0134-EMC-Configurable-disable-give-dropping.patch +++ b/patches/server/0133-EMC-Configurable-disable-give-dropping.patch @@ -20,7 +20,7 @@ index a0dc380e90415de9068ea408d62a1605c82631df..60fd566f7e1499ecf2ad91216a667f12 itemStack.setCount(1); ItemEntity itemEntity2 = serverPlayer.drop(itemStack, false, false, true); // Paper - Fix duplicating /give items on item drop cancel diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 731c85911c3d763d06f9f6a602f93e33eeadf3f6..ad4908c00ea98ea26aa211436c572b4ec04cd030 100644 +index b87478ce6f9ed3ef0f329622268e9133930ae7b8..c727654feb472518bdeaa780ba885ec85616902e 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -326,6 +326,11 @@ public class PurpurConfig { diff --git a/patches/server/0135-Lobotomize-stuck-villagers.patch b/patches/server/0134-Lobotomize-stuck-villagers.patch similarity index 97% rename from patches/server/0135-Lobotomize-stuck-villagers.patch rename to patches/server/0134-Lobotomize-stuck-villagers.patch index 2d919bad1..63f74f56e 100644 --- a/patches/server/0135-Lobotomize-stuck-villagers.patch +++ b/patches/server/0134-Lobotomize-stuck-villagers.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Lobotomize stuck villagers diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 1d03e936b696f3b7e88b411816a8195a716fc3eb..80d86ce8944e38dcdbd15574aea4e3cb073d2cf7 100644 +index a1725ccc7b194c26c4f94561a228da9f56e24cfc..14c616f3159e4227da90c1fcc097bb46b11cc6f7 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -142,6 +142,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler diff --git a/patches/server/0136-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch b/patches/server/0135-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch similarity index 99% rename from patches/server/0136-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch rename to patches/server/0135-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch index 6f5ae3292..7549ea3f7 100644 --- a/patches/server/0136-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch +++ b/patches/server/0135-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch @@ -145,7 +145,7 @@ index b615dc2a2127f0874775d1707e96edfb4d95b987..72ae6b3282aac806ae11b87024ee940e brain.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, list); } else { diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 80d86ce8944e38dcdbd15574aea4e3cb073d2cf7..98411df8a36e29b818e990b3c1aa4e30417c87ca 100644 +index 14c616f3159e4227da90c1fcc097bb46b11cc6f7..7a3c19b07c87394bc73ea16f9f0be22d7ea4f470 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -238,7 +238,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler diff --git a/patches/server/0137-Toggle-for-Zombified-Piglin-death-always-counting-as.patch b/patches/server/0136-Toggle-for-Zombified-Piglin-death-always-counting-as.patch similarity index 100% rename from patches/server/0137-Toggle-for-Zombified-Piglin-death-always-counting-as.patch rename to patches/server/0136-Toggle-for-Zombified-Piglin-death-always-counting-as.patch diff --git a/patches/server/0138-Spread-out-and-optimise-player-list-ticksSpread-out-.patch b/patches/server/0137-Spread-out-and-optimise-player-list-ticksSpread-out-.patch similarity index 91% rename from patches/server/0138-Spread-out-and-optimise-player-list-ticksSpread-out-.patch rename to patches/server/0137-Spread-out-and-optimise-player-list-ticksSpread-out-.patch index 44a225e57..db2d7820a 100644 --- a/patches/server/0138-Spread-out-and-optimise-player-list-ticksSpread-out-.patch +++ b/patches/server/0137-Spread-out-and-optimise-player-list-ticksSpread-out-.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Spread out and optimise player list ticksSpread out and diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index c1d79527abc7c8a165872758db3d5240615a63aa..2381d75295554c0310e36a26f5332063b126adc9 100644 +index bd5ab259d37f13542c2510530fdf5fc5d6496975..e17c61e3b807dbc1a7bca4952349145617204154 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1012,22 +1012,22 @@ public abstract class PlayerList { +@@ -1011,22 +1011,22 @@ public abstract class PlayerList { } public void tick() { @@ -46,7 +46,7 @@ index c1d79527abc7c8a165872758db3d5240615a63aa..2381d75295554c0310e36a26f5332063 public void broadcastAll(Packet packet) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ec4397cc98b66fef55a91854c42518479b839bbe..15f7092468fd341d4e5d22163ea0e265803e5139 100644 +index f7649d5e27888724f672de7673865522a30f7225..c29ada6d77617e366248d5ba786394babbe9c6e3 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1569,7 +1569,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0139-Configurable-chance-for-wolves-to-spawn-rabid.patch b/patches/server/0138-Configurable-chance-for-wolves-to-spawn-rabid.patch similarity index 100% rename from patches/server/0139-Configurable-chance-for-wolves-to-spawn-rabid.patch rename to patches/server/0138-Configurable-chance-for-wolves-to-spawn-rabid.patch diff --git a/patches/server/0140-Configurable-default-wolf-collar-color.patch b/patches/server/0139-Configurable-default-wolf-collar-color.patch similarity index 100% rename from patches/server/0140-Configurable-default-wolf-collar-color.patch rename to patches/server/0139-Configurable-default-wolf-collar-color.patch diff --git a/patches/server/0141-Phantom-flames-on-swoop.patch b/patches/server/0140-Phantom-flames-on-swoop.patch similarity index 100% rename from patches/server/0141-Phantom-flames-on-swoop.patch rename to patches/server/0140-Phantom-flames-on-swoop.patch diff --git a/patches/server/0142-Option-for-chests-to-open-even-with-a-solid-block-on.patch b/patches/server/0141-Option-for-chests-to-open-even-with-a-solid-block-on.patch similarity index 100% rename from patches/server/0142-Option-for-chests-to-open-even-with-a-solid-block-on.patch rename to patches/server/0141-Option-for-chests-to-open-even-with-a-solid-block-on.patch diff --git a/patches/server/0143-Implement-TPSBar.patch b/patches/server/0142-Implement-TPSBar.patch similarity index 95% rename from patches/server/0143-Implement-TPSBar.patch rename to patches/server/0142-Implement-TPSBar.patch index 34b7b485c..6977dae35 100644 --- a/patches/server/0143-Implement-TPSBar.patch +++ b/patches/server/0142-Implement-TPSBar.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Implement TPSBar diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index a5712108fbbe5ddc61cdfd390f667ab013ba609d..73953ea69776bfe1dcb1504cd14a0f003f1b5766 100644 +index 42deff516bd363d0882b441fa6928ac7eecbfccc..386e9ad013369633e2be543b9281e5a5fdce9c74 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -201,6 +201,7 @@ public class Commands { @@ -17,10 +17,10 @@ index a5712108fbbe5ddc61cdfd390f667ab013ba609d..73953ea69776bfe1dcb1504cd14a0f00 if (environment.includeIntegrated) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 1622eedaaada332f589eddfdb1dae38387ce0a0c..a456c7f6eedb2cff1b58ec6f0ef330c74dfcdaed 100644 +index 023566ddf2b1910dc90955289baff3bb4404abb7..807269b3fc6a1fe7cdbaef6f5336ee40e988505b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1119,6 +1119,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop. Co-authored-by: Mariell Hoversholm diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index a5d7fdd9ec0342e000e467a002846873a10d75fc..f71cc1f5e5d594e82a4e6132d438bae74b9370a7 100644 +index 4ed70cc15abd52e8e474d57a3d6be20e94a2f027..a4292e82cdb678d941056e5b059753eb4447b661 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -311,7 +311,14 @@ public abstract class ChunkGenerator { +@@ -348,7 +348,14 @@ public abstract class ChunkGenerator { if (structuresettingsfeature != null) { StructureStart structurestart1 = feature.generate(registryManager, this, this.biomeSource, structureManager, worldSeed, chunkcoordintpair, biome, j, structuresettingsfeature, chunk); diff --git a/patches/server/0153-Farmland-trampling-changes.patch b/patches/server/0152-Farmland-trampling-changes.patch similarity index 97% rename from patches/server/0153-Farmland-trampling-changes.patch rename to patches/server/0152-Farmland-trampling-changes.patch index 059b3c703..520d65b60 100644 --- a/patches/server/0153-Farmland-trampling-changes.patch +++ b/patches/server/0152-Farmland-trampling-changes.patch @@ -12,7 +12,7 @@ necessary to trample in the first place. Feather Falling 1 requires you to fall over 3+ blocks to trample. FF 2 requires 4+, etc. diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index 2a33fbdc1d047584b0cd4b3da5892ccd7efc6943..6bfaeaeb6f9accf269febbf3e0d71d575db32151 100644 +index e06a8a68ccb9c9a77df061264e58fd850cf1f794..010da2b44fa3a4f033e4f86e9a0917b5c94b6ab5 100644 --- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java @@ -114,12 +114,20 @@ public class FarmBlock extends Block { diff --git a/patches/server/0154-Movement-options-for-armor-stands.patch b/patches/server/0153-Movement-options-for-armor-stands.patch similarity index 94% rename from patches/server/0154-Movement-options-for-armor-stands.patch rename to patches/server/0153-Movement-options-for-armor-stands.patch index f90eb3603..500a440b0 100644 --- a/patches/server/0154-Movement-options-for-armor-stands.patch +++ b/patches/server/0153-Movement-options-for-armor-stands.patch @@ -17,10 +17,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index f9516fb2072dff1426d249ee25449e1c7c9cf625..4214dc49e2758be99ca204cb33f2dcc7b0109b65 100644 +index 307f51ca7a27574c3b5f1bf42bac5a56bdebb949..bd225cf3e8b8c6ab72134fecdef357b444eb5e68 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1614,7 +1614,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -1617,7 +1617,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return this.isInWater() || flag; } @@ -66,7 +66,7 @@ index 796ab61f4513c02b0d55d34044d2f7084c447796..d119f8ab447bc17deabc494463de4961 + // Purpur end } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index c4795689fdf5bdccd6f2b16f93801be769fa8565..50f271ff9949241caec638d96caa782f945b7d52 100644 +index 08f96bb13b0bc201a298a91c04d9fa22f0aba77f..3135325fa86dd88f28c72b1a132939c921149eb7 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -102,10 +102,16 @@ public class PurpurWorldConfig { diff --git a/patches/server/0155-Fix-stuck-in-portals.patch b/patches/server/0154-Fix-stuck-in-portals.patch similarity index 92% rename from patches/server/0155-Fix-stuck-in-portals.patch rename to patches/server/0154-Fix-stuck-in-portals.patch index 45f1d665b..473e545f8 100644 --- a/patches/server/0155-Fix-stuck-in-portals.patch +++ b/patches/server/0154-Fix-stuck-in-portals.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Fix stuck in portals diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index b09cd5f750b6789ac21ed7d585d72ad393141a97..e081a02d6799d8d74db06ca84e224c395e95a308 100644 +index cefbdb8f5892d5d46ca6ddc8aa6710be42c189a6..4a201004d397cf960822259d4f7d19cf53d28cf7 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1144,6 +1144,7 @@ public class ServerPlayer extends Player { @@ -17,10 +17,10 @@ index b09cd5f750b6789ac21ed7d585d72ad393141a97..e081a02d6799d8d74db06ca84e224c39 // CraftBukkit end this.setLevel(worldserver); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 4214dc49e2758be99ca204cb33f2dcc7b0109b65..a1cbeb306d5bcf619a3a338822209f6f68992b5a 100644 +index bd225cf3e8b8c6ab72134fecdef357b444eb5e68..6beffbc4769972778477d86ac8a53d26d3b520ae 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2722,12 +2722,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -2725,12 +2725,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return Vec3.directionFromRotation(this.getRotationVector()); } diff --git a/patches/server/0156-Toggle-for-water-sensitive-mob-damage.patch b/patches/server/0155-Toggle-for-water-sensitive-mob-damage.patch similarity index 98% rename from patches/server/0156-Toggle-for-water-sensitive-mob-damage.patch rename to patches/server/0155-Toggle-for-water-sensitive-mob-damage.patch index 893da3fe8..3ab143172 100644 --- a/patches/server/0156-Toggle-for-water-sensitive-mob-damage.patch +++ b/patches/server/0155-Toggle-for-water-sensitive-mob-damage.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Toggle for water sensitive mob damage diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 30a566f84db07523367da7ca26fde6b9ad891b10..730f3e8c3d410363e55f1c3d7cfcc3c388e75aa9 100644 +index a53173ec096c059e1913f4af124c834b5411e5bc..a52ea8628f70861a80c2d62301da1cbf478b477f 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -865,7 +865,7 @@ public abstract class Mob extends LivingEntity { diff --git a/patches/server/0157-Config-to-always-tame-in-Creative.patch b/patches/server/0156-Config-to-always-tame-in-Creative.patch similarity index 100% rename from patches/server/0157-Config-to-always-tame-in-Creative.patch rename to patches/server/0156-Config-to-always-tame-in-Creative.patch diff --git a/patches/server/0158-End-crystal-explosion-options.patch b/patches/server/0157-End-crystal-explosion-options.patch similarity index 100% rename from patches/server/0158-End-crystal-explosion-options.patch rename to patches/server/0157-End-crystal-explosion-options.patch diff --git a/patches/server/0159-Add-unsafe-Entity-serialization-API.patch b/patches/server/0158-Add-unsafe-Entity-serialization-API.patch similarity index 97% rename from patches/server/0159-Add-unsafe-Entity-serialization-API.patch rename to patches/server/0158-Add-unsafe-Entity-serialization-API.patch index 55014ee90..20ae5ff4d 100644 --- a/patches/server/0159-Add-unsafe-Entity-serialization-API.patch +++ b/patches/server/0158-Add-unsafe-Entity-serialization-API.patch @@ -17,10 +17,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 4175462de0d6306e4cd0871853ef4f0a06895359..2fb5c5ea01d5f1071c8e8a39e7863ed0640d3fc9 100644 +index bff5eec5823d0de0fd6bcfaaccab70685ea56081..40640e8ddaa3870e18945a4cc10fe064e3dbe849 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1260,5 +1260,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -1265,5 +1265,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { public boolean isRidableInWater() { return getHandle().rideableUnderWater(); } diff --git a/patches/server/0160-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch b/patches/server/0159-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch similarity index 100% rename from patches/server/0160-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch rename to patches/server/0159-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch diff --git a/patches/server/0161-Dont-run-with-scissors.patch b/patches/server/0160-Dont-run-with-scissors.patch similarity index 93% rename from patches/server/0161-Dont-run-with-scissors.patch rename to patches/server/0160-Dont-run-with-scissors.patch index b940546e8..1fc290a78 100644 --- a/patches/server/0161-Dont-run-with-scissors.patch +++ b/patches/server/0160-Dont-run-with-scissors.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Dont run with scissors! diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 2e67a26419c706d78bd793bd616cbbff704833bb..43d124818c4538bc0d84111dfab25c38aab249c1 100644 +index 3d73f44edca1b13a98f858ae0c1fd0bc79055a12..a015afdc3fedb0c86a1bc2a59ee37fd41d74b8fd 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1555,6 +1555,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser @@ -23,7 +23,7 @@ index 2e67a26419c706d78bd793bd616cbbff704833bb..43d124818c4538bc0d84111dfab25c38 this.lastGoodX = this.player.getX(); this.lastGoodY = this.player.getY(); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index da4d5b05cf2daa31ecd70d2815017bbb6e771313..ccd228aa323eef108526640dfe03b07541041236 100644 +index a51de18eee2caf87b710e3ab863b7157d093859c..d8ec1c94b018ce566ed81a41023b4192557dc06d 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -165,6 +165,7 @@ public class PurpurConfig { @@ -43,7 +43,7 @@ index da4d5b05cf2daa31ecd70d2815017bbb6e771313..ccd228aa323eef108526640dfe03b075 public static int seedFeatureBamboo = -1; diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index ee84e6aef5c0e747c71c2b345eebfb99da406b8d..7ea2cf4712963cbb2a750ade4d5609ee49be9732 100644 +index bc81ceaef6ac2da472c49a74870d5bfd74ad0c3f..d51e861fe8ffab512ef42c2bde7f316b6a231101 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -156,6 +156,8 @@ public class PurpurWorldConfig { diff --git a/patches/server/0162-One-Punch-Man.patch b/patches/server/0161-One-Punch-Man.patch similarity index 96% rename from patches/server/0162-One-Punch-Man.patch rename to patches/server/0161-One-Punch-Man.patch index 579b52a42..1770ada87 100644 --- a/patches/server/0162-One-Punch-Man.patch +++ b/patches/server/0161-One-Punch-Man.patch @@ -5,7 +5,7 @@ Subject: [PATCH] One Punch Man! diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 4f8f29264971f53ca273c5b21732864dedcb5463..68f247f9e3a6dbb3b92b5a077de170c4dd58276b 100644 +index 10ed6cf0d1543e1fbfb54308aa785cc206abd13d..ee4f096d4b3d23981074eb6013624c85d6890b4e 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -2137,6 +2137,20 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0163-Add-config-for-snow-on-blue-ice.patch b/patches/server/0162-Add-config-for-snow-on-blue-ice.patch similarity index 100% rename from patches/server/0163-Add-config-for-snow-on-blue-ice.patch rename to patches/server/0162-Add-config-for-snow-on-blue-ice.patch diff --git a/patches/server/0164-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch b/patches/server/0163-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch similarity index 98% rename from patches/server/0164-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch rename to patches/server/0163-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch index 275207b43..1e655b54e 100644 --- a/patches/server/0164-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch +++ b/patches/server/0163-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch @@ -43,7 +43,7 @@ index 749ab72edc0d2e9c6f1161415ab8d59d3d6ca976..897c202c0905040072a06fdfa2032a7f // Paper end if (user instanceof net.minecraft.server.level.ServerPlayer) { diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 2b2668e3245a9bf13942de18fdfc3ea38a41a873..44ffdbe9fa16ab111e2f598a47ba54194d4d94dd 100644 +index 9956f0d219b8570eadff207aeffedee079250135..80e1d3c7ea6f5228924d8c2dc033262fd46c4691 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -158,6 +158,10 @@ public class PurpurWorldConfig { diff --git a/patches/server/0165-Config-to-ignore-nearby-mobs-when-sleeping.patch b/patches/server/0164-Config-to-ignore-nearby-mobs-when-sleeping.patch similarity index 96% rename from patches/server/0165-Config-to-ignore-nearby-mobs-when-sleeping.patch rename to patches/server/0164-Config-to-ignore-nearby-mobs-when-sleeping.patch index dfca8b49e..cc863a1a9 100644 --- a/patches/server/0165-Config-to-ignore-nearby-mobs-when-sleeping.patch +++ b/patches/server/0164-Config-to-ignore-nearby-mobs-when-sleeping.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Config to ignore nearby mobs when sleeping diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index e081a02d6799d8d74db06ca84e224c395e95a308..26fcead85fe017a27d41697cbf7b6d1da16c8879 100644 +index 4a201004d397cf960822259d4f7d19cf53d28cf7..b0bbd09379e451798b3fa965c2c61ad029faea5b 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1307,7 +1307,7 @@ public class ServerPlayer extends Player { diff --git a/patches/server/0166-Add-back-player-spawned-endermite-API.patch b/patches/server/0165-Add-back-player-spawned-endermite-API.patch similarity index 100% rename from patches/server/0166-Add-back-player-spawned-endermite-API.patch rename to patches/server/0165-Add-back-player-spawned-endermite-API.patch diff --git a/patches/server/0167-Config-Enderman-aggressiveness-towards-Endermites.patch b/patches/server/0166-Config-Enderman-aggressiveness-towards-Endermites.patch similarity index 100% rename from patches/server/0167-Config-Enderman-aggressiveness-towards-Endermites.patch rename to patches/server/0166-Config-Enderman-aggressiveness-towards-Endermites.patch diff --git a/patches/server/0168-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch b/patches/server/0167-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch similarity index 100% rename from patches/server/0168-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch rename to patches/server/0167-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch diff --git a/patches/server/0169-Tick-fluids-config.patch b/patches/server/0168-Tick-fluids-config.patch similarity index 100% rename from patches/server/0169-Tick-fluids-config.patch rename to patches/server/0168-Tick-fluids-config.patch diff --git a/patches/server/0170-Config-to-disable-Llama-caravans.patch b/patches/server/0169-Config-to-disable-Llama-caravans.patch similarity index 100% rename from patches/server/0170-Config-to-disable-Llama-caravans.patch rename to patches/server/0169-Config-to-disable-Llama-caravans.patch diff --git a/patches/server/0171-Config-to-make-Creepers-explode-on-death.patch b/patches/server/0170-Config-to-make-Creepers-explode-on-death.patch similarity index 100% rename from patches/server/0171-Config-to-make-Creepers-explode-on-death.patch rename to patches/server/0170-Config-to-make-Creepers-explode-on-death.patch diff --git a/patches/server/0172-Configurable-ravager-griefable-blocks-list.patch b/patches/server/0171-Configurable-ravager-griefable-blocks-list.patch similarity index 100% rename from patches/server/0172-Configurable-ravager-griefable-blocks-list.patch rename to patches/server/0171-Configurable-ravager-griefable-blocks-list.patch diff --git a/patches/server/0173-Sneak-to-bulk-process-composter.patch b/patches/server/0172-Sneak-to-bulk-process-composter.patch similarity index 98% rename from patches/server/0173-Sneak-to-bulk-process-composter.patch rename to patches/server/0172-Sneak-to-bulk-process-composter.patch index cd16000af..a063d7de6 100644 --- a/patches/server/0173-Sneak-to-bulk-process-composter.patch +++ b/patches/server/0172-Sneak-to-bulk-process-composter.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Sneak to bulk process composter diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index e97e3b4de132a452d560c19a1dcecd28f8010c62..0011b8305a95d5570f85cdac87655e66bbab94f1 100644 +index 8975a806979ac028b916b826e0d051af5e760550..d13a237319c2a581ab9300f16accc722116cba5a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java @@ -582,7 +582,7 @@ public class ServerPlayerGameMode { diff --git a/patches/server/0174-Config-for-skipping-night.patch b/patches/server/0173-Config-for-skipping-night.patch similarity index 96% rename from patches/server/0174-Config-for-skipping-night.patch rename to patches/server/0173-Config-for-skipping-night.patch index 133a4de2d..df1e26ca8 100644 --- a/patches/server/0174-Config-for-skipping-night.patch +++ b/patches/server/0173-Config-for-skipping-night.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Config for skipping night diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 33ee5844fed6cca2aecf8b84b03c396b445ba0c2..54c353224ae3e72544af2a34304039b58a2b0efe 100644 +index f0b62a3ec03cdbba853be815834e56c4d136197c..6add1cb8a35c1e16670ba2e9db7878f27bbf3752 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -717,7 +717,7 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0175-Add-config-for-villager-trading.patch b/patches/server/0174-Add-config-for-villager-trading.patch similarity index 97% rename from patches/server/0175-Add-config-for-villager-trading.patch rename to patches/server/0174-Add-config-for-villager-trading.patch index 1a021251c..30e6c5a30 100644 --- a/patches/server/0175-Add-config-for-villager-trading.patch +++ b/patches/server/0174-Add-config-for-villager-trading.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add config for villager trading diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 98411df8a36e29b818e990b3c1aa4e30417c87ca..581c1fc648eb281e15296b6640dfe7297db9555e 100644 +index 7a3c19b07c87394bc73ea16f9f0be22d7ea4f470..597d21bd2d7dde000e02986557be205380e2aa0a 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -383,7 +383,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler diff --git a/patches/server/0176-Allow-infinity-on-crossbows.patch b/patches/server/0175-Allow-infinity-on-crossbows.patch similarity index 98% rename from patches/server/0176-Allow-infinity-on-crossbows.patch rename to patches/server/0175-Allow-infinity-on-crossbows.patch index fd3c4fdac..56f4afe8b 100644 --- a/patches/server/0176-Allow-infinity-on-crossbows.patch +++ b/patches/server/0175-Allow-infinity-on-crossbows.patch @@ -59,7 +59,7 @@ index 6f6106ca4d74d50a7b74b086adc96c58c7906cb6..d6417c1e77ac8823e18a179dc9f61757 public abstract boolean canEnchant(Item item); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index ccd228aa323eef108526640dfe03b07541041236..80fc65c5f3a89241fb7aadaccbf730a5f05dec64 100644 +index d8ec1c94b018ce566ed81a41023b4192557dc06d..110f12af4c0e5e27578e2db4d15ddc30689d5fdf 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -378,6 +378,7 @@ public class PurpurConfig { diff --git a/patches/server/0177-Drowning-Settings.patch b/patches/server/0176-Drowning-Settings.patch similarity index 89% rename from patches/server/0177-Drowning-Settings.patch rename to patches/server/0176-Drowning-Settings.patch index ae19c2c5c..342af1e6b 100644 --- a/patches/server/0177-Drowning-Settings.patch +++ b/patches/server/0176-Drowning-Settings.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Drowning Settings diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a1cbeb306d5bcf619a3a338822209f6f68992b5a..b04ce8c54e282eb95b15abf5b928f872233da645 100644 +index 6beffbc4769972778477d86ac8a53d26d3b520ae..e03f7211d30919764daa53438a0647109b007138 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2956,7 +2956,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -2959,7 +2959,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n } public int getMaxAirSupply() { @@ -18,7 +18,7 @@ index a1cbeb306d5bcf619a3a338822209f6f68992b5a..b04ce8c54e282eb95b15abf5b928f872 public int getAirSupply() { diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 68f247f9e3a6dbb3b92b5a077de170c4dd58276b..c186a6f2a8d3e788e544768eace8035d02d18915 100644 +index ee4f096d4b3d23981074eb6013624c85d6890b4e..fe0e0670fce56f96a7d9204ca20a483ad709493a 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -424,7 +424,7 @@ public abstract class LivingEntity extends Entity { @@ -40,7 +40,7 @@ index 68f247f9e3a6dbb3b92b5a077de170c4dd58276b..c186a6f2a8d3e788e544768eace8035d } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index d734218c0b7277348b0ea4002259f19e59bc31f0..106ab026e1cdd4365176ac3d6fdd3012a1d4d345 100644 +index e6a317143896dec02be183b4726fcddaf5826a8f..72979fd75f25c48a9421f8c1ba66a693eb227114 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -121,6 +121,15 @@ public class PurpurWorldConfig { diff --git a/patches/server/0178-Break-individual-slabs-when-sneaking.patch b/patches/server/0177-Break-individual-slabs-when-sneaking.patch similarity index 97% rename from patches/server/0178-Break-individual-slabs-when-sneaking.patch rename to patches/server/0177-Break-individual-slabs-when-sneaking.patch index 52605be7a..0fe23e19c 100644 --- a/patches/server/0178-Break-individual-slabs-when-sneaking.patch +++ b/patches/server/0177-Break-individual-slabs-when-sneaking.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Break individual slabs when sneaking diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 0011b8305a95d5570f85cdac87655e66bbab94f1..e9b2b0c8f5c61787af3ee3c402e5d65656868422 100644 +index d13a237319c2a581ab9300f16accc722116cba5a..67be5a160e1be4a277b436477294574f2232fa74 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java @@ -420,6 +420,7 @@ public class ServerPlayerGameMode { diff --git a/patches/server/0179-Config-to-disable-hostile-mob-spawn-on-ice.patch b/patches/server/0178-Config-to-disable-hostile-mob-spawn-on-ice.patch similarity index 100% rename from patches/server/0179-Config-to-disable-hostile-mob-spawn-on-ice.patch rename to patches/server/0178-Config-to-disable-hostile-mob-spawn-on-ice.patch diff --git a/patches/server/0180-Config-to-show-Armor-Stand-arms-on-spawn.patch b/patches/server/0179-Config-to-show-Armor-Stand-arms-on-spawn.patch similarity index 96% rename from patches/server/0180-Config-to-show-Armor-Stand-arms-on-spawn.patch rename to patches/server/0179-Config-to-show-Armor-Stand-arms-on-spawn.patch index 2a14c008a..71a39ab94 100644 --- a/patches/server/0180-Config-to-show-Armor-Stand-arms-on-spawn.patch +++ b/patches/server/0179-Config-to-show-Armor-Stand-arms-on-spawn.patch @@ -17,7 +17,7 @@ index d119f8ab447bc17deabc494463de496161c9b126..c9a44a4765f43b9c0247ed1005f4c134 public ArmorStand(Level world, double x, double y, double z) { diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index e9ff5fbf5d4524cee836afd85618355bd9c53821..95277d97f1e35e9a05fd289f6a639b50fa820c61 100644 +index 5473bab042800baf78e4db6dc5f49a96f4b2f6f9..148c54151d5555533667eb6f429ca44c0b82b3de 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -105,6 +105,7 @@ public class PurpurWorldConfig { diff --git a/patches/server/0181-Option-to-make-doors-require-redstone.patch b/patches/server/0180-Option-to-make-doors-require-redstone.patch similarity index 100% rename from patches/server/0181-Option-to-make-doors-require-redstone.patch rename to patches/server/0180-Option-to-make-doors-require-redstone.patch diff --git a/patches/server/0182-Config-to-allow-for-unsafe-enchants.patch b/patches/server/0181-Config-to-allow-for-unsafe-enchants.patch similarity index 93% rename from patches/server/0182-Config-to-allow-for-unsafe-enchants.patch rename to patches/server/0181-Config-to-allow-for-unsafe-enchants.patch index d6c939f85..e68fb00ac 100644 --- a/patches/server/0182-Config-to-allow-for-unsafe-enchants.patch +++ b/patches/server/0181-Config-to-allow-for-unsafe-enchants.patch @@ -27,7 +27,7 @@ index 514cc0e8805045549eacde6c280859aa2dc4a91d..a3ac6bebcef7b1e1f9c3ebe525656a15 ++i; } else if (targets.size() == 1) { diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index 410ac71efff92dfa1f1e11895d0f5bf3fca1be17..f380659b261253e327f018ce9b54b15195ad65d7 100644 +index 81ffe2c1597487188cfcce09c5e160d81529c710..bb80328af5051cc01609dfd79b749d9acd2d69ac 100644 --- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java +++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java @@ -209,7 +209,7 @@ public class AnvilMenu extends ItemCombinerMenu { @@ -48,8 +48,8 @@ index 410ac71efff92dfa1f1e11895d0f5bf3fca1be17..f380659b261253e327f018ce9b54b151 ++i; } } -@@ -332,7 +332,7 @@ public class AnvilMenu extends ItemCombinerMenu { - org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit +@@ -333,7 +333,7 @@ public class AnvilMenu extends ItemCombinerMenu { + sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client this.broadcastChanges(); // Purpur start - if (canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) { @@ -75,7 +75,7 @@ index d1b4fe830170ddee2b6f39eba29e7068e6ae37a3..115f8eb919e90bc4a79db1d0f7875a31 this.getOrCreateTag().put(key, tag); } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 80fc65c5f3a89241fb7aadaccbf730a5f05dec64..01330b33775a340237df6175c208162cec0379d6 100644 +index 110f12af4c0e5e27578e2db4d15ddc30689d5fdf..52d105d363219f8fc7e8b373ab8d8288ca377003 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -379,6 +379,7 @@ public class PurpurConfig { diff --git a/patches/server/0183-Configurable-sponge-absorption.patch b/patches/server/0182-Configurable-sponge-absorption.patch similarity index 100% rename from patches/server/0183-Configurable-sponge-absorption.patch rename to patches/server/0182-Configurable-sponge-absorption.patch diff --git a/patches/server/0184-Projectile-offset-config.patch b/patches/server/0183-Projectile-offset-config.patch similarity index 100% rename from patches/server/0184-Projectile-offset-config.patch rename to patches/server/0183-Projectile-offset-config.patch diff --git a/patches/server/0185-Config-for-powered-rail-activation-distance.patch b/patches/server/0184-Config-for-powered-rail-activation-distance.patch similarity index 100% rename from patches/server/0185-Config-for-powered-rail-activation-distance.patch rename to patches/server/0184-Config-for-powered-rail-activation-distance.patch diff --git a/patches/server/0186-Piglin-portal-spawn-modifier.patch b/patches/server/0185-Piglin-portal-spawn-modifier.patch similarity index 100% rename from patches/server/0186-Piglin-portal-spawn-modifier.patch rename to patches/server/0185-Piglin-portal-spawn-modifier.patch diff --git a/patches/server/0187-Config-to-change-max-number-of-bees.patch b/patches/server/0186-Config-to-change-max-number-of-bees.patch similarity index 96% rename from patches/server/0187-Config-to-change-max-number-of-bees.patch rename to patches/server/0186-Config-to-change-max-number-of-bees.patch index ee2d3a393..e72fa29aa 100644 --- a/patches/server/0187-Config-to-change-max-number-of-bees.patch +++ b/patches/server/0186-Config-to-change-max-number-of-bees.patch @@ -18,7 +18,7 @@ index 8484e80a70129fb0358d56efab6fd54798b54e6e..ffacc4b8cc3ab8285c4131aec58e48ff public BeehiveBlockEntity(BlockPos pos, BlockState state) { super(BlockEntityType.BEEHIVE, pos, state); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 01330b33775a340237df6175c208162cec0379d6..14e732da4c80a09f39047e4940cf73c1d6130572 100644 +index 52d105d363219f8fc7e8b373ab8d8288ca377003..ca9f6aa9f773c0017a499311ffdde00e00955b25 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -360,6 +360,7 @@ public class PurpurConfig { diff --git a/patches/server/0188-Configurable-damage-settings-for-magma-blocks.patch b/patches/server/0187-Configurable-damage-settings-for-magma-blocks.patch similarity index 95% rename from patches/server/0188-Configurable-damage-settings-for-magma-blocks.patch rename to patches/server/0187-Configurable-damage-settings-for-magma-blocks.patch index 023301383..3138478bb 100644 --- a/patches/server/0188-Configurable-damage-settings-for-magma-blocks.patch +++ b/patches/server/0187-Configurable-damage-settings-for-magma-blocks.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configurable damage settings for magma blocks diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index b04ce8c54e282eb95b15abf5b928f872233da645..c187e182384cd82bfa085d43ba8010a6ab3f1303 100644 +index e03f7211d30919764daa53438a0647109b007138..bd1d12e64a709f63339aaf9725246b68fe198d9d 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1027,7 +1027,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -1030,7 +1030,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n } // CraftBukkit end diff --git a/patches/server/0189-Config-for-wither-explosion-radius.patch b/patches/server/0188-Config-for-wither-explosion-radius.patch similarity index 100% rename from patches/server/0189-Config-for-wither-explosion-radius.patch rename to patches/server/0188-Config-for-wither-explosion-radius.patch diff --git a/patches/server/0190-Gamemode-extra-permissions.patch b/patches/server/0189-Gamemode-extra-permissions.patch similarity index 96% rename from patches/server/0190-Gamemode-extra-permissions.patch rename to patches/server/0189-Gamemode-extra-permissions.patch index ef2fe00db..63293243b 100644 --- a/patches/server/0190-Gamemode-extra-permissions.patch +++ b/patches/server/0189-Gamemode-extra-permissions.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Gamemode extra permissions diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index d9e868b6c70da18b4ce23c80e2aaf347f2dc6d50..0fcb54f3a0eae8639931866c8c3d7e1ac8c11960 100644 +index 224669ecaad37ac2f16900700eea40ef52d938a5..3c668bb739ee92b6d1130889cc42f73a129bf5a2 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -193,6 +193,21 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy +@@ -195,6 +195,21 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy } // CraftBukkit end @@ -54,7 +54,7 @@ index 79f6089b934124c3309c6bee2e48b36b937252e0..dff8ef0a1a2e52792070d93685c29002 for(ServerPlayer serverPlayer : targets) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 14e732da4c80a09f39047e4940cf73c1d6130572..36a1e1bd8988b1dbad1aa8edb59c010d1af629d9 100644 +index ca9f6aa9f773c0017a499311ffdde00e00955b25..0371ce09bbddbd08aaed0e059c28d0d2384ce9ea 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -343,6 +343,7 @@ public class PurpurConfig { diff --git a/patches/server/0191-Config-for-changing-the-blocks-that-turn-into-dirt-p.patch b/patches/server/0190-Config-for-changing-the-blocks-that-turn-into-dirt-p.patch similarity index 100% rename from patches/server/0191-Config-for-changing-the-blocks-that-turn-into-dirt-p.patch rename to patches/server/0190-Config-for-changing-the-blocks-that-turn-into-dirt-p.patch diff --git a/patches/server/0192-Configurable-piston-push-limit.patch b/patches/server/0191-Configurable-piston-push-limit.patch similarity index 100% rename from patches/server/0192-Configurable-piston-push-limit.patch rename to patches/server/0191-Configurable-piston-push-limit.patch diff --git a/patches/server/0193-Configurable-broadcast-settings.patch b/patches/server/0192-Configurable-broadcast-settings.patch similarity index 94% rename from patches/server/0193-Configurable-broadcast-settings.patch rename to patches/server/0192-Configurable-broadcast-settings.patch index acc025bb8..cdeb8ae7b 100644 --- a/patches/server/0193-Configurable-broadcast-settings.patch +++ b/patches/server/0192-Configurable-broadcast-settings.patch @@ -17,7 +17,7 @@ index c46df052a5a39d92688f51377ee1f7b5b5b36faa..d7d2a975386cecb0d50b4f7ed37de8ad // Paper end } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 26fcead85fe017a27d41697cbf7b6d1da16c8879..ba690d310ee6b9d3a1b1bf2ae13e016daabeb0fc 100644 +index b0bbd09379e451798b3fa965c2c61ad029faea5b..d4b9a31fb3a26a8939e1d30f5b6bc2d66fc7620a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -882,6 +882,7 @@ public class ServerPlayer extends Player { @@ -29,7 +29,7 @@ index 26fcead85fe017a27d41697cbf7b6d1da16c8879..ba690d310ee6b9d3a1b1bf2ae13e016d if (scoreboardteambase.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) { this.server.getPlayerList().broadcastToTeam((Player) this, ichatbasecomponent); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 36a1e1bd8988b1dbad1aa8edb59c010d1af629d9..5052879dd910180918052d9cc00df63e398479ee 100644 +index 0371ce09bbddbd08aaed0e059c28d0d2384ce9ea..d04fff457bb1ec4b0291c0691569d74f17711c8c 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -178,6 +178,18 @@ public class PurpurConfig { diff --git a/patches/server/0194-Fix-SPIGOT-6278.patch b/patches/server/0193-Fix-SPIGOT-6278.patch similarity index 100% rename from patches/server/0194-Fix-SPIGOT-6278.patch rename to patches/server/0193-Fix-SPIGOT-6278.patch diff --git a/patches/server/0195-Configurable-mob-blindness.patch b/patches/server/0194-Configurable-mob-blindness.patch similarity index 96% rename from patches/server/0195-Configurable-mob-blindness.patch rename to patches/server/0194-Configurable-mob-blindness.patch index aff210fc4..0fae588b2 100644 --- a/patches/server/0195-Configurable-mob-blindness.patch +++ b/patches/server/0194-Configurable-mob-blindness.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Configurable mob blindness Ported from https://github.com/raltsmc/mobblindness diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index c186a6f2a8d3e788e544768eace8035d02d18915..53627b5482522f62ee375697ef604a5deb9d331f 100644 +index fe0e0670fce56f96a7d9204ca20a483ad709493a..d1237c85995d3aab5d9a664db6b6ef32fe10b439 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -991,6 +991,17 @@ public abstract class LivingEntity extends Entity { diff --git a/patches/server/0196-Hide-hidden-players-from-entity-selector.patch b/patches/server/0195-Hide-hidden-players-from-entity-selector.patch similarity index 98% rename from patches/server/0196-Hide-hidden-players-from-entity-selector.patch rename to patches/server/0195-Hide-hidden-players-from-entity-selector.patch index 05c41bb8f..c8f929c62 100644 --- a/patches/server/0196-Hide-hidden-players-from-entity-selector.patch +++ b/patches/server/0195-Hide-hidden-players-from-entity-selector.patch @@ -59,7 +59,7 @@ index 0fb8f32427843f4bfd90ab88ecb3ab3e4a4fda31..f99f1ba7f912a2fd503e12c446b342a8 + // Purpur end } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 5052879dd910180918052d9cc00df63e398479ee..0496d20d982815cc1c56051331ffb51e3d9d0038 100644 +index d04fff457bb1ec4b0291c0691569d74f17711c8c..74f8b416eb1746088c1785a97a2b595ce405e08b 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -356,6 +356,7 @@ public class PurpurConfig { diff --git a/patches/server/0197-Config-for-health-to-impact-Creeper-explosion-radius.patch b/patches/server/0196-Config-for-health-to-impact-Creeper-explosion-radius.patch similarity index 100% rename from patches/server/0197-Config-for-health-to-impact-Creeper-explosion-radius.patch rename to patches/server/0196-Config-for-health-to-impact-Creeper-explosion-radius.patch diff --git a/patches/server/0198-Iron-golem-poppy-calms-anger.patch b/patches/server/0197-Iron-golem-poppy-calms-anger.patch similarity index 100% rename from patches/server/0198-Iron-golem-poppy-calms-anger.patch rename to patches/server/0197-Iron-golem-poppy-calms-anger.patch diff --git a/patches/server/0199-Breedable-parrots.patch b/patches/server/0198-Breedable-parrots.patch similarity index 100% rename from patches/server/0199-Breedable-parrots.patch rename to patches/server/0198-Breedable-parrots.patch diff --git a/patches/server/0200-Configurable-powered-rail-boost-modifier.patch b/patches/server/0199-Configurable-powered-rail-boost-modifier.patch similarity index 96% rename from patches/server/0200-Configurable-powered-rail-boost-modifier.patch rename to patches/server/0199-Configurable-powered-rail-boost-modifier.patch index 648f6f136..86ff2e35f 100644 --- a/patches/server/0200-Configurable-powered-rail-boost-modifier.patch +++ b/patches/server/0199-Configurable-powered-rail-boost-modifier.patch @@ -18,7 +18,7 @@ index 1e3077a22d9d3d26356b865001dcce81c9c1d7e5..cc57ff699d159a0cc748e91b61d53965 Vec3 vec3d5 = this.getDeltaMovement(); double d21 = vec3d5.x; diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index b54dba107a355fe8f4e12f0763fb0b6590788c05..2bef8f37783cd83ac10a41103c3fa868a8cc9fea 100644 +index 98ef2440cbdfad53687bc144b083324b70e42a34..a477c7cdf85c7f1a30c0c19d7bb1464058e011e5 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -226,6 +226,7 @@ public class PurpurWorldConfig { diff --git a/patches/server/0201-Add-config-change-multiplier-critical-damage-value.patch b/patches/server/0200-Add-config-change-multiplier-critical-damage-value.patch similarity index 95% rename from patches/server/0201-Add-config-change-multiplier-critical-damage-value.patch rename to patches/server/0200-Add-config-change-multiplier-critical-damage-value.patch index 8e97d8fec..dc1060b24 100644 --- a/patches/server/0201-Add-config-change-multiplier-critical-damage-value.patch +++ b/patches/server/0200-Add-config-change-multiplier-critical-damage-value.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add config change multiplier critical damage value diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 51e0701385c94822f83e8b628967ef9d36a10085..ace974dd50765602aa234cb7be9151714f072f5a 100644 +index d7a3d2928a63517a1513f5572b121f77979f1b17..d201e3ad325cd6a6cca49ae310a70f36599f99b0 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1255,7 +1255,7 @@ public abstract class Player extends LivingEntity { diff --git a/patches/server/0202-Option-to-disable-dragon-egg-teleporting.patch b/patches/server/0201-Option-to-disable-dragon-egg-teleporting.patch similarity index 100% rename from patches/server/0202-Option-to-disable-dragon-egg-teleporting.patch rename to patches/server/0201-Option-to-disable-dragon-egg-teleporting.patch diff --git a/patches/server/0203-Config-for-unverified-username-message.patch b/patches/server/0202-Config-for-unverified-username-message.patch similarity index 94% rename from patches/server/0203-Config-for-unverified-username-message.patch rename to patches/server/0202-Config-for-unverified-username-message.patch index 079d72168..359867e01 100644 --- a/patches/server/0203-Config-for-unverified-username-message.patch +++ b/patches/server/0202-Config-for-unverified-username-message.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Config for unverified username message diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 9ab220ef0d20151d4e205f3edc213fd9353601ad..2ac8770beec518df79ad3f9324e78b03b72c24d6 100644 +index 01fee879c946b6640da34d5890d686f0152437dc..503db7080701bad3408c2feecde15cd45fcaeafa 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -306,7 +306,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener @@ -18,7 +18,7 @@ index 9ab220ef0d20151d4e205f3edc213fd9353601ad..2ac8770beec518df79ad3f9324e78b03 } } catch (AuthenticationUnavailableException authenticationunavailableexception) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 0496d20d982815cc1c56051331ffb51e3d9d0038..b1cb0e5857509921c2f2c112e98ec2801ce5c4c2 100644 +index 74f8b416eb1746088c1785a97a2b595ce405e08b..61b617d3cd867dfe5898e8fad788848295a8d74f 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -166,6 +166,7 @@ public class PurpurConfig { diff --git a/patches/server/0204-Make-anvil-cumulative-cost-configurable.patch b/patches/server/0203-Make-anvil-cumulative-cost-configurable.patch similarity index 88% rename from patches/server/0204-Make-anvil-cumulative-cost-configurable.patch rename to patches/server/0203-Make-anvil-cumulative-cost-configurable.patch index 55d690366..23094c092 100644 --- a/patches/server/0204-Make-anvil-cumulative-cost-configurable.patch +++ b/patches/server/0203-Make-anvil-cumulative-cost-configurable.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Make anvil cumulative cost configurable diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index f380659b261253e327f018ce9b54b15195ad65d7..080449cf3aa0394bd179e26fda8d7248f488ea8d 100644 +index bb80328af5051cc01609dfd79b749d9acd2d69ac..9dd5dfc95049de84916bbbd63acb6125ec9ee0a0 100644 --- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java +++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -341,7 +341,7 @@ public class AnvilMenu extends ItemCombinerMenu { +@@ -342,7 +342,7 @@ public class AnvilMenu extends ItemCombinerMenu { } public static int calculateIncreasedRepairCost(int cost) { @@ -18,7 +18,7 @@ index f380659b261253e327f018ce9b54b15195ad65d7..080449cf3aa0394bd179e26fda8d7248 public void setItemName(String newItemName) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index b1cb0e5857509921c2f2c112e98ec2801ce5c4c2..dcb0aca3303b92f955700f784934396a4808f7ed 100644 +index 61b617d3cd867dfe5898e8fad788848295a8d74f..11e563ba1aec3006205de91761ec14698577267a 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -379,6 +379,7 @@ public class PurpurConfig { diff --git a/patches/server/0205-ShulkerBox-allow-oversized-stacks.patch b/patches/server/0204-ShulkerBox-allow-oversized-stacks.patch similarity index 97% rename from patches/server/0205-ShulkerBox-allow-oversized-stacks.patch rename to patches/server/0204-ShulkerBox-allow-oversized-stacks.patch index 0fc038fcb..a224ac0ab 100644 --- a/patches/server/0205-ShulkerBox-allow-oversized-stacks.patch +++ b/patches/server/0204-ShulkerBox-allow-oversized-stacks.patch @@ -9,7 +9,7 @@ creating an itemstack using the TileEntity's NBT data (how it handles it for creative players) instead of routing it through the LootableBuilder. diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index e9b2b0c8f5c61787af3ee3c402e5d65656868422..dd5bc68171ce5a67ecf30de65f0c1d280cc88419 100644 +index 67be5a160e1be4a277b436477294574f2232fa74..2b2ac97e31dc8742f0294ec065eaf96959df6d34 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java @@ -449,7 +449,7 @@ public class ServerPlayerGameMode { diff --git a/patches/server/0206-Bee-can-work-when-raining-or-at-night.patch b/patches/server/0205-Bee-can-work-when-raining-or-at-night.patch similarity index 100% rename from patches/server/0206-Bee-can-work-when-raining-or-at-night.patch rename to patches/server/0205-Bee-can-work-when-raining-or-at-night.patch diff --git a/patches/server/0207-API-for-any-mob-to-burn-daylight.patch b/patches/server/0206-API-for-any-mob-to-burn-daylight.patch similarity index 96% rename from patches/server/0207-API-for-any-mob-to-burn-daylight.patch rename to patches/server/0206-API-for-any-mob-to-burn-daylight.patch index ca9b7fde8..298d007d2 100644 --- a/patches/server/0207-API-for-any-mob-to-burn-daylight.patch +++ b/patches/server/0206-API-for-any-mob-to-burn-daylight.patch @@ -6,10 +6,10 @@ Subject: [PATCH] API for any mob to burn daylight Co-authored by: Encode42 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index c187e182384cd82bfa085d43ba8010a6ab3f1303..44330d19cf56a2efa46b98ff37c00a1aab50faf3 100644 +index bd1d12e64a709f63339aaf9725246b68fe198d9d..b31830f3c71f206730b775671aa0b43d87e10629 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4316,5 +4316,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -4319,5 +4319,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n public boolean canSaveToDisk() { return true; } @@ -29,7 +29,7 @@ index c187e182384cd82bfa085d43ba8010a6ab3f1303..44330d19cf56a2efa46b98ff37c00a1a // Purpur end } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 53627b5482522f62ee375697ef604a5deb9d331f..90be441ca0222f9df6ab0f8111b204f9673a8e66 100644 +index d1237c85995d3aab5d9a664db6b6ef32fe10b439..c3e5ed21f67b421a645eb8d15593d18af498e40c 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -264,6 +264,7 @@ public abstract class LivingEntity extends Entity { @@ -89,7 +89,7 @@ index 53627b5482522f62ee375697ef604a5deb9d331f..90be441ca0222f9df6ab0f8111b204f9 public boolean isSensitiveToWater() { diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 730f3e8c3d410363e55f1c3d7cfcc3c388e75aa9..d52b7294c6ad137008d0caae21ca1616ae34f04a 100644 +index a52ea8628f70861a80c2d62301da1cbf478b477f..5e62ecb980199f8dba97703403ef811167a24ec5 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -1643,17 +1643,7 @@ public abstract class Mob extends LivingEntity { @@ -333,10 +333,10 @@ index 1f90c40c5e92232c38a33097903fd6e2f6f2ff02..39fa4a9a52c510e88036ab790a8739d2 // Paper end diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 2fb5c5ea01d5f1071c8e8a39e7863ed0640d3fc9..e1513023d7f9701f2c1fde816fa81767af5097dc 100644 +index 40640e8ddaa3870e18945a4cc10fe064e3dbe849..e1e9cca7293483cc4928c96ddd72e616c857b4c9 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1267,5 +1267,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -1272,5 +1272,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); return !entity.valid && entity.level.addEntity(entity, spawnReason); } @@ -348,10 +348,10 @@ index 2fb5c5ea01d5f1071c8e8a39e7863ed0640d3fc9..e1513023d7f9701f2c1fde816fa81767 // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 6234d72de5b6c4c3dd3f65cc53c99c63ab2f251d..6c258c7eadce0f0c2a4af5bef9527bf5b7d53c40 100644 +index 7a888d9c464f080297fa27e39837734a06b013a9..9ecf1ef7e876418d2b454d6cd8ac8739194acfaa 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -910,5 +910,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { +@@ -933,5 +933,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { if (slot == null) return; getHandle().broadcastBreakEvent(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)); } diff --git a/patches/server/0208-Fix-advancement-triggers-on-entity-death.patch b/patches/server/0207-Fix-advancement-triggers-on-entity-death.patch similarity index 96% rename from patches/server/0208-Fix-advancement-triggers-on-entity-death.patch rename to patches/server/0207-Fix-advancement-triggers-on-entity-death.patch index 42423bdbc..65ddd41b0 100644 --- a/patches/server/0208-Fix-advancement-triggers-on-entity-death.patch +++ b/patches/server/0207-Fix-advancement-triggers-on-entity-death.patch @@ -16,7 +16,7 @@ restoring it back to the entity just before the criterion triggers run and then finally clearing the equipment again right after the criterion is done. diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 90be441ca0222f9df6ab0f8111b204f9673a8e66..3bef0780fa95a63887fdb64cb1b038d44cf1c028 100644 +index c3e5ed21f67b421a645eb8d15593d18af498e40c..ad3ef0b1f3d6d00a0aca909812127b09302e5a8c 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -1661,10 +1661,13 @@ public abstract class LivingEntity extends Entity { @@ -47,7 +47,7 @@ index 90be441ca0222f9df6ab0f8111b204f9673a8e66..3bef0780fa95a63887fdb64cb1b038d4 CompoundTag nbttagcompound = stack.getTag(); diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index d52b7294c6ad137008d0caae21ca1616ae34f04a..f79b35b117231b5fa0bf7b9ebe9380dab043ab33 100644 +index 5e62ecb980199f8dba97703403ef811167a24ec5..0f8e261912feac68bdc8119d7368d8719618e787 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -1026,6 +1026,41 @@ public abstract class Mob extends LivingEntity { @@ -139,7 +139,7 @@ index c9a44a4765f43b9c0247ed1005f4c13469bdee95..6d08c8c31a32ea38f06410fbaddf19b9 public boolean canTakeItem(ItemStack stack) { net.minecraft.world.entity.EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(stack); diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index ace974dd50765602aa234cb7be9151714f072f5a..24523dd712329f2f3abe40bb3f1801ef7946e831 100644 +index d201e3ad325cd6a6cca49ae310a70f36599f99b0..b7e8ba03bd46b257ec97a494c4e7a20d0286a5dd 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1991,6 +1991,52 @@ public abstract class Player extends LivingEntity { diff --git a/patches/server/0209-Config-MobEffect-by-world.patch b/patches/server/0208-Config-MobEffect-by-world.patch similarity index 98% rename from patches/server/0209-Config-MobEffect-by-world.patch rename to patches/server/0208-Config-MobEffect-by-world.patch index 844f6ac81..776424d5f 100644 --- a/patches/server/0209-Config-MobEffect-by-world.patch +++ b/patches/server/0208-Config-MobEffect-by-world.patch @@ -40,7 +40,7 @@ index 79e036d79dec2ec4404baf02c23ba5ccad20cdce..6706d8e6d43cc5f3058f08fdfde77bed ((ServerPlayer) entityhuman).connection.send(new ClientboundSetHealthPacket(((ServerPlayer) entityhuman).getBukkitEntity().getScaledHealth(), entityhuman.getFoodData().foodLevel, entityhuman.getFoodData().saturationLevel)); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 5f474e9acfeb02e86a4afc7a3ada24368aadfc2c..4fc9bd6a8b84a77008dad75b8d62b82180093320 100644 +index 7530ae70ec2dccd1e565fc4a5a188e2ee331618e..5fdeafe905ea542adc7e72719118d4d6fcc4ecfe 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -282,6 +282,21 @@ public class PurpurWorldConfig { diff --git a/patches/server/0210-Beacon-Activation-Range-Configurable.patch b/patches/server/0209-Beacon-Activation-Range-Configurable.patch similarity index 100% rename from patches/server/0210-Beacon-Activation-Range-Configurable.patch rename to patches/server/0209-Beacon-Activation-Range-Configurable.patch diff --git a/patches/server/0211-Add-toggle-for-sand-duping-fix.patch b/patches/server/0210-Add-toggle-for-sand-duping-fix.patch similarity index 100% rename from patches/server/0211-Add-toggle-for-sand-duping-fix.patch rename to patches/server/0210-Add-toggle-for-sand-duping-fix.patch diff --git a/patches/server/0212-Add-toggle-for-end-portal-safe-teleporting.patch b/patches/server/0211-Add-toggle-for-end-portal-safe-teleporting.patch similarity index 95% rename from patches/server/0212-Add-toggle-for-end-portal-safe-teleporting.patch rename to patches/server/0211-Add-toggle-for-end-portal-safe-teleporting.patch index 28014146a..e4c5e23ec 100644 --- a/patches/server/0212-Add-toggle-for-end-portal-safe-teleporting.patch +++ b/patches/server/0211-Add-toggle-for-end-portal-safe-teleporting.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add toggle for end portal safe teleporting diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 44330d19cf56a2efa46b98ff37c00a1aab50faf3..650de6e5ca9637b9034774feba8ef35ae6442b3a 100644 +index b31830f3c71f206730b775671aa0b43d87e10629..4af1929cb5b8959d45d5d72616441f7eba5f9d15 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2773,7 +2773,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -2776,7 +2776,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n } this.processPortalCooldown(); diff --git a/patches/server/0213-Flying-Fall-Damage-API.patch b/patches/server/0212-Flying-Fall-Damage-API.patch similarity index 91% rename from patches/server/0213-Flying-Fall-Damage-API.patch rename to patches/server/0212-Flying-Fall-Damage-API.patch index f99adc94e..c52cfaf5b 100644 --- a/patches/server/0213-Flying-Fall-Damage-API.patch +++ b/patches/server/0212-Flying-Fall-Damage-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Flying Fall Damage API diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 24523dd712329f2f3abe40bb3f1801ef7946e831..ebd744b08e27d6fc6dda31ada7ad8bb1864a6982 100644 +index b7e8ba03bd46b257ec97a494c4e7a20d0286a5dd..b0661f7ad41157c5e25ee2d87f9a0efd79039475 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -183,6 +183,7 @@ public abstract class Player extends LivingEntity { @@ -26,7 +26,7 @@ index 24523dd712329f2f3abe40bb3f1801ef7946e831..ebd744b08e27d6fc6dda31ada7ad8bb1 } else { if (fallDistance >= 2.0F) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index e409c6c4f4da1cb2d4a42971dbc362a258a51d3b..0c1d64731c3c9581b0cf9b720057ef07be4f764e 100644 +index 02457e346b43f0ac76bb03f482d2a8bc7ef1d3af..f8985617ea339804356784ac69b4361df738300e 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -2600,5 +2600,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0214-Make-lightning-rod-range-configurable.patch b/patches/server/0213-Make-lightning-rod-range-configurable.patch similarity index 92% rename from patches/server/0214-Make-lightning-rod-range-configurable.patch rename to patches/server/0213-Make-lightning-rod-range-configurable.patch index 7379c440e..30f89fe88 100644 --- a/patches/server/0214-Make-lightning-rod-range-configurable.patch +++ b/patches/server/0213-Make-lightning-rod-range-configurable.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Make lightning rod range configurable diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 54c353224ae3e72544af2a34304039b58a2b0efe..e3e4dc544e4d2a2ae01c3f653d2f0de3ddbc5062 100644 +index 6add1cb8a35c1e16670ba2e9db7878f27bbf3752..8c1e06dab7198e8331d39c39a27b6bce854fae9e 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1017,7 +1017,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -18,7 +18,7 @@ index 54c353224ae3e72544af2a34304039b58a2b0efe..e3e4dc544e4d2a2ae01c3f653d2f0de3 return optional.map((blockposition1) -> { return blockposition1.above(1); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index dcb0aca3303b92f955700f784934396a4808f7ed..f1db3948b7284da35b9905862229bafb87a863fb 100644 +index 11e563ba1aec3006205de91761ec14698577267a..f53139a2db91403f17608f05149076c37db05d04 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -380,6 +380,7 @@ public class PurpurConfig { diff --git a/patches/server/0215-Burp-after-eating-food-fills-hunger-bar-completely.patch b/patches/server/0214-Burp-after-eating-food-fills-hunger-bar-completely.patch similarity index 97% rename from patches/server/0215-Burp-after-eating-food-fills-hunger-bar-completely.patch rename to patches/server/0214-Burp-after-eating-food-fills-hunger-bar-completely.patch index 8d4aedefe..ff00e969e 100644 --- a/patches/server/0215-Burp-after-eating-food-fills-hunger-bar-completely.patch +++ b/patches/server/0214-Burp-after-eating-food-fills-hunger-bar-completely.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Burp after eating food fills hunger bar completely diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index ebd744b08e27d6fc6dda31ada7ad8bb1864a6982..bae254bd927cf1715a98c55354941c2341f69694 100644 +index b0661f7ad41157c5e25ee2d87f9a0efd79039475..8e81bdbaaf25d4a7e5724260b59fd327d36bc203 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -196,6 +196,8 @@ public abstract class Player extends LivingEntity { diff --git a/patches/server/0216-Allow-player-join-full-server-by-permission.patch b/patches/server/0215-Allow-player-join-full-server-by-permission.patch similarity index 89% rename from patches/server/0216-Allow-player-join-full-server-by-permission.patch rename to patches/server/0215-Allow-player-join-full-server-by-permission.patch index de1e0c737..05b26f2e3 100644 --- a/patches/server/0216-Allow-player-join-full-server-by-permission.patch +++ b/patches/server/0215-Allow-player-join-full-server-by-permission.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Allow player join full server by permission diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index a387b3b5aa510dcd99d71446d723ce79c82dad33..1b61cc59a120261dbf178865471a7ee2620977f1 100644 +index cf016f139895690d5a0e0ef2709e31eaea31649a..eea99b8f6fabae1b0c5c9ef55798173f8ba99f28 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -765,7 +765,7 @@ public abstract class PlayerList { +@@ -764,7 +764,7 @@ public abstract class PlayerList { event.disallow(PlayerLoginEvent.Result.KICK_BANNED, PaperAdventure.asAdventure(chatmessage)); // Paper - Adventure } else { // return this.players.size() >= this.maxPlayers && !this.d(gameprofile) ? new ChatMessage("multiplayer.disconnect.server_full") : null; diff --git a/patches/server/0217-Populator-seed-controls.patch b/patches/server/0216-Populator-seed-controls.patch similarity index 100% rename from patches/server/0217-Populator-seed-controls.patch rename to patches/server/0216-Populator-seed-controls.patch diff --git a/patches/server/0218-Add-permission-bypass-for-portal-waiting.patch b/patches/server/0217-Add-permission-bypass-for-portal-waiting.patch similarity index 94% rename from patches/server/0218-Add-permission-bypass-for-portal-waiting.patch rename to patches/server/0217-Add-permission-bypass-for-portal-waiting.patch index 6af7fee31..9880b45e7 100644 --- a/patches/server/0218-Add-permission-bypass-for-portal-waiting.patch +++ b/patches/server/0217-Add-permission-bypass-for-portal-waiting.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add permission bypass for portal waiting diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index bae254bd927cf1715a98c55354941c2341f69694..8d62bbb4fb818bea940bbac565cb8e30cb85818e 100644 +index 8e81bdbaaf25d4a7e5724260b59fd327d36bc203..841e21e160f728af12daef1eba8d25e5cd081bda 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -184,6 +184,7 @@ public abstract class Player extends LivingEntity { diff --git a/patches/server/0219-Shulker-spawn-from-bullet-options.patch b/patches/server/0218-Shulker-spawn-from-bullet-options.patch similarity index 100% rename from patches/server/0219-Shulker-spawn-from-bullet-options.patch rename to patches/server/0218-Shulker-spawn-from-bullet-options.patch diff --git a/patches/server/0220-Eating-glow-berries-adds-glow-effect.patch b/patches/server/0219-Eating-glow-berries-adds-glow-effect.patch similarity index 97% rename from patches/server/0220-Eating-glow-berries-adds-glow-effect.patch rename to patches/server/0219-Eating-glow-berries-adds-glow-effect.patch index 439dd0dfc..7bbc45847 100644 --- a/patches/server/0220-Eating-glow-berries-adds-glow-effect.patch +++ b/patches/server/0219-Eating-glow-berries-adds-glow-effect.patch @@ -18,7 +18,7 @@ index 89d4b7e4cd4222b61b49833fceda56ffa39710fa..1eb50f0bc41db79f091f900861ba71d7 public static final Item SOUL_CAMPFIRE = registerBlock(Blocks.SOUL_CAMPFIRE, CreativeModeTab.TAB_DECORATIONS); public static final Item SHROOMLIGHT = registerBlock(Blocks.SHROOMLIGHT, CreativeModeTab.TAB_DECORATIONS); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 35a0a270fad348a2f60ae3f9a480f1a527f525ed..a45d894c8234babc0a7b3b8ee03b92d192df168f 100644 +index 26d78cdc82d83138f1f0916f8ff958aa32c33339..c12cb45034ed98f9fe24b38c0c86adbce97ae3d7 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -173,6 +173,7 @@ public class PurpurWorldConfig { diff --git a/patches/server/0221-Option-to-make-drowned-break-doors.patch b/patches/server/0220-Option-to-make-drowned-break-doors.patch similarity index 100% rename from patches/server/0221-Option-to-make-drowned-break-doors.patch rename to patches/server/0220-Option-to-make-drowned-break-doors.patch diff --git a/patches/server/0222-Configurable-hunger-starvation-damage.patch b/patches/server/0221-Configurable-hunger-starvation-damage.patch similarity index 100% rename from patches/server/0222-Configurable-hunger-starvation-damage.patch rename to patches/server/0221-Configurable-hunger-starvation-damage.patch diff --git a/patches/server/0223-Redirect-System.out-calls-to-plugin-loggers.patch b/patches/server/0222-Redirect-System.out-calls-to-plugin-loggers.patch similarity index 95% rename from patches/server/0223-Redirect-System.out-calls-to-plugin-loggers.patch rename to patches/server/0222-Redirect-System.out-calls-to-plugin-loggers.patch index 4c848879b..7c0bacc1a 100644 --- a/patches/server/0223-Redirect-System.out-calls-to-plugin-loggers.patch +++ b/patches/server/0222-Redirect-System.out-calls-to-plugin-loggers.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Redirect System.out calls to plugin loggers diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index a36750cc08fbda22362211507a10f9e1d89e0a8a..1da53b46c69dc5cfca0fea805cc491e79a841153 100644 +index c7db9d6357935c6004867ded2b422f8a2b4a6668..77eb1b3bf77d496fb0675fbb681efb0df32fb5c4 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -178,8 +178,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -91,10 +91,10 @@ index 0000000000000000000000000000000000000000..f88da0b86a683b25d429ceea4a36d6dd + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 10fbfe04369861cf27d8eff941157f2a4b4bbcc2..c687ab0e629f40e5c0900b27f9243e09b7d217d4 100644 +index 34a2ca46b6a049c744e63e443beddf2d238da2ce..badfecb3613cebf66a27610baf494a95a74a0214 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -278,7 +278,7 @@ public final class CraftServer implements Server { +@@ -284,7 +284,7 @@ public final class CraftServer implements Server { public int reloadCount; private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper public static Exception excessiveVelEx; // Paper - Velocity warnings diff --git a/patches/server/0224-Armor-click-equip-options.patch b/patches/server/0223-Armor-click-equip-options.patch similarity index 98% rename from patches/server/0224-Armor-click-equip-options.patch rename to patches/server/0223-Armor-click-equip-options.patch index 7ad1c1900..6852dac17 100644 --- a/patches/server/0224-Armor-click-equip-options.patch +++ b/patches/server/0223-Armor-click-equip-options.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Armor click equip options diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index dd5bc68171ce5a67ecf30de65f0c1d280cc88419..38323c95dc36e5ead294670ce120114492de37d5 100644 +index 2b2ac97e31dc8742f0294ec065eaf96959df6d34..693c6cbd90cde4d605931c6d80ae8056e260bf34 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java @@ -499,7 +499,7 @@ public class ServerPlayerGameMode { diff --git a/patches/server/0225-Add-uptime-command.patch b/patches/server/0224-Add-uptime-command.patch similarity index 95% rename from patches/server/0225-Add-uptime-command.patch rename to patches/server/0224-Add-uptime-command.patch index 7f9a9172a..f282cf272 100644 --- a/patches/server/0225-Add-uptime-command.patch +++ b/patches/server/0224-Add-uptime-command.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add uptime command diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 73953ea69776bfe1dcb1504cd14a0f003f1b5766..528fd87ae1c1c01e13885d88fc8056b0f932fb61 100644 +index 386e9ad013369633e2be543b9281e5a5fdce9c74..48a70900082c6c2c99c955a6ac40b48859a74979 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -201,6 +201,7 @@ public class Commands { @@ -17,19 +17,19 @@ index 73953ea69776bfe1dcb1504cd14a0f003f1b5766..528fd87ae1c1c01e13885d88fc8056b0 } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index a456c7f6eedb2cff1b58ec6f0ef330c74dfcdaed..8d9704ce916b13de96a6c95bfcb553ddd130b21c 100644 +index 807269b3fc6a1fe7cdbaef6f5336ee40e988505b..2576e2c6bce86cacc54092559f6ed05969f3e01c 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -294,6 +294,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; public boolean serverAutoSave = false; // Paper diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index f1db3948b7284da35b9905862229bafb87a863fb..2def6767b2ee97d9c662b93796ed97bcfd3bbebc 100644 +index f53139a2db91403f17608f05149076c37db05d04..820ef4ade5a38ca158ee5ec841abbdde80fc1399 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -166,6 +166,7 @@ public class PurpurConfig { diff --git a/patches/server/0226-Structure-seed-options.patch b/patches/server/0225-Structure-seed-options.patch similarity index 92% rename from patches/server/0226-Structure-seed-options.patch rename to patches/server/0225-Structure-seed-options.patch index 0aa483039..6a89e5730 100644 --- a/patches/server/0226-Structure-seed-options.patch +++ b/patches/server/0225-Structure-seed-options.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Structure seed options diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index f71cc1f5e5d594e82a4e6132d438bae74b9370a7..77948e19dd99b6f30bf294c9d5308228a271929b 100644 +index a4292e82cdb678d941056e5b059753eb4447b661..5ee7dfda765e3a2f49ee5cd0f4cb7cd5929ac48b 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -389,6 +389,17 @@ public abstract class ChunkGenerator { +@@ -426,6 +426,17 @@ public abstract class ChunkGenerator { case "village": seed = conf.villageSeed; break; @@ -27,7 +27,7 @@ index f71cc1f5e5d594e82a4e6132d438bae74b9370a7..77948e19dd99b6f30bf294c9d5308228 updated.put(entry.getKey(), new StructureFeatureConfiguration(feature.spacing(), feature.separation(), seed)); diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 2def6767b2ee97d9c662b93796ed97bcfd3bbebc..97dba790a02fe54da4278c7e913dbbcf8a25d126 100644 +index 820ef4ade5a38ca158ee5ec841abbdde80fc1399..a2e3594c92f3b16fe70d327616040a4afac77765 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -247,6 +247,9 @@ public class PurpurConfig { diff --git a/patches/server/0227-Tool-actionable-options.patch b/patches/server/0226-Tool-actionable-options.patch similarity index 100% rename from patches/server/0227-Tool-actionable-options.patch rename to patches/server/0226-Tool-actionable-options.patch diff --git a/patches/server/0228-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch b/patches/server/0227-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch similarity index 89% rename from patches/server/0228-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch rename to patches/server/0227-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch index 6bfa3bf9a..ea8d5da3d 100644 --- a/patches/server/0228-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch +++ b/patches/server/0227-SPIGOT-5988-Fix-bed-respawn-location-not-resetting.patch @@ -5,10 +5,10 @@ Subject: [PATCH] SPIGOT-5988 Fix bed respawn location not resetting diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 1b61cc59a120261dbf178865471a7ee2620977f1..9770a8b7ce0b27c0cb9851ac942b3089a053dc7b 100644 +index eea99b8f6fabae1b0c5c9ef55798173f8ba99f28..71705517943f62ae85a9298cf484bb7c78438267 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -903,6 +903,7 @@ public abstract class PlayerList { +@@ -902,6 +902,7 @@ public abstract class PlayerList { location = new Location(worldserver1.getWorld(), vec3d.x, vec3d.y, vec3d.z, f1, 0.0F); } else if (blockposition != null) { entityplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); @@ -17,7 +17,7 @@ index 1b61cc59a120261dbf178865471a7ee2620977f1..9770a8b7ce0b27c0cb9851ac942b3089 } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 97dba790a02fe54da4278c7e913dbbcf8a25d126..60412d24201bbd61162662b3a2270eecab39fa3d 100644 +index a2e3594c92f3b16fe70d327616040a4afac77765..0006d4a7e67cf282bdad93017ceffc45a36e9885 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -407,6 +407,7 @@ public class PurpurConfig { diff --git a/patches/server/0229-Store-placer-on-Block-when-placed.patch b/patches/server/0228-Store-placer-on-Block-when-placed.patch similarity index 94% rename from patches/server/0229-Store-placer-on-Block-when-placed.patch rename to patches/server/0228-Store-placer-on-Block-when-placed.patch index 66927c5fc..ab597766f 100644 --- a/patches/server/0229-Store-placer-on-Block-when-placed.patch +++ b/patches/server/0228-Store-placer-on-Block-when-placed.patch @@ -25,10 +25,10 @@ index 115f8eb919e90bc4a79db1d0f7875a31cc962f07..d8df4457c28225508d9cb53ed6ea12d2 world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point } diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 94a69b7a1443231cf807fb792478c35334f73e62..2d742ba9d05b599c38b4ffe78b8cf7044652e95f 100644 +index 577f38fcff55ef23fcacce1b05b6d0de117efd5e..938e427aaf762e107685579cbf3f4d2076112067 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -465,7 +465,17 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -482,7 +482,17 @@ public class Block extends BlockBehaviour implements ItemLike { Block.dropResources(state, world, pos, blockEntity, player, stack); } diff --git a/patches/server/0230-Summoner-API.patch b/patches/server/0229-Summoner-API.patch similarity index 100% rename from patches/server/0230-Summoner-API.patch rename to patches/server/0229-Summoner-API.patch diff --git a/patches/server/0231-Customizable-sleeping-actionbar-messages.patch b/patches/server/0230-Customizable-sleeping-actionbar-messages.patch similarity index 95% rename from patches/server/0231-Customizable-sleeping-actionbar-messages.patch rename to patches/server/0230-Customizable-sleeping-actionbar-messages.patch index a0317d914..2f42d3b8c 100644 --- a/patches/server/0231-Customizable-sleeping-actionbar-messages.patch +++ b/patches/server/0230-Customizable-sleeping-actionbar-messages.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Customizable sleeping actionbar messages diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index e3e4dc544e4d2a2ae01c3f653d2f0de3ddbc5062..7bd74f7bdd23636f7d6c4f2325fd6430780fc95d 100644 +index 8c1e06dab7198e8331d39c39a27b6bce854fae9e..11208321ae766bfc5506e54c280894e132f10faa 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1060,11 +1060,29 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -40,7 +40,7 @@ index e3e4dc544e4d2a2ae01c3f653d2f0de3ddbc5062..7bd74f7bdd23636f7d6c4f2325fd6430 } diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index 60412d24201bbd61162662b3a2270eecab39fa3d..adfec9c94849b5371e9188eb0ce18565c2d17fc9 100644 +index 0006d4a7e67cf282bdad93017ceffc45a36e9885..419b5766ffcd240751b34f340f53ccf76523521c 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -168,6 +168,8 @@ public class PurpurConfig { diff --git a/patches/server/0232-option-to-disable-shulker-box-items-from-dropping-co.patch b/patches/server/0231-option-to-disable-shulker-box-items-from-dropping-co.patch similarity index 96% rename from patches/server/0232-option-to-disable-shulker-box-items-from-dropping-co.patch rename to patches/server/0231-option-to-disable-shulker-box-items-from-dropping-co.patch index 929ae962c..690469dd7 100644 --- a/patches/server/0232-option-to-disable-shulker-box-items-from-dropping-co.patch +++ b/patches/server/0231-option-to-disable-shulker-box-items-from-dropping-co.patch @@ -19,7 +19,7 @@ index 6c261b9ddee80139140bd1f091fcdacc3a70c8ef..65917d1438b0f480385e9117ba2a386e if (nbttagcompound != null) { diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 2eb8beff069fea2cff9b95bffc7adaef331197f9..def41828b2d2c8b37f03a571924bc62152c6f2fe 100644 +index 2b455827bc9db50dc0821672a98167a337f5c2b9..3caf11332258b6bbb6cf239b67f5fa58841b90c9 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -174,6 +174,7 @@ public class PurpurWorldConfig { diff --git a/patches/server/0233-Silk-touchable-budding-amethyst.patch b/patches/server/0232-Silk-touchable-budding-amethyst.patch similarity index 100% rename from patches/server/0233-Silk-touchable-budding-amethyst.patch rename to patches/server/0232-Silk-touchable-budding-amethyst.patch diff --git a/patches/server/0234-Big-dripleaf-tilt-delay.patch b/patches/server/0233-Big-dripleaf-tilt-delay.patch similarity index 100% rename from patches/server/0234-Big-dripleaf-tilt-delay.patch rename to patches/server/0233-Big-dripleaf-tilt-delay.patch diff --git a/patches/server/0235-Player-ridable-in-water-option.patch b/patches/server/0234-Player-ridable-in-water-option.patch similarity index 96% rename from patches/server/0235-Player-ridable-in-water-option.patch rename to patches/server/0234-Player-ridable-in-water-option.patch index 44bf921c3..d538226da 100644 --- a/patches/server/0235-Player-ridable-in-water-option.patch +++ b/patches/server/0234-Player-ridable-in-water-option.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Player ridable in water option diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 8d62bbb4fb818bea940bbac565cb8e30cb85818e..4d7e9a0d59ca2e3d9df1a7e47637bdbd6bf26809 100644 +index 841e21e160f728af12daef1eba8d25e5cd081bda..8102ee4cc9f936de20a0cb6875ada524800f28f7 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -2062,6 +2062,11 @@ public abstract class Player extends LivingEntity { diff --git a/patches/server/0236-Config-to-disable-Enderman-teleport-on-projectile-hi.patch b/patches/server/0235-Config-to-disable-Enderman-teleport-on-projectile-hi.patch similarity index 100% rename from patches/server/0236-Config-to-disable-Enderman-teleport-on-projectile-hi.patch rename to patches/server/0235-Config-to-disable-Enderman-teleport-on-projectile-hi.patch diff --git a/patches/server/0237-Fix-Important-Issue-Crash-with-Plugin-or-Datapack-Ge.patch b/patches/server/0236-Fix-Important-Issue-Crash-with-Plugin-or-Datapack-Ge.patch similarity index 100% rename from patches/server/0237-Fix-Important-Issue-Crash-with-Plugin-or-Datapack-Ge.patch rename to patches/server/0236-Fix-Important-Issue-Crash-with-Plugin-or-Datapack-Ge.patch diff --git a/patches/server/0238-Add-compass-command.patch b/patches/server/0237-Add-compass-command.patch similarity index 96% rename from patches/server/0238-Add-compass-command.patch rename to patches/server/0237-Add-compass-command.patch index a635171a6..274672cf8 100644 --- a/patches/server/0238-Add-compass-command.patch +++ b/patches/server/0237-Add-compass-command.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add compass command diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 528fd87ae1c1c01e13885d88fc8056b0f932fb61..bfad241892b8280d261ab8301245b91b5403b51a 100644 +index 48a70900082c6c2c99c955a6ac40b48859a74979..8c2424b0917d278bb0b9e687d116d8de73696446 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -203,6 +203,7 @@ public class Commands { @@ -17,7 +17,7 @@ index 528fd87ae1c1c01e13885d88fc8056b0f932fb61..bfad241892b8280d261ab8301245b91b if (environment.includeIntegrated) { diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index ba690d310ee6b9d3a1b1bf2ae13e016daabeb0fc..3582316c356ea0ed773602ebbe57cad4ad7a6299 100644 +index d4b9a31fb3a26a8939e1d30f5b6bc2d66fc7620a..6d0257c35081991e925d85348aff168c6ca58ad7 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -261,6 +261,7 @@ public class ServerPlayer extends Player { @@ -44,7 +44,7 @@ index ba690d310ee6b9d3a1b1bf2ae13e016daabeb0fc..3582316c356ea0ed773602ebbe57cad4 } // CraftBukkit start - World fallback code, either respawn location or global spawn -@@ -2561,5 +2564,13 @@ public class ServerPlayer extends Player { +@@ -2563,5 +2566,13 @@ public class ServerPlayer extends Player { public void tpsBar(boolean tpsBar) { this.tpsBar = tpsBar; } @@ -81,7 +81,7 @@ index 9d541c9e53f3f8db871f01f8d083e4cfc0de0de1..046bf9cbf02b002e89f7d39b616dd0f5 CompoundTag compoundTag = stack.getOrCreateTag(); if (compoundTag.contains("LodestoneTracked") && !compoundTag.getBoolean("LodestoneTracked")) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java -index adfec9c94849b5371e9188eb0ce18565c2d17fc9..526a1032a2f61792c7f5791dbb3e9a7292fc186d 100644 +index 419b5766ffcd240751b34f340f53ccf76523521c..07bdddf241df745f483a7318f5c08ac791958d05 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -369,6 +369,11 @@ public class PurpurConfig { @@ -111,7 +111,7 @@ index adfec9c94849b5371e9188eb0ce18565c2d17fc9..526a1032a2f61792c7f5791dbb3e9a72 hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector); uptimeFormat = getString("settings.command.uptime.format", uptimeFormat); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index d481c7235af2bc9144b9b03fed83e283fe35725f..3f6c3dc857bf212b069f4a848d973de281efe64a 100644 +index 1facdf93ce63c786a459cfff8293a41477f91d21..c053a04fb5de1c1974a8bc34de41e736d3b27438 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -175,6 +175,7 @@ public class PurpurWorldConfig { diff --git a/patches/server/0239-Config-to-prevent-horses-from-standing-with-riders.patch b/patches/server/0238-Config-to-prevent-horses-from-standing-with-riders.patch similarity index 100% rename from patches/server/0239-Config-to-prevent-horses-from-standing-with-riders.patch rename to patches/server/0238-Config-to-prevent-horses-from-standing-with-riders.patch diff --git a/patches/server/0240-Toggle-for-kinetic-damage.patch b/patches/server/0239-Toggle-for-kinetic-damage.patch similarity index 92% rename from patches/server/0240-Toggle-for-kinetic-damage.patch rename to patches/server/0239-Toggle-for-kinetic-damage.patch index abdcda903..8d6e94b2e 100644 --- a/patches/server/0240-Toggle-for-kinetic-damage.patch +++ b/patches/server/0239-Toggle-for-kinetic-damage.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Toggle for kinetic damage diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 3bef0780fa95a63887fdb64cb1b038d44cf1c028..34bf7a2a869329a4a1dd8b36fd8ab09fbcd3669e 100644 +index ad3ef0b1f3d6d00a0aca909812127b09302e5a8c..4ed72b06786505f61502772bba973b12c2076be0 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -2792,7 +2792,11 @@ public abstract class LivingEntity extends Entity { @@ -22,7 +22,7 @@ index 3bef0780fa95a63887fdb64cb1b038d44cf1c028..34bf7a2a869329a4a1dd8b36fd8ab09f } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 0cb6779f0da78830564b7d30ac2c1e018b9a0861..6e0c228e6171ce0acc3ee2a85527785a2e1204fb 100644 +index a00e489b13e12eee56505dcc146a759020e98546..652adf619711171ac98c1b4dce5d8ce7acb0f769 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -137,12 +137,14 @@ public class PurpurWorldConfig { diff --git a/patches/server/0241-Add-Option-for-disable-observer-clocks.patch b/patches/server/0240-Add-Option-for-disable-observer-clocks.patch similarity index 95% rename from patches/server/0241-Add-Option-for-disable-observer-clocks.patch rename to patches/server/0240-Add-Option-for-disable-observer-clocks.patch index 0e66e408b..f9a175e31 100644 --- a/patches/server/0241-Add-Option-for-disable-observer-clocks.patch +++ b/patches/server/0240-Add-Option-for-disable-observer-clocks.patch @@ -18,7 +18,7 @@ index 101317912b8299f5be406b75c19cfddb30c1f3f3..21f5632bbc58a1c34b85d9fef2408938 } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 6e0c228e6171ce0acc3ee2a85527785a2e1204fb..a986b6a2ef808a4b4796c160820e73b08121a889 100644 +index 652adf619711171ac98c1b4dce5d8ce7acb0f769..830ce09925b39286eafb0166d897b4daa87346f1 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -320,6 +320,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0242-Customizeable-Zombie-Villager-curing-times.patch b/patches/server/0241-Customizeable-Zombie-Villager-curing-times.patch similarity index 100% rename from patches/server/0242-Customizeable-Zombie-Villager-curing-times.patch rename to patches/server/0241-Customizeable-Zombie-Villager-curing-times.patch diff --git a/patches/server/0243-Option-for-sponges-to-work-on-lava.patch b/patches/server/0242-Option-for-sponges-to-work-on-lava.patch similarity index 100% rename from patches/server/0243-Option-for-sponges-to-work-on-lava.patch rename to patches/server/0242-Option-for-sponges-to-work-on-lava.patch diff --git a/patches/server/0244-Toggle-for-Wither-s-spawn-sound.patch b/patches/server/0243-Toggle-for-Wither-s-spawn-sound.patch similarity index 100% rename from patches/server/0244-Toggle-for-Wither-s-spawn-sound.patch rename to patches/server/0243-Toggle-for-Wither-s-spawn-sound.patch diff --git a/patches/server/0245-Cactus-breaks-from-solid-neighbors-config.patch b/patches/server/0244-Cactus-breaks-from-solid-neighbors-config.patch similarity index 100% rename from patches/server/0245-Cactus-breaks-from-solid-neighbors-config.patch rename to patches/server/0244-Cactus-breaks-from-solid-neighbors-config.patch diff --git a/patches/server/0246-Config-to-remove-curse-of-binding-with-weakness.patch b/patches/server/0245-Config-to-remove-curse-of-binding-with-weakness.patch similarity index 100% rename from patches/server/0246-Config-to-remove-curse-of-binding-with-weakness.patch rename to patches/server/0245-Config-to-remove-curse-of-binding-with-weakness.patch diff --git a/patches/server/0247-Conduit-behavior-configuration.patch b/patches/server/0246-Conduit-behavior-configuration.patch similarity index 100% rename from patches/server/0247-Conduit-behavior-configuration.patch rename to patches/server/0246-Conduit-behavior-configuration.patch diff --git a/patches/server/0248-Cauldron-fill-chances.patch b/patches/server/0247-Cauldron-fill-chances.patch similarity index 100% rename from patches/server/0248-Cauldron-fill-chances.patch rename to patches/server/0247-Cauldron-fill-chances.patch diff --git a/patches/server/0249-Config-to-allow-mobs-to-pathfind-over-rails.patch b/patches/server/0248-Config-to-allow-mobs-to-pathfind-over-rails.patch similarity index 100% rename from patches/server/0249-Config-to-allow-mobs-to-pathfind-over-rails.patch rename to patches/server/0248-Config-to-allow-mobs-to-pathfind-over-rails.patch diff --git a/patches/server/0250-Add-force-and-prompt-parameters-to-resource-pack-api.patch b/patches/server/0249-Add-force-and-prompt-parameters-to-resource-pack-api.patch similarity index 95% rename from patches/server/0250-Add-force-and-prompt-parameters-to-resource-pack-api.patch rename to patches/server/0249-Add-force-and-prompt-parameters-to-resource-pack-api.patch index 573040cdc..e4273a62b 100644 --- a/patches/server/0250-Add-force-and-prompt-parameters-to-resource-pack-api.patch +++ b/patches/server/0249-Add-force-and-prompt-parameters-to-resource-pack-api.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add force and prompt parameters to resource pack api diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 0c1d64731c3c9581b0cf9b720057ef07be4f764e..588214ed4ed06541d0c561c9f1da63c8fbf78f6c 100644 +index f8985617ea339804356784ac69b4361df738300e..524f059ec5e064a4f9798c29faa2fff744c81bac 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -25,6 +25,8 @@ import java.util.WeakHashMap; diff --git a/patches/server/0251-Shulker-change-color-with-dye.patch b/patches/server/0250-Shulker-change-color-with-dye.patch similarity index 100% rename from patches/server/0251-Shulker-change-color-with-dye.patch rename to patches/server/0250-Shulker-change-color-with-dye.patch diff --git a/patches/server/0252-Extended-OfflinePlayer-API.patch b/patches/server/0251-Extended-OfflinePlayer-API.patch similarity index 99% rename from patches/server/0252-Extended-OfflinePlayer-API.patch rename to patches/server/0251-Extended-OfflinePlayer-API.patch index 22b8d8a1a..7e0c66aa6 100644 --- a/patches/server/0252-Extended-OfflinePlayer-API.patch +++ b/patches/server/0251-Extended-OfflinePlayer-API.patch @@ -223,7 +223,7 @@ index b20bfe5ab165bf86985e5ff2f93f415d9710e0e4..830d3163990002c7c1ba0a5a63531fa1 + // Purpur end - OfflinePlayer API } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 3230631551e530afdf0022a4c863cc57c0374df2..d0408f5554b68aa2009ba7d67591c3c628403deb 100644 +index 524f059ec5e064a4f9798c29faa2fff744c81bac..53ec1f1725a8b7bff4d93f4d1d6a7344818799f0 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1925,6 +1925,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0254-Added-the-ability-to-add-combustible-items.patch b/patches/server/0252-Added-the-ability-to-add-combustible-items.patch similarity index 90% rename from patches/server/0254-Added-the-ability-to-add-combustible-items.patch rename to patches/server/0252-Added-the-ability-to-add-combustible-items.patch index ab3f186a0..ee5b2aa7f 100644 --- a/patches/server/0254-Added-the-ability-to-add-combustible-items.patch +++ b/patches/server/0252-Added-the-ability-to-add-combustible-items.patch @@ -36,7 +36,7 @@ index 2c64622577fdb6c2a5746471121403b633bf9042..0bd838b95d87fd2436f3674b7f16155e private int maxStack = MAX_STACK; public List transaction = new java.util.ArrayList(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c687ab0e629f40e5c0900b27f9243e09b7d217d4..012aa07f2f9e2711fbc4dc3af640bfbc59b8dbce 100644 +index badfecb3613cebf66a27610baf494a95a74a0214..c72777cacff992661a35f3464e1040e38977d016 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -4,7 +4,6 @@ import com.google.common.base.Charsets; @@ -55,15 +55,15 @@ index c687ab0e629f40e5c0900b27f9243e09b7d217d4..012aa07f2f9e2711fbc4dc3af640bfbc import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import java.awt.image.BufferedImage; import java.io.File; -@@ -100,6 +98,7 @@ import net.minecraft.world.level.GameType; - import net.minecraft.world.level.LevelSettings; +@@ -101,6 +99,7 @@ import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.biome.BiomeManager; + import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; - import net.minecraft.world.level.levelgen.PatrolSpawner; -@@ -230,6 +229,7 @@ import org.bukkit.potion.PotionEffectType; + import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +@@ -236,6 +235,7 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitWorker; import org.bukkit.util.StringUtil; import org.bukkit.util.permissions.DefaultPermissions; @@ -71,7 +71,7 @@ index c687ab0e629f40e5c0900b27f9243e09b7d217d4..012aa07f2f9e2711fbc4dc3af640bfbc import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.error.MarkedYAMLException; -@@ -1362,6 +1362,19 @@ public final class CraftServer implements Server { +@@ -1384,6 +1384,19 @@ public final class CraftServer implements Server { return true; } diff --git a/patches/server/0253-Fix-sinking-boats.patch b/patches/server/0253-Fix-sinking-boats.patch deleted file mode 100644 index b08cbb0cb..000000000 --- a/patches/server/0253-Fix-sinking-boats.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 22 Aug 2021 14:45:14 -0500 -Subject: [PATCH] Fix sinking boats - - -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -index 0f6e577e47a3b1ce5a356801b6192d1d306d19c2..24c8e3eedcc95a6d12477fb6a5150976d2f5e533 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -@@ -695,7 +695,10 @@ public class Boat extends Entity { - this.invFriction = 0.05F; - if (this.oldStatus == Boat.Status.IN_AIR && this.status != Boat.Status.IN_AIR && this.status != Boat.Status.ON_LAND) { - this.waterLevel = this.getY(1.0D); -- this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).add(0.0, ((double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D) - this.getY(), 0.0)); // Paper -+ // Purpur start - boats should not sink -+ this.setPos(this.getX(), (double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D, this.getZ()); -+ this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); -+ // Purpur end - this.lastYd = 0.0D; - this.status = Boat.Status.IN_WATER; - } else { diff --git a/patches/server/0255-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch b/patches/server/0253-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch similarity index 97% rename from patches/server/0255-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch rename to patches/server/0253-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch index fa0b72abd..ca3215c7f 100644 --- a/patches/server/0255-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch +++ b/patches/server/0253-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Option for if rain and thunder should stop on sleep diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 7bd74f7bdd23636f7d6c4f2325fd6430780fc95d..754a5c63c2a7b89082306ec189273bdc89735ff3 100644 +index 11208321ae766bfc5506e54c280894e132f10faa..a2da1b6880ea23b3a17dcf2a5f85e96c9b4b842d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1112,6 +1112,7 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0256-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch b/patches/server/0254-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch similarity index 100% rename from patches/server/0256-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch rename to patches/server/0254-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch diff --git a/patches/server/0257-Shift-right-click-to-use-exp-for-mending.patch b/patches/server/0255-Shift-right-click-to-use-exp-for-mending.patch similarity index 96% rename from patches/server/0257-Shift-right-click-to-use-exp-for-mending.patch rename to patches/server/0255-Shift-right-click-to-use-exp-for-mending.patch index 010daf7b0..ff88f2da8 100644 --- a/patches/server/0257-Shift-right-click-to-use-exp-for-mending.patch +++ b/patches/server/0255-Shift-right-click-to-use-exp-for-mending.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Shift right click to use exp for mending diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 38323c95dc36e5ead294670ce120114492de37d5..a4410485d8b1b8bfbbd72240f078ed5e3af0d0de 100644 +index 693c6cbd90cde4d605931c6d80ae8056e260bf34..645c76e6dd50d915263db576650c7a62a238d5ea 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java @@ -526,6 +526,7 @@ public class ServerPlayerGameMode { @@ -36,7 +36,7 @@ index 38323c95dc36e5ead294670ce120114492de37d5..a4410485d8b1b8bfbbd72240f078ed5e + // Purpur end } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 43d124818c4538bc0d84111dfab25c38aab249c1..67433627b69b81b5ddaa24600ab87de8999d962e 100644 +index a015afdc3fedb0c86a1bc2a59ee37fd41d74b8fd..852f7efbd2c60d51d50bf19df3acb6efdb5833ee 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1902,6 +1902,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser